Kapitel 6: Flusssteuerung
Skripterstellung
Wenn Sie nicht mehr nur noch PowerShell-Einzeiler, sondern ganze Skripts schreiben sollen, klingt dies erst einmal wesentlich komplizierter, als es tatsächlich ist. Ein Skript besteht aus denselben oder ähnlichen Befehlen, die Sie sonst interaktiv in der PowerShell-Konsole ausführen würden, außer dass diese jetzt als .PS1
-Datei gespeichert werden. Es gibt einige Skriptkonstrukte, die Sie verwenden können, z. B. eine foreach
-Schleife anstelle des Cmdlets ForEach-Object
. Für Einsteiger können die Unterschiede verwirrend sein, besonders wenn Sie bedenken, dass foreach
sowohl ein Skriptkonstrukt als auch ein Alias für das Cmdlet ForEach-Object
ist.
Schleifen
Eine der großartigen Eigenschaften von PowerShell ist, dass es, sobald Sie herausgefunden haben, wie Sie etwas mit einem Element machen, fast genauso einfach ist, dieselbe Aufgabe für Hunderte von Elementen auszuführen. Durchlaufen Sie die Elemente einfach in einer Schleife, indem Sie eine der zahlreichen verschiedenen Arten von Schleifen in PowerShell verwenden.
ForEach-Object
ForEach-Object
ist ein Cmdlet zum Durchlaufen von Elementen in einer Pipeline, wie mit PowerShell-Einzeilern. ForEach-Object
streamt die Objekte durch die Pipeline.
Obwohl der Parameter Module von Get-Command
mehrere Werte akzeptiert, die Zeichenfolgen sind, akzeptiert er sie nur über die Pipelineeingabe mittels Eigenschaftsname oder über Parametereingaben. Wenn Sie im folgenden Szenario zwei Zeichenfolgen als Wert an Get-Command
übergeben möchten, um sie mit dem Parameter Module zu verwenden, müssten Sie das Cmdlet ForEach-Object
verwenden.
'ActiveDirectory', 'SQLServer' |
ForEach-Object {Get-Command -Module $_} |
Group-Object -Property ModuleName -NoElement |
Sort-Object -Property Count -Descending
Count Name
----- ----
147 ActiveDirectory
82 SqlServer
Im vorherigen Beispiel ist das aktuelle Objekt $_
. Ab PowerShell-Version 3.0 kann anstelle von $_
$PSItem
verwendet werden. Ich bin aber der Meinung, dass die meisten erfahrenen PowerShell-Benutzer immer noch lieber $_
verwenden, weil es abwärtskompatibel und weniger einzugeben ist.
Wenn Sie das Schlüsselwort foreach
verwenden, müssen Sie zuerst alle Elemente im Arbeitsspeicher speichern, bevor Sie diese durchlaufen, was sich schwierig gestalten kann, wenn Sie nicht wissen, mit wie vielen Elementen Sie arbeiten.
$ComputerName = 'DC01', 'WEB01'
foreach ($Computer in $ComputerName) {
Get-ADComputer -Identity $Computer
}
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :
DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
Häufig ist eine Schleife wie foreach
oder ForEach-Object
erforderlich. Andernfalls erhalten Sie eine Fehlermeldung.
Get-ADComputer -Identity 'DC01', 'WEB01'
Get-ADComputer : Cannot convert 'System.Object[]' to the type
'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter 'Identity'.
Specified method is not supported.
At line:1 char:26
+ Get-ADComputer -Identity 'DC01', 'WEB01'
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], ParameterBindingExc
eption
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirectory.Management
.Commands.GetADComputer
In anderen Fällen können sie dieselben Ergebnisse erzielen und gleichzeitig die Schleife vollständig beseitigen. Sehen Sie in der Cmdlet-Hilfe nach, um Ihre Optionen herauszufinden.
'DC01', 'WEB01' | Get-ADComputer
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :
DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
Wie Sie in den vorherigen Beispielen sehen können, akzeptiert der Parameter Identity für Get-ADComputer
nur einen einzelnen Wert, wenn er über die Parametereingabe bereitgestellt wird, lässt aber mehrere Elemente zu, wenn die Eingabe über eine Pipelineeingabe bereitgestellt wird.
For
Eine for
-Schleife wird durchlaufen, während eine bestimmte Bedingung erfüllt (true) ist. Die for
-Schleife verwende ich nicht häufig, aber sie hat ihre Berechtigung.
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
}
Sleeping for 1 seconds
Sleeping for 2 seconds
Sleeping for 3 seconds
Sleeping for 4 seconds
Im vorherigen Beispiel wird die Schleife viermal durchlaufen, beginnend mit der Zahl 1, und wird fortgesetzt, solange die Zählervariable $i
kleiner als 5 ist. Sie setzt für insgesamt 10 Sekunden aus.
Empfohlen
Es gibt zwei verschiedene do
-Schleifen in PowerShell. Do Until
wird ausgeführt, während die angegebene Bedingung nicht erfüllt (false) ist.
$number = Get-Random -Minimum 1 -Maximum 10
do {
$guess = Read-Host -Prompt "What's your guess?"
if ($guess -lt $number) {
Write-Output 'Too low!'
}
elseif ($guess -gt $number) {
Write-Output 'Too high!'
}
}
until ($guess -eq $number)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Das vorherige Beispiel ist ein Zahlenspiel, das solange fortgesetzt wird, bis der von Ihnen geschätzte Wert mit der Zahl übereinstimmt, die das Cmdlet Get-Random
generiert hat.
Do While
ist genau das Gegenteil. Sie wird ausgeführt, solange die angegebene Bedingung als „true“ ausgewertet wird.
$number = Get-Random -Minimum 1 -Maximum 10
do {
$guess = Read-Host -Prompt "What's your guess?"
if ($guess -lt $number) {
Write-Output 'Too low!'
} elseif ($guess -gt $number) {
Write-Output 'Too high!'
}
}
while ($guess -ne $number)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Too low!
What's your guess?: 4
Dieselben Ergebnisse werden mit einer Do While
-Schleife erzielt, indem die Testbedingung in „ungleich“ umgekehrt wird.
Do
-Schleifen werden immer mindestens einmal ausgeführt, weil die Bedingung am Ende der Schleife ausgewertet wird.
While
Ähnlich wie bei der Do While
-Schleife, wird eine While
-Schleife ausgeführt, solange die angegebene Bedingung erfüllt (true) ist. Der Unterschied besteht jedoch darin, dass eine While
-Schleife die Bedingung am Anfang der Schleife auswertet, bevor überhaupt Code ausgeführt wird. Somit wird sie gar nicht ausgeführt, wenn die Bedingung als „false“ ausgewertet wird.
$date = Get-Date -Date 'November 22'
while ($date.DayOfWeek -ne 'Thursday') {
$date = $date.AddDays(1)
}
Write-Output $date
Thursday, November 23, 2017 12:00:00 AM
Im vorherigen Beispiel wird berechnet, an welchem Tag in den USA „Thanksgiving“ (Erntedankfest) ist. Dies ist immer am vierten Donnerstag im November. Die Schleife beginnt also mit dem 22. Tag im November und fügt einen Tag hinzu, solange der Wochentag nicht gleich Donnerstag ist. Wenn der 22. ein Donnerstag ist, wird die Schleife überhaupt nicht ausgeführt.
Break, Continue und Return
Break
dient dem Unterbrechen einer Schleife. Es wird auch häufig mit der switch
-Anweisung verwendet.
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
break
}
Sleeping for 1 seconds
Die im vorherigen Beispiel gezeigte break
-Anweisung bewirkt, dass die Schleife bei der ersten Iterationen beendet wird.
„Continue“ ist so konzipiert, dass zur nächsten Iteration einer Schleife gesprungen wird.
while ($i -lt 5) {
$i += 1
if ($i -eq 3) {
continue
}
Write-Output $i
}
1
2
4
5
Das vorherige Beispiel gibt die Zahlen 1, 2, 4 und 5 aus. Es überspringt die Zahl 3 und fährt mit der nächsten Iteration der Schleife fort. Ähnlich wie bei break
, unterbricht continue
die Schleife, wenn auch nur für die aktuelle Iteration. Die Ausführung wird mit der nächsten Iteration fortgesetzt, anstatt die Schleife zu unterbrechen und zu beenden.
„Return“ ist so konzipiert, dass der vorhandene Bereich verlassen wird.
$number = 1..10
foreach ($n in $number) {
if ($n -ge 4) {
Return $n
}
}
4
Beachten Sie, dass im vorherigen Beispiel das erste Ergebnis zurückgegeben und dann aus der Schleife beendet wird. Eine ausführlichere Erläuterung der Ergebnisausweisung finden Sie in einem meiner Blogartikel: "Die PowerShell gibt Schlüsselwort (keyword) zurück".
Zusammenfassung
In diesem Kapitel haben Sie die verschiedenen Arten von Schleifen kennengelernt, die in PowerShell vorhanden sind.
Überprüfung
- Worin besteht der Unterschied zwischen dem
ForEach-Object
-Cmdlet und dem foreach-Skriptkonstrukt? - Worin besteht der primäre Vorteil bei der Verwendung einer While-Schleife anstelle einer „Do While“- oder „Do Until“-Schleife?
- Worin unterscheiden sich break- und continue-Anweisungen?