Adam the Automator

author
13 minutes, 59 seconds Read

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

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.

Der globale Bereich kann 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.

Variable ist im Skript- und im Globalbereich verfügbar

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.

Ein untergeordneter Bereich kann einen übergeordneten Bereich nicht überschreiben

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“.

Originalvariable überschrieben

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.

Variable 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.

Der Skriptbereich kann die Variable mit privatem Zugriff nicht sehen

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:

  1. Anstatt Bereiche in Funktionen anzugeben, verwenden Sie Parameter, um die erforderlichen Informationen an die Funktion zu übergeben.
  2. Bleiben Sie so weit wie möglich innerhalb des lokalen Bereichs.
  3. 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

Similar Posts

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.