über Bereiche in Powershell

Aug 24 2020

Ich lerne über Bereiche in Powershell und habe einige Fragen:

  1. Über den "lokalen Bereich": Nach dem, was ich gelesen habe, ist der lokale Bereich immer der aktuelle Bereich. Wenn wir also standardmäßig ein Element (ohne Bereichsmodifikator) erstellen, z. B. eine Variable, in einem bestimmten Bereich, sei es ein Skript oder global, ist der Bereich entsprechend script / global. Meine Frage lautet also: Wann müssen wir den localModifikator explizit angeben ?
  2. MSDN sagt:

Sie können einen neuen Bereich erstellen, indem Sie ein Skript oder eine Funktion ausführen, eine Sitzung erstellen oder eine neue Instanz von PowerShell starten. Wenn Sie einen neuen Bereich erstellen, ist das Ergebnis ein übergeordneter Bereich (der ursprüngliche Bereich) und ein untergeordneter Bereich (der von Ihnen erstellte Bereich). ...
Sofern Sie die Elemente nicht explizit privat machen, stehen die Elemente im übergeordneten Bereich dem untergeordneten Bereich zur Verfügung. Elemente, die Sie im untergeordneten Bereich erstellen und ändern, wirken sich jedoch nicht auf den übergeordneten Bereich aus, es sei denn, Sie geben den Bereich beim Erstellen der Elemente explizit an.

Aber wenn ich folgendes versuche:

PS> $Name = "John" PS> Powershell.exe PS>echo $Name  // No Output

Aus dem obigen Zitat geht hervor, dass das "Starten einer neuen Instanz von Powershell" ein untergeordneter Bereich ist, sodass alle Elemente im übergeordneten Bereich dort sichtbar sein sollten. Kann jemand erklären?

Antworten

2 mklement0 Aug 24 2020 at 23:16

Zur Ergänzung der hilfreichen Antwort von iRon :

  1. [...] wann müssen wir den lokalen Modifikator explizit angeben?

$local:wird selten benötigt , da der lokale Bereich ohne einen Bereichsspezifizierer impliziert wird .

Dies gilt jedoch nur, wenn die referenzierte Variable tatsächlich als lokale Variable vorhanden ist , da durch das dynamische Scoping von PowerShell Variablen aus übergeordneten (übergeordneten) Bereichen auch für untergeordnete (untergeordnete) Bereiche sichtbar werden ( weitere Informationen finden Sie in dieser Antwort ):

  • Angenommen, Sie haben $foo = 'bar'im globalen Bereich deklariert. Wenn Sie dann $fooin einem Skript auf verweisen, wird zuerst nach einer lokalen $foo Instanz gesucht. Wenn keine vorhanden ist, wird ggf. eine $fooin einem übergeordneten (übergeordneten) Bereich definierte Datei verwendet, die in diesem Beispiel global $foo ist und 'bar'zurückgegeben wird.

  • Im Gegensatz dazu , wenn in Ihrem Skript verwenden Sie $local:foo, ohne eine lokale $fooVariable definiert wird, entweder Sie erhalten $nullstandardmäßig oder, falls Set-StrictMode -Version 2oder höher wirksam ist, eine Aussage tritt -terminating Fehler.


  1. MSDN sagt: [...] durch Erstellen einer Sitzung oder durch Starten einer neuen Instanz von PowerShell [...] ist das Ergebnis ein übergeordneter Bereich (der ursprüngliche Bereich) und ein untergeordneter Bereich (der von Ihnen erstellte Bereich).

Die Dokumentation ist diesbezüglich zum Zeitpunkt dieses Schreibens falsch (ein GitHub-Problem wurde eingereicht):

  • Ahnenbeziehungen (Eltern-Kind-Beziehungen) zwischen Bereichen bestehen nur im Kontext einer bestimmten Sitzung (Runspace) .

    • Das heißt, dynamisches Scoping - die Sichtbarkeit von Variablen und anderen Definitionen aus übergeordneten Bereichen - gilt nur für Bereiche innerhalb einer bestimmten Sitzung.

    • Eine bemerkenswerte Ausnahme ist , dass Funktionen aus einem Modul nicht nicht in einem untergeordneten Umfang des anrufenden Umfangs laufen - es sei denn, die dieser Rahmen Aufruf ist nun mal der seine globale Umfang; Module haben ihre eigenen Bereichsdomänen (technisch als Sitzungsstatus bezeichnet ), die nur mit dem globalen Bereich verknüpft sind. Weitere Informationen finden Sie in dieser Ausgabe der GitHub-Dokumente .

  • Daher wird in den folgenden Szenarien kein untergeordneter Bereich des aufrufenden Bereichs erstellt, in dem der neu gestartete Code nichts von den Variablen (und anderen Definitionen) im aufrufenden Bereich kennt :

    • Starten einer neuen Sitzung über PowerShell-Remoting (z. B. mit Enter-PSSession) oderInvoke-Command -Computer

    • Starten eines Hintergrundjobs [Thread] mit Start-Joboder Start-ThreadJoboder Ausführen von Threads parallel zu ForEach-Object -ParallelVersion 7.0 +

    • Starten einer neuen PowerShell-Instanz ( eines neuen Prozesses) mithilfe der PowerShell-CLI ( pwshfür PowerShell [Core], powershell.exefür Windows PowerShell).

    • Um in diesen Szenarien Werte aus dem aufrufenden Bereich an den neu gestarteten Code zu kommunizieren, sind explizite Maßnahmen erforderlich :

      • Beim Aufrufen der CLI oder beim Verwenden Start-Jobeines untergeordneten Prozesses auf demselben Computer werden dem untergeordneten Prozess automatisch nur Umgebungsvariablen zur Verfügung gestellt, die im aufrufenden Prozess definiert sind.
      • Andernfalls müssen Werte vom Aufrufer als Argumente übergeben werden oder - außer bei Verwendung der CLI - über den $using:Bereich - diese Antwort anzeigen .
4 iRon Aug 24 2020 at 14:48

Beginnend mit der letzteren Frage:

Bereiche spielen mit Funktionen und aufgerufenen Skripten (Cmdlets) eine Rolle, wie z.

Function Test {
    $Test++ Write-Host 'Local:' $Test
}
$Test = 5 Test Write-Host 'Global:' $Test

Kehrt zurück:

Local: 6
Global: 5

Und:

Function Test {
    $Global:Test++ Write-Host 'Local:' $Test
}
$Test = 5 Test Write-Host 'Global:' $Test

Kehrt zurück:

Local: 6
Global: 6

Oder wenn Sie die Funktion in ein Skript einfügen (z. B. MyScript.ps1):

$Test = 5 .\MyScript.ps1 Write-Host $Test # $Test is unaffected unless you use the $Global scope in your script

Dies liefert im Grunde die gleichen Ergebnisse wie oben, es sei denn, Sie geben Ihr Skript als Dot-Source an, wo es im aktuellen Bereich ausgeführt wird:

$Test = 5 . .\MyScript.ps1 Write-Host $Test # $Test might be affected by MyScript.ps1 if you just use $Test

Für das, was Sie tun:
Sie erstellen eine vollständig neue PowerShell-Sitzung (mit Powershell.exe), die mit einer neuen Liste von Variablen beginnt.
Beachten Sie hier, dass Sie die anfänglichen Variablen wieder sehen, wenn Sie exitaus der neuen Sitzung:

PS C:\> $Name = "John" PS C:\> Powershell.exe Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. Try the new cross-platform PowerShell https://aka.ms/pscore6 PS C:\> Write-Host 'New session' $Name
New session
PS C:\> Exit
PS C:\> Write-Host 'Initial session' $Name
Initial session John

In Bezug auf die erste Frage denke ich nicht, dass es viele Anwendungen gibt, bei denen Sie explizit auf den $LocalBereich verweisen müssen , sondern um Ihnen ein Beispiel zu geben, wo Sie ihn verwenden könnten:

$Test = 5 Function Test { Write-Host ($Local:Test++)
}
Test

Im obigen Beispiel beginnt der unäre Inkrementoperator mit, 0wenn Sie den Bereich explizit verwenden $Local(tatsächlich beginnen Sie mit einer leeren lokalen Variablen, in die umgewandelt wird 0), und mit, 5wenn Sie den $LocalBereich weglassen, von dem Sie eine Kopie der $TestVariablen erben der übergeordnete Bereich.