Quando si scrive uno script PowerShell senza funzioni e senza dipendenze esterne da altri script, il concetto di ambiti PowerShell non è molto importante. Il concetto di variabili globali PowerShell non è al centro dell’attenzione. Ma quando si inizia a creare funzioni, moduli e si impara a chiamare script da altri script, l’argomento diventa più importante.
In questo articolo, riceverai una lezione approfondita su cosa sono gli ambiti in PowerShell, come funzionano e come è possibile scrivere codice tenendo conto degli ambiti. Quando avrai finito, comprenderai le variabili globali di PowerShell e molto altro ancora!
Ambiti: un po’ come secchielli
Hai mai scritto uno script in cui si definisce una variabile e quando si controlla il valore di quella variabile, è diverso? Potresti grattarti la testa chiedendoti come quella variabile sia cambiata quando l’hai chiaramente definita. Un motivo potrebbe essere che il valore della variabile viene sovrascritto in un altro ambito.
Forse ti sei chiesto come mai alcune variabili PowerShell hanno dei valori quando le si fa riferimento nella console, ma non esistono negli script. Probabilmente quelle variabili si trovano in un altro “secchiello” che non è disponibile in quel momento.
Gli ambiti sono come secchielli. Gli ambiti influiscono sul modo in cui PowerShell isola le variabili, gli alias, le funzioni e i PSDrive tra diverse aree. Un ambito è come un secchiello. È un luogo in cui raccogliere tutti questi elementi insieme.
Quando PowerShell viene avviato, crea automaticamente questi “secchielli” per te. A quel punto, stai già utilizzando gli ambiti senza rendermene conto. Tutti gli ambiti sono definiti da PowerShell e vengono creati senza la tua assistenza.
Tipi di ambito
Quando PowerShell si avvia, crea automaticamente quattro “contenitori” o ambiti in cui vengono collocati vari elementi. Non è possibile creare ambiti autonomamente. È possibile solo aggiungere e rimuovere elementi da questi ambiti definiti di seguito.
Ambito globale
Gli elementi definiti all’avvio di PowerShell sono impostati nell’ambito globale. Questi elementi includono oggetti creati dal sistema come i drive di PowerShell e qualsiasi cosa tu abbia definito in un profilo di PowerShell dato che il profilo viene eseguito all’avvio.
Gli elementi nell’ambito globale sono disponibili ovunque. È possibile fare riferimento agli elementi nell’ambito globale in modo interattivo sulla console, in qualsiasi script che si esegue e in qualsiasi funzione. Le variabili globali di PowerShell sono ovunque. Per questo motivo, l’uso comune delle variabili globali di PowerShell è quello di utilizzare variabili globali di PowerShell tra script.
C’è solo un unico ambito globale che prevale su tutti gli altri.
Ambito dello script
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.
Solo gli elementi creati in quella particolare istanza di ambito di script possono fare riferimento gli uni agli altri.
Ambito privato
Tipicamente, un elemento definito può essere accessibile da altri ambiti, ma non è vero per gli elementi in un ambito privato. Gli elementi in un ambito privato contengono oggetti che sono nascosti ad altri ambiti. Un ambito privato viene utilizzato per creare elementi con lo stesso nome di elementi in altri ambiti per evitare sovrapposizioni.
Ambito locale
A differenza degli altri ambiti, l’ambito locale è leggermente diverso. L’ambito locale è un puntatore all’ambito globale, allo script o all’ambito privato. L’ambito locale è relativo al contesto in cui viene eseguito il codice in quel momento.
Se si crea una variabile, un alias, una funzione o una PSDrive senza assegnare esplicitamente un ambito (che vedremo più avanti), verrà inserito nell’ambito locale.
Riferimento agli ambiti
Ora che hai un’idea dei quattro tipi di ambiti che esistono, dovresti anche sapere che ci sono due modi per fare riferimento a quegli ambiti.
In PowerShell, ci sono due modi per fare riferimento agli ambiti: nominati o numerati. Entrambi i metodi fanno riferimento agli stessi ambiti, ma semplicemente in modo diverso. Questi sono due modi diversi di interagire con gli ambiti.
Ambiti nominati
Nella sezione Tipo di ambito sopra, hai appreso degli ambiti che vengono referenziati per nome. Fare riferimento a un ambito per nome è, intuitivamente, chiamato un ambito nominato. Lo scopo principale di fare riferimento a un ambito per nome è assegnare un elemento a un ambito. Di seguito imparerai come farlo.
Ambiti numerati
Oltre a un nome, ogni ambito ha un numero che parte da zero e sarà sempre l’ambito locale. Gli ambiti vengono numerati dinamicamente in relazione all’ambito locale corrente.
Ad esempio, non appena apri una sessione di PowerShell, stai operando nell’ambito globale. A questo punto, l’ambito globale è l’ambito locale (ricorda che l’ambito locale è solo un puntatore).
Poiché lo scope locale è sempre lo scope zero, in questo momento lo scope globale è anche attualmente lo scope zero. Ma, quando si esegue uno script dalla stessa sessione, viene creato uno scope script. Durante l’esecuzione, il puntatore dello scope locale viene quindi cambiato nello scope script. Ora lo scope script è lo scope zero e lo scope globale è lo scope uno.
Gli scope sono numerati. Questo processo si ripete per quanti scope hai in cui lo scope locale è 0. Gli scope sono numerati dinamicamente in base alla gerarchia degli scope.
Gerarchia degli Scope e Ereditarietà
Come accennato in precedenza, quando si avvia una sessione di PowerShell, PowerShell crea alcuni elementi per te nello scope globale. Questi elementi possono essere funzioni, variabili, alias o PSDrive. Tutto ciò che si definisce nella sessione di PowerShell sarà definito anche nello scope globale.
Dato che sei nello scope globale per impostazione predefinita, se fai qualcosa che crea un altro scope come l’esecuzione di uno script o l’esecuzione di una funzione, verrà creato uno scope figlio con lo scope genitore che è lo scope globale. Gli scope sono simili a processi con genitori e figli.
Tutto ciò che è definito in uno scope genitore, lo scope globale in questo caso, sarà accessibile nello scope figlio. Ma questi elementi sono modificabili solo nello scope in cui sono stati definiti.
Supponiamo che tu abbia uno script chiamato Test.ps1. All’interno di questo script c’è una singola riga come mostrato di seguito.
Quando esegui questo script, $a
viene assegnato a un valore nello scope locale (script mentre lo script è in esecuzione). Quando Test.ps1 viene eseguito, puoi vedere di seguito che non è possibile fare riferimento ad esso dopo l’esecuzione dello script. Poiché $a
è stato assegnato nello scope dello script, lo scope globale (nella console interattiva) non può vederlo.

Portiamo questo esempio un passo avanti e facciamo in modo che lo script Test.ps1 sia così. Lo script sta ora cercando di stampare il valore di $a
prima di impostarlo nello stesso scope.
Per dimostrare, assegna un valore a $a
nella console interattiva. Questo assegna il valore nello scope globale. Ora, quando lo script viene eseguito, erediterà lo scope genitore (globale) e dovrebbe essere in grado di vedere il valore.
Puoi vedere di seguito che quando Test.ps1 viene eseguito (creando uno scope figlio dello scope globale), può vedere il valore di $a
. Puoi anche vedere che il valore della variabile è disponibile anche nello scope globale poiché questo è l’ambito in cui è stato impostato. Ciò significa che $a
è disponibile sia nello scope dello script (figlio) che nello scope genitore (globale).

Ricorda questo comportamento di ereditarietà dello scope. Farlo ti aiuterà quando si verificheranno situazioni di risoluzione dei problemi in cui si verificheranno conflitti di variabili, come variabili in diversi ambiti con lo stesso nome.
Definizione e accesso degli elementi negli ambiti
Ora che sai cos’è uno scope e come funzionano, come si accede ad essi? Vediamo come utilizzare PowerShell per impostare uno scope di variabile (e accedervi).
Get/Set-Variable
In PowerShell, ci sono due cmdlet che ti consentono di impostare variabili chiamate Get-Variable
e Set-Variable
. Questi cmdlet ti consentono di recuperare il valore di una variabile o definire un valore.
Entrambi i cmdlet sono simili con un parametro Name
e Scope
. Utilizzando questi parametri, PowerShell ti consente di impostare e recuperare i valori delle variabili in tutti gli scope.
Scopi locali
Per impostare una variabile in uno scope locale, utilizza Set-Variable
e fornisci un nome di variabile locale e un valore come mostrato di seguito.
Lo scope locale è sempre quello predefinito, quindi non utilizzare il parametro Scope
definirà sempre la variabile nello scope locale.
Per recuperare il valore di una variabile a scope locale, utilizza Get-Variable
fornendo il nome.
Scopi privati/script/globali
Utilizzerai gli stessi parametri (Name
e Value
) quando lavori anche con variabili private, di script e globali. L’unica differenza è che questa volta utilizzerai il parametro Scope per definire esplicitamente lo scope.
I metodi per impostare una variabile a scope privato, di script o globale sono gli stessi. Sostituisci semplicemente il valore passato al parametro Scope
come Private
, Script
, Global
.
Per recuperare il valore di uno script o di una variabile a livello globale, utilizza Get-Variable
fornendo il nome e lo scope.
Nota: Puoi anche fare riferimento agli scope utilizzando numeri di scope invece di nomi con i cmdlet
Get
/Set-Variable
.
Scope “Prefisso”
Puoi anche recuperare e impostare variabili negli scope utilizzando una scorciatoia. Invece di utilizzare i cmdlet di PowerShell, prefigurerai lo scope alla variabile quando la stai referenziando.
Scope Locali
Dato che lo scope locale è sempre quello predefinito, semplicemente definendo una variabile e referenziandola imposterai e recupererai una variabile a livello locale.
Scope Privato/Script/Globale
Se desideri definire e referenziare scope di script o globali, puoi prefigurare le variabili con il nome dello scope e un punto e virgola.
Ad esempio, per impostare la variabile $a
nello scope globale, puoi prefigurare $global:
.
Lo stesso può essere fatto per una variabile a scope di script.
Una volta che le variabili sono impostate nello scope preferito, le referenzierai allo stesso modo. Inoltre, nota che puoi escludere il prefisso dello scope se lo scope definito è quello locale.
Scope in Blocchi di Script
PowerShell ha una costruzione utile chiamata blocchi di script. I blocchi di script ti permettono di spostare porzioni di codice ed eseguirle praticamente ovunque.
Come uno script PS1, i blocchi di script vengono eseguiti nel loro scope di script. Quando esegui un blocco di script, stai essenzialmente eseguendo uno script PS1.
Nota nell’esempio sottostante dove una variabile viene definita nello scope globale e poi viene tentato di sovrascriverla nello scope dello script. Come hai appreso in precedenza, questo non funzionerà perché uno scope figlio non può fare riferimento a uno scope padre.

In questo esempio si può vedere che quando $a
viene modificato nello script, la definizione della variabile globale per $a
non viene modificata perché lo script è uno scope figlio.
Esecuzione di script tramite dot-sourcing (Scambio di scope locali)
PowerShell ha un concetto chiamato dot-sourcing. Questo è un metodo che consente di eseguire uno script PS1 e portare tutto ciò che sarebbe in uno scope di script nello scope locale invece.
Inserendo un punto (.) prima di fare riferimento a uno script PS1 ed eseguendolo, si “dot-sourca” il contenuto dello script e si porta tutto nello scope locale.
Per dimostrare ciò, ho uno script Test.ps1 che definisce una variabile come mostrato di seguito.
In una console di PowerShell, imposta un valore per una variabile $a
e poi esegui lo script utilizzando il dot-sourcing come mostrato di seguito. Nota che la variabile originale è stata sovrascritta. PowerShell ha “unito” i due scope locali insieme.

Utilizzo della proprietà AllScope (Opzione)
Hai visto come interagire con elementi in scope specifici, ma finora ogni elemento è ancora definito in un singolo scope. Ma cosa succede se non sai in quale scope una variabile è definita?
Quando si definisce una variabile con il cmdlet Set-Variable
, è possibile inserire la variabile in tutte le scoperte contemporaneamente. Per farlo, utilizzare il valore AllScope
per il parametro Option
.
Per dimostrare ciò, lo script Test.ps1 è stato modificato per impostare una variabile in tutte le scope. Quella variabile viene quindi restituita come mostrato di seguito.
Puoi quindi vedere che un valore viene impostato per $a
nella scope globale e viene eseguito lo script Test.ps1. Tuttavia, invece di non avere alcun effetto, il valore di $a
è stato sovrascritto. Non solo è stato definito nella scope dello script (Write-Output $a
) ma ha anche sovrascritto la scope globale.

L’opzione AllScope
è utile, ma bisogna fare attenzione. Questa opzione elimina praticamente il concetto di scope e unisce tutto insieme.
Scope delle funzioni
Quando si esegue una funzione, tutto il codice all’interno di quella funzione si trova nella sua propria scope figlia. Le scope delle funzioni seguono lo stesso comportamento di scope figlia/genitore delle altre scope.
Avere scope separate per ogni funzione è una buona idea. Consente un migliore controllo degli elementi senza doversi preoccupare di conflitti tra gli elementi e offre anche il vantaggio aggiunto della pulizia automatica delle variabili in una funzione. Non appena la funzione viene completata, tutti gli elementi definiti nella funzione vengono cancellati.
Per dimostrare, copia/incolla la funzione qui sotto direttamente nella console di PowerShell.
Una volta incollata, esegui la funzione. Nota che non puoi accedere alla variabile $var
al di fuori della funzione.
Mantenere gli Elementi Privati (Disabilitare l’Ereditarietà)
Tipicamente, se una variabile è definita in un ambito genitore, quella variabile sarà definita nell’ambito figlio. Ma forse vuoi usare un nome di variabile che è già stato definito in uno degli ambiti da eseguire in una sessione. In tal caso, puoi scegliere un nome di variabile diverso o definire la variabile in un ambito privato, rendendola una variabile privata.
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.
Puoi vedere qui sotto che sto definendo una variabile con ambito privato a livello globale e poi eseguendo lo script Test.ps1. Di solito, quando si definisce una variabile in un ambito genitore, quella variabile sarà disponibile nell’ambito figlio – non così con una variabile con ambito privato.
Nell’esempio qui sotto, puoi vedere che lo scope figlio dello script creato eseguendo lo script Test.ps1 non poteva vedere la variabile $a
con ambito privato definita nell’ambito genitore.

A differenza degli ambiti globali o dell’opzione AllScope
sul cmdlet Set-Variable
, le variabili con ambito privato sono un ottimo modo per compartimentare gli elementi.
Pratiche Ottimali per gli Scope
Pensare che definire le variabili nello scope globale o utilizzare l’opzione AllScope
sia la strada da seguire è comune. Dopotutto, tutte le variabili sono disponibili ovunque. Non c’è bisogno di preoccuparsi delle complicazioni degli scope. Anche se questo fornisce una maggiore libertà di accesso a ciò che è definito, può diventare rapidamente fuori controllo e difficile da risolvere.
Invece di cercare di evitare l’uso degli scope, segui questi consigli:
- Piuttosto che specificare gli scope nelle funzioni, utilizza i parametri per passare le informazioni necessarie alla funzione.
- Resta nel limite dello scope locale il più possibile.
- Invece di definire variabili globali da uno script, utilizza il cmdlet
Write-Output
per visualizzare tutto e salvarlo in una variabile quando necessario dalla console.
Il punto principale qui è abbracciare gli scope e imparare a usarli a tuo vantaggio invece di cercare di evitarli.