PowerShell Parameter

Sowohl beim Aufruf von PowerShell-Skripten als auch Funktionen ist die Übergabe von Parametern möglich und sollte auch genutzt werden. Die Arbeit mit "globalen" Variablen ist nicht wirklich ratsam. PowerShell unterstützt und dabei sehr gut.

PowerShell und Funktionen und Parameter

Wer eine Funktion baut, macht die mit dem Ziel bestimmte Codeteile häufiger zu verwenden und den Code zu strukturieren. Man kann damit aber auch interne Verarbeitungen mit privaten Variablen aus dem Hauptprogramm auslagern. Die zur Verarbeitung erforderlichen Werte sind dann als Parameter an die Funktion zu übergeben. Hierzu gibt es zwei Wege, Parameter an eine PowerShell Funktion zu übergeben:

  • Definition im Funktionskopf
    Die erforderlichen Variablen können direkt hinter dem Funktionsnamen spezifiziert werden.

function Funktionsname ([int]$param1=10,[string]param2=msxfaq.de) {
    # Befehle
}

  • Definition als PARAMS-Block
    Alternativ können Parameter auch als eigener Block angegeben werden. Oft ist die übersichtlicher. Dies geht auch, wenn Sie direkt ein PowerShell Skript ganz ohne Funktionen einsetzen, d.h. Parameter an das aufgerufene Skript selbst übergeben wollen

function Funktionsname {
    PARAM (
            [int]$param1=10,
            [string]$param2=msxfaq.de
     )
    # Befehle
}

Wenn Sie aber die Parameter schon per PowerShell definieren, dann kann ab PowerShell 2.0 auch die "Autocomplete-"Funktion helfen, d.h. nach der Eingabe des Skripts starten Sie die Parameter mit einem "-" und nutzen dann die TAB-Taste, um durch die einzelnen Parameter zu laufen.

Typisierung

Perfekt wird es dann, wenn Sie die Parameter gleich auf "Gültigkeit" prüfen lassen. Schon eine Typisierung der Parameters verhindert viele Fehlzuweisungen

[int]$variable       # 32-bit integer mit Vorzeichen
[long]$variable      # 64-bit integer mit Vorzeichen
[string]$variable    # string mit unicode characters
[char]$variable      # A unicode 16-bit character
[byte]$variable      # 8-bit Zahl
[bool]$variable      # Boolean True/False
[decimal]$variable   # 128-bit Dezimalzahl
[single]$variable    # Single-precision 32-bit Fließkommazahl
[double]$variable    # Double-precision 64-bit Fließkommazahl
[xml]$variable       # Xml object
[array]$variable     # Array
[hashtable]$variable # Hashtabelle

# Denkbar sind aber auch Arrays
[String[]]$Userliste

Vorbelegung

Sie können einen Parameter schon mit Daten "vorbelegen". Die Angabe auf der Kommandozeile oder beim Funktionsaufruf überschreibt dann diese Vorbelegung

[string]$variablenname = "Beispielwert"

Zwang und Position und Hilfe

Weiterhin kann vorgegeben werden, ob ein Parameter zwingend angegeben werden muss und welche Position er hat, wenn Daten ohne Parameterangabe übergeben werden. Dazu setzen Sie einfach ein "[Parameter()]" davor.
Siehe auch Parameter Attribute Declaration http://msdn.microsoft.com/en-us/library/ms714348(v=VS.85).aspx
Den "Parameterset-Namen" kann man im Code einfach über $PsCmdlet.ParameterSetName z.B. in einer Switch-Anweisung abfragen

[Parameter(
   Position=0,'
   Mandatory=$true,
   HelpMessage="Dies ist eine Hilfe",
   ValueFromPipeline=$false,
   ParameterSetName="Setname"]
)][string]$variablenname

Erweiterte Validierung

Über die Angabe des Typs hinaus ist sogar noch eine Validierung direkt in der Parametrisierung möglich. So kann der Aufruf eines Scripts schon bei falschen Angaben gestoppt werden und muss nicht mehr im Code selbst später geprüft werden.

# Check gegen regular expressions
[Validatepattern("regexdausdruck")][string]$variablenname

# erweiterte Datumsabfrage
[ValidateRange( "06/10/2010 02:00:00 PM", "06/17/2010 03:00:00 PM")][DateTime]$Datum

# das ganze mit errechneten Min und Max Werten
[ValidateRange( [DateTime]::Now.AddDays(-7), [DateTime]::Now)]

# Check gegen eine Liste von Optionen
[ValidateSet("Ja", "Nein", "Vielleicht", IgnoreCase = $true)]

# Verifizierung per Code, z.B. dass die Zeit nach dem 1.1. 2010 ist
[ValidateScript({$_ -le [DateTime]::Now -and $_ -ge "1/1/2010"})

# Begrenzung der Element in einem Array
[ValidateCount(1,3)][String[]]$UserName

# erwartet einen Text mit 5-8 Buchstaben
[ValidateLength(5,8)][string]$variablenname

# weitere Funktionen
[ValidateNotNullOrEmpty], [ValidateNotNull], [AllowNull], [AllowEmptyString], [AllowEmptyCollection]

Wem diese einfachen Checks nicht reichen, kann natürlich als Teil der Parameter aber auch später im Code natürlich eine bessere Überprüfung und Erzwingung machen. So muss man überlegen, ob ein Parameter in der Definition schon als "Mandantory" vorgegeben werden sollte oder der Code prüft, ob der Inhalt sinnhaft ist und dann den Wert zu erfragen.

param (
   $dateiname = "keine Angabe"
)

while (!(test-path -path $dateiname -pathtype leaf)) {
   write-host "Datei konnte nicht gefunden werden"
   $dateiname = read-host "Bitte Dateinamen eingeben"
}
write-host "Dateiname:" $dateiname

Mit so einer Konstruktion muss ein Anwender einen gültigen Dateinamen eingeben, ehe das Skript weiter macht. für eine Automatisierung ist dies natürlich nicht hilfreich.

Dynamische Parameter

Wem das dann immer noch nicht reicht, kann Parameter dynamisch ein und ausschalten, indem der Wert eines anderen Parameter ausgewertet wird.. Interessanterweise steht viel davon in der PowerShell Online Hilfe:

get-help about_Functions_Advanced_Parameters

Beim Aufruf der Funktion sollte man sich aber an PowerShell und "Komma" erinnern. Parameter werden nicht durch Komma getrennt übergeben sondern mit Leereichen. Ein Komma macht aus den zwei oder mehr Parametern ein Array, welches die Funktion als ersten Parameter erhält.

# FALSCH
funktionsname wert1, wert2, wert3

#Richtig
funktionsname wert1 wert2 wert3

Die Rückübergabe von Ergebnissen erfolgt ebenfalls einfach über die Pipeline, d.h. alles was das Skript einfach "ausgibt" bekommt der aufrufende Prozess zurück. Insofern muss an Ende keine Zuweisung des Ergebnisses an den Funktionsnamen stehen, sondern einfach die Variable mit dem Inhalt.

PowerShell und Kommandozeile

Analog zur Parameterübergabe für eine Funktion können Sie natürlich auch einem PS1-Skript direkt die Parameter übergeben. Da es hier aber keine Funktionsüberschrift gibt, wird der PARAM -Block direkt am Anfang geschrieben.

PARAM(
    [int]$Interval=60 ,
    [string]$domain="msxfaq.de" .
    [ScriptBlock]$skriptteil={(get-mailboxserver| select name)}
)

Der Aufruf kann dann wie gewohnt mit Parametrisierung erfolgen.

.\scriptname -interval 30 -domain andere.domain

 Es müssen auch nicht alle Parameter übergeben werden. Überzählige Parameter werden einfach ignoriert, d.h. vorsicht bei Tippfehlern. Erst die PowerShell 2 wertet die PowerShell diese Parameterblöcke im Skript auch derart aus, dass Sie über die AutoComplete-Funktion der Kommandozeile erreichbar werden.

Man kann hier auch die Defaults angeben, wenn der aufrufende Prozess keine Daten hinterlegt. Interessant ist hier auch die Funktion, direkt einen [Scriptblock] mit zu übergeben, welcher später einfach mit "$skriptteil" aufgerufen werden kann.

write-host "Argumente sind $args"

Default Parameter

Fast alle PowerShell-Commandlets haben Parameter wie "-verbose", "-errorpreference" etc. Diese Parameter müssen Sie nun aber nicht selbst alles codieren. Die PowerShell kennt einen "Default Parameter Set", den man nur aktivieren muss. Addieren Sie vor dem "param" einfach ein "[CmdletBinding()]" wie hier im Beispiel

[CmdletBinding()]
param (
    $URL = "http://www.msxfaq.de"
)

Und schon haben Sie ihren Parametersatz auch um diese eingebauten Parameter erweitert. Der Große Vorteil dabei ist, dass Sie nun auch "Write-Verbose" etc. einfach sinnvoll nutzen können.

Parameter mit dem Typ "Switch"

Bei einer Funktion könne Sie auch "[switch]" als Typ angeben. In diesem Fall heisst ein vorhandensein eines Parameters, dass dieser "true" ist. Ein explizites "$true" muss nicht mehr mit angegeben werden.

function switchdemo([switch]$test ) {
  if( $test ) { 'true' }
  else { 'false' } 
}

PS C:\> switchdemo -test:$true
true
PS C:\> switchdemo -test:$false
false
PS C:\> switchdemo -test
true
PS C:\> switchdemo
false
PS C:\> switchdemo -test $false
true

Bei der Angabe von "$true" oder "$False" ist aber nur die Schreibweise mit einem Doppelpunkt (":") zulässig. Bei einem Aufruf mit Leerzeichen als Trenner wird das $False z.B. als zweiter Parameter betrachtet.

Weitere Links