demande de rappel immédiat

Un menu contextuel "Full PowerShell" dans l'explorer de Windows

Posted by Jean-Paul Blanc Tuesday, February 01, 2011 6:07:00 PM
Rate this Content 0 Votes

 

 

Pour créer un menu contextuel dans "Explorer.exe" sans objet COM, ni script sur le disque, j'ai embarqué une fonction PoweShell dans une clef de base de registre. J'ai ensuite mis au point le code PowerShell qui lit une fonction en base de registre et l'exécute. Enfin J'ai positionné le tout dans la base de registre pour ajouter un menu contextuel à "Explorer.exe".

 Voici une description en trois étapes :

  1. Embarquer une fonction dans une clef de base de registre.
  2. Charger et exécuter une fonction embarquée dans une base de registre.
  3. Créer le menu contextuel.

Je termine par un exemple concret dans lequel j'ajoute un menu contextuel permettant de calculer le digest MD5 d'un fichier. Vous trouverez les fichiers associés à cet article dans les ressources PowShell.

1)Embarquer une fonction dans une clef de base de registre.

A partir du moment où une fonction est déjà définie dans un script elle est accessible à travers le lecteur "function:". Il est alors possible de récupérer le block de script associé. Je n'ai pas réussi à récupérer automatiquement la signature de la fonction, je la crée donc à la main. Voici le résultat (Extrait1.PS1):

function Aff { # Utilisation des Windows Forms Add-Type -AssemblyName "system.windows.forms" [Windows.Forms.MessageBox]::show( "Un message","Test", "OK","Information") $i = 0 foreach ($arg in $args) { [Windows.Forms.MessageBox]::show($arg,"Argument $i", "OK","Information") $i++ } } # Positionne le script à exécuter dans la valeur chaine "script" [String]$clefExistante = 'HKCU:\SOFTWARE\Test' $scripCode = [string]::Format("function Aff`n{{{0}`n}}", ((get-item function:\Aff).ScriptBlock)) $defValue = New-ItemProperty -Path ($clefExistante) -Name "script" -Value $scripCode -PropertyType "String"

2) Charger et exécuter une fonction embarquée dans une base de registre

Je récupère la fonction PowerShell stockée précédemment dans la base de registre et je fabrique un nouveau module dynamique à partir du block de script créé depuis cette chaine. Il reste à charger le module et à appeler la fonction (Extrait2.PS1).

[String]$clefExistante = 'HKCU:\SOFTWARE\Test' $chaine = Get-ItemProperty $clefExistante -Name "script" $mod = new-module -scriptblock ([scriptblock]::create($chaine.script)) -Name slxFunc Import-Module $mod; Aff "Coucou"

Ces quelques lignes sont triviales, mais elles sont la clef de tout le mécanisme. En les passant, en tant que commandes, à l'interpréteur PowerShell, on peut exécuter la fonction stockée dans la clef "script" sans fichier extérieur. La difficulté consiste à fabriquer la ligne de commande comprise par le système d'exploitation qui passe les bonnes commandes à l'interpréteur Powershell. Cela parait simple, mais il faut jouer habillement avec les différentes substitutions de caractères.
Voici la commande dans cmd.exe :

%systemroot%\system32\WindowsPowerShell\v1.0\powershell.exe -command "&{$chaine = Get-ItemProperty 'HKCU:\SOFTWARE\Test' -Name "script";$mod = new-module -scriptblock ([scriptblock]::create($chaine.script)) -Name slxFunc;Import-Module $mod;Aff $args[0];}" "coucou"

 

Il reste à transposer cette ligne de commande de sorte à ce qu'elle soit considérée comme une chaine dans le script PowerShell qui va l'écrire dans la base de registre.

 

3) Créer le menu contextuel

Ce n'est pas le propos ici de documenter les clefs et les valeurs à ajouter dans la base de registre pour ajouter un menu contextuel. Voici le code "regedit" de départ :

Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\slxFunc] @="Fonction PowerShell" "Extended"="" [HKEY_CLASSES_ROOT\*\shell\slxFunc\command] @="C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe ...blabla...."

Remarque : La présence de la valeur "Extended" implique de maintenir la touche "majuscule" enfoncée pour voir le nouveau menu. 

Voici le résultat dans une fonction avancée "set-AffMenu" qui prend en charge la création et la suppression du menu (MenuContextuelAff.PS1):

function Aff { # Utilisation des Windows Forms Add-Type -AssemblyName "system.windows.forms" [Windows.Forms.MessageBox]::show( "Un message","Test", "OK","Information") $i = 0 foreach ($arg in $args) { [Windows.Forms.MessageBox]::show($arg,"Argument $i", "OK","Information") $i++ } } <# .SYNOPSIS Installe un menu contextuel sur les objets fichier. Ce menu permet de calculer et d'afficher l'empreinte MD5 du fichier. .DESCRIPTION Ajoute un menu contextuel dont le code est stocké dns une clef de base de registre. .NOTES Nom du fichier : ModifExplorer.ps1 Auteur : J.P. Blanc - jean-paul_blanc@silogix-fr.com Prérequis : PowerShell V2 sur Vista et les versions suivantes. Copyright 2010 - Jean Paul Blanc/Silogix .LINK Script posté sur: http://preprod.silogix.fr .EXAMPLE #>  function Set-AffMenu { [CmdletBinding()] Param ( [Parameter(mandatory=$false,ValueFromPipeline=$false)] [Alias("Active")] [switch] [bool]$On ) begin { if ($On.IsPresent) { Write-Host "Positionne le menu sur les objets fichiers" } else { Write-Host "Retire le menu sur les objets fichiers" } } Process { # Texte du Menu [string]$TexteMenu = "Une Fonction PowerShell" # Clef à créer # ATTENTION le caractère * pose un problème avec les CMDLET d'accès aux propriétès [String]$clefACreerFichier = "HKLM:\SOFTWARE\Classes\*\shell\slxFunc" [String]$clefACreerFichierCV = 'HKLM:\SOFTWARE\Classes\`*\shell\slxFunc' [String]$clefACreerFichierCmdCV = 'HKLM:\SOFTWARE\Classes\`*\shell\slxFunc\command' # Texte du programme à créer # Version powershell.exe  [string]$TexteCommande = "%systemroot%\system32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden -command ""&{`$chaine = Get-ItemProperty '$clefACreerFichierCmdCV' -Name ""script"";`$mod = new-module -scriptblock ([scriptblock]::create(`$chaine.script)) -Name slxMod;Import-Module `$mod;Aff `$args[0];}"" '%1'" try { if ($On.IsPresent) { # Crée la clef d'entrée $regKey = New-Item -Path $clefACreerFichier -ErrorAction Stop # Positionne le texte du menu (valeur par défaut de la clef) $defValue = New-ItemProperty -Path $clefACreerFichierCV -Name "(default)" -Value $TexteMenu -PropertyType "String" # Positionne le fait que le menu n'apparaisse que dans un élément complémentaire $defValue = New-ItemProperty -Path $clefACreerFichierCV -Name "Extended" -Value "" -PropertyType "String" # Crée une sous clef "command" $regKey = New-Item -Path ($clefACreerFichier + "\command") -ErrorAction Stop # Positionne la ligne de code à exécuter (valeur par défaut de la sous clef) $defValue = New-ItemProperty -Path ($clefACreerFichierCV + "\command") -Name "(default)" -Value $TexteCommande -PropertyType "ExpandString" # Positionne le script à exécuter $scripCode = [string]::Format("function Aff`n{{{0}`n}}", ((get-item function:\Aff).ScriptBlock)) $defValue = New-ItemProperty -Path ($clefACreerFichierCV + "\command") -Name "script" -Value $scripCode -PropertyType "String" Write-Host "c'est fait !" } else { Remove-Item -Path $clefACreerFichierCV -Recurse -ErrorAction Stop Write-Host "c'est fait !" } } catch { $_.exception.message } } end {} } Clear-Host Set-AffMenu -On 

 

Conclusion

Il reste encore des détails à régler. D'abord une fenêtre intempestive apparait, ensuite le temps d'exécution est un peu long entre le clic sur le menu contextuel et le résultat.

Ces deux soucis disparaissent simultanément en remplaçant "PowerShell.exe" par "slxPShell.exe" un petit programme .NET qui embarque l'interpréteur PowerShell. Vous trouverez dans les ressources PowerShell un script qui permet d'obtenir le calcul du digest MD5 d'un fichier dans "Explorer.exe"(MenuContextuelDigest.PS1).

Attention : Le scipt "MenuContextuelDigest.PS1" modifie le menu contextuel etendu, il faut appuyer sur la touche SHIFT en même temps que sur le clic droit pour obtenir le menu contextuel.

Comments are closed on this post.