Wenn Sie ein PowerShell-Skript ohne Funktionen und ohne externe Abhängigkeiten von anderen Skripts schreiben, ist das Konzept der PowerShell-Bereiche nicht von großer Bedeutung. Das Konzept der globalen PowerShell-Variablen steht nicht im Vordergrund. Wenn Sie jedoch beginnen, Funktionen und Module zu erstellen und lernen, Skripts von anderen Skripts aus aufzurufen, wird das Thema immer wichtiger.
In diesem Artikel erhalten Sie eine ausführliche Lektion darüber, was Scopes in PowerShell sind, wie sie funktionieren und wie Sie Code unter Berücksichtigung von Scopes schreiben können. Wenn Sie fertig sind, werden Sie die globalen Variablen von PowerShell und vieles mehr verstehen!
Inhaltsverzeichnis
- Scopes: Eine Art von Eimern
- Bereichstypen
- Globaler Bereich
- Skriptbereich
- Privater Bereich
- Lokaler Bereich
- Referenzieren von Bereichen
- Benannte Bereiche
- Nummerierte Bereiche
- Bereichshierarchie und Vererbung
- Definieren von und Zugreifen auf Elemente in Bereichen
- Get/Set-Variable
- Lokale Bereiche
- Private/Skript/Globale Geltungsbereiche
- Bereich „Prefacing“
- Lokale Bereiche
- Private/Skript/Globale Bereiche
- Bereiche in Skriptblöcken
- Dot-Sourcing-Skripte (Austauschen lokaler Bereiche)
- Verwenden der AllScope-Eigenschaft (Option)
- Funktionsbereiche
- Elemente privat halten (Vererbung deaktivieren)
- Best Practices für das Scoping
- Weitere Lektüre
Scopes: Eine Art von Eimern
Haben Sie schon einmal ein Skript geschrieben, in dem Sie eine Variable definieren, und wenn Sie den Wert dieser Variable überprüfen, ist es etwas anderes? Sie werden sich vielleicht den Kopf darüber zerbrechen, wie sich die Variable geändert hat, obwohl Sie sie eindeutig definiert haben. Ein Grund dafür kann sein, dass der Wert der Variable in einem anderen Bereich überschrieben wird.
Vielleicht haben Sie sich schon einmal gefragt, warum bestimmte PowerShell-Variablen Werte haben, wenn Sie in Ihrer Konsole darauf verweisen, aber in Ihren Skripts nicht vorhanden sind. Wahrscheinlich befinden sich diese Variablen in einem anderen „Bucket“, der zu diesem Zeitpunkt nicht verfügbar ist.
Scopes sind wie Buckets. Scopes beeinflussen die Art und Weise, wie PowerShell Variablen, Aliase, Funktionen und PSDrives zwischen verschiedenen Bereichen isoliert. Ein Bereich ist wie ein Eimer. Es ist ein Ort, an dem all diese Elemente gesammelt werden.
Wenn PowerShell startet, werden diese „Buckets“ automatisch für Sie erstellt. Zu diesem Zeitpunkt verwenden Sie bereits Scopes, ohne es zu merken. Alle Bereiche werden von PowerShell definiert und ohne Ihr Zutun erstellt.
Bereichstypen
Wenn PowerShell startet, werden automatisch vier „Bereiche“ oder Scopes erstellt, in die verschiedene Elemente eingeordnet werden können. Sie können keine eigenen Bereiche erstellen. Sie können nur Elemente aus diesen unten definierten Bereichen hinzufügen und entfernen.
Globaler Bereich
Elemente, die beim Öffnen von PowerShell definiert werden, werden im globalen Bereich festgelegt. Zu diesen Elementen gehören vom System erstellte Objekte wie PowerShell-Laufwerke und auch alles, was Sie in einem PowerShell-Profil definiert haben, da Ihr Profil beim Start ausgeführt wird.
Elemente im globalen Bereich sind überall verfügbar. Sie können Elemente im globalen Bereich interaktiv auf der Konsole, in jedem ausgeführten Skript und in jeder Funktion referenzieren. Die globalen Variablen von PowerShell sind überall verfügbar. Aus diesem Grund werden globale PowerShell-Variablen in der Regel zwischen Skripten verwendet.
Es gibt nur einen globalen Bereich, der insgesamt gilt.
Skriptbereich
Ein Skriptbereich wird automatisch erstellt, wenn ein PowerShell-Skript ausgeführt wird. Sie können viele verschiedene Skriptbereich-Instanzen haben. Skriptbereiche werden erstellt, wenn Sie z. B. ein PS1-Skript oder ein Modul ausführen.
Nur Elemente, die in dieser bestimmten Skriptbereichsinstanz erstellt wurden, können sich gegenseitig referenzieren.
Privater Bereich
Normalerweise kann auf ein definiertes Element von anderen Bereichen aus zugegriffen werden – dies gilt nicht für Elemente in einem privaten Bereich. Elemente in einem privaten Bereich enthalten Objekte, die für andere Bereiche verborgen sind. Ein privater Bereich wird verwendet, um Elemente mit dem gleichen Namen wie Elemente in anderen Bereichen zu erstellen, um Überschneidungen zu vermeiden.
Lokaler Bereich
Im Gegensatz zu den anderen Bereichen ist der lokale Bereich ein wenig anders. Der lokale Bereich ist ein Zeiger auf den globalen, skriptbezogenen oder privaten Bereich. Der lokale Bereich ist relativ zu dem Kontext, in dem der Code gerade läuft.
Wenn Sie eine Variable, einen Alias, eine Funktion oder ein PSDrive erstellen, ohne ihr/ihm explizit einen Bereich zuzuweisen (was wir später behandeln werden), wird sie in den lokalen Bereich aufgenommen.
Referenzieren von Bereichen
Nachdem Sie nun eine Vorstellung von den vier Arten von Bereichen haben, die es gibt, sollten Sie auch wissen, dass es zwei Möglichkeiten gibt, auf diese Bereiche zu verweisen.
In PowerShell gibt es zwei Möglichkeiten, auf Bereiche zu verweisen – benannt oder nummeriert. Beide Methoden verweisen auf dieselben Bereiche, aber einfach auf eine andere Weise. Es handelt sich um zwei verschiedene Arten der Interaktion mit Bereichen.
Benannte Bereiche
Oben im Abschnitt Bereichstyp haben Sie etwas über Bereiche gelernt, auf die mit einem Namen verwiesen wird. Die namentliche Bezugnahme auf einen Bereich wird intuitiv als benannter Bereich bezeichnet. Der Hauptzweck der namentlichen Referenzierung eines Bereichs besteht darin, einem Bereich ein Element zuzuweisen. Wie das geht, erfahren Sie weiter unten.
Nummerierte Bereiche
Neben einem Namen hat jeder Bereich eine Nummer, die bei Null beginnt und immer der lokale Bereich ist. Die Bereiche werden dynamisch in Bezug auf den aktuellen lokalen Bereich nummeriert.
Sobald Sie beispielsweise eine PowerShell-Sitzung öffnen, arbeiten Sie im globalen Bereich. Zu diesem Zeitpunkt ist der globale Bereich der lokale Bereich (denken Sie daran, dass der lokale Bereich nur ein Zeiger ist).
Da der lokale Bereich immer der Bereich Null ist, ist der globale Bereich zu diesem Zeitpunkt auch der Bereich Null. Wenn Sie jedoch ein Skript in der gleichen Sitzung ausführen, wird ein Skriptbereich erstellt. Bei der Ausführung hat sich der Zeiger des lokalen Bereichs in den Skriptbereich geändert. Jetzt ist der Skriptbereich der Bereich Null und der globale Bereich der Bereich Eins.
Bereiche werden nummeriert Dieser Vorgang wiederholt sich für so viele Bereiche, wie Sie haben, wobei der lokale Bereich 0 ist. Bereiche werden dynamisch durch die Bereichshierarchie nummeriert.
Bereichshierarchie und Vererbung
Wie bereits erwähnt, erstellt PowerShell beim Starten einer PowerShell-Sitzung einige Elemente für Sie im globalen Bereich. Diese Elemente können Funktionen, Variablen, Aliase oder PSDrives sein. Alles, was Sie in Ihrer PowerShell-Sitzung definieren, wird auch im globalen Bereich definiert.
Da Sie sich standardmäßig im globalen Bereich befinden, wird ein untergeordneter Bereich erstellt, wenn Sie etwas tun, das einen anderen Bereich erstellt, z. B. ein Skript ausführen oder eine Funktion ausführen, wobei der übergeordnete Bereich der globale Bereich ist. Bereiche sind wie Prozesse mit Eltern und Kindern.
Alles, was in einem übergeordneten Bereich, in diesem Fall dem globalen Bereich, definiert ist, ist auch im untergeordneten Bereich zugänglich. Aber diese Elemente können nur in dem Bereich bearbeitet werden, in dem sie definiert wurden.
Angenommen, Sie haben ein Skript namens Test.ps1. In diesem Skript befindet sich eine einzelne Zeile wie unten gezeigt.
$a = 'Hello world!'
Wenn Sie dieses Skript ausführen, wird $a
ein Wert im lokalen Bereich zugewiesen (Skript, während das Skript ausgeführt wird). Wenn Test.ps1 ausgeführt wird, können Sie unten sehen, dass Sie nach der Ausführung des Skripts nicht darauf verweisen können. Da $a
im Skriptbereich zugewiesen wurde, kann der globale Bereich (auf der interaktiven Konsole) die Variable nicht sehen.
Gehen wir in diesem Beispiel einen Schritt weiter und lassen das Skript Test.ps1 wie folgt aussehen. Das Skript versucht nun, den Wert von $a
auszugeben, bevor es ihn im gleichen Bereich setzt.
Write-Output $a$a = 'Hello world!'
Zur Demonstration weisen Sie $a
auf der interaktiven Konsole einen Wert zu. Dadurch wird der Wert im globalen Bereich zugewiesen. Wenn das Skript nun ausgeführt wird, erbt es den übergeordneten Bereich (global) und sollte den Wert sehen können.
Wenn Test.ps1 ausgeführt wird (und einen untergeordneten Bereich des globalen Bereichs erstellt), kann es den Wert von $a
sehen. Sie können auch sehen, dass der Wert der Variablen auch im globalen Bereich verfügbar ist, da er in diesem Bereich festgelegt wurde. Das bedeutet, dass $a
sowohl im Skriptbereich (Child) als auch im übergeordneten Bereich (Global) verfügbar ist.
Merken Sie sich dieses Verhalten der Bereichsvererbung. Dies hilft Ihnen bei der Fehlersuche, wenn Variablenkonflikte auftreten, z. B. wenn Variablen in verschiedenen Bereichen denselben Namen haben.
Definieren von und Zugreifen auf Elemente in Bereichen
Nun, da Sie wissen, was ein Bereich ist und wie er funktioniert, wie greifen Sie auf ihn zu? Sehen wir uns an, wie Sie mit PowerShell einen Variablenbereich festlegen (und auf sie zugreifen).
Get/Set-Variable
In PowerShell gibt es zwei Cmdlets, mit denen Sie Variablen festlegen können: Get-Variable
und Set-Variable
. Mit diesen Cmdlets können Sie den Wert einer Variablen abrufen oder einen Wert definieren.
Beide Cmdlets ähneln sich mit einem Name
– und Scope
-Parameter. Mit diesen Parametern ermöglicht PowerShell das Festlegen und Abrufen von Variablenwerten in allen Bereichen.
Lokale Bereiche
Um eine Variable in einem lokalen Bereich festzulegen, verwenden Sie Set-Variable
und geben einen lokalen Variablennamen und einen Wert an, wie unten gezeigt.
PS> Set-Variable -Name a -Value 'foo'
Der lokale Bereich ist immer der Standard, sodass die Variable ohne den Scope
-Parameter immer im lokalen Bereich definiert wird.
Um den Wert einer Variable mit lokalem Geltungsbereich abzurufen, verwenden Sie Get-Variable
und geben Sie den Namen an.
PS> Get-Variable -Name aName Value---- -----a foo
Private/Skript/Globale Geltungsbereiche
Sie verwenden dieselben Parameter (Name
und Value
), wenn Sie auch mit privaten, Skript- und globalen Variablen arbeiten. Der einzige Unterschied besteht darin, dass Sie diesmal den Scope-Parameter verwenden, um den Bereich explizit zu definieren.
Die Methoden zum Setzen einer privaten, Skript- oder globalen Variable sind dieselben. Ersetzen Sie einfach den an den Parameter Scope
übergebenen Wert durch Private
, Script
Global
.
PS> Set-Variable -Name a -Value 'foo' -Scope <Private|Script|Global>
Um den Wert einer Skript- oder Global-Scoped-Variable abzurufen, verwenden Sie Get-Variable
und geben Sie den Namen und den Scope an.
PS> Get-Variable -Name a -Scope <Script|Global>Name Value---- -----a foo
Hinweis: Sie können mit den Cmdlets
Get
/Set-Variable
auch auf Bereiche verweisen, indem Sie Bereichsnummern anstelle von Namen verwenden.
Bereich „Prefacing“
Sie können Variablen in Bereichen auch über eine Abkürzung abrufen und festlegen. Anstatt PowerShell-Cmdlets zu verwenden, stellen Sie der Variablen den Bereich voran, wenn Sie auf sie verweisen.
Lokale Bereiche
Da der lokale Bereich immer der Standard ist, wird durch einfaches Definieren einer Variablen und Verweisen eine Variable im lokalen Bereich festgelegt und abgerufen
PS> $a = 'foo'PS> $afoo
Private/Skript/Globale Bereiche
Wenn Sie Skript- oder globale Bereiche definieren und referenzieren möchten, können Sie den Variablen den Bereichsnamen und ein Semikolon voranstellen.
Um zum Beispiel die Variable $a
in den globalen Bereich zu setzen, können Sie a mit $global:
einleiten.
$global:a = 'foo'
Das Gleiche gilt für eine Variable, die in den Skriptbereich fällt.
$script:a = 'foo'
Sobald die Variablen in den bevorzugten Bereich gesetzt sind, können Sie sie auf die gleiche Weise referenzieren. Beachten Sie auch, dass Sie das Bereichsvorwort ausschließen können, wenn der definierte Bereich der lokale Bereich ist.
PS> $global:a = 'foo'PS> $global:afooPS> $afoo
Bereiche in Skriptblöcken
PowerShell verfügt über ein praktisches Konstrukt namens Skriptblöcke. Mit Skriptblöcken können Sie Codeschnipsel verschieben und sie fast überall ausführen.
Wie ein PS1-Skript laufen Skriptblöcke in einem eigenen Skriptbereich. Wenn Sie einen Skriptblock ausführen, führen Sie im Grunde ein PS1-Skript aus.
Beachten Sie das folgende Beispiel, in dem eine Variable im globalen Bereich definiert ist und dann versucht wird, sie in einem Skriptbereich zu überschreiben. Wie Sie oben gelernt haben, funktioniert das nicht, weil ein untergeordneter Bereich nicht auf einen übergeordneten Bereich verweisen kann.
Dieses Beispiel zeigt, dass, wenn $a
im Skriptblock geändert wird, die globale Variablendefinition für $a
nicht geändert wird, weil der Skriptblock ein untergeordneter Skriptbereich ist.
Dot-Sourcing-Skripte (Austauschen lokaler Bereiche)
PowerShell verfügt über ein Konzept namens Dot-Sourcing. Dies ist eine Methode, mit der Sie ein PS1-Skript ausführen und stattdessen alles, was in den Skriptbereich fallen würde, in den lokalen Bereich bringen können.
Indem Sie einen Punkt (.) vor dem Verweis auf ein PS1-Skript setzen und es ausführen, wird der Inhalt des Skripts „dot-sourcing“ und alles in den lokalen Bereich gebracht.
Zur Veranschaulichung habe ich wieder ein Skript „Test.ps1“, das eine Variable wie unten gezeigt definiert.
$a = 'Hello world!'
Setzen Sie in einer PowerShell-Konsole einen Wert für eine $a
-Variable und führen Sie dieses Skript dann wie unten gezeigt als Punktquelle aus. Beachten Sie, dass die ursprüngliche Variable überschrieben wurde. PowerShell hat die beiden lokalen Bereiche „zusammengeführt“.
Verwenden der AllScope-Eigenschaft (Option)
Sie haben gesehen, wie Sie mit Elementen in bestimmten Bereichen interagieren können, aber bisher ist jedes Element immer noch in einem einzelnen Bereich definiert. Was aber, wenn Sie nicht wissen, in welchem Bereich eine Variable definiert ist?
Wenn Sie eine Variable mit dem Cmdlet Set-Variable
definieren, können Sie die Variable in alle Bereiche auf einmal platzieren. Verwenden Sie dazu den Wert AllScope
für den Parameter Option
.
Zur Veranschaulichung wurde das Skript Test.ps1 so geändert, dass eine Variable in allen Bereichen festgelegt wird. Diese Variable wird dann wie unten gezeigt ausgegeben.
Set-Variable -Name a -Value 'Hello world!' -Option AllScopeWrite-Output $a
Sie können dann unten sehen, dass ein Wert für $a im globalen Bereich festgelegt wird und das Skript „Test.ps1“ ausgeführt wird. Der Wert von $a
wurde jedoch überschrieben, anstatt keine Auswirkungen zu haben. Er wurde nicht nur im Skriptbereich (Write-Output $a
) definiert, sondern auch im globalen Bereich überschrieben.
Die Option AllScope
ist praktisch, aber seien Sie vorsichtig. Diese Option hebt im Wesentlichen das Konzept der Bereiche auf und verschmilzt alles miteinander.
Funktionsbereiche
Wenn Sie eine Funktion ausführen, befindet sich der gesamte Code innerhalb dieser Funktion in ihrem eigenen untergeordneten Bereich. Funktionsbereiche folgen demselben Kind-/Eltern-Verhalten wie andere Bereiche.
Es ist eine gute Idee, für jede Funktion einen eigenen Bereich zu haben. Es ermöglicht eine bessere Kontrolle über die Elemente, ohne dass man sich Gedanken über Konflikte machen muss, und es hat den zusätzlichen Vorteil, dass die Variablen in einer Funktion automatisch bereinigt werden. Sobald die Funktion abgeschlossen ist, werden alle in der Funktion definierten Elemente gelöscht.
Zur Veranschaulichung kopieren Sie die folgende Funktion direkt in die PowerShell-Konsole.
Function Do-Thing { $var = 'bar'}
Nach dem Einfügen führen Sie die Funktion aus. Beachten Sie, dass Sie außerhalb der Funktion nicht auf die Variable $var
zugreifen können.
PS> Do-ThingPS> $var
Elemente privat halten (Vererbung deaktivieren)
Wenn eine Variable in einem übergeordneten Bereich definiert ist, wird diese Variable normalerweise auch im untergeordneten Bereich definiert. Aber vielleicht möchten Sie einen Variablennamen verwenden, der aber bereits in einem der Bereiche definiert wurde, die in einer Sitzung ausgeführt werden sollen. In diesem Fall können Sie entweder einen anderen Variablennamen wählen oder die Variable in einem privaten Bereich definieren, wodurch sie zu einer privaten Variable wird.
Eine Möglichkeit, Bereiche zu verwenden, um Konflikte zu reduzieren, ist die Verwendung des privaten Bereichs. Die Verwendung des privaten Bereichs deaktiviert die Vererbung für diese spezifische Variable. Wenn mehrere untergeordnete Bereiche erstellt werden, sehen diese untergeordneten Bereiche keine Variablen, die in einem privaten Bereich definiert sind.
Ein Skript „Test.ps1“ gibt den Wert von $a wie unten gezeigt aus.
Write-Output $a
Wie Sie unten sehen, definiere ich eine Variable mit privatem Bereich im globalen Bereich und führe dann das Skript „Test.ps1“ aus. Wenn Sie eine Variable in einem übergeordneten Bereich definieren, ist diese Variable normalerweise auch im untergeordneten Bereich verfügbar – nicht so bei einer Variablen mit privatem Zugriff.
Im folgenden Beispiel können Sie sehen, dass der untergeordnete Skriptbereich, der durch die Ausführung des Skripts „Test.ps1“ erstellt wurde, die im übergeordneten Bereich definierte Variable „private-scoped $a
“ nicht sehen kann.
Im Gegensatz zu globalen Bereichen oder der Option AllScope
des Cmdlets Set-Variable
sind Variablen mit privatem Zugriff eine hervorragende Möglichkeit, Elemente zu unterteilen.
Best Practices für das Scoping
Die Vorstellung, dass das Definieren von Variablen im globalen Bereich oder die Verwendung der Option AllScope
der richtige Weg ist, ist weit verbreitet. Schließlich sind alle Variablen überall verfügbar. Es gibt keinen Grund, sich über die Komplikationen von Bereichen Gedanken zu machen. Dies bietet zwar zusätzliche Freiheit für den Zugriff auf das, was definiert ist, kann aber schnell aus dem Ruder laufen und die Fehlersuche erschweren.
Anstatt zu versuchen, die Verwendung von Bereichen zu vermeiden, befolgen Sie diese Tipps:
- Anstatt Bereiche in Funktionen anzugeben, verwenden Sie Parameter, um die erforderlichen Informationen an die Funktion zu übergeben.
- Bleiben Sie so weit wie möglich innerhalb des lokalen Bereichs.
- Anstatt globale Variablen in einem Skript zu definieren, verwenden Sie das Cmdlet
Write-Output
, um alles auszugeben und bei Bedarf in einer Variable auf der Konsole zu speichern.
Der wichtigste Punkt hier ist, Bereiche zu akzeptieren und zu lernen, sie zu Ihrem Vorteil zu nutzen, anstatt zu versuchen, sie zu umgehen.
Weitere Lektüre
- Über erweiterte Funktionen und Funktionsparameter
- Verwenden von Umgebungsvariablen in PowerShell