Hoe Scopes invloed hebben op PowerShell-scripts
In batch-scripts hebben wijzigingen in omgevingsvariabelen standaard een wereldwijde impact op de huidige sessie. Voor PowerShell geldt precies het tegenovergestelde, omdat scopes worden gebruikt om de wijzigingen van een script te isoleren. Hier zullen we onderzoeken hoe scopes van invloed zijn op PowerShell-scripts en hoe je in en om hen heen kunt werken.
Wat is een bereik?
In PowerShell verwijst een "scope" naar de huidige omgeving waarin een script of opdrachtshell wordt uitgevoerd. Scopes worden gebruikt om te voorkomen dat bepaalde objecten in de omgeving per ongeluk worden gewijzigd door scripts of functies. In het bijzonder worden de volgende dingen beschermd tegen wijziging door opdrachten uitgevoerd vanuit een ander bereik, tenzij anders aangegeven door parameters in die opdrachten:
- Variabelen
- aliassen
- functies
- PowerShell-schijven (PSDrives)
Nieuwe scopes worden gemaakt wanneer u een script of functie uitvoert, of wanneer u een nieuwe sessie of exemplaar van PowerShell maakt. Scopes die zijn gemaakt door scripts en functies uit te voeren, hebben een "ouder / kind" -relatie met het bereik waaruit ze zijn gemaakt. Er zijn een aantal scopes met een bijzonder speciale betekenis en deze zijn op naam toegankelijk:
- De Globaal bereik is de scope die wordt gemaakt wanneer PowerShell wordt gestart. Het bevat de variabelen, aliassen, functies en PSDrives die zijn ingebouwd in PowerShell, evenals alle variaties die zijn gemaakt door uw PowerShell-profiel.
- De lokaal scope verwijst naar wat de huidige scope is. Wanneer u PowerShell start, verwijst het naar de algemene scope, binnen een script wordt dit de scope van het script, enzovoort.
- De Script bereik wordt gemaakt wanneer een script wordt uitgevoerd. De enige opdrachten die binnen dit bereik worden uitgevoerd, zijn die in het script.
- Privaat scopes kunnen binnen het huidige bereik worden gedefinieerd, om te voorkomen dat opdrachten in andere scopes in staat zijn om items te lezen of aan te passen waarvoor ze anders toegang zouden kunnen hebben.
Scopes kunnen ook worden doorverwezen naar het aantal in bepaalde opdrachten, waarbij de huidige scope wordt aangeduid als nul en de voorouders ervan worden aangeduid door de verhogende gehele getallen. In een script dat wordt uitgevoerd vanuit het algemene bereik, zou het scriptbereik bijvoorbeeld 0 zijn en zou het algemene bereik 1 zijn. Een bereik dat verder is genest binnen het scriptbereik, zoals een functie, zou verwijzen naar het algemene bereik als 2 Negatieve getallen zullen echter niet werken om te verwijzen naar kindscopes - de reden hiervoor zal snel duidelijk worden.
Hoe Scopes de opdrachten beïnvloeden
Zoals eerder vermeld, hebben opdrachten die binnen een scope worden uitgevoerd, geen invloed op dingen in een andere scope tenzij specifiek wordt aangegeven dit te doen. Als bijvoorbeeld $ MyVar in de globale scope bestaat en een script een opdracht uitvoert om $ MyVar op een andere waarde in te stellen, blijft de algemene versie van $ MyVar ongewijzigd, terwijl een kopie van $ MyVar in de scriptscope wordt geplaatst met de nieuwe waarde. Als een $ MyVar niet bestaat, maakt een script dit standaard binnen het Script-bereik - niet in de globale scope. Dit is belangrijk om te onthouden naarmate u meer leert over de feitelijke ouder / kindrelatie tussen scopes.
De ouder-kindrelatie van scopes in PowerShell is one-way. Opdrachten kunnen de huidige scope, de bovenliggende scope en eventuele scopes daarboven bekijken en optioneel aanpassen. Ze kunnen echter geen dingen zien of wijzigen in kinderen van de huidige scope. Dit komt vooral omdat, als je eenmaal bent verhuisd naar een bovenliggende scope, de onderliggende scope al is vernietigd omdat deze zijn doel heeft vervuld. Waarom zou u bijvoorbeeld een variabele in het Script-bereik moeten zien of wijzigen, vanuit de globale scope, nadat het script is beëindigd? Er zijn veel gevallen waarin u de wijzigingen van een script of functie nodig hebt om verder te gaan dan voltooid, maar niet zo veel waar u wijzigingen moet aanbrengen aan objecten binnen het bereik van het script of de functie vóór of na de uitvoering. (Meestal worden dergelijke dingen als onderdeel van het script of de functie zelf verwerkt.)
Wat zijn natuurlijk regels zonder uitzonderingen? Een uitzondering op het bovenstaande zijn privé-scopes. Objecten in de privéscopes zijn alleen toegankelijk voor opdrachten die worden uitgevoerd binnen het bereik van waaruit ze zijn gemaakt. Een andere belangrijke uitzondering zijn items met de eigenschap AllScope. Dit zijn speciale variabelen en aliassen waarvoor een wijziging in een bereik van invloed is op alle scopes. De volgende opdrachten laten zien welke variabelen en aliassen de AllScope-eigenschap hebben:
Get-Variable | Where-Object $ _. Opties -match 'AllScope' Get-alias | Where-Object $ _. Opties -match 'AllScope')
Scopes in actie
Voor onze eerste blik op scopes in actie zullen we starten in een PowerShell-sessie waarbij de variabele $ MyVar is ingesteld op een string, 'Ik ben een globale variabele!', Vanaf de opdrachtregel. Vervolgens wordt het volgende script uitgevoerd vanuit een bestand met de naam Scope-Demo.ps1:
Functie FunctionScope 'Wijzigen van $ MyVar met een functie.' $ MyVar = 'Ik ben ingesteld door een functie!' "MyVar zegt $ MyVar" "Huidige waarde van $ MyVar controleren." "MyVar zegt $ MyVar" "$ MyVar per script wijzigen." $ MyVar = 'Ik ben ingesteld door een script!' "MyVar zegt $ MyVar" "FunctionScope" De definitieve waarde van MyVar controleren voordat het script wordt afgesloten. ' "MyVar zegt $ MyVar" "
Als PowerShell-scripts hetzelfde werkten als batch-scripts, verwachten we dat het gemiddelde van $ MyVar (of% MyVar% in batchsyntaxis) verandert van 'Ik ben een globale variabele!', Naar 'Ik ben door een script ingesteld!' en tot slot: 'Ik ben ingesteld door een functie!' waar het zou blijven totdat het expliciet opnieuw wordt gewijzigd of de sessie wordt beëindigd. Kijk echter wat hier werkelijk gebeurt als we door elk van de scopes gaan - met name nadat de functie FunctionScope zijn werk heeft voltooid en we de variabele opnieuw controleren vanuit het script en later het globale bereik.
Zoals je ziet, leek de variabele te veranderen toen we door het script gingen omdat, tot de functie FunctionScope voltooid was, we de variabele aan het controleren waren vanuit dezelfde scope als voor het laatst gewijzigd. Nadat FunctionScope echter was voltooid, keerden we terug naar het Script-bereik waar $ MyVar onaangeroerd bleef door de functie. Toen het script werd beëindigd, kwamen we weer terug in de globale scope waar het helemaal niet was aangepast.
Buiten de lokale scope bereiken
Dit is dus allemaal goed en wel om te voorkomen dat u per ongeluk wijzigingen in de omgeving toepast die verder gaan dan uw scripts en functies, maar wat als u dergelijke wijzigingen echt wilt aanbrengen? Er is een speciale, en vrij eenvoudige, syntaxis voor het maken en wijzigen van objecten buiten de lokale scope. Plaats de naam van het bereik aan het begin van de naam van de variabele en plaats een dubbele punt tussen de bereik- en variabelenamen. Zoals dit:
$ global: MyVar $ script: MyVar $ local: MyVar
U kunt deze modifiers zowel gebruiken bij het bekijken en instellen van variabelen. Laten we eens kijken wat er gebeurt met dit demonstratiescript:
Functie FunctionScope "Wijzigen van $ MyVar in de lokale functieomvang ... '$ local: MyVar =" Dit is MyVar in het lokale bereik van de functie. "' Wijzigen van $ MyVar in het scriptbereik ... '$ script: MyVar =' MyVar was vroeger ingesteld door een script. Nu ingesteld door een functie. "Wijzigen van $ MyVar in de globale scope ... '$ global: MyVar =' MyVar werd ingesteld in de globale scope. Nu ingesteld door een functie. "Controle van $ MyVar in elke scope ... '" Lokaal: $ local: MyVar "" Script: $ script: MyVar "" Globaal: $ global: MyVar "" "Huidige waarde van $ MyVar krijgen." "MyVar zegt $ MyVar" "$ MyVar per script wijzigen." $ MyVar = 'Ik ben ingesteld door een script!' "MyVar zegt $ MyVar" FunctionScope 'Controle van $ MyVar van scriptscope voor afsluiten.' "MyVar zegt $ MyVar" "
Net als eerder beginnen we met het instellen van de variabele in de globale scope en eindigen we met het controleren van het uiteindelijke mondiale bereikresultaat.
Hier kunt u zien dat FunctionScope de variabele in de Script-scope heeft kunnen wijzigen en dat de wijzigingen kunnen blijven bestaan nadat deze is voltooid. Ook bleef de wijziging van de variabele in de globale scope bestaan, zelfs nadat het script was afgesloten. Dit kan met name handig zijn als u variabelen binnen een script of binnen de globale scope herhaaldelijk moet wijzigen met dezelfde code - u definieert alleen een functie of script dat is geschreven om de variabele aan te passen waar en hoe u dit gedaan moet hebben, en vraag dat wanneer die veranderingen nodig zijn.
Zoals eerder vermeld, kunnen scope-aantallen ook in bepaalde opdrachten worden gebruikt om de variabele op verschillende niveaus in relatie tot de lokale scope te wijzigen. Hier is hetzelfde script dat wordt gebruikt in het tweede voorbeeld hierboven, maar waarbij de functie is gewijzigd om de opdrachten Get-Variable en Set-Variable met scope-nummers te gebruiken in plaats van rechtstreeks naar de variabele met benoemde scopes te verwijzen:
Functie FunctieScope "Wijzigen $ MyVar in scope 0, ten opzichte van FunctionScope ... 'Set-Variable MyVar" Dit is MyVar binnen het bereik van de functie 0. "-Scope 0' Wijzigen van $ MyVar in scope 1, ten opzichte van FunctionScope ... 'Set-Variable MyVar 'MyVar is in scope 1 veranderd, vanuit een functie.' -Scope 1 'Changing MyVar in scope 2, tov Functionscope ...' Set-Variable MyVar 'MyVar is in scope 2 veranderd, vanuit een functie.' -Scope 2 "Controle van $ MyVar in elke scope ..." Scope 0: 'Get-Variable MyVar -Scope 0 -ValueOnly' Scope 1: 'Get-Variable MyVar -Scope 1 -ValueOnly' Scope 2: 'Get-Variable MyVar -Scope 2 -ValueOnly "" De huidige waarde van $ MyVar krijgen. ' "MyVar zegt $ MyVar" "$ MyVar per script wijzigen." $ MyVar = 'Ik ben ingesteld door een script!' "MyVar zegt $ MyVar" FunctionScope 'Controle van $ MyVar van scriptscope voor afsluiten.' "MyVar zegt $ MyVar" "
Net als voorheen, kunnen we hier zien hoe opdrachten in een bereik objecten in de bovenliggende scope kunnen wijzigen.
Extra informatie
Er is nog veel meer dat met scopes kan worden gedaan dan in dit artikel past. Scopes beïnvloeden meer dan alleen variabelen en er is nog meer te leren over privé-scopes en de AllScope-variabelen. Voor meer nuttige informatie kunt u de volgende opdracht uitvoeren vanuit PowerShell:
Get-Help over scopes
Hetzelfde helpbestand is ook beschikbaar op TechNet.
Scope image credit: spadassin op openclipart