PowerShell Scopes: Verstehen des Variablenskopes

Wenn Sie ein PowerShell-Skript ohne Funktionen und ohne externe Abhängigkeiten von anderen Skripten schreiben, spielt das Konzept von PowerShell-Bereichen keine große Rolle. Die Konzeption von globalen Variablen in PowerShell steht nicht im Vordergrund. Aber wenn Sie anfangen, Funktionen und Module zu erstellen und lernen, Skripte aus anderen Skripten aufzurufen, wird das Thema wichtiger.

In diesem Artikel erhalten Sie eine ausführliche Lektion darüber, was Bereiche in PowerShell sind, wie sie funktionieren und wie Sie Code unter Berücksichtigung von Bereichen schreiben können. Bis Sie fertig sind, werden Sie die globalen Variablen von PowerShell und vieles mehr verstehen!

Bereiche: So etwas wie Eimer

Haben Sie schon einmal ein Skript geschrieben, in dem Sie eine Variable definieren und wenn Sie den Wert dieser Variable überprüfen, ist er etwas anderes? Sie mögen sich wundern, wie sich diese Variable geändert hat, wenn Sie sie klar definiert haben. Ein Grund könnte sein, dass der Wert der Variable in einem anderen Bereich überschrieben wird.

Vielleicht haben Sie sich gefragt, warum bestimmte PowerShell-Variablen Werte haben, wenn Sie auf sie in Ihrer Konsole verweisen, aber in Ihren Skripten nicht existieren. Wahrscheinlich befinden sich diese Variablen in einem anderen „Eimer“, der zu diesem Zeitpunkt nicht verfügbar ist.

Bereiche sind wie Eimer. Bereiche beeinflussen die Art und Weise, wie PowerShell Variablen, Aliasse, Funktionen und PSDrives zwischen verschiedenen Bereichen isoliert. Ein Bereich ist wie ein Eimer. Es ist ein Ort, um all diese Elemente zusammenzufassen.

Wenn PowerShell startet, erstellt es automatisch diese „Eimer“ für Sie. Zu diesem Zeitpunkt verwenden Sie bereits Bereiche, ohne es zu realisieren. Alle Bereiche werden von PowerShell definiert und werden ohne Ihre Hilfe erstellt.

Bereichstypen

Wenn PowerShell startet, werden automatisch vier „Behälter“ oder Bereiche für verschiedene Elemente erstellt. Du kannst keine Bereiche selbst erstellen. Du kannst nur Elemente zu diesen unten definierten Bereichen hinzufügen und aus ihnen entfernen.

Globaler Bereich

Elemente, die definiert werden, wenn PowerShell öffnet, werden auf globaler Ebene festgelegt. Zu diesen Elementen gehören von System erstellte Objekte wie PowerShell-Laufwerke und auch alles, was du in einem PowerShell-Profil definiert hast, da dein Profil beim Start ausgeführt wird.

Elemente im globalen Bereich sind überall verfügbar. Du kannst Elemente im globalen Bereich interaktiv in der Konsole, in jedem Skript, das du ausführst, und in jeder Funktion referenzieren. PowerShell-Globale Variablen sind überall. Aus diesem Grund ist die übliche Verwendung von PowerShell globalen Variablen, PowerShell globale Variablen zwischen Skripten zu verwenden.

Es gibt nur einen globalen Bereich, der insgesamt regiert.

Skriptbereich

A script scope is automatically created every time a PowerShell script runs. You can have many different script scope instances. Script scopes are created when you execute a PS1 script or a module, for example.

Nur Elemente, die in dieser bestimmten Skriptbereichsinstanz erstellt wurden, können sich gegenseitig referenzieren.

Privater Bereich

Typischerweise kann ein definiertes Element aus anderen Bereichen zugegriffen werden – nicht wahr bei Elementen 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 demselben Namen wie Elemente in anderen Bereichen zu erstellen, um Überschneidungen zu vermeiden.

Lokaler Bereich

Im Gegensatz zu den anderen Bereichen ist der lokale Bereich etwas anders. Der lokale Bereich ist ein Zeiger auf den globalen, Skript- oder privaten Bereich. Der lokale Bereich bezieht sich auf den Kontext, in dem der Code zur Laufzeit ausgeführt wird.

Wenn Sie eine Variable, einen Alias, eine Funktion oder einen PSDrive erstellen, ohne ihm explizit einen Bereich zuzuweisen (was wir später behandeln werden), wird er in den lokalen Bereich eingefügt.

Verweis auf Bereiche

Jetzt, da Sie eine Vorstellung von den vier Arten von Bereichen haben, 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 die gleichen Bereiche, jedoch einfach auf unterschiedliche Weise. Dies sind zwei verschiedene Möglichkeiten, mit Bereichen zu interagieren.

Benannte Bereiche

Oben im Abschnitt Bereichstyp haben Sie gelernt, dass Bereiche nach Namen referenziert werden. Das Referenzieren eines Bereichs nach Namen wird intuitiv als benannter Bereich bezeichnet. Der Hauptzweck des Referenzierens eines Bereichs nach Namen besteht darin, einem Element einen Bereich zuzuweisen. Sie lernen unten, wie dies gemacht wird.

Nummerierte Bereiche

Zusätzlich zu einem Namen hat jeder Bereich eine Nummer, die bei null beginnt und immer der lokale Bereich sein wird. Bereiche werden dynamisch in Bezug auf den aktuellen lokalen Bereich nummeriert.

Zum Beispiel, sobald Sie 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).

Seit der lokale Gültigkeitsbereich immer Gültigkeitsbereich Null ist, ist der globale Gültigkeitsbereich in diesem Moment ebenfalls Gültigkeitsbereich Null. Aber wenn Sie ein Skript aus derselben Sitzung ausführen, wird ein Skriptgültigkeitsbereich erstellt. Beim Ausführen hat der lokale Gültigkeitsbereichszeiger dann auf den Skriptgültigkeitsbereich gewechselt. Jetzt ist der Skriptgültigkeitsbereich Gültigkeitsbereich Null und der globale Gültigkeitsbereich ist Gültigkeitsbereich Eins.

Die Gültigkeitsbereiche sind nummeriert. Dieser Vorgang wiederholt sich für so viele Gültigkeitsbereiche, wie Sie haben, wobei der lokale Gültigkeitsbereich 0 ist. Gültigkeitsbereiche werden dynamisch nach der Gültigkeitsbereichshierarchie nummeriert.

Gültigkeitsbereichshierarchie und Vererbung

Wie bereits erwähnt, erstellt PowerShell beim Start einer PowerShell-Sitzung einige Elemente für Sie im globalen Gültigkeitsbereich. Diese Elemente können Funktionen, Variablen, Aliasse oder PSDrives sein. Alles, was Sie in Ihrer PowerShell-Sitzung definieren, wird auch im globalen Gültigkeitsbereich definiert.

Weil Sie standardmäßig im globalen Gültigkeitsbereich sind, wird beim Ausführen einer Aktion, die einen weiteren Gültigkeitsbereich erstellt, wie das Ausführen eines Skripts oder das Ausführen einer Funktion, ein untergeordneter Gültigkeitsbereich mit dem übergeordneten Gültigkeitsbereich erstellt. Gültigkeitsbereiche sind wie Prozesse mit Eltern und Kindern.

Alles, was in einem übergeordneten Gültigkeitsbereich, dem globalen Gültigkeitsbereich in diesem Fall, definiert ist, ist im untergeordneten Gültigkeitsbereich zugänglich. Diese Elemente können jedoch nur im Gültigkeitsbereich, in dem sie definiert wurden, bearbeitet werden.

Angenommen, Sie haben ein Skript namens Test.ps1. Innerhalb dieses Skripts befindet sich eine einzige Zeile wie unten gezeigt.

$a = 'Hello world!'

Wenn Sie dieses Skript ausführen, wird $a im lokalen Bereich (Skript während des Skriptbetriebs) zugewiesen. Wenn Test.ps1 ausgeführt wird, können Sie unten sehen, dass Sie nicht darauf verweisen können, nachdem das Skript ausgeführt wurde. Da $a zugewiesen wurde, während es im Skriptbereich war, kann der globale Bereich (an der interaktiven Konsole) ihn nicht sehen.

Global scope cannot see the variable

Lassen Sie uns dieses Beispiel einen Schritt weiterführen und das Skript Test.ps1 wie folgt aussehen lassen. Das Skript versucht nun, den Wert von $a auszugeben, bevor er im gleichen Bereich festgelegt wird.

Write-Output $a
$a = 'Hello world!'

Um zu demonstrieren, weisen Sie $a an der interaktiven Konsole einen Wert zu. Dies weist den Wert im globalen Bereich zu. Wenn das Skript jetzt ausgeführt wird, erbt es den übergeordneten Bereich (global) und sollte den Wert sehen können.

Wie unten zu sehen ist, wenn Test.ps1 ausgeführt wird (wodurch ein untergeordneter Bereich des globalen Bereichs erstellt wird), kann er den Wert von $a sehen. Sie können auch sehen, dass der Wert der Variablen auch im globalen Bereich verfügbar ist, da dies der Bereich ist, in dem er festgelegt wurde. Das bedeutet, dass $a sowohl in den Skript- (untergeordnet) als auch im Eltern- (global) Bereich verfügbar ist.

Variable is available in script and global scopes

Merken Sie sich dieses Vererbungsverhalten des Bereichs. Dadurch wird Ihnen geholfen, wenn bei der Fehlerbehebung Konflikte mit Variablen auftreten, wie etwa Variablen in verschiedenen Bereichen mit dem gleichen Namen.

Definition und Zugriff auf Elemente in Bereichen

Nun, da Sie wissen, was ein Geltungsbereich ist und wie sie funktionieren, wie greifen Sie auf sie zu? Schauen wir uns an, wie Sie PowerShell verwenden, um einen Variablenbereich festzulegen (und darauf zuzugreifen).

Get/Set-Variable

In PowerShell gibt es zwei Cmdlets, mit denen Sie Variablen setzen können, genannt Get-Variable und Set-Variable. Diese Cmdlets ermöglichen es Ihnen, den Wert einer Variable abzurufen oder einen Wert zu definieren.

Beide Cmdlets sind ähnlich mit einem Name und einem Scope Parameter. Mit diesen Parametern ermöglicht PowerShell das Setzen und Abrufen von Variablenwerten in allen Bereichen.

Lokale Bereiche

Um eine Variable in einem lokalen Bereich zu setzen, verwenden Sie Set-Variable und geben Sie ihm einen lokalen Variablennamen und einen Wert wie unten gezeigt.

PS> Set-Variable -Name a -Value 'foo'

Der lokale Bereich ist immer der Standard, sodass das Nichtverwenden des Scope-Parameters die Variable immer im lokalen Bereich definiert.

Um den Wert einer lokal begrenzten Variable abzurufen, verwenden Sie Get-Variable und geben Sie ihm den Namen.

PS> Get-Variable -Name a

Name         Value
----         -----
a            foo

Private/Script/Global Bereiche

Sie verwenden dieselben Parameter (Name und Value), wenn Sie mit privaten, Skript- und globalen Variablen arbeiten. Der einzige Unterschied besteht darin, dass Sie dieses Mal den Scope-Parameter verwenden, um den Bereich explizit zu definieren.

Die Methoden zum Setzen einer privat, skript- oder globalbegrenzten Variable sind dieselben. Ersetzen Sie einfach den Wert, der dem Scope-Parameter übergeben wird, als Private, Script Global.

PS> Set-Variable -Name a -Value 'foo' -Scope <Private|Script|Global>

Um den Wert eines Skripts oder einer globalen Variablen abzurufen, verwenden Sie Get-Variable und geben Sie den Namen und den Bereich an.

PS> Get-Variable -Name a -Scope <Script|Global>

Name         Value
----         -----
a            foo

Hinweis: Sie können auch Bereiche unter Verwendung von Bereichsnummern anstelle von Namen mit den Get/Set-Variable-Befehlen referenzieren.

Bereich „Vorstellen“

Sie können auch Variablen in Bereichen mit einer Abkürzung abrufen und setzen. Anstatt PowerShell-Befehle zu verwenden, fügen Sie dem Variablennamen den Bereich vor, wenn Sie darauf verweisen.

Lokale Bereiche

Da der lokale Bereich immer der Standard ist, wird durch einfaches Definieren einer Variablen und Verweisen ein lokaler Bereichsvariablen gesetzt und abgerufen.

PS> $a = 'foo'
PS> $a

foo

Private/Skript/Globale Bereiche

Wenn Sie Skript- oder globale Bereiche definieren und darauf verweisen möchten, fügen Sie den Variablen den Bereichsnamen und ein Semikolon vor.

Zum Beispiel, um die Variable $a im globalen Bereich zu setzen, fügen Sie vor a $global: hinzu.

$global:a = ‘foo’

Das Gleiche kann für eine Skriptbereichsvariable getan werden.

$script:a = ‘foo’

Nachdem die Variablen im bevorzugten Bereich gesetzt wurden, werden sie auf dieselbe Weise referenziert. Beachten Sie auch, dass Sie den Bereichsvorgriff ausschließen können, wenn der definierte Bereich der lokale Bereich ist.

PS> $global:a = 'foo'
PS> $global:a
foo
PS> $a
foo

Bereiche in Skriptblöcken

PowerShell hat eine praktische Konstruktion namens Skriptblöcke. Skriptblöcke ermöglichen es Ihnen, Codeausschnitte zu verschieben und sie praktisch überall auszuführen.

Wie ein PS1-Skript werden Skriptblöcke in ihrem eigenen Skriptbereich ausgeführt. Wenn Sie einen Skriptblock ausführen, führen Sie im Wesentlichen ein PS1-Skript aus.

Hinweis im folgenden Beispiel, wo eine Variable im globalen Gültigkeitsbereich definiert und dann im Skript-Gültigkeitsbereich zu überschreiben versucht wird. Wie Sie oben gelernt haben, funktioniert dies nicht, weil ein untergeordneter Gültigkeitsbereich nicht auf einen übergeordneten Gültigkeitsbereich verweisen kann.

A child scope cannot overwrite a parent scope

In diesem Beispiel wird gezeigt, dass, wenn $a im Skriptblock geändert wird, die globale Variablendefinition für $a nicht geändert wird, weil der Skriptblock ein untergeordneter Skop ist.

Skripte durch Punktnotation einbinden (Austausch lokaler Bereiche)

PowerShell hat ein Konzept namens Punkt-Quellen. Dies ist eine Methode, die es Ihnen ermöglicht, ein PS1-Skript auszuführen und alles, was im Skript-Gültigkeitsbereich wäre, stattdessen in den lokalen Gültigkeitsbereich zu bringen.

Indem Sie einen Punkt (.) vor einem Verweis auf ein PS1-Skript setzen und es ausführen, „punktiert“ PowerShell den Inhalt des Skripts und bringt alles in den lokalen Gültigkeitsbereich.

Zur Veranschaulichung habe ich erneut ein Test.ps1-Skript, das eine Variable wie unten gezeigt definiert.

$a = 'Hello world!'

In einer PowerShell-Konsole setzen Sie einen Wert für eine $a-Variable und „punktieren“ dann dieses Skript wie unten gezeigt. Beachten Sie, dass die ursprüngliche Variable überschrieben wurde. PowerShell hat die beiden lokalen Gültigkeitsbereiche „zusammengeführt“.

Original variable overwritten

Verwenden der AllScope-Eigenschaft (Option)

Sie haben gesehen, wie Sie mit Elementen in bestimmten Gültigkeitsbereichen interagieren können, aber bisher ist jedes Element immer noch in einem einzelnen Gültigkeitsbereich definiert. Aber was ist, wenn Sie nicht wissen, in welchem Gültigkeitsbereich eine Variable definiert ist?

Beim Definieren einer Variable mit dem Set-Variable-Cmdlet können Sie die Variable auf einmal in allen Scopes platzieren. Verwenden Sie dazu den AllScope-Wert für den Option-Parameter.

Um dies zu demonstrieren, wurde das Skript Test.ps1 geändert, um eine Variable in allen Scopes zu setzen. Diese Variable wird dann wie unten gezeigt ausgegeben.

Set-Variable -Name a -Value 'Hello world!' -Option AllScope
Write-Output $a

Sie können dann unten sehen, dass ein Wert für $a im globalen Scope gesetzt wird und das Skript Test.ps1 ausgeführt wird. Anstatt jedoch keine Wirkung zu haben, wurde der Wert von $a überschrieben. Er wurde nicht nur im Skript-Scope definiert (Write-Output $a), sondern hat auch den globalen Scope überschrieben.

Variable overwritten in global scope

Die AllScope-Option ist praktisch, aber seien Sie vorsichtig. Diese Option hebt im Wesentlichen das Konzept von Scopes auf und fusioniert alles zusammen.

Funktions-Scopes

Wenn Sie eine Funktion ausführen, befindet sich der gesamte Code innerhalb dieser Funktion in seinem eigenen Child-Scope. Funktions-Scopes folgen dem gleichen Child/Parent-Verhalten wie andere Scopes.

Es ist eine gute Idee, separate Scopes für jede Funktion zu haben. Dies ermöglicht eine bessere Kontrolle über Elemente, ohne sich Gedanken darüber machen zu müssen, dass Elemente in Konflikt geraten. Es bietet auch den zusätzlichen Vorteil der automatischen Bereinigung von Variablen in einer Funktion. Sobald die Funktion abgeschlossen ist, werden alle in der Funktion definierten Elemente gelöscht.

Um zu demonstrieren, 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 $var-Variable zugreifen können.

PS> Do-Thing
PS> $var

Private Elemente behalten (Vererbung deaktivieren)

Normalerweise, wenn eine Variable in einem übergeordneten Bereich definiert ist, wird diese Variable im untergeordneten Bereich definiert. Vielleicht möchten Sie jedoch einen Variablennamen verwenden, der bereits in einem der Bereiche für die Ausführung in einer Sitzung definiert wurde. In diesem Fall können Sie entweder einen anderen Variablennamen wählen oder die Variable in einem privaten Bereich definieren, sodass es sich um eine private Variable handelt.

A way to use scopes to reduce conflicts is to use the private scope. Using the private scope disables inheritance on that specific variable. When multiple child scopes are created, those child scopes will not see any variables defined in a private scope.

A Test.ps1 script outputs the value of $a as shown below.

Write-Output $a

Unten sehen Sie, dass ich eine privat definierte Variable im globalen Bereich definiere und dann das Skript Test.ps1 ausführe. Normalerweise, wenn Sie eine Variable in einem übergeordneten Bereich definieren, ist diese Variable im untergeordneten Bereich verfügbar – nicht so bei einer privat definierten Variable.

In dem untenstehenden Beispiel sehen Sie, dass der von der Ausführung des Skripts Test.ps1 erstellte Skriptunterbereich die in dem übergeordneten Bereich definierte privat definierte Variable $a nicht sehen konnte.

Script scope cannot see the private-scoped variable

Im Gegensatz zu globalen Bereichen oder der AllScope-Option des Set-Variable-Befehls sind privat definierte Variablen eine ausgezeichnete Möglichkeit, Elemente zu kompartimentieren.

Bewährte Praktiken für den Bereich

Denken Sie daran, dass es üblich ist, Variablen im globalen Bereich zu definieren oder die Option AllScope zu verwenden. Immerhin sind alle Variablen überall verfügbar. Es ist nicht notwendig, sich um die Komplikationen von Bereichen zu kümmern. Obwohl dies zusätzliche Freiheit für den Zugriff auf das Definierte bietet, kann es schnell außer Kontrolle geraten und schwierig werden, Probleme zu beheben.

Statt zu versuchen, die Verwendung von Bereichen zu verhindern, befolgen Sie diese Tipps:

  1. Statt Bereiche in Funktionen anzugeben, verwenden Sie Parameter, um die erforderlichen Informationen an die Funktion zu übergeben.
  2. Halten Sie sich so weit wie möglich im lokalen Bereich auf.
  3. Statt globale Variablen aus einem Skript zu definieren, verwenden Sie das Write-Output-Cmdlet, um alles auszugeben und speichern Sie es bei Bedarf von der Konsole in einer Variablen.

Der Hauptpunkt hier ist, Bereiche zu akzeptieren und zu lernen, sie zu Ihrem Vorteil zu nutzen, anstatt zu versuchen, sie zu umgehen.

Weitere Informationen

Source:
https://adamtheautomator.com/powershell-scopes/