Metsys Blog

Créer des outils PowerShell accessibles depuis la barre des tâches

Cliquez pour évaluer cet article !
0 avis

Introduction

Dans ce post, je vais vous expliquer comment créer des outils PowerShell pouvant s’exécuter depuis la barre des tâches par le biais d’un menu composé de différents sous-menus.

Le script est disponible ici.
Pour l’exemple de ce post, j’ai crée un dossier C:\MySystrayTool, qui contiendra mon outil systray.

Qu’est-ce qu’un outil systray ?

Un outil systray, est un logiciel ou outil pouvant se lancer depuis la barre de tâches.
Nous pourrions prendre l’exemple de l’antivirus qui dispose généralement de sa propre icône dans la partie systray tel que ci-dessous.
En effectuant un clic droit sur cet icône, différentes options sont disponibles.

Exemple d’outil ?

Vous trouverez sur ce lien, un outil que j’avais créé permettant depuis la barre des tâches d’avoir des informations sur des utilisateurs et ordinateurs Active Directory sans avoir à passer par la console AD.

Cela permettait par exemple de :

  • Saisir le nom d’un utilisateur
  • Voir directement si cet utilisateur est verrouillé, la date de changement de son mot de passe, l’OU dans laquelle il se trouve…
  • Une partie « actions » permet également de déverrouiller, activer ou changer le mot de passe d’un utilisateur.

Ci-dessous un aperçu de cet outil.

Que voulons-nous ?

Dans notre outil présenté dans cet article nous voulons:

  • Afficher une icône dans la barre des tâches
  • Afficher différents sous-menus après avoir effectué un clic droit sur l’icône
  • Afficher différentes interfaces graphiques WPF et PowerShell après avoir cliqué sur l’un des sous-menus
  • Fermer l’interface ouverte si l’on clique en dehors de la fenêtre

Création de l’icône


La première étape est de créer notre icône dans la barre des tâches.

  • Nous allons d’abord charger différentes assemblies permettant l’utilisation de WPF et du thème Mahapps.
  • Puis nous allons choisir notre icône en utilisant
 [System.Drawing.Icon]::ExtractAssociatedIcon
  • Nous allons ensuite créer un objet System.Windows.Forms.NotifyIcon pour créer notre icône.

Ci-dessous le code permettant de faire tout cela :

$Current_Folder = split-path $MyInvocation.MyCommand.Path
# Add assemblies for WPF and Mahapps
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('presentationframework')   | out-null
[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('WindowsFormsIntegration') | out-null
[System.Reflection.Assembly]::LoadFrom("$Current_Folder\assembly\MahApps.Metro.dll") | out-null
# Choose an icon to display in the systray
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon("C:\Windows\System32\ServerManager.exe")

# Add the systray icon
$Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
$Main_Tool_Icon.Text = "Mon outil PS1"
$Main_Tool_Icon.Icon = $icon
$Main_Tool_Icon.Visible = $true

# Make PowerShell Disappear - Thanks Chrissy
$windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)

# Use a Garbage colection to reduce Memory RAM
# https://dmitrysotnikov.wordpress.com/2012/02/24/freeing-up-memory-in-powershell-using-garbage-collector/
# https://docs.microsoft.com/fr-fr/dotnet/api/system.gc.collect?view=netframework-4.7.2
[System.GC]::Collect()

# Create an application context for it to all run within - Thanks Chrissy
# This helps with responsiveness, especially when clicking Exit - Thanks Chrissy
$appContext = New-Object System.Windows.Forms.ApplicationContext
[void][System.Windows.Forms.Application]::Run($appContext)

Dans cet exemple l’icône utilisée sera la suivante :

Vous pouvez choisir une autre icône existant sur votre machine en listant par exemple les .exe dans  C:\Windows\System32, tel que ci-dessous :

Nous avons pour l’instant créer l’icône dans la barre des tâches.
Nous allons maintenant ajouter des menus.

Ajout des menus contextuels


Nous voulons maintenant afficher les sous-menus ci-dessous après avoir effectué un clic droit sur l’icône:

  • Utilisateurs
  • Ordinateurs
  • Redémarrer l’outil
  • Exit

Le code ci-dessous permet d’afficher ces différents sous-menus

# Add icon the systray
$Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
$Main_Tool_Icon.Text = "Mon outil PS1"
$Main_Tool_Icon.Icon = $icon
$Main_Tool_Icon.Visible = $true

# Add menu users
$Menu_Utilisateurs = New-Object System.Windows.Forms.MenuItem
$Menu_Utilisateurs.Text = "Mes utilisateurs"

# Add menu computers
$Menu_Ordinateurs = New-Object System.Windows.Forms.MenuItem
$Menu_Ordinateurs.Text = "Mes ordinateurs"

# Add Restart the tool
$Menu_Redemarrer = New-Object System.Windows.Forms.MenuItem
$Menu_Redemarrer.Text = "Redémarrer (dans 10secs)"

# Add menu exit
$Menu_Exit = New-Object System.Windows.Forms.MenuItem
$Menu_Exit.Text = "Exit"

# Add all menus as context menus
$contextmenu = New-Object System.Windows.Forms.ContextMenu
$Main_Tool_Icon.ContextMenu = $contextmenu
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Utilisateurs)
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Ordinateurs)
$Main_Tool_Icon.contextMenu.MenuItems.AddRange(Menu_Redemarrer)
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Exit)

Le résultat sera le suivant :

Nous avons jusque-là :

  • Créer une icône dans la barre des tâches
  • Ajouter des sous-menus

Nous allons maintenant créer les interfaces à afficher.

Interfaces à afficher


Nous voulons afficher deux interfaces différentes lorsque nous cliquons sur Utilisateurs ou Ordinateurs.
Dans mon exemple, j’utilise le thème Mahapps qui utilise un fichiers xml pour ses icônes localisés dans resources.

Le path complet est C:\MySystrayTool\resources\Icons.xaml.
Si vous utilisez un autre dossier il faudra donc le renommer.


Le code utilisé pour créer l’interface Utilisateurs sera le suivant :

# GUI to display for Users part
[xml]$XAML_Utilisateurs =
@"
<Controls:MetroWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="Partie Utilisateurs" Width="470" ResizeMode="NoResize" Height="300"
BorderBrush="DodgerBlue" BorderThickness="0.5" WindowStartupLocation ="CenterScreen">

<Window.Resources>
<resourcedictionary>
<ResourceDictionary.MergedDictionaries>
<resourcedictionary Source="$Current_Folder\resources\Icons.xaml" />
<resourcedictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<resourcedictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<resourcedictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<resourcedictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Cobalt.xaml" />
<resourcedictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands>
<button>
<stackpanel Orientation="Horizontal">
<rectangle Width="15" Height="15" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<visualbrush Stretch="Fill" Visual="{StaticResource appbar_user}" />
</Rectangle.OpacityMask>
</Rectangle>
</StackPanel>
</Button>
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>

<grid>
</Grid>
</Controls:MetroWindow>
"@
$Interface_Utilisateurs = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $XAML_Utilisateurs))
# Part to decvlare your controls from the User GUI
$MyControl = $Interface_Utilisateurs.findname("MyControl")

Celui pour la partie Ordinateurs sera similaire.


Nous avons créer les interfaces à afficher.
Cependant, nous n’avons aucune action permettant de les afficher lors du clic sur les sous-menus.

Ajout des actions sur les menus


Nous voulons les actions suivantes :

  • Clic sur le sous-menu utilisateurs ==> Affiche l’interface Utilisateurs
  • Clic sur le sous-menu ordinateurs ==> Affiche l’interface Ordinateurs
  • Clic sur Redémarrer ==> Ferme l’outil et le relance 10 secondes plus tard
  • Clic sur Exit ==> Ferme l’outil

Pour gérer les actions, il faut considérer que chaque sous-menu est un bouton.
Comme pour chaque Control en WPF, différents événements permettent de gérer vos actions.
Ces événements peuvent se traduire par « à quel moment je veux exécuter telle action ».

De ce fait nous pourrions par exemple avoir des événements tels que :

  • Au clic droit
  • Sur un simple clic
  • Au passage de du curseur de la souris sur le sous-menu


Dans cet exemple nous voulons des actions sur un simple clic des sous-menus.

L’événement à utiliser sera « Add_Click ».
Il faudra donc utiliser le nom de sous-menu suivi de Add_Click.


Prenons, par exemple, le sous-menu Exit dont le nom est Exit.
L’action sur un simple clic sera donc telle que ci-dessous :

[code language="powershell"] # Action after clicking on the Exit context menu
$Menu_Exit.add_Click({
$Main_Tool_Icon.Visible = $false
$window.Close()
Stop-Process $pid
}) [/code]

Afficher les interfaces


Ci-dessous les actions permettant d’afficher nos deux interfaces.

# Action when after a click on the main systray icon
$Main_Tool_Icon.Add_Click({
[System.Windows.Forms.Integration.ElementHost]::EnableModelessKeyboardInterop($Interface_Utilisateurs)
If ($_.Button -eq [Windows.Forms.MouseButtons]::Left) {
$Interface_Utilisateurs.WindowStartupLocation = "CenterScreen"
$Interface_Utilisateurs.Show()
$Interface_Utilisateurs.Activate()
}
})

# Action after clicking on the Users context menu
$Menu_Utilisateurs.Add_Click({
$Interface_Utilisateurs.WindowStartupLocation = "CenterScreen"
[System.Windows.Forms.Integration.ElementHost]::EnableModelessKeyboardInterop($Interface_Utilisateurs)
$Interface_Utilisateurs.ShowDialog()
$Interface_Utilisateurs.Activate()
})

# Action after clicking on the Computers context menu
$Interface_Ordinateurs.Add_Click({
[System.Windows.Forms.Integration.ElementHost]::EnableModelessKeyboardInterop($Interface_Ordinateurs)
$Interface_Ordinateurs.Show()
$Interface_Ordinateurs.Activate()
})

Maintenant lorsque nous cliquons sur le menu Utilisateurs, la fenêtre ci-dessous s’affiche.

Cependant, lorsque nous cliquons autre part que sur cette fenêtre, par exemple sur le bureau, cette fenêtre est toujours présente.

Dans le but de fermer cette fenêtre lorsque nous cliquons autre part nous allons utiliser un autre événement. Lorsque le clic de la souris n’est plus sur l’interface, on dit qu’il perd le focus


Nous allons pour cela utiliser l’événement « Add_Deactivated » qui permettra de spécifier l’action lorsque l’on perd le focus sur l’interface.


Nous allons également ajouter cet événement pour l’interface Ordinateurs.
Ci-dessous les codes des événements à utiliser:

# Close the Users GUI if it loses focus
$Interface_Utilisateurs.Add_Deactivated({
$Interface_Utilisateurs.Hide()
})

# Close the Computers GUI if it loses focus
$Interface_Ordinateurs.Add_Deactivated({
$Interface_Ordinateurs.Hide()
})

Ci-dessous le résultat obtenu:

Maintenant nous allons ajouter une autre option permettant d’empêcher la fermeture des interfaces Utilisateurs ou Ordinateurs via le bouton Fermeture dans la barre de titre.
Pour cela nous utiliserons l’événement « Add_Closing ».
Cet événement permet de spécifier les actions à effectuer lors de la fermeture d’une interface.

Nous allons ici lui spécifier de :

  • Ne pas fermer l’interface lors d’un clic sur le bouton fermer
  • Afficher un message en cas de clic sur le bouton de fermeture

Ci-dessous le code utilisé pour cela :

# Action on the close button from the Users GUI
$Interface_Utilisateurs.Add_Closing({
$_.Cancel = $true
[MahApps.Metro.Controls.Dialogs.DialogManager]::ShowMessageAsync($Interface_Utilisateurs, "Oops :-(", "Pour fermer l'interface, cliquez en dehors !!!")
})

# Action on the close button from the Computers GUI
$Interface_Ordinateurs.Add_Closing({
$_.Cancel = $true
[MahApps.Metro.Controls.Dialogs.DialogManager]::ShowMessageAsync($Interface_Ordinateurs, "Oops :-(", "Pour fermer l'interface, cliquez en dehors !!!")
})

Ci-dessous le résultat obtenu :

Redémarrer


L’action sur le bouton redémarrer devrait être de relancer l’outil dans 10 secondes.
Dans un premier temps nous allons créer l’action sur le bouton, tel que ci-dessous:

# Action after clicking on the Restart context menu
$Menu_Redemarrer.add_Click({
$Restart = "Yes"
start-process -WindowStyle hidden powershell.exe "C:\ProgramData\MyTool\MyPS1.ps1 '$Restart'"

$Main_Tool_Icon.Visible = $false
$window.Close()
Stop-Process $pid
})

Puis nous allons ajouter un paramètre au début de notre script afin de lui spécifier d’attendre 10 secondes avant de lancer l’outil, seulement si le bouton Redémarrer a été cliqué.

Param
(
[String]$Restart
)

If ($Restart -ne "")
{
sleep 10
}

Ci-dessous le code complet pour créer l’outil.
N’oubliez pas au préalable d’avoir les dossiers assembly et resources.

Param
(
[String]$Restart
)

If ($Restart -ne "")
{
sleep 10
}

$Current_Folder = split-path $MyInvocation.MyCommand.Path

# Add assemblies for WPF and Mahapps
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('presentationframework')   | out-null
[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('WindowsFormsIntegration') | out-null
[System.Reflection.Assembly]::LoadFrom("$Current_Folder\assembly\MahApps.Metro.dll") | out-null

# Choose an icon to display in the systray
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon("C:\Windows\System32\mmc.exe")

########################################################################################################################################################################################################
#*******************************************************************************************************************************************************************************************************
#																						INTERFACES A AFFICHER
#*******************************************************************************************************************************************************************************************************
########################################################################################################################################################################################################

# ----------------------------------------------------
# Partie Utilisateurs
# ----------------------------------------------------

[xml]$XAML_Utilisateurs =
@"
&amp;amp;amp;amp;lt;Controls:MetroWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="Partie Utilisateurs" Width="470" ResizeMode="NoResize" Height="300"
BorderBrush="DodgerBlue" BorderThickness="0.5" WindowStartupLocation ="CenterScreen"&amp;amp;amp;amp;gt;

&amp;amp;amp;amp;lt;Window.Resources&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary.MergedDictionaries&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="$Current_Folder\resources\Icons.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /&amp;amp;amp;amp;gt;;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Cobalt.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/ResourceDictionary.MergedDictionaries&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/ResourceDictionary&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Window.Resources&amp;amp;amp;amp;gt;

&amp;amp;amp;amp;lt;Controls:MetroWindow.LeftWindowCommands&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Controls:WindowCommands&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Button&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;StackPanel Orientation="Horizontal"&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Rectangle Width="15" Height="15" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Rectangle.OpacityMask&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;VisualBrush Stretch="Fill" Visual="{StaticResource appbar_user}" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Rectangle.OpacityMask&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Rectangle&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/StackPanel&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Button&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Controls:WindowCommands&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Controls:MetroWindow.LeftWindowCommands&amp;amp;amp;amp;gt;

&amp;amp;amp;amp;lt;Grid&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Grid&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Controls:MetroWindow&amp;amp;amp;amp;gt;
"@
$Interface_Utilisateurs = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $XAML_Utilisateurs))
$MyControl = $Interface_Utilisateurs.findname("MyControl")

# ----------------------------------------------------
# Partie Utilisateurs
# ----------------------------------------------------

[xml]$XAML_Ordinateurs =
@"
&amp;amp;amp;amp;lt;Controls:MetroWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="Partie Ordinateurs" Width="470" ResizeMode="NoResize" Height="300"
BorderBrush="DodgerBlue" BorderThickness="0.5" WindowStartupLocation ="CenterScreen"&amp;amp;amp;amp;gt;

&amp;amp;amp;amp;lt;Window.Resources&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary.MergedDictionaries&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="$Current_Folder\resources\Icons.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Cobalt.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/ResourceDictionary.MergedDictionaries&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/ResourceDictionary&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Window.Resources&amp;amp;amp;amp;gt;

&amp;amp;amp;amp;lt;Controls:MetroWindow.LeftWindowCommands&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Controls:WindowCommands&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Button&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;StackPanel Orientation="Horizontal"&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Rectangle Width="15" Height="15" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;Rectangle.OpacityMask&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;VisualBrush Stretch="Fill" Visual="{StaticResource appbar_user}" /&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Rectangle.OpacityMask&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Rectangle&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/StackPanel&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Button&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Controls:WindowCommands&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Controls:MetroWindow.LeftWindowCommands&amp;amp;amp;amp;gt;

&amp;amp;amp;amp;lt;Grid&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Grid&amp;amp;amp;amp;gt;
&amp;amp;amp;amp;lt;/Controls:MetroWindow&amp;amp;amp;amp;gt;
"@
$Interface_Ordinateurs = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $XAML_Ordinateurs))
$MyControl2 = $Interface_Ordinateurs.findname("MyControl2")

# Add icon the systray
$Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
$Main_Tool_Icon.Text = "Mon outil PS1"
$Main_Tool_Icon.Icon = $icon
$Main_Tool_Icon.Visible = $true

# Add menu users
$Menu_Utilisateurs = New-Object System.Windows.Forms.MenuItem
$Menu_Utilisateurs.Text = "Mes utilisateurs"

# Add menu computers
$Menu_Ordinateurs = New-Object System.Windows.Forms.MenuItem
$Menu_Ordinateurs.Text = "Mes ordinateurs"

# Add Restart the tool
$Menu_Redemarrer = New-Object System.Windows.Forms.MenuItem
$Menu_Redemarrer.Text = "Redemarrer (dans 10secs)"

# Add menu exit
$Menu_Exit = New-Object System.Windows.Forms.MenuItem
$Menu_Exit.Text = "Exit"

# Add all menus as context menus
$contextmenu = New-Object System.Windows.Forms.ContextMenu
$Main_Tool_Icon.ContextMenu = $contextmenu
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Utilisateurs)
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Ordinateurs)
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Redemarrer)
$Main_Tool_Icon.contextMenu.MenuItems.AddRange($Menu_Exit)

# Action after a click on the main systray icon
$Main_Tool_Icon.Add_Click({
[System.Windows.Forms.Integration.ElementHost]::EnableModelessKeyboardInterop($Interface_Utilisateurs)
If ($_.Button -eq [Windows.Forms.MouseButtons]::Left)
{
$Interface_Utilisateurs.WindowStartupLocation = "CenterScreen"
$Interface_Utilisateurs.Show()
$Interface_Utilisateurs.Activate()
}
})

# Action after clicking on the Users context menu
$Menu_Utilisateurs.Add_Click({
# $Menu_Utilisateurs.WindowStartupLocation = "CenterScreen"
[System.Windows.Forms.Integration.ElementHost]::EnableModelessKeyboardInterop($Interface_Utilisateurs)
$Interface_Utilisateurs.ShowDialog()
$Interface_Utilisateurs.Activate()
})

# Action after clicking on the Computers context menu
$Menu_Ordinateurs.Add_Click({
[System.Windows.Forms.Integration.ElementHost]::EnableModelessKeyboardInterop($Interface_Ordinateurs)
$Interface_Ordinateurs.Show()
$Interface_Ordinateurs.Activate()
})

# Close the Users GUI if it loses focus
$Interface_Utilisateurs.Add_Deactivated({
$Interface_Utilisateurs.Hide()
})

# Close the Computers GUI if it loses focus
$Interface_Ordinateurs.Add_Deactivated({
$Interface_Ordinateurs.Hide()
})

# Action on the close button from the Users GUI
$Interface_Utilisateurs.Add_Closing({
$_.Cancel = $true
[MahApps.Metro.Controls.Dialogs.DialogManager]::ShowMessageAsync($Interface_Utilisateurs, "Oops :-(", "Pour fermer l'interface, cliquez en dehors !!!")
})

# Action on the close button from the Computers GUI
$Interface_Ordinateurs.Add_Closing({
$_.Cancel = $true
[MahApps.Metro.Controls.Dialogs.DialogManager]::ShowMessageAsync($Interface_Ordinateurs, "Oops :-(", "Pour fermer l'interface, cliquez en dehors !!!")
})

# Action after clicking on the Restart context menu
$Menu_Redemarrer.add_Click({
$Restart = "Yes"
start-process -WindowStyle hidden powershell.exe "PathDeVotrePS1\MONPS1.ps1 '$Restart'"

$Main_Tool_Icon.Visible = $false
$window.Close()
Stop-Process $pid
})

# Action after clicking on the Exit context menu
$Menu_Exit.add_Click({
$Main_Tool_Icon.Visible = $false
$window.Close()
Stop-Process $pid
})

# Make PowerShell Disappear - Thanks Chrissy
$windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)

# Use a Garbage colection to reduce Memory RAM
# https://dmitrysotnikov.wordpress.com/2012/02/24/freeing-up-memory-in-powershell-using-garbage-collector/
# https://docs.microsoft.com/fr-fr/dotnet/api/system.gc.collect?view=netframework-4.7.2
[System.GC]::Collect()

# Create an application context for it to all run within - Thanks Chrissy
# This helps with responsiveness, especially when clicking Exit - Thanks Chrissy
$appContext = New-Object System.Windows.Forms.ApplicationContext
[void][System.Windows.Forms.Application]::Run($appContext)

Notez cet article

Vous avez aimé cet article ?

Rendez-le plus visible auprès des internautes en lui mettant une bonne note.

Cliquez pour évaluer cet article !
0 avis

Articles pouvant vous intéresser

RETEX CERT

Tout d’abord, en termes d’éthique et pour respecter la confidentialité des sujets aussi sensibles que