Schleifen
Schleifen werden verwendet, wenn Programmcode mehrfach hintereinander ausgeführt werden muss. Anstatt den Code x-mal hintereinander aufzuschreiben, können Sie den Code einmal als Codeblock angeben und festlegen, wie oft er ausgeführt werden soll.
Jede Pipeline kann durch eine Schleife ersetzt werde, da die Pipeline auch nur eine Form von Schleifenverarbeitung darstellt. Schleifen sind im Normalfall schneller als die Pipeline, gehen dafür aber auf Kosten des Arbeitsspeichers.
Powershell kennt alle klassischen Typen von Schleifen. Die dabei einfachste und universellste, mit der man alle anderen Schleifen abbilden kann, ist die While-Schleife. Sie arbeitet wie ein IF mit einer Bedingung und einem Skriptblock. Der einzige Unterschied ist, dass IF einen Skriptblock nur ein einziges Mal ausführt, während eine While-Schleife den Skriptblock so lange immer wieder aufruft, bis die Bedingung False ergibt. Sie können aus jeder einfachen IF-Bedingung eine While-Schleife machen, indem Sie einfach IF durch While ersetzen.
$counter = 1
While ( $true )
{
$counter
$counter++
Start-Sleep -Seconds 1
}
In diesem Beispiel ist die Bedingung hinter While immer $true, wodurch der Skriptblock unendlich lange ausgeführt wird. Der Skriptblock gibt die Variable $Counter aus, erhöht ihren Inhalt um 1 ($Counter ++ ist die Kurzschreibform von $Counter = $Counter +1), wartet eine Sekunde und da die Bedingung dann immer noch wahr ist, startet While dem Skriptblock erneut.
Um die Codeausführung abzubrechen, können Sie Strg+C drücken!
Damit die Schleife nicht endlos läuft, muss die Durchlaufbedingung irgendwann False ergeben.
$counter = 1
While ( $Counter -le 10 )
{
$counter
$counter++
Start-Sleep -Seconds 1
}
Für Schleifen, die wie im vorigen Beispiel nach einer festen Anzahl von Durchläufen beendet werden, stellt Powershell einen eigenen Schleifentyp zur Verfügung, die For-Schleife. Statt einer einfachen Abbruchbedingung definiert man hier im Schleifenkopf direkt die Zählervariable, die in der While-Schleife vor dem Starten des ersten Schleifendurchlaufs erst definiert werden musste ($Count). Außerdem definiert man eine Ausführungsbedingung und legt eine automatische Aktualisierung des Counters fest, jeweils getrennt mit einem Semikolon:
For ( $counter=1; $counter -le 10; $Counter++ )
{
$counter
Start-Sleep -Seconds 1
}
Die For-Schleife erfüllt exakt die gleiche Funktion wie die zählende While-Schleife, ist aber etwas kompakter, weil der Counter direkt von der Schleife gesteuert wird.
Prinzipiell kann man einzelne Definitionsbereiche auch auslassen - die For-Schleife sieht damit wieder ähnlich aus wie die While-Schleife:
$counter = 1
for ( ; $counter -le 10 )
{
$counter
$counter++
Start-Sleep -Seconds 1
}
Eine besonders kreative Anwendung einer For-Schleife ist diese Variante, die den ersten freien Laufwerksbuchstaben ausgibt:
For ( $j=67; Get-PSDrive -name ( $d=[char]++$j ) -ErrorAction SilentlyContinue )
{ }
$d
Das Original findet man unter http://www.powershellmagazine.com/2012/01/12/find-an-unused-drive-letter/.
Wie funktioniert die Schleife? Als Startwert wird die Zahl 67 definiert, was dem Buchstaben C in ASCII-Repräsentation entspricht. Um den ASCII-Wert 67 in einen Buchstaben umzuwandeln, kann an einfach die Zahl in einen Buchstaben umwandeln:
[char]67
> C
Get-PSDrive liefert, wie schon im Abschnitt Powershell-Provider gesehen, die Laufwerke zurück, die von den Providern zur Verfügung gestellt werden. Gibt man einen spezifischen Namen an, wird nur dieses Laufwerk ausgegeben. Im obigen Fall wird ein Laufwerksbuchstabe angefordert, und zwar der nächste Buchstabe nach dem C (++$j). $Counter++ haben wir schon gesehen, ++$Counter macht im Prinzip das Gleiche, allerdings wird bei $Counter++ immer erst der Befehl ausgeführt, bevor die Variable erhöht wird, während bei ++$Counter erst die Variable erhöht wird, bevor der Wert verarbeitet wird. ++$J erhöht 67 also um 1, wandelt den Wert in eine Zahl um, und anschließend gibt PSDrive das entsprechende Laufwerk aus.
Ist D als Laufwerksbuchstabe vorhanden, führt For das Skript aus, das in diesem Fall ein leerer Skriptblock ist, und startet die Schleife erneut. Ist der Laufwerksname aber nicht vorhanden, wirft Powershell einen Fehler und beendet die Schleife – der Parameter -Erroraction SilentlyContinue unterdrückt die Fehlermeldung. In der Variablen $D ist der Buchstabe gespeichert, der einen Fehler geworfen hat. Er muss dementsprechend frei sein und wird ausgegeben.
For-Schleifen können auch dazu verwendet werden, jedes Element in einem Array genau einmal zu verarbeiten. Das folgende Beispiel prüft jede Datei auf ihre Größe und gibt sie nur dann aus, wenn sie größer als 1MB ist – das gleiche Beispiel wurde auch schon einmal in Verbindung mit Where-Object verwendet.
[array]$FileList = Get-ChildItem -path c:\windows\system32\
For ( $i=0; $i -lt $fileList.Length; $i++ )
{
If ( $FileList[$i].Length -gt 1MB)
{
$fileList[$i]
}
}
> Mode LastWriteTime Length Name
> ---- --------- ----- ------
> -a---- 07.12.2019 10:08 1413632 aadtb.dll
> -a---- 06.12.2019 17:25 1704448 ActiveSyncProvider.dll
> -a---- 16.02.2019 00:55 1784544 adal.dll
> -a---- 07.12.2019 10:52 1201152 AgentService.exe
Die Schleife startet den Zähler mit 0 und beendet die Schleife, sobald $i größer oder gleich
$Files.Length ist. $Files.Length entspricht der Anzahl der Elemente im Array, also der Anzahl der Dateien.
Im Skriptblock der Schleife werden die einzelnen Elemente des Arrays angesprochen, indem der Zähler der Schleife als Index verwendet wird: $files[$i].
Das kann man ein wenig übersichtlicher schreiben, indem man die Variable $Files[$i] im Scriptblock zuerst einer neuen Variablen zuweist:
[array]$FileList = Get-ChildItem -path c:\windows\system32\
For ( $i=0; $i -lt $fileList.Length; $i++ )
{
$File = $Files[$i]
If ( $File.Length -gt 1MB)
{
$File
}
}
Diese spezielle Variante der For-Schleife, die immer eine feste Anzahl von Array-Elementen bearbeitet, kommt sehr häufig vor, und daher gibt es in Powershell dafür eine vereinfachte Variante , die Foreach-Schleife.
Die Foreach-Schleife ist auf die Verarbeitung von Listen spezialisiert und nimmt dem Programmierer das Zählen der Elemente ab. Man definiert man in der runden Klammer nur noch das zu durchlaufende Array und die Variable, der das jeweilige Array-Element zugewiesen werden soll:
Foreach ( $SpeichertDasAktuelleElement in $Array )
{}
Der obige Code löst sich dann folgendermaßen auf:
[array]$FileList = Get-ChildItem -path c:\windows\system32\
Foreach ( $File in $FileList )
{
If ( $File.Length -gt 1MB)
{
$File
}
}
Der Zählerblock der For-Schleife entfällt hier komplett – es muss ja eh jedes Element einmal verarbeitet werden. Powershell kümmert sich intern um den Zähler. Außerdem findet für jeden Schleifendurchlauf eine Neuzuweisung des jeweiligen Arrayelements statt – genau so, wie im letzten For-Beispiel rot markiert.
Wenn Sie eine Schleife abbrechen möchten, stehen Ihnen die Schlüsselwörter Break und Continue zur Verfügung. Während Continue den aktuellen Durchlauf beendet, aber die Schleife beim nächsten Element fortführt, beendet break die Schleife komplett.