| Jacques's profilejanelPhotosBlogLists | Help |
|
July 30 Interactions avec un Windows FormSi vous avez déjà testé l’utilisation des objets de la classe Windows.Forms dans PowerShell, vous aurez remarqué que PowerShell lance le formulaire en mode synchrone, ce qui veut dire qu’il faut fermer le formulaire pour pouvoir revenir à la session PowerShell.
PS> [reflection.assembly]::loadwithpartialname("system.windows.forms")
PS> $form = new-object windows.forms.form
PS> $form.text = “Mon éditeur”
PS> $textbox = new-object windows.forms.richtextbox
PS> $textbox.dock = "fill"
PS> $form.controls.add($textbox)
PS> [void] $form.showdialog()
< basculez vers le formulaire Windows, saisissez du texte, fermez le formulaire et revenez dans cette session >
PS> $textbox.text
Bon, cet exemple n’est pas d’une utilité évidente, mais il vous aura permis de constater que le contrôle de la session ne vous est rendu qu’une fois le formulaire fermé. Cette contrainte limite sérieusement les interactions avec le formulaire depuis PowerShell. On ne peut qu’affecter des valeurs aux différents contrôles avant affichage du formulaire, puis récupérer les valeurs modifiées après fermeture. C’est déjà pas mal, penserez-vous peut-être, et vous aurez sans doute raison. Mais on peut faire mieux.
Il existe une technique permettant d’exécuter un formulaire en parallèle de la session en cours. Cette technique repose sur la notion de runspace, espace d’exécution dans une traduction littérale non officielle. Ce concept a été introduit dans PowerShell pour gérer la possibilité d’exécuter plusieurs pipelines en parallèle. C’est indispensable si vous lancez une suite de commandes qui contiennent des pipelines imbriqués.
Il se trouve que les classes de gestion de cet espace d’exécution sont disponibles à l’utilisateur, et sont d’ailleurs documentées – ou plutôt, en cours de documentation car certains passages sont encore incomplets ; de plus, la documentation n’est disponible qu’en anglais pour l’instant, je suppose que la traduction en français sera disponible en même temps que la sortie officielle de Windows PowerShell.
Je n’irai pas plus loin dans l’explication des espaces d’exécution. Je n’ai pas encore eu tellement le temps de m’y frotter. Je reviendrai sans doute sur le sujet dans les prochains mois. Pour l’heure, vous trouverez la documentation existante ici.
Mais revenons à nos moutons. Voici un script fourni par Bruce Payette – un des créateurs de PowerShell – qui exploite les espaces d’exécution pour lancer un formulaire en asynchrone :
# start-form.ps1
#
# Démarre un formulaire Windows en asynchrone.
# Permet d’interagir avec le formulaire depuis PowerShell.
#
# Usage: start-form $form
#
# Attention, $form et tous ses contrôles doivent être créés dans le contexte global.
#
$form = $args[0]
$global:runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$runspace.open()
$runspace.SessionStateProxy.SetVariable("form",$form)
$pipeline = $runspace.CreatePipeline(@'
trap {[console]::writeline("Exception $_")}
$form.ShowDialog()
'@
)
$pipeline.Input.Close()
$pipeline.InvokeAsync()
On pourra maintenant faire ceci (par exemple):
PS> $global:form = new-object windows.forms.form
PS> $form.text = "Ma liste de tâches"
PS> $global:textbox = new-object windows.forms.richtextbox
PS> $textbox.font = "courier new"
PS> $textbox.dock = "fill"
PS> $form.controls.add($textbox)
PS> start-form $form
PS> $form.topmost = $true
PS> while ($true) {$textbox.text = (get-process | out-string); start-sleep 1}
Vous devrez certainement redimensionner la fenêtre du formulaire pour que la liste des tâches s’affiche correctement.
Vous pouvez interrompre à tout moment en pressant Ctrl-C (depuis la session PowerShell). Vous constaterez que le formulaire reste ouvert et que vous pouvez continuer à le manipuler à volonté. Vous pouvez notamment ajouter et supprimer des contrôles. Attention cependant, si vous voulez ajouter des contrôles à la volée, vous devez les avoir créés avant le lancement du formulaire.
Pour l’instant, ce script a de sérieuses limitations. Hormis celle déjà énoncée concernant l’obligation de créer tous les contrôles à l’avance, je n’ai pas encore réussi à faire dialoguer les différents contrôles entre eux. J’ai encore quelques heures de lecture et de tests acharnés devant moi !
Janel D'un dir à l'autreTommy Williams (MSFT) vient de proposer une table d’équivalences entre la commande dir du bon vieil interpréteur de commandes standard (cmd.exe) et la commandelette get-childitem de Windows PowerShell. Vous noterez que l’équivalence en PowerShell reprend dir qui est un alias standard de get-childitem :
J’espère que cette table vous sera très utile. La liste n’est évidemment pas exhaustive, mais elle doit couvrir les besoins les plus courants.
En même temps, l’utilité d’une telle table démontre que get-childitem n’est pas du tout une transposition de la commande dir dans PowerShell, malgré l’alias qui pourrait nous le faire croire. De très nombreuses discussions sur le forum MS dédié à PowerShell ont déjà remué le sujet de la syntaxe parfois très obscure de cette commandelette. L’équipe PowerShell travaille activement à son amélioration, nous verrons ce que cela donne dans les prochaines versions (à venir à la rentrée vraisemblablement).
Janel Dates et culture dans PowerShellSi vous avez essayé d’analyser des variables du type System.DateTime avec PowerShell RC1, vous avez peut-être rencontré quelques problèmes, comme par exemple :
PS> ([DateTime]"30/07/2006").DayOfWeek
Cannot convert value "30/07/2006" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At line:1 char:12
+ ([DateTime]" <<<< 30/07/2006").DayOfWeek
Pourtant, l’exemple ci-dessus vient de mon propre poste sur lequel j’ai activé les paramètres régionaux applicables à la France. Et d’ailleurs, PowerShell confirme bien cette information :
PS> get-culture
LCID Name DisplayName
---- ---- -----------
1036 fr-FR French (France)
L’anglais Chris Warwick a rencontré le même problème et l’a rapporté sur le forum microsoft.public.windows.powershell. La réponse apportée par l’équipe PowerShell est que pour des raisons de compatibilité et de cohérence, les conversions de chaînes de caractères en dates se font désormais en utilisant les informations de la classe .NET InvariantCulture, c’est-à-dire une même culture de référence. Malheureusement pour le reste du monde, la culture invariante prise comme référence est celle du pays d’origine des développeurs de cette classe, à savoir les Etats-Unis. Et comme chacun le sait, aux Etats-Unis les dates sont au format mm/jj/aaaa. La date 30/07/2006 correspondrait donc au 7e jour du 30e mois de l’année 2006. Evidemment, ça ne donne rien de bon.
En fouillant un peu la documentation MSDN de la classe System.DateTime, j’ai trouvé la méthode Parse() qui permet de préciser la culture à utiliser pour analyser la date passée en argument. Le paramètre indiquant la culture doit être du type System.Globalization.CultureInfo ; qu’à cela ne tienne !
PS> $culture=new-object system.globalization.cultureinfo("fr-fr")
PS> ([DateTime]::parse("30/07/2006",$culture)).DayOfWeek
Sunday
Bon, mon système est en anglais US, donc l’analyse de la propriété DayOfWeek se fait en anglais. Mais au moins, l’analyse de la date se fait au bon format. C’est assez déroutant, mais au moins c’est plus fiable ! Si votre poste est en français, vous devriez avoir le jour écrit dans la bonne langue (n’hésitez pas à me laisser un commentaire si ce n’est pas le cas).
L’exemple ci-dessus permet de spécifier n’importe quelle culture. Si l’on veut exclusivement utiliser sa propre culture définie sur son poste, on peut ramener les deux lignes à une seule:
PS> ([DateTime]::Parse("30/07/2006",$(get-culture))).DayOfWeek
Sunday
On peut aller un peu plus loin, et reprendre le script que l’équipe PowerShell avait posté sur son blog il y a plusieurs mois :
function Using-Culture (
[System.Globalization.CultureInfo]$culture = (throw "USAGE: Using-Culture -Culture culture -Script {scriptblock}"),
[ScriptBlock]$script= (throw "USAGE: Using-Culture -Culture culture -Script {scriptblock}"))
{
$OldCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
trap
{
[System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
}
[System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
$script.invoke()
[System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
}
J’ai remplacé invoke-command $script par $script.invoke(), sinon le reste est inchangé.
Avec cette fonction je peux passer à une culture différente de celle définie par défaut, le temps de l’exécution d’un script, d’une fonction ou d’une suite de commandes :
PS> using-culture es-es {get-date}
sábado, 22 de julio de 2006 2:28:09
Mais revenons trente secondes sur les formats de date. La discussion que j’évoquais au début de ce billet, a abouti à une suggestion fort pertinente du remarquable MVP Alex K. Angelopoulos. Alex propose qu’en lieu et place des paramètres US, soit utilisée la norme ISO 8601 pour l’affichage des dates et heures.
Le principe du format ISO 8601 est de présenter les informations d’une date dans un ordre de « poids » décroissant : d’abord l’année, puis le mois, puis le jour, et enfin heure, minutes et secondes. Le fait de commencer par l’année permet au lecteur de comprendre instantanément le format utilisé (alors qu’il y aura toujours ambigüité dans la lecture de « 12/10/2006 » entre le 12 octobre 2006 et le 10 décembre 2006). La norme ISO 8601 définit entre autres deux formats, l’un « de base » et l’autre « étendu », qui se présentent ainsi :
- Le 30 juillet 2006, 14h42 au format de base : 20060730144200
- Le 30 juillet 2006, 14h42 au format étendu : 2006-07-30 14:42:00
Le format de base sera plutôt réservé à des fichiers logs ou à des bases de données ne nécessitant pas d’intervention humaine. On voit bien que le format étendu est très lisible.
Malheureusement, il est fort peu probable que soit implémenté le support de cette norme dans Windows PowerShell, en tout cas dans sa v1. Principalement, parce que PowerShell repose là sur les choix faits par l’équipe .NET dans le paramétrage de la classe InvariantCulture. Je crois personnellement qu’il est bon que PowerShell reste aligné sur cette classe. Il faudrait donc convaincre l’équipe .NET d’adopter ISO 8601 comme base pour sa classe InvariantCulture (ou au moins pour la partie date et heure de cette classe), ce qui est loin d’être gagné pour d’évidentes raisons de souci de compatibilité avec les applications existantes.
Malgré tout, PowerShell pourrait modifier le type DateTime pour permettre à l’utilisateur d’écrire (et de lire) des dates dans un format universel. En attendant, il est toujours possible d’implémenter ses propres propriétés – dont l’intérêt ne sera réel que si les utilisateurs avec lesquels vous échangez des informations utilisent eux-aussi le format ISO 8601 . Pour implémenter ces propriétés, créez un fichier que vous appellerez par exemple datetime.types.ps1xml et copiez-y les lignes suivantes :
<Types>
<Type>
<Name>System.DateTime</Name>
<Members>
<ScriptProperty>
<Name>ISO8601</Name>
<GetScriptBlock>
$this.ToString("yyyyMMddHHmmss")
</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>ISO8601Ext</Name>
<GetScriptBlock>
$this.ToString("yyyy-MM-dd HH:mm:ss")
</GetScriptBlock>
</ScriptProperty>
</Members>
</Type>
</Types>
Pour prendre en compte les modifications décrites dans ce fichier, tapez la commande suivante :
update-typedate datetime.types.ps1xml
Vous pouvez maintenant taper :
PS> (get-date).ISO8601Ext
2006-07-30 13:03:24
Janel July 25 A l'aide, à l'aide!Depuis mon dernier billet sur l’aide en ligne de Windows PowerShell, j’ai reçu des centaines d’e-mails me demandant s’il est possible de concevoir un système simple d’aide en ligne pour des scripts. (vous y croyez, vous, à cette histoire d’e-mails ? J)
Si vous écrivez des scripts pour Windows PowerShell, vous avez sans doute pris l’habitude de commencer chacun de vos scripts par quelques lignes de commentaire qui expliquent (plus ou moins sommairement) ce que fait le script. Pour ceux d’entre vous qui n’ont pas cette habitude :
- je vous recommande vivement de l’adopter,
- je vous rappelle que pour PowerShell est considéré comme commentaire tout le texte d’une ligne qui suit le caractère # :
# Ceci est mon exemple :
write-host ‘Ceci est mon texte’ # Ceci est mon commentaire
L’idée a donc circulé sur le forum Microsoft dédié à PowerShell que l’on pourrait obtenir des infos sur un script si on avait une fonction qui extraie du script les premières lignes de commentaire. Voici ma version :
# Whatis.ps1
# Crée une fonction qui extrait les premières lignes de commentaire d’un script
# Usage: whatis script.ps1
# (c) janel, 2006
function whatis ([string]$script) {
$text = get-content (gcm -commandtype ExternalScript $script).definition
$cursor = 0
while ($text[$cursor] -match "^#")
{$text[$cursor]; $cursor++}
}
On peut alors faire :
PS> whatis whatis.ps1
# Whatis.ps1
# Crée une fonction qui extrait les premières lignes de commentaire d’un script
# Usage: whatis script.ps1
# (c) janel, 2006
Janel July 17 Au démarrage de ma session PowerShellJ’avais prévu de faire mon prochain billet sur la gestion des processus sous PowerShell (et notamment la communication avec des processus fils en asynchrone, possibilité mal connue et peu évidente) mais le temps me manque – hé oui, y’en a qui bossent par cette chaleur J
Entre temps j’ai installé Office 2007 sur mon poste. J’entends d’ici les esprits grincheux qui se disent : pour quelqu’un qui bosse j’ai du temps à perdre… Je répondrai à ces mal pensants que mon travail consiste (en partie) à tester le nouveaux logiciels de Microsoft. Et toc J
Dans la suite Office 2007, une des nouveautés d’Outlook qui m’intéressait le plus est l’intégration des flux RSS. Sous Outlook 2003 j’ai utilisé plusieurs add-ons avec des succès variés. J’ai toujours rechigné à utiliser un lecteur dédié ; je trouve déjà pénible de devoir passer à Outlook Express pour les newsgroups (je sais, il existe aussi des add-ons pour lire les news sous Outlook, mais tous ceux que j’ai essayé étaient vraiment nuls – et pas forcément de leur fait : je pense qu’Outlook n’est tout simplement pas fait pour suivre des conversations NNTP).
Donc, à peine Office 2007 installé, j’ai commencé à vouloir tester la lecture de mes blogs favoris.
Première surprise, une bonne : j’avais pris la précaution d’exporter ma configuration RSS pour pouvoir la réimporter sans avoir à tout ressaisir (une quinzaine de blogs, ce n’est pas la mort à saisir, mais quand on peut se l’épargner), or Outlook 2007 a automatiquement reconnu les réglages de l’add-on d’Outlook 2003 et a configuré la récupération des blogs dans son dossier « RSS Subscriptions ».
Par contre, le dossier « RSS Subscriptions » est présent dans mon Inbox sur le serveur, ce qui ne m’intéresse que moyennement. J’ai donc commencé à chercher comment déplacer ce dossier dans un de mes PST. J’ai rapidement trouvé comment changer le dossier d’une souscription particulière, mais je n’ai pas l’impression que ça marche très bien. J’ai ensuite trouvé comment indiquer à Outlook de faire pointer la racine des souscriptions ailleurs, mais s’il a bien créé une copie de mes dossiers je trouve toujours les originaux dans mon Inbox, et qui plus est le menu contextuel de la copie ne me semble pas être celui du dossier qu’Outlook considère comme son dossier RSS… bref, je vais devoir creuser le sujet un peu plus.
Pour en savoir plus, j’ai justement décidé de créer un fil sur mon blog et de voir dans quel dossier il arrivera (hé oui, aucun des autres blogs auxquels je suis inscrit n’a eu de nouvelle contribution depuis deux jours, à moins qu’en modifiant les réglages j’aie « cassé la machine » ?…).
Donc, comme je disais au début de ce fil un peu décousu, je n’ai pas le temps de faire un vrai fil sur le sujet qui m’intéressait – les processus et PowerShell. A la place, je vais donc simplement vous dire deux ou trois choses sur ce qui se passe au démarrage de ma session PowerShell.
Vous le savez sans doute maintenant (si vous avez lu la doc en anglais, ou si vous avez un peu suivi les autres blogs sur PowerShell), un fichier profil est exécuté au démarrage de chaque session. En fait, plusieurs fichiers profil sont potentiellement chargés au démarrage :
1 - Le profil de base commun à tous les utilisateurs :
“Documents and settings\All users\Documents\PsConfiguration\profile.ps1”
2 - Le profil commun à tous les utilisateurs, propre à chaque hôte PowerShell :
"\Documents and settings\All users\Documents\PsConfiguration\Microsoft.PowerShell_profile.ps1"
3 - Le profil de base pour mon compte:
"<My Documents>\PsConfiguration\profile.ps1"
4 - Le profil de mon compte, propre à chaque hôte PowerShell :
"<My Documents>\PsConfiguration\Microsoft.PowerShell_profile.ps1"
(voir le blog de Lee Holmes pour plus d’infos sur le sujet)
Les profils 2 et 4 peuvent vous paraître curieux. Qu’est-ce qu’un hôte PowerShell ? En fait, la console installée avec PowerShell est un hôte parmi d’autres possibles. PowerShell en tant que tel n’est pas limité à cette console, il peut être utilisé par n’importe quelle application Windows. C’est ainsi qu’on trouve déjà des hôtes graphiques sur Internet (voir notamment PowerShell IDE et PowerShell Analyser). Sur les prochaines versions d’Exchange Server et de MOM, les outils d’administration seront également des hôtes PowerShell. Chaque hôte pourra donc avoir ses propres réglages définis pour tous les utilisateurs (profil 2 ci-dessus) ou pour un utilisateur en particulier (profil 4 ci-dessus).
Dans une session de commande PowerShell, on a une variable $profile qui pointe vers le profil 4 (le plus spécifique possible). On peut donc très facilement éditer le fichier en question :
ii $profile
ii est un alias de la commandelette invoke-item. Sur mon poste, cela ouvre mon fichier profil avec le Bloc-notes de Windows. Si vous avez configuré un autre éditeur de texte par défaut, invoke-item l’utilisera automatiquement.
Alors, qu’y a-t-il dans mon profil ? Normalement (enfin, les recommandations sont que) je ne devrais avoir qu’une ligne pointant vers un autre script. Quelque chose comme :
. c:\scripts\monprofil.ps1
En effet, si jamais une installation à venir de PowerShell écrase les fichiers de configuration standards, je n’ai pas à tout recréer. Il me suffit de rajouter la ligne ci-dessus pour retrouver tous mes réglages particuliers. Mais je suis un rebelle, et j’aime vivre dangereusement. J’ai donc plusieurs lignes dans $profile, dont la définition de ma fonction prompt :
function prompt
{
$nextId = (get-history -count 1).Id + 1;
$currentPath = (get-location).Path.replace($home, "~")
$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$windowsPrincipal = new-object 'System.Security.Principal.WindowsPrincipal' $windowsIdentity
if ($windowsPrincipal.IsInRole("Administrators") -eq 1)
{
$color = "Red"
$role = "Admin"
}
else
{
$color = "Green"
$role = "User";
}
$dirs = ([array](gci | where {$_.PSIsContainer})).length
$files = ([array](gci | where {! $_.PSIsContainer})).length
$host.UI.RawUI.windowTitle = ($CurrentPath + " (as " + $role + ")")
write-host ((split-path -leaf $CurrentPath) + "[" + $files + "/" + $dirs + "]>") -nonewline -foregroundcolor $color
return " "
}
Je vous laisse le plaisir de voir tout ce que ça fait. Attention, mon prompt n’est pas super-compatible avec le parcours de lecteurs réseau. Enfin, ça marche mais ça peut parfois être un peu lent. Je vous laisse comprendre pourquoi, ce n’est pas très sorcier.
Dans mon $profile je crée également quelques alias supplémentaires pour les commandelettes ayant trait à l’objet object. Les alias que je crée consistent simplement à ne reprendre que le verbe : par exemple la commandelette new-object génère l’alias new.
gcm -noun object | %{set-alias $_.Verb $_ -ea silentlycontinue}
Ensuite, je charge un fichier qui contient mes définitions de types personnalisées (voir notamment mon fil sur l’aide en ligne de PowerShell) :
# ajouter mes définitions de types
#
write-host "Updating type information:"
gci "$(split-path $profile)\scripts\startup" | ? {$_.name -match "types.ps1xml"} | % {$_.fullname; update-typedata $_.fullname}
Comme vous pouvez le voir, j’ai créé un sous-dossier \scripts dans le dossier PSConfiguration qui contient mon $profile, et dans \scripts j’ai créé un sous-dossier \startup. A quoi me servent ces dossiers ?
PSConfiguration\Scripts contient tous les scripts PowerShell auxquels je veux pouvoir accéder à tout moment depuis n’importe quelle session, quel que soit mon répertoire en cours. J’ai ajouté le chemin complet de ce dossier dans ma variable d’environnement PATH. Je pourrais d’ailleurs le faire directement dans mon $profile. A vous de voir comment on fait cela.
PSConfiguration\Scripts\Startup contient tous les fichiers que je veux charger automatiquement au démarrage de chaque session PowerShell. Cela inclut le fichier de définition de types ci-dessus, mais aussi des scripts (définitions de fonctions principalement). Les dernières lignes de mon $profile s’occupent de charger les scripts en question :
# exécuter tous les scripts présents dans le sous-répertoire \Scripts\Startup
#
write-host "Executing scripts:"
gci "$(split-path $profile)\scripts\startup" | ? {$_.extension -eq ".ps1"} | % {$_.fullname; . $_.fullname}
Cela me permet de très facilement ajouter des fonctionnalités à mes sessions PowerShell sans avoir à modifier $profile. Au passage, je peux également surveiller plus finement ce qui se charge au démarrage de ma session.
J’espère que cela vous aura donné des idées (et des bonnes J). Maintenant, à vous de jouer !
Janel July 11 Pour une lecture plus facile de l'aide de PowerShellSi vous utilisez PowerShell (et je suppose que c’est le cas, sinon la raison pour laquelle vous lisez ce blog m’intéresse J) vous devez régulièrement utiliser l’aide en ligne de PowerShell pour connaître les arcanes de telle ou telle commandelette. L’usage typique de l’aide en ligne est sous cette forme :
PS> get-help suspend-service
NAME
Suspend-Service
SYNOPSIS
Suspends a running service.
SYNTAX
…
Jusqu’à présent, PowerShell déroulait alors des kilomètres de pages d’aide, qu’il fallait remonter pour pouvoir lire le texte dans le bon ordre. Quelques astuces permettaient de s’en tirer un peu mieux. La première, la plus simple, consiste à utiliser une fonction de pagination, comme la fonction more intégrée à PowerShell :
PS> get-help suspend-service | more
L’affichage de l’aide est alors interrompu en bas de page et une navigation sommaire (ligne par ligne ou page par page) est proposée.
Une autre astuce consiste à ne faire appel qu’aux parties de l’aide qui nous intéressent. Cette astuce repose sur le fait que l’aide en ligne de PowerShell est, comme tout sous PowerShell, un objet. Et les éléments de cet objet sont autant de propriétés accessibles séparément. Pour s’en convaincre, on peut taper ceci :
PS> get-help suspend-service | get-member
TypeName: MamlCommandHelpInfo
Name MemberType Definition
---- ---------- ----------
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
ToString Method System.String ToString()
alertSet NoteProperty System.Management.Automation.PSObject alertSet=@{title=; alert=System.Management.A...
Category NoteProperty System.String Category=Cmdlet
Component NoteProperty Component=null
description NoteProperty System.Management.Automation.PSObject[] description=System.Management.Automation.P...
details NoteProperty System.Management.Automation.PSObject details=@{name=Suspend-Service; verb=suspend...
examples NoteProperty System.Management.Automation.PSObject examples=@{example=@{code=suspend-service w3...
Functionality NoteProperty Functionality=null
inputTypes NoteProperty System.Management.Automation.PSObject inputTypes=@{inputType=@{description=; type=...
Name NoteProperty System.String Name=Suspend-Service
nonTerminatingErrors NoteProperty System.Management.Automation.PSObject nonTerminatingErrors=
parameters NoteProperty System.Management.Automation.PSObject parameters=@{parameter=System.Management.Aut...
PSSnapIn NoteProperty System.Management.Automation.PSSnapInInfo PSSnapIn=Microsoft.PowerShell.Management
relatedLinks NoteProperty System.Management.Automation.PSObject relatedLinks=@{navigationLink=System.Managem...
returnValues NoteProperty System.Management.Automation.PSObject returnValues=@{returnValue=@{description=; t...
Role NoteProperty Role=null
Synopsis NoteProperty System.String Synopsis=Suspends a running service.
syntax NoteProperty System.Management.Automation.PSObject syntax=@{syntaxItem=System.Management.Automa...
terminatingErrors NoteProperty System.Management.Automation.PSObject terminatingErrors=
xmlns:command NoteProperty System.String xmlns:command=http://schemas.microsoft.com/maml/dev/command/2004/10
xmlns:dev NoteProperty System.String xmlns:dev=http://schemas.microsoft.com/maml/dev/2004/10
xmlns:maml NoteProperty System.String xmlns:maml=http://schemas.microsoft.com/maml/2004/10
MSDN ScriptMethod System.Object MSDN();
Le résultat pourra être sensiblement différent selon la version de PowerShell que vous utilisez et les personnalisations éventuelles que vous aurez apportées. Les principales propriétés devraient malgré tout être présentes sur toutes les versions actuellement en circulation. Ces propriétés correspondent aux différentes sections de l’aide :
PS> (get-help suspend-service).synopsis
Suspends a running service.
PS> (get-help suspend-service).syntax
Suspend-Service [-name] <string[]> [-include <string[]>] [-exclude <string[]>] [-passthru] [-whatIf] [-confirm] [<Commo
nParameters>]Suspend-Service [-include <string[]>] [-exclude <string[]>] -displayName <string[]> [-passthru] [-whatIf]
[-confirm] [<CommonParameters>]Suspend-Service [-include <string[]>] [-exclude <string[]>] [-passthru] [-inputObject <S
erviceController[]>] [-whatIf] [-confirm] [<CommonParameters>]
PS> (get-help suspend-service).parameters
-name <string[]>
Specifies the service name for the service being suspended. NOTE: This parameter is aliased to -ServiceName, an
d cannot be used with -DisplayName.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? true
-include <string[]>
Retrieves only the specified items. Wildcards are permitted. If you use -Include and -Exclude in the same comma
nd, -Exclude takes precedence over -Include.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? true
…
La liste des paramètres est en général assez longue, on retombe donc ici dans les problèmes de lisibilité qui nous ont amené à cette discussion. Heureusement, les paramètres sont eux aussi des objets, que l’on peut donc filtrer et formater. Par exemple :
PS> (get-help suspend-service).parameters.parameter | ft name, parametervalue, required -a
name parameterValue required
---- -------------- --------
name string[] true
include string[] false
exclude string[] false
displayName string[] true
passthru SwitchParameter false
inputObject ServiceController[] false
whatIf false
confirm false
Dans une version plus récente de PowerShell (la RC2, bientôt disponible en téléchargement si ce n’est pas déjà le cas à l’heure où j’écris), la commandelette get-help se dote de plusieurs niveaux de détails. Par défaut, get-help renvoie quelques lignes d’information affichables sur une seule page écran. L’utilisateur doit taper get-help –detailed pour une aide détaillée, voire get-help –full pour une aide exhaustive. Nul doute que cela améliorera un peu les choses, mais le recours à des techniques alternatives (comme celles proposées ci-dessus) restera d’actualité pour les gros consommateurs d’aide.
Pour ma part, je me suis créé une petite fonction (chargée à partir de mon profil) :
function read-help {
get-help $args[0] -full | out-file "$($env:temp)\$($args[0]).help.txt"
ii "$($env:temp)\$($args[0]).help.txt"
start-sleep 1
del "$($env:temp)\$($args[0]).help.txt"
}
Si vous utilisez PowerShell en version RC1 ou précédente, vous devrez enlever le paramètre -full de la commande get-help $args[0] –full.
Cette fonction lit l’aide complète, envoie le résultat dans un fichier texte temporaire et ouvre ce fichier avec l’application définie dans Windows pour ouvrir les fichiers texte (Notepad est l’application définie par défaut mais rien ne vous empêche d’avoir choisi un autre éditeur). On invoque la fonction de la manière suivante :
PS> read-help suspend-service
L’aide étant ouverte dans un éditeur, on peut alors la parcourir avec toute la facilité offerte par l’éditeur, et surtout on peut continuer à travailler dans sa session PowerShell tout en consultant l’aide ouverte à côté.
Enfin, je signalerai un freeware qui semble très pratique pour parcourir l’aide de PowerShell : ShinyPower. Je n’ai pas encore testé, j’attends donc vos commentaires !
Bon plaisir,
Janel July 10 Complétez l'aide en ligne de PowerShellAprès une absence de plusieurs semaines, me voici de retour pour de nouvelles aventures avec PowerShell. Aux esprits tordus : il n’y a aucun rapport entre mon absence de ces dernières semaines et le déroulement de la Coupe du Monde de football en Allemagne. Non, je n’y étais pas. Et même si j’ai suivi à la télé le beau parcours des Bleus jusqu’à la finale malheureuse d’hier, mon inactivité sur ce blog n’était pas directement liée à cette soudaine assiduité.
Bref, revenons à nos activités. Une de fonctionnalités les plus intéressantes et les plus prometteuses de PowerShell est la capacité donnée à l’utilisateur d’étendre les fonctionnalités disponibles. Le blog de l’équipe Windows PowerShell a récemment illustré cette capacité à travers plusieurs exemples. Je m’arrêterai juste sur l’un de ces exemples, qui consiste à ajouter à tout objet une méthode d’accès à l’aide en ligne MSDN le concernant. Comment ça marche ?
Dans le répertoire d’installation de PowerShell (accessible par la variable $pshome), vous trouverez un fichier très important, types.ps1xml. Ce fichier contient de nombreuses extensions au système de types .NET. Par exemple, c’est dans ce fichier que sont ajoutées à certains types les propriétés Name ou Count en alias de propriétés aux noms parfois moins évocateurs. N’hésitez pas à parcourir ce fichier pour vous familiariser avec la façon dont il est construit :
notepad (join-path $pshome types.ps1xml)
Comme il est rappelé dans la note en tête du fichier, il est déconseillé de modifier directement types.ps1xml. Cela ne vous interdit pas d’apporter vos propres extensions aux types NET. Pour ce faire, vous devez utiliser la commandelette update-typedata à laquelle vous donnerez vos propres fichiers écrits au format XML voulu et portant l’extension .ps1xml.
La force de cette méthode d’extension est non seulement qu’elle est ouverte à personnalisations par l’utilisateur, mais en plus qu’elle accepte les extensions sous la forme de véritables scripts PowerShell. L’exemple de l’ajout d’une méthode MSDN() en est une belle illustration :
<Types>
<Type>
<Name>System.Object</Name>
<Members>
<ScriptMethod>
<Name>MSDN</Name>
<Script>
$culture = $host.currentculture
if ($args[0])
{
$culture = $args[0]
}
if (($global:MSDNViewer -eq $null) -or ($global:MSDNViewer.HWND -eq $null))
{
$global:MSDNViewer = new-object -ComObject InternetExplorer.Application
}
$Uri = "http://msdn2.microsoft.com/" + $culture + "/library/" + $this.GetType().FullName + ".ASPX"
$global:MSDNViewer.Navigate2($Uri)
$global:MSDNViewer.Visible = $TRUE
$ShellObj = new-object -com WScript.Shell
$ShellObj.AppActivate((get-process | where {$_.MainWindowHandle -eq $global:MSDNViewer.HWND}).Id)
</Script>
</ScriptMethod>
</Members>
</Type>
</Types>
Le fait d’ajouter cette méthode au type de base System.Object permet à tous les types d’en hériter. Pour en profiter, enregistrez le texte ci-dessus dans un fichier (par exemple my.types.ps1xml), et chargez le contenu de ce fichier en tapant la commande suivante:
update-typedata my.types.ps1xml # précisez le chemin complet si le fichier n’est pas dans le répertoire en cours
Vous pouvez ensuite voir et utiliser la méthode avec n’importe quel objet manipulable dans PowerShell:
PS> "hello" | get-member
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone()
CompareTo Method System.Int32 CompareTo(Object value), System.Int32 CompareTo(String strB)
Contains Method System.Boolean Contains(String value)
…
MSDN ScriptMethod System.Object MSDN();
PS> “hello”.MSDN() # ouvre une fenêtre IE sur la page MSDN décrivant le type System.String
PS> (get-date).MSDN() # ouvre une fenêtre IE sur la page MSDN décrivant le type System.DateTime
Vous noterez au passage que la méthode ouvre la page correspondant à la langue spécifiée dans vos réglages régionaux. Vous pouvez voir ces réglages depuis PowerShell:
PS> $host.CurrentCulture
LCID Name DisplayName
---- ---- -----------
1036 fr-FR French (France)
Dans mon cas (comme vraisemblablement dans le vôtre) la section MSDN retenue sera donc fr-fr.
Si vous voulez disposer de cette méthode systématiquement à chaque session PowerShell, n’oubliez pas d’ajouter la ligne « update-data … » à votre profil.
Bonne lecture,
Janel |
|
|