PowerShell 7.5 : comment créer une interface graphique WPF avec le style Windows 11 ?
Sommaire
I. Présentation
Avec Windows PowerShell, vous avez découvert comment créer des interfaces graphiques avec PowerShell WPF et Windows Forms grâce à nos articles précédents (que nous vous recommandons de lire pour une meilleure compréhension de cet article).
Aujourd’hui, nous allons apprendre à créer des applications WPF avec PowerShell 7.5 (appelé aussi PowerShell Core) et les versions supérieures. Avec la récente mise à jour de PowerShell en version 7.5, les composants .NET en version 9 ont apporté beaucoup de changement aux applications WPF… C’est ce que nous allons découvrir dans ce tutoriel.
- Comment créer une application graphique avec PowerShell et WPF ?
- PowerShell : comment créer une interface graphique avec Windows Forms ?
II. Les prérequis
PowerShell 7.5 est la version multiplateforme de Windows PowerShell. Son installation est possible sur l’ensemble des plateformes MacOs, Linux et Windows, bien sûr. En complément, vous devez aussi installer .NET Desktop Runtime en version 9 sur votre machine.
A. Installer PowerShell Core avec WinGet
Je pense que vous connaissez le gestionnaire paquets de Windows ? Sinon, je vous invite à le découvrir dans cet article. Il permet d’installer des applications en ligne de commande.
- Pour rechercher PowerShell, utiliser la ligne de commande suivante :
PS > winget search Microsoft.PowerShell
Nous remarquons que nous avons la version 7.5 et même la version en preview 7.6.0.4 de PowerShell Core disponibles dans les dépôts.
- Pour installer PowerShell, utiliser la ligne de commande suivante :
PS > winget install Microsoft.PowerShell
B. Installer .NET Desktop Runtime 9 avec WinGet
Maintenant, passons à l’installation du .NET Desktop Runtime en version 9, toujours avec WinGet.
PS > winget install Microsoft.DotNet.DesktopRuntime.9
Nous disposons désormais de tous les prérequis pour entrer dans le vif du sujet : créer des applications WPF avec un thème moderne, sans recourir à des bibliothèques tierces comme MahApps ou WPF UI, en utilisant cette fois le thème Fluent.
Pour découvrir les contrôles ainsi que les styles utilisés dans Fluent, Microsoft a créé une application Galerie WPF disponible dans le Store de Windows.
III. L’application WPF avec PowerShell 7.5
A. La partie XAML
Nous allons utiliser à nouveau la même application que nous avions créée précédemment avec Mahapps ou MaterialDesign, mais cette fois en PowerShell 7.5 avec le thème Fluent de Windows 11.
Quels changements pour prendre en compte le nouveau thème Fluent ? Pas grand-chose en fait, regardons de plus près le XAML.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Width="480"
Height="350"
Title="IT Connect WPF Pwsh 7.5"
ThemeMode="System"
WindowStartupLocation="CenterScreen"
ResizeMode="CanMinimize"
Topmost="True">
<DockPanel>
<Button Name="Switch" Content="Switch Theme"
Margin="10"
HorizontalAlignment="Right"
VerticalAlignment="Top"
DockPanel.Dock="Top"
Style="{DynamicResource AccentButtonStyle}"/>
<Grid>
<StackPanel HorizontalAlignment="Center" Margin="0,10,0,0" Orientation="Vertical">
<Label Name="Label" HorizontalAlignment="Center" Content="Active Directory" FontSize="20" BorderBrush="Black"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"/>
<GroupBox
Width="400"
Height="100"
Margin="0,10,0,0"
Header="Utilisateurs du domaine">
<StackPanel HorizontalAlignment="Center" Margin="0" Orientation="Vertical">
<StackPanel HorizontalAlignment="Center" Margin="0,10,0,0" Orientation="Horizontal">
<Button
Name="MonBouton"
Width="80"
Height="35"
Margin="0 10 0 0"
Content="Check"
Style="{DynamicResource AccentButtonStyle}"/>
<ComboBox Name="MonComboBox" Width="200" Margin="5 10 0 0" SelectedIndex="0" />
</StackPanel>
<Label Name="Label2" Content="" Margin="5" Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"/>
</StackPanel>
</GroupBox>
</StackPanel>
</Grid>
</DockPanel>
</Window>
L’ajout de la propriété ThemeMode
au contrôle Window
, il accepte trois paramètres :
Light
: thème blancDark
: thème noirSystem
: récupère le thème actif du système.- L’ajout de la propriété
Style
au contrôleButton
avec la valeurDynamicResource AccentButtonStyle
, ce qui va lui permettre de récupérer la couleur de la valeur de l’accent au sein du système d’exploitation.
Pour une documentation plus complète sur les styles ainsi que les accents, je vous recommande le site Learn Microsoft pour avoir l’ensemble des paramètres.
B. La partie PowerShell
Et le code PowerShell ! Pour faire simple, j’ai décidé d’utiliser un seul fichier. J’ai décidé d’ajouter une vérification de la version de PowerShell. Ainsi, si la version n’est pas du PowerShell 7.5, alors le script s’arrête avec un message d’erreur.
Cette vérification est effectuée via le code suivant :
if ($PSVersionTable.PSVersion.Major -lt 7 -or ($PSVersionTable.PSVersion.Major -eq 7 -and $PSVersionTable.PSVersion.Minor -lt 5)) {
Write-Host "This script requires PowerShell 7.5 or later. Please upgrade your PowerShell version." -ForegroundColor Red
exit
}
Pour ce qui est du corps du script PowerShell, voici son contenu en intégralité :
# Check if the script is running on PowerShell 7 or later
if ($PSVersionTable.PSVersion.Major -lt 7 -or ($PSVersionTable.PSVersion.Major -eq 7 -and $PSVersionTable.PSVersion.Minor -lt 5)) {
Write-Host "This script requires PowerShell 7.5 or later. Please upgrade your PowerShell version." -ForegroundColor Red
exit
}
# Define the xaml code for the window
[xml]$xaml = @'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Width="480"
Height="350"
Title="IT Connect WPF Pwsh 7.5"
ThemeMode="System"
WindowStartupLocation="CenterScreen"
ResizeMode="CanMinimize"
Topmost="True">
<DockPanel>
<Button Name="Switch" Content="Switch Theme"
Margin="10"
HorizontalAlignment="Right"
VerticalAlignment="Top"
DockPanel.Dock="Top"
Style="{DynamicResource AccentButtonStyle}"/>
<Grid>
<StackPanel HorizontalAlignment="Center" Margin="0,10,0,0" Orientation="Vertical">
<Label Name="Label" HorizontalAlignment="Center" Content="Active Directory" FontSize="20" BorderBrush="Black"
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"/>
<GroupBox
Width="400"
Height="100"
Margin="0,10,0,0"
Header="Utilisateurs du domaine">
<StackPanel HorizontalAlignment="Center" Margin="0" Orientation="Vertical">
<StackPanel HorizontalAlignment="Center" Margin="0,10,0,0" Orientation="Horizontal">
<Button
Name="MonBouton"
Width="80"
Height="35"
Margin="0 10 0 0"
Content="Check"
Style="{DynamicResource AccentButtonStyle}"/>
<ComboBox Name="MonComboBox" Width="200" Margin="5 10 0 0" SelectedIndex="0" />
</StackPanel>
<Label Name="Label2" Content="" Margin="5" Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"/>
</StackPanel>
</GroupBox>
</StackPanel>
</Grid>
</DockPanel>
</Window>
'@
# Charger l'assembly WPF
Add-Type -AssemblyName PresentationFramework
# Charger la fenêtre et les éléments nommés en tant que variables dans une table de hachage
$UI = [System.Collections.Hashtable]::Synchronized(@{})
$UI.Window = [System.Windows.Markup.XamlReader]::Load((New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $xaml))
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") |
ForEach-Object -Process {
$UI.$($_.Name) = $UI.Window.FindName($_.Name)
}
# Amener la fenêtre au premier plan
$UI.Window.Add_Loaded({
$This.Activate()
})
function Get-ADUserLastLogon {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)][ValidateScript({ Get-ADUser $_ })]$Identity = $null
)
# Récupérer la liste de tous les DC du domaine AD
$DCList = Get-ADDomainController -Filter * | Sort-Object Name | Select-Object Name
# Initialiser le LastLogon sur $null comme point de départ
$TargetUserLastLogon = $null
# Date par défaut
$DefaultDate = [Datetime]'01/01/1601 01:00:00'
Foreach ($DC in $DCList) {
$DCName = $DC.Name
Try {
# Récupérer la valeur de l'attribut lastLogon à partir d'un DC (chaque DC tour à tour)
$LastLogonDC = Get-ADUser -Identity $Identity -Properties lastLogon -Server $DCName
# Convertir la valeur au format date/heure
$LastLogon = [Datetime]::FromFileTime($LastLogonDC.lastLogon)
# Si la valeur obtenue est plus récente que celle contenue dans $TargetUserLastLogon
# la variable est actualisée : ceci assure d'avoir le lastLogon le plus récent à la fin du traitement
If ($LastLogon -gt $TargetUserLastLogon) {
$TargetUserLastLogon = $LastLogon
}
# Nettoyer la variable
Clear-Variable LastLogon
}
Catch {
Write-Host $_.Exception.Message -ForegroundColor Red
}
}
if ($TargetUserLastLogon -eq $DefaultDate) {
return "Jamais"
}
else {
return $TargetUserLastLogon.ToString(" dd/MM/yyyy à HH:mm:ss ")
}
}
$UI.Label.Content = "Active Directory - LastLogon - $((Get-ADDomain).DNSRoot)"
# Remplir la ComboBox avec les données des utilisateurs
Get-ADUser -Filter { Enabled -eq $true } | Select-Object samAccountName | Foreach {
$ComboBoxItem = New-Object System.Windows.Controls.ComboBoxItem
$ComboBoxItem.Content = $_.SamAccountName
$ComboBoxItem.HorizontalContentAlignment = 'Stretch'
[void]$UI.MonComboBox.Items.Add($ComboBoxItem)
}
$UI.MonBouton.Add_Click(
{
# Assurez-vous que l'élément sélectionné n'est pas nul et récupérez son contenu
if ($UI.MonComboBox.SelectedItem -ne $null) {
$SelectedUser = $UI.MonComboBox.SelectedItem.Content
if ($SelectedUser -ne $null) {
$LastLogonOfUser = Get-ADUserLastLogon -Identity $SelectedUser
$UI.Label2.Content = "Dernière connexion de $SelectedUser : $LastLogonOfUser"
} else {
$UI.Label2.Content = "Aucun utilisateur sélectionné."
}
} else {
$UI.Label2.Content = "Aucun utilisateur sélectionné."
}
}
)
# Ajouter un événement de clic au bouton Switch
$UI.Switch.Add_Click({
if ($UI.Window.ThemeMode -eq "Dark") {
$UI.Window.ThemeMode = "Light"
$UI.Switch.Content = "Switch to Dark"
} else {
$UI.Window.ThemeMode = "Dark"
$UI.Switch.Content = "Switch to Light"
}
})
# Définir le texte initial pour le bouton Switch en fonction du thème actuel
if ($UI.Window.ThemeMode -eq "Dark") {
$UI.Switch.Content = "Switch to Light"
} else {
$UI.Switch.Content = "Switch to Dark"
}
# Afficher la fenêtre
[void]$UI.Window.ShowDialog()
Quels sont les changements lors de l’utilisation de PowerShell 7.X ?
Nous avons chargé l’ensemble de la fenêtre ainsi que les contrôles dans une Hashtable dans notre variable $UI
.
$UI.Window = [System.Windows.Markup.XamlReader]::Load((New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $xaml))
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") |
ForEach-Object -Process {
$UI.$($_.Name) = $UI.Window.FindName($_.Name)
}
# Amener la fenêtre au premier plan
$UI.Window.Add_Loaded({
$This.Activate()
})
Découvrez ci-dessous un aperçu de notre application !
C. Changement de thème
Pour changer de thème, il suffit de changer la propriété ThemeMode de l’objet Window. Pour cela, ce code PowerShell nous permet de changer à la volée le thème de l’application.
$UI.SwitchThemeButton.Add_Click({
if ($UI.Window.ThemeMode -eq "Dark") {
$UI.Window.ThemeMode = "Light"
} else {
$UI.Window.ThemeMode = "Dark"
}
})
Découvrez ceci avec l'animation suivante :
IV. Conclusion
En suivant ce tutoriel, vous devriez être en mesure de migrer vos applications de Windows PowerShell WPF à PowerShell Core ! La seule limite qui existe maintenant reste votre imagination.
Si vous avez des questions, pensez à commenter cet article.