Adam the Automator

author
14 minutes, 13 seconds Read

Wanneer je een PowerShell script schrijft zonder functies en zonder externe afhankelijkheden van andere scripts, is het concept van PowerShell scopes niet van veel belang. Het concept van PowerShell globale variabelen staat niet op de voorgrond. Maar als je begint met het bouwen van functies, modules en leert om scripts vanuit andere scripts aan te roepen, wordt het onderwerp belangrijker.

In dit artikel krijg je een diepgaande les in wat scopes in PowerShell zijn, hoe ze werken, en hoe je code kunt schrijven met scopes in gedachten. Tegen de tijd dat je klaar bent, begrijp je de globale variabelen van PowerShell en nog veel meer!

Inhoudsopgave

Scopes: Kinda Like Buckets

Heb je ooit een script geschreven waarin je een variabele definieert en wanneer je de waarde van die variabele controleert, het iets anders is? Je vraagt je misschien af hoe die variabele is veranderd terwijl je hem duidelijk hebt gedefinieerd. Een van de redenen kan zijn dat de waarde van de variabele wordt overschreven in een ander bereik.

Misschien heb je je afgevraagd hoe bepaalde PowerShell variabelen waarden hebben wanneer je ernaar verwijst in je console, maar niet bestaan in je scripts. De kans is groot dat die variabelen in een andere ‘emmer’ zitten die op dat moment niet beschikbaar is.

Scopes zijn net emmers. Scopes hebben invloed op de manier waarop PowerShell variabelen, aliassen, functies en PSDrives isoleert tussen verschillende gebieden. Een scope is als een emmer. Het is een plaats om al deze items bij elkaar te verzamelen.

Wanneer PowerShell start, maakt het automatisch deze “emmers” voor u aan. Op dat moment maakt u al gebruik van scopes zonder het te beseffen. Alle scopes worden gedefinieerd door PowerShell en worden gemaakt zonder enige hulp van uw kant.

Scope Types

Wanneer PowerShell opstart, maakt het automatisch vier “buckets” of scopes voor verschillende items om in te worden geplaatst. U kunt zelf geen scopes maken. U kunt alleen items toevoegen en verwijderen uit deze hieronder gedefinieerde scopes.

Global Scope

Items die worden gedefinieerd wanneer PowerShell wordt geopend, worden ingesteld op de global scope. Deze items omvatten door het systeem gecreëerde objecten zoals PowerShell-stations en ook alles wat u hebt gedefinieerd in een PowerShell-profiel, aangezien uw profiel wordt uitgevoerd bij het opstarten.

Items in de globale reikwijdte zijn overal beschikbaar. U kunt verwijzen items in de global scope interactief op de console, in elk script dat u uitvoert, en in elke functie. PowerShell’s Global variabelen zijn overal. Om deze reden is het gemeenschappelijke gebruik van PowerShell globale variabelen tussen scripts.

Er is slechts één globaal toepassingsgebied dat over het geheel heerst.

Script Scope

Een script scope wordt automatisch gemaakt elke keer dat een PowerShell script wordt uitgevoerd. U kunt veel verschillende script scope instanties hebben. Script scopes worden gemaakt wanneer u bijvoorbeeld een PS1 script of een module uitvoert.

Alleen items die zijn gemaakt in die specifieke script scope instance kunnen naar elkaar verwijzen.

Private Scope

Typisch is een item gedefinieerd kan worden benaderd vanuit andere scopes – niet waar met items in een private scope. Items in een private scope, bevatten objecten die verborgen zijn voor andere scopes. Een private scope wordt gebruikt om items te maken met dezelfde naam als items in andere scopes om overlap te voorkomen.

Local Scope

In tegenstelling tot de andere scopes, is de local scope een beetje anders. De local scope is een pointer naar de global, script of private scope. De local scope is relatief aan de context waarin de code op dat moment draait.

Als je een variabele, alias, functie, of PSDrive maakt zonder deze expliciet een scope toe te wijzen (wat we later zullen behandelen) zal deze in de local scope gaan.

Verwijzen naar scopes

Nu je een idee hebt van de vier soorten scopes die er zijn, moet je ook weten dat er twee manieren zijn om naar die scopes te verwijzen.

In PowerShell zijn er twee manieren om naar scopes te verwijzen – met naam of genummerd. Beide methoden verwijzen naar dezelfde scopes, maar gewoon op een andere manier. Dit zijn twee verschillende manieren van interactie met scopes.

Genoemde scopes

Hierboven in de Scope Type sectie, heb je geleerd over scopes die met naam worden gerefereerd. Referencen van een scope met naam wordt, intuïtief, een named scope genoemd. Het belangrijkste doel van het verwijzen naar een scope met naam is om een item toe te wijzen aan een scope. Je leert hieronder hoe je dit moet doen.

Genummerde scopes

Gelijk met een naam, heeft ieder bereik een nummer, beginnend bij nul, wat altijd het lokale bereik zal zijn. Scopes worden dynamisch genummerd in relatie tot de huidige lokale scope.

Zodra u bijvoorbeeld een PowerShell sessie opent bent u actief in de globale scope. Op dit punt is de global scope de local scope (onthoud dat de local scope slechts een pointer is).

Omdat de local scope altijd scope nul is, is op dit punt de global scope ook op dit moment scope nul. Maar, als je een script uitvoert vanuit diezelfde sessie, wordt er een script scope aangemaakt. Tijdens het uitvoeren is de local scope pointer dan veranderd naar de script scope. Nu is de script scope scope nul en de global scope is scope één.

Scopes zijn genummerd Dit proces herhaalt zich voor zoveel scopes als je hebt waarbij de local scope 0 is. Scopes worden dynamisch genummerd door scope hiërarchie.

Scope Hiërarchy and Inheritance

Zoals gezegd, wanneer u een PowerShell-sessie start, maakt PowerShell een aantal items voor u aan in de global scope. Deze items kunnen functies, variabelen, aliassen of PSDrives zijn. Alles wat u definieert in uw PowerShell-sessie zal ook worden gedefinieerd in de global scope.

Doordat u zich standaard in de global scope bevindt, als u iets doet dat een andere scope creëert, zoals het uitvoeren van een script of het uitvoeren van een functie, zal een child scope worden gemaakt met als ouder de global scope. Scopes zijn als processen met ouders en kinderen.

Alles dat is gedefinieerd in een ouder scope, het globale scope, in dit geval, zal toegankelijk zijn in het kind scope. Maar deze items zijn alleen te bewerken in het bereik waarin ze zijn gedefinieerd.

Stel dat je een script hebt met de naam Test.ps1. In dit script staat een enkele regel zoals hieronder getoond.

$a = 'Hello world!'

Wanneer je dit script uitvoert, wordt $a een waarde toegewezen in het lokale bereik (script terwijl het script wordt uitgevoerd). Wanneer Test.ps1 wordt uitgevoerd, kun je hieronder zien dat je niet in staat bent om ernaar te verwijzen nadat het script is uitgevoerd. Omdat $a is toegewezen in het scriptbereik, kan het globale bereik (op de interactieve console) het niet zien.

Globaal bereik kan de variabele niet zien

Nemen we dit voorbeeld een stapje verder en laten we het Test.ps1 script eruit zien zoals hieronder. Het script probeert nu de waarde van $a uit te voeren voordat het in hetzelfde bereik wordt ingesteld.

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

Om dit te demonstreren, wijs een waarde toe aan $a op de interactieve console. Dit wijst de waarde toe aan het globale bereik. Als nu het script wordt uitgevoerd, zal het het bovenliggende bereik erven (globaal) en in staat zijn om de waarde te zien.

Je kunt hieronder zien dat wanneer Test.ps1 wordt uitgevoerd (en een kind bereik van het globale bereik maakt), het in staat is om de waarde van $a te zien. Je kunt ook zien dat de waarde van de variabele ook beschikbaar is in het globale bereik, omdat dit bereik is waar het was ingesteld. Dit betekent dat $a beschikbaar is in zowel de script (child) als de parent (global) scopes.

Variabele is beschikbaar in script en global scopes

Onthoud dit scope overervings gedrag. Dit helpt je bij het oplossen van problemen met variabelen, zoals variabelen in verschillende scopes met dezelfde naam.

Items in scopes definiëren en benaderen

Nu je weet wat een scope is en hoe ze werken, hoe krijg je er dan toegang toe? Laten we eens kijken hoe u PowerShell kunt gebruiken om een variabele scope in te stellen (en ze te benaderen).

Get/Set-Variable

In PowerShell zijn er twee cmdlets waarmee u variabelen kunt instellen, genaamd Get-Variable en Set-Variable. Met deze cmdlets kunt u de waarde van een variabele opvragen of een waarde definiëren.

Beide cmdlets lijken op elkaar met een Name en Scope parameter. Met behulp van deze parameters kunt u met PowerShell variabele waarden instellen en ophalen over alle scopes.

Lokale Scopes

Om een variabele in een lokaal bereik in te stellen, gebruikt u Set-Variable en geeft u het een lokale variabelenaam en een waarde zoals hieronder getoond.

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

Het lokale bereik is altijd de standaard, dus als u de Scope parameter niet gebruikt, zal de variabele altijd in het lokale bereik worden gedefinieerd.

Om de waarde van een local-scope variabele op te halen, gebruik Get-Variable en geef het de naam.

PS> Get-Variable -Name aName Value---- -----a foo

Private/Script/Global Scopes

Je gebruikt dezelfde parameters (Name en Value) wanneer je werkt met private, script en global variabelen. Het enige verschil is dat je deze keer de Scope parameter gebruikt om de scope expliciet te definiëren.

De methodes om een private, script of globally-scope variabele in te stellen zijn hetzelfde. Vervang gewoon de waarde die is doorgegeven aan de Scope parameter als Private, Script Global.

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

Om de waarde van een script of globally-scoped variabele op te halen, gebruik Get-Variable en geef het de naam en scope.

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

Note: U kunt ook naar scopes verwijzen met behulp van scope-nummers in plaats van namen met de Get/Set-Variable cmdlets.

Scope “Prefacing”

U kunt ook variabelen in scopes ophalen en instellen met behulp van een snelkoppeling. In plaats van PowerShell-cmdlets te gebruiken, geeft u de scope aan de variabele vooraf wanneer u ernaar verwijst.

Lokale scopes

Doordat de lokale scope altijd de standaard is, zal het definiëren van een variabele en het verwijzen ernaar een lokale scope variabele instellen en opvragen

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

Private/Script/Globale scopes

Als u script of globale scopes wilt definiëren en ernaar wilt verwijzen, kunt u de variabelen vooraf laten gaan door de scope naam en een puntkomma.

Bijv. om de variabele $a in het globale bereik te zetten, kun je a vooraf laten gaan door $global:.

$global:a = 'foo'

Hetzelfde kan worden gedaan voor een script-gebaseerde variabele.

$script:a = 'foo'

Als de variabelen eenmaal zijn ingesteld in het gewenste bereik, kun je er op dezelfde manier naar verwijzen. Merk ook op dat u de scope preface kunt uitsluiten als de gedefinieerde scope de lokale scope is.

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

Scopes in Scriptblocks

PowerShell heeft een handige constructie genaamd scriptblocks. Scriptblocks kunt u rond snippets van code en voer ze uit zowat overal.

Net als een PS1 script, scriptblocks draaien in hun eigen script scope. Wanneer u een scriptblok uitvoert, voert u in wezen een PS1-script uit.

Merk in het onderstaande voorbeeld op dat een variabele is gedefinieerd in het globale bereik en vervolgens wordt geprobeerd om het te overschrijven in een scriptbereik. Zoals je hierboven hebt geleerd, zal dit niet werken omdat een child scope niet kan verwijzen naar een parent scope.

Een child scope kan een parent scope niet overschrijven

Dit voorbeeld laat zien dat wanneer $a wordt gewijzigd in het scriptblock, de globale variabele definitie voor $a niet wordt gewijzigd omdat het scriptblock een script child scope is.

Dot Sourcing Scripts (Swapping Local Scopes)

PowerShell heeft een concept dat dot-sourcing heet. Dit is een methode die u in staat stelt om een PS1 script uit te voeren en alles wat script-scoped zou zijn in plaats daarvan in de lokale scope te brengen.

Door een punt (.) te plaatsen voor het verwijzen naar een PS1 script en het uit te voeren, deze “dot sources” de inhoud van het script en brengt alles in de lokale scope.

Om dit te demonstreren, heb ik weer een Test.ps1 script dat een variabele definieert zoals hieronder getoond.

$a = 'Hello world!'

In een PowerShell console, stel een waarde in voor een $a variabele en “dot source” dan dit script zoals hieronder getoond. Merk op dat de oorspronkelijke variabele is overschreven. PowerShell heeft de twee lokale scopes “samengevoegd”.

Oorspronkelijke variabele overschreven

De AllScope-eigenschap gebruiken (optie)

U hebt gezien hoe u met items in specifieke scopes kunt werken, maar tot nu toe is elk item nog steeds in een enkele scope gedefinieerd. Maar wat als je niet weet in welk bereik een variabele is gedefinieerd?

Wanneer je een variabele definieert met het Set-Variable cmdlet, kun je de variabele in één keer in alle scopes plaatsen. Om dit te doen, gebruikt u de AllScope waarde voor de Option parameter.

Om dit te demonstreren, is het Test.ps1 script aangepast om een een variabele in alle scopes te zetten. Die variabele wordt dan uitgevoerd zoals hieronder getoond.

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

Je kunt dan hieronder zien dat er een waarde wordt ingesteld voor $a in het globale bereik en het Test.ps1 script wordt uitgevoerd. Echter, in plaats van dat het geen effect heeft, is de waarde van $a overschreven. Niet alleen is het gedefinieerd in het script bereik (Write-Output $a), maar het is ook overschreven in het globale bereik.

Variabele overschreven in globaal bereik

De AllScope optie is handig, maar wees voorzichtig. Deze optie maakt in wezen korte metten met het concept van scopes en voegt alles samen.

Functie Scopes

Wanneer je een functie uitvoert, bevindt alle code binnen die functie zich in zijn eigen child scope. Functie scopes volgen hetzelfde child/parent gedrag als andere scopes.

Het hebben van aparte scopes voor elke functie is een goed idee. Het geeft betere controle over items en geen zorgen over conflicterende items. Het geeft ook het voordeel van automatisch opruimen van variabelen in een functie. Zodra de functie is voltooid, worden alle in de functie gedefinieerde items gewist.

Om dit te demonstreren, kopieer/plak de onderstaande functie rechtstreeks in de PowerShell console.

Function Do-Thing { $var = 'bar'}

Eenmaal geplakt, voert u de functie uit. Merk op dat u geen toegang heeft tot de $var variabele buiten de functie.

PS> Do-ThingPS> $var

Keeping Items Private (Inheritance uitschakelen)

Typisch, als een variabele is gedefinieerd in een parent scope, zal die variabele worden gedefinieerd in de child scope. Maar misschien wil je een variabele naam gebruiken, maar is die variabele naam al gedefinieerd in een van de scopes die in een sessie worden uitgevoerd. In dat geval kun je of een andere variabele naam kiezen of de variabele definiëren in een private scope waardoor het een private variabele wordt.

Een manier om scopes te gebruiken om conflicten te verminderen is door de private scope te gebruiken. Het gebruik van de private scope schakelt overerving uit op die specifieke variabele. Wanneer meerdere child scopes worden gemaakt, zullen die child scopes geen variabelen zien die in een private scope zijn gedefinieerd.

Een Test.ps1 script voert de waarde van $a uit zoals hieronder getoond.

Write-Output $a

Je kunt hieronder zien dat ik een private-scoped variabele definieer in de global scope en vervolgens het Test.ps1 script uitvoer. Normaal gesproken, wanneer je een variabele definieert in een parent scope, zal die variabele beschikbaar zijn in het child scope – niet zo met een privately-scoped variabele.

In het onderstaande voorbeeld kun je zien dat het script child scope dat is gemaakt door het uitvoeren van het Test.ps1 script de private-scoped $a variabele die in het parent scope is gedefinieerd niet kan zien.

Script scope kan de private-scoped variabele niet zien

In tegenstelling tot globale scopes of de AllScope optie op het Set-Variable cmdlet, zijn private-scoped variabelen een uitstekende manier om items te compartimenteren.

Scoping Best Practices

De gedachte dat het definiëren van variabelen in het globale bereik of het gebruik van de AllScope optie de juiste manier is, komt vaak voor. Immers, alle variabelen zijn overal beschikbaar. Je hoeft je geen zorgen te maken over de complicaties van scopes. Hoewel dit extra vrijheid geeft voor toegang tot wat is gedefinieerd, kan het snel uit de hand lopen en moeilijk worden om problemen op te lossen.

In plaats van te proberen het gebruik van scopes te voorkomen, volg deze tips:

  1. In plaats van scopes te specificeren in functies, gebruik parameters om de benodigde informatie door te geven aan de functie.
  2. Blijf zo veel mogelijk binnen het lokale bereik.
  3. In plaats van globale variabelen te definiëren vanuit een script, gebruik het Write-Output cmdlet om alles uit te voeren en op te slaan in een variabele wanneer dat nodig is vanuit de console.

Het belangrijkste punt hier is om scopes te omarmen en te leren ze in uw voordeel te gebruiken in plaats van te proberen ze te omzeilen.

Verder lezen

  • Over geavanceerde functies en functieparameters
  • Het gebruik van omgevingsvariabelen in PowerShell

Similar Posts

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.