MAIN MENU
Solutions

Paquets d'installation

blue box
Starter pack

Toute la puissance de Devolutions à moitié prix pour les équipes de 5

Preuve de concept : 100+ utilisateurs?

Vue d'ensemble rapide

Conformité

Votre partenaire de confiance en matière de sécurité et de conformité.

Intégrations

Unifiez vos solutions avec les intégrations qu'offre Devolutions

Le blogue Devolutions

Annonces, mises à jour et analyses de Devolutions

PowerShell
Thumbnail for Séparer l'interface et les données dans PSU : création d'applications et de points de terminaison efficaces

Séparer l'interface et les données dans PSU : création d'applications et de points de terminaison efficaces

Dans cette deuxième partie de la série PSU, découvrez comment séparer l’interface et les données grâce aux applications et aux points de terminaison. Vous apprendrez à créer des tableaux de bord réutilisables, à exposer des données via des services Web et à concevoir des flux de travail d’automatisation plus modulaires et évolutifs.

Dans cette deuxième partie de la série, nous allons séparer l’interface des données. Cette approche vous permet de créer des tableaux de bord élégants et puissants avec quelques lignes de code seulement, tout en tirant parti des services Web pour fournir les données nécessaires.

Comme vous le verrez à la fin, cette approche offre une flexibilité considérable et vous permet de relever facilement des défis qui, autrement, vous donneraient bien du fil à retordre.

Bref rappel : les applications PSU

Si vous avez suivi la partie 1, vous apprécierez immédiatement le premier avantage majeur que PSU offre : il agit comme un système de gestion et un dépôt pour votre code, ce qui vous permet de réutiliser facilement vos travaux antérieurs.

Par exemple, la « liste de services » créée dans la partie 1 est toujours disponible dans PSU. Chaque fois que vous avez besoin d’informations supplémentaires sur vos services, vous pouvez y accéder depuis le tableau de bord principal de PSU :

N’oubliez pas que chaque application PSU est directement accessible via son URL unique; vous pouvez l’ouvrir en naviguant vers son lien, par exemple : http://localhost:5000/list-services/Home

Création d’un tableau de bord d’actions

Nous allons créer un tableau de bord central avec des boutons de navigation. Comme tout ce qui concerne une interface, les tableaux de bord sont simplement des applications PSU. Nous reprenons donc là où nous nous étions arrêtés :

# use a scriptblock to save the different pages to one variable

$Pages = & {

  # FIRST PAGE (root page) defines your cockpit with all of your buttons

  New-UDPage -Name 'Home' -Url '/' -Content {

    # add a small header:

    New-UDTypography -Text 'My personal Dashboard' -Variant h6

    # add three buttons

    New-UDButton -Text 'Services' -OnClick {

      # tell the button what to do when clicked

      # use -Native to open an external app (URL is relative to PSU root)

      Invoke-UDRedirect '/list-services' -Native

    }

    New-UDButton -Text 'Processes' -OnClick {

      # tell the button what to do when clicked

      # DO NOT use -Native to open a child page within this app (URL is relative to this app)

      Invoke-UDRedirect '/list-processes'

    }

    # third button, same as before

    New-UDButton -Text 'Something else' -OnClick {

      Invoke-UDRedirect '/list-more'

    }

  }



  # add as many CHILD PAGES as you need. Their URL is relative to the root URL of this app

  New-UDPage -Name 'Processes' -Url '/list-processes' -Content {

    New-UDTypography -Text 'Here you could implement your own code to display something more useful.'

  }



  New-UDPage -Name 'More' -Url '/list-more' -Content {

    New-UDTypography -Text 'Here you could implement your own code to display something more useful.'

  }

}

New-UDApp -Title 'My Cockpit' -Pages $Pages

Cet exemple illustre quelques concepts fondamentaux. Explorons d’abord l’interface, puis examinons les détails :

Appel d’applications externes

Le bouton « Services » montre comment intégrer des applications externes dans votre tableau de bord. En utilisant Invoke-UDRedirect '/list-services' avec le commutateur -Native, vous pouvez spécifier des URL relatives à la racine PSU principale et accéder à toute autre application créée précédemment.

Bien qu’il soit possible d’incorporer des applications externes de cette façon, ce n’est pas considéré comme une bonne pratique, car cela a un coût : vous perdez la navigation automatique. Le menu de navigation dans le coin supérieur gauche n’est plus disponible dans l’application externe. C’est normal, puisque vous naviguez effectivement vers une application complètement différente.

Appel de sous-pages

Les deux autres boutons fonctionnent différemment : ils naviguent vers des sous-pages de l’application tableau de bord. Ils utilisent le même applet de commande UDRedirect, mais sans le commutateur -Native, de sorte que l’URL fait référence à une sous-page interne créée dans votre tableau de bord à l’aide de New-UDPage.

Comme ces sous-pages font partie de votre application tableau de bord, la navigation automatique fonctionne comme prévu et le menu de navigation reste visible quelle que soit la page affichée.

Puisque vous définissez ces sous-pages dans votre application tableau de bord, vous avez un contrôle total et pouvez facilement ajouter des fonctionnalités d’interface de façon cohérente, par exemple en ajoutant un bouton « Retour à l’accueil » bien visible.

Voici un exemple. Remplacez simplement votre code (et n’oubliez pas de cliquer sur le bouton Enregistrer avant de visualiser l’application) :

function New-CockpitBackBar {

    New-UDStack -Direction row -Spacing 2 -Children {

        New-UDButton -Text '← Home' -OnClick {

            Invoke-UDRedirect '/'

        }

    }

}

# use a scriptblock to save the different pages to one variable

$Pages = & {

  # FIRST PAGE (root page) defines your cockpit with all of your buttons

  New-UDPage -Name 'Home' -Url '/' -Content {

    # add a small header

    New-UDTypography -Text 'My personal Dashboard' -Variant h6

    # add three buttons

    New-UDButton -Text 'Services' -OnClick {

      # tell the button what to do when clicked

      # use -Native to open an external app (URL is relative to PSU root)

      Invoke-UDRedirect '/list-services' -Native

    }

    New-UDButton -Text 'Processes' -OnClick {

      # tell the button what to do when clicked

      # DO NOT use -Native to open a child page within this app (URL is relative to this app)

      Invoke-UDRedirect '/list-processes'

    }

    # third button, same as before

    New-UDButton -Text 'Something else' -OnClick {

      Invoke-UDRedirect '/list-more'

    }

  }



  # add as many CHILD PAGES as you need. Their URL is relative to the root URL of this app

  New-UDPage -Name 'Processes' -Url '/list-processes' -Content {

    New-CockpitBackBar

    New-UDTypography -Text 'Here you could implement your own code to display something more useful.'

  }



  New-UDPage -Name 'More' -Url '/list-more' -Content {

    New-CockpitBackBar

    New-UDTypography -Text 'Here you could implement your own code to display something more useful.'

  }

}

New-UDApp -Title 'My Cockpit' -Pages $Pages

Sur les sous-pages, vous trouverez maintenant un bouton « Home » qui vous ramène commodément à la racine du tableau de bord.


Bouton Home

Qu’en est-il de la réutilisabilité du code?

L’utilisation des sous-pages implique des compromis : vous ne pouvez pas réutiliser le travail investi dans les applications précédentes. Pour que les sous-pages affichent du contenu utile, vous devez y ajouter vous-même le code approprié.

Cela nous amène à de meilleures stratégies de conception. Dans la partie 1, nous avons investi des efforts dans la création de listes de services complètes et les avons mises en œuvre comme une seule application. L’application fonctionnait comme prévu, mais comme vous pouvez le voir maintenant, elle n’est pas réutilisable. Une meilleure approche aurait été de séparer les données et l’interface en composants distincts — et c’est exactement ce que nous allons faire aujourd’hui.

Dans la partie 1, nous avons présenté les applications PSU comme la couche interface (présentation). Pour compléter le tableau, nous allons maintenant présenter les points de terminaison PSU comme la couche données.

Création d’un point de terminaison (alias service Web)

Pour que les informations sur la liste de services développées dans la partie 1 soient véritablement réutilisables, nous aurions dû les implémenter comme un service Web plutôt que comme une application. Corrigeons cela maintenant :

function Get-ServiceProcessId {

    [CmdletBinding()]

    param

    (

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='ServiceName')]

        [string]

        $Name,



        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='ActualService')]

        [System.ServiceProcess.ServiceController]

        $Service,



        [switch]

        $PassThru

    )

    begin

    {

        $hash = Get-CimInstance Win32_Service -ErrorAction Ignore |

        Group-Object -Property Name -AsHashTable -AsString

    }



    process

    {

        # since the user now has the option to either specify the service name

        # or pipe in an actual service, let's look up the pendant so we always

        # have both and can simplify the remaining code

        if ($PSCmdlet.ParameterSetName -eq 'ServiceName')

        {

            $Service = Get-Service -Name $Name -ErrorAction Ignore

        }

        else

        {

            $Name = $Service.Name

        }

        # make sure "0" values are replaced by NULL

        $id = $hash.$Name.ProcessId | Where-Object { $_ -gt 0 }



        if ($PassThru)

        {

            # take the service and add the process ID

            $Service |

            Add-Member -MemberType NoteProperty -Name ProcessId -Value $id -PassThru

        }

        else

        {

            $id

        }

    }

}

# pipe in any object with a property "ProcessId" or "Id", and add a property with

# the actual process name

function Get-ProcessNameById {

    [CmdletBinding()]

    param

    (

        [Parameter(Mandatory, ValueFromPipeline)]

        [Object]

        $InputObject,



        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]

        [int]

        [Alias('Id')]

        $ProcessId,



        [switch]

        $PassThru

    )



    process

    {

        $processName = (Get-Process -Id $ProcessId -ErrorAction Ignore).Name



        if ($PassThru)

        {

            $InputObject |

            Add-Member -MemberType NoteProperty -Name ProcessName -Value $processName -PassThru

        }

        else

        {

            $processName

        }

    }

}

# pipe in services and add a "GroupName" property that identifies the svchost group

function Get-ServiceGroupName {

    [CmdletBinding()]

    param

    (

        [Parameter(Mandatory, ValueFromPipeline)]

        [System.ServiceProcess.ServiceController]

        $Service,



        [switch]

        $PassThru

    )



    process

    {

        $groupName = (Get-CimInstance Win32_Service -Filter "Name='$($Service.Name)'" -ErrorAction Ignore).StartName



        if ($PassThru)

        {

            $Service |

            Add-Member -MemberType NoteProperty -Name GroupName -Value $groupName -PassThru

        }

        else

        {

            $groupName

        }

    }

}

Get-Service -ErrorAction Ignore |

    # ...add the service process ID...

    Get-ServiceProcessId -PassThru |

    # ...take only services that have a process ID...

    Where-Object ProcessId |

    # ...add the process name for the process ID...

    Get-ProcessNameById -PassThru |

    # ...add the service group name so we can differentiate svchost...

    Get-ServiceGroupName -PassThru |

    # ...sort by service displayname...

    Sort-Object -Property DisplayName |

    # select the properties to display in the table

    Select-Object -Property DisplayName, Name, ProcessName, GroupName, ProcessId

Par défaut, le service Web que vous avez créé est sécurisé et nécessite une authentification. Nous aborderons les options d’authentification et de sécurité séparément; pour l’instant, nous allons désactiver l’authentification :

Votre service Web est maintenant accessible à tous, y compris aux sessions PowerShell externes. Testons-le en ouvrant une console PowerShell ordinaire. Votre service Web possède une URL unique — dans notre exemple : http://localhost:5000/get-service. Lancez simplement n’importe quelle console PowerShell et exécutez :

PS> Invoke-RestMethod -Uri http://localhost:5000/get-service

Le service Web vous retourne les données — mission accomplie : les données et l’interface sont maintenant séparées.


Service Web PowerShell

Version finale du tableau de bord

Maintenant que vous savez comment séparer clairement les données de l’interface, nous pouvons revoir notre application tableau de bord en nous concentrant entièrement sur l’interface. Nous ne faisons plus appel à des applications externes; à la place, nous gardons tout axé sur l’interface.

function New-CockpitBackBar {

    New-UDStack -Direction row -Spacing 2 -Children {

        New-UDButton -Text '← Home' -OnClick {

            Invoke-UDRedirect '/'

        }

    }

}

$Pages = & {

  New-UDPage -Name 'Home' -Url '/' -Content {

    New-UDTypography -Text 'My personal Dashboard' -Variant h6

    New-UDButton -Text 'Services' -OnClick {

      # do NOT go to a separate App, handle everything WITHIN this App (do NOT use -Native)

      Invoke-UDRedirect '/list-services'

    }

    New-UDButton -Text 'Processes' -OnClick {

      Invoke-UDRedirect '/list-processes'

    }

    New-UDButton -Text 'Something else' -OnClick {

      Invoke-UDRedirect '/list-more'

    }

  }



  # handle service list in a CHILD PAGE

  New-UDPage -Name 'Services' -Url '/list-services' -Content {

    New-CockpitBackBar



    # get the data from a web service (reusable, modular, flexible)

    $data = Invoke-RestMethod -Uri http://localhost:5000/get-service

    New-UDTable -Data $data

  }

  New-UDPage -Name 'Processes' -Url '/list-processes' -Content {

    New-CockpitBackBar

    New-UDTypography -Text 'Here you could implement your own code to display something more useful.'

  }



  New-UDPage -Name 'More' -Url '/list-more' -Content {

    New-CockpitBackBar

    New-UDTypography -Text 'Here you could implement your own code to display something more useful.'

  }

}

New-UDApp -Title 'My Cockpit' -Pages $Pages

Cliquez sur « View App » pour tester cette version finale. Vous verrez les mêmes trois boutons, mais cette fois, lorsque vous cliquez sur « Services », vous naviguez de façon transparente vers une sous-page affichant la liste de services enrichie. À ce stade, le menu de navigation est toujours disponible, vous avez accès au bouton « Home » et toute la complexité de la création de la liste de services est maintenant déléguée à un service Web.


Services

Prochaine partie

Maintenant que nous avons clarifié comment séparer proprement les données de l’interface, vous avez vu deux des principales fonctionnalités de PSU : les « Apps », qui servent de couche de présentation, et les « Endpoints », qui sont essentiellement des points de terminaison fournissant des données brutes sous forme de services Web.

Dans les prochaines parties, nous approfondirons les avantages que PSU peut offrir avec cette approche :

More from PowerShell

Read more articles