Zum Hauptinhalt springen

Parameter in Powershell-Funktionen und Skripten vor Intellisense verstecken

Der Scriptblock in Powershell stellt standardmäßig einen Param-Block zur Verfügung, über den Parameter an Skripte und Funktionen übergeben werden können. Erweiterte Funktionen bieten darüber hinaus eine ganze Reihe von Parameter-Optionen, um das Verhalten der Parameter steuern zu können. Eine manchmal sehr hilfreiche, unbekannte Parameter-Option ist DontShow, mit der man verhindern kann, dass ein Parameter in Intellisense angezeigt wird. Das kann z.B. nützlich sein, wenn man Hilfsfunktionen baut, die allgemein nutzbar (öffentlich) sind, bei denen bestimmte Hilfsparameter aber nur unter ganz bestimmten Spezialfällen sinnvoll sind. Geben Sie bei den Parameter-Optionen einfach DontShow mit an:

 

function Test-HiddenParam {
(
   Param( [Parameter(DontShow)] [string]$hiddenParameter
)
   $hiddenParameter
}

 

Den Proxy-Server für Powershell setzen

Wenn Sie mit den Interneteinstellungen den Proxy-Server setzen, werden diese Einstellungen nur vom IE übernommen. Alle anderen Netzwerkeinstellungen ignorieren nach wie vor die Proxy-Konfiguration. Einzige Ausnahme sind die Tools, die direkt auf die IE-Konfiguration zugreifen. Um den

Proxy global zu setzen, müssen Sie auf das Kommandozeilentool netsh.exe zurückgreifen. Zum systemweiten setzen des Proxys geben Sie in der Kommandozeile in Powershell ein

netsh winhttp set proxy <Proxyserver:Port>

Wenn Sie die vorhandenen Interneteinstellungen als globale Einstellungen verwenden wollen, geben Sie ein

netsh winhttp import proxy source=ie

Eine Ausnahmeliste geben Sie über byPassList mit:

netsh winhttp set proxy <Proxyserver:Port> bypass-list="*.Netz-Weise.intern"

 

Texte umschliessen und kommaseparierte Listen erstellen

Ein häufig auftretendes Problem ist das Umschliessen von Texten z.B. mit Anführungszeichen. Für Transact-SQL gibt es dafür sogar eine eigene Funktion, Quotename, die das übernimmt. In Powershell fehlt diese Funktion zwar, sie lässt sich aber durch den Format-Operator -f sehr einfach nachrüsten. Der Format-Operator kann in einen String beliebige Texte einfügen. Im Text werden dafür Platzhalter definiert. Ein Platzhalter ist eine Zahl, die in geschweifte Klammern eingeschlossen ist, z.B. {0}. Hinter dem Text folgt der Format-Operator -f, wiederum gefolgt von den Werten, die in die Platzhalter eingefügt werden sollen:

'Dies ist ein {0} Text mit {2} Platzhaltern, der als {1} dient' -f "sinnloser","Beispiel","drei"

Das Prinzip ist sehr einfach. Hinter dem -f folgen 3 Strings, die durch Kommas getrennt sind. Die Strings werden von 0 ab durchgezählt und in die entsprechenden Platzhalter eingefügt. Das Ergebnis lautet also:

Dies ist ein sinnloser Text mit drei Platzhaltnern, der als Beispiel dient.

Das kann man sich zunutze machen, um Texte einfach mit beliebigen Zeichen zu umschliessen:

'{1}{0}{1}' -f 'Eingabe',"''"

Logischerweise kann man das auch in der Pipeline nutzen, um z.B. Daten aus einer Textdatei zu umschliessen, oder im folgenden Beispiel einfach für ein paar Zahlen:

1..10 | foreach-object { '{1}{0}{1}' -f $_,"''" }
'1'
'2'
'3'
'4'
'5'
'6'
'7'
'8'
'9'
'10'

Jetzt wäre es noch schön, wenn wir den Text nicht als Einzelzeichen bekommen würden, sondern Komma-separiert. Hierfür ist der -join Operator sehr hilfreich, der einfach mehrere Eingaben mit einem Trennzeichen zusammenfügt. Um den join-Operator nutzen zu können, muss die Eingabeliste aber erst mal vollständig erzeugt werden. Daher speichern wir die vorige Ausgabe erst in ein Array und fügen die Werte anschließend zusammen:

$Zahlenarray = 1..10 | foreach-object { '{1}{0}{1}' -f $_,"`'" }
$zahlenarray -join ','

Alternativ können wir das Ergebnis auch in einer Zeile erzeugen:

( 1..10 | foreach-object { '{1}{0}{1}' -f $_,"''" }) -join ','

 

 

Sichere Kennwörter in Powershell erstellen

In meinem Blogeintrag Zufällige (Komplexe) Kennwörter erzeugen mit Powershell vom 23.04 habe ich gezeigt, wie man komplexe Kennwörter mit Powershell generieren kann, indem man zufällige Zeichen mit Get-Random erzeugt. Aber es geht auch einfacher, denn das .NET-Framework bietet bereits eine fertige statische Methode zum Generieren von Kennwörtern, die man in Powershell nur noch laden muss. Die Methode heißt GeneratePassword und befindet sich in der [System.Web] - Assembly. Die Assembly ist in Powershell allerdings nicht standardmäßig geladen. Dies kann man mit dem Cmdlet Add-Type erledigen:

Add-Type -AssemblyName System.web

 Nun können Sie die Methode GeneratePassword aus der Klasse [System.Web.Security.Membership] aufrufen. Der Aufruf erfolgt über [Klasse]::Methodenname(Parameter):

[System.Web.Security.Membership]::GeneratePassword(10,3)

 

Die beiden Parameter 10 und 3 bestimmen die Anzahl der Zeichen sowie die nicht-Alphanumerischen Zeichen, die das Kennwort enthalten muss.

In eine Funktion gegossen sieht das dann so aus:

function New-Password { param
(
   # The Length of the Password 
   [ValidateRange(3,128)] [String]$Length = 12,

   # Number of non-Alpanumeric Characters 
   [String]$Specials = '3'
)

   Add-Type -AssemblyName System.web
   System.Web.Security.Membership]::GeneratePassword($Length,$Specials)
}

 

 

function New-Password { param

(

# The Length of the Password [ValidateRange(3,128)] [String]$Length = 12,

# Number of non-Alpanumeric Characters [String]$Specials = '3'

)



Add-Type -AssemblyName System.web [System.Web.Security.Membership]::GeneratePassword($Length,$Specials)

}

 

Parametrisierte Programme in Powershell starten

Wenn man in Powershell ein ausführbares Programm starten möchte, kann man das normalerweise machen, indem man den direkten Pfad in der Konsole einfach aufruft. Genauso kann man ein Programm in einem Script direkt referenzieren.

C:\programme\7zip\7z.exe

Problematischer wird das, wenn der Pfad, in dem sich das Programm befindet, Leerzeichen enthält. Der Programmpfad muss dann in Anführungszeichen gesetzt werden, wird nun aber als String interpretiert und kann nicht mehr direkt aufgerufen. Powershell gibt stattdessen einfach nur den String zurück.

'C:\Program Files\7Zip\7z.exe' C:\Program Files\7Zip\7z.exe

 Die Lösung bietet der Ausführungsoperator &, der Powershell anweist, den folgenden String direkt auszuführen:

& 'C:\Program Files\7Zip\7z.exe'

Wenn dem Programm aber Parameter übergeben sollen, verhält sich der Ausführungsoperator erst einmal merkwürdig. Gibt man nämlich den Befehl inklusive der Parameter im String ein, erhält man eine Fehlermeldung:

& "'C:\Program Files\7Zip\7z.exe x -oC:\temp\extract C:\temp\archiv.7z"

& : Die Benennung ".\7z.exe x -oC:\temp\extract 'C:\temp\website test\website.7z'" wurde nicht als Name eines Cmdlet, einer Funktion, einer Skriptdatei oder eines ausführbaren Programms erkannt.

Der Ausführungsoperator benötigt die auszuführende Datei als einzelnen String. Die naheliegende Lösung ist also, die Parameter als zweiten String zu übergeben: 

& "C:\Program Files\7Zip\7z.exe" "x -oC:\temp\extract C:\temp\archiv.7z" 
Command Line Error: Unsupported command: x -oC:\temp\extract 'C:\temp\archiv.7z'

Tatsächlich müssen alle Parameter einzeln in einem Array übergeben werden, damit der Befehl korrekt ausgeführt wird. Achten Sie darauf, dass die Parameter Kommasepariert aufgelistet sind! 

$arguments = "x","-oC:\temp\extract","C:\temp\archiv.7z" & "C:\Program Files\7Zip\7z.exe" $arguments

Die Ausgabe des Befehls kann aufgefangen werden, indem man sie in eine Variable umleitet:

 Man kann das Problem auch vermeintlich elegant mit Start-Process lösen:

& "C:\Program Files\7Zip\7z.exe" "x -oC:\temp\extract C:\temp\archiv.7z" 
Command Line Error: Unsupported command: x -oC:\temp\extract 'C:\temp\archiv.7z'

Das hat allerdings einen anderen Haken, denn die Rückgabe von 7z.exe kann nicht mehr aufgefangen werden, da Start-Process eine eigene Konsole startet. Möchten Sie die Rückgabe unterdrücken, indem Sie sie z.B. in die Variable $null umleiten, funktioniert das mit Start-Process nicht:

$null = Start-Process -FilePath C:\Program Files\7Zip\7z.exe -ArgumentList 'x -oc:\temp\extract C:\temp\archive.7z' -NoNewWindow -Wait

7-Zip [64] 16.02 : Copyright © 1999-2016 Igor Pavlov : 2016-05-21 Scanning the drive for archives:
1 file, 117778 bytes (116 KiB) Extracting archive: C:\temp\archive.7z [...]

Beim Übergeben der Parameter müssen Sie außerdem noch den Sonderfall betrachten, dass auch in den Pfaden der Argumente Leerzeichen stehen können. Da der String selber schon mit " (Doppelten Anführungszeichen) markiert ist, kann man nicht einfach Anführungszeichen um den Pfad setzen, sondern muss Sie für Powershell als nicht interpretierbare Zeichen markieren. Das geschieht mit Hilfe des ' (Backtick oder für die Französischfreunde: Der Accent Graph):

$arguments = "x","-oC:\temp\extract","'"C:\temp\mein archiv.7z'"" & "C:\Program Files\7Zip\7z.exe" $arguments

 

 
& "'C:\Program Files\7Zip\7z.exe x -oC:\temp\extract C:\temp\archiv.7z"

& : Die Benennung ".\7z.exe x -oC:\temp\extract 'C:\temp\website test\website.7z'" wurde nicht als Name eines Cmdlet, einer Funktion, einer Skriptdatei oder eines ausführbaren Programms erkannt.