---
title: "PowerShell Scopes: Understanding Variable Scope"
description: "Learn about PowerShell scopes for variables and write code with scopes in mind."
canonical: "https://adamtheautomator.com/powershell-scopes/"
---

# PowerShell Scopes: Understanding Variable Scope

> Learn about PowerShell scopes for variables and write code with scopes in mind.

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

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![PowerShell Scopes: Understanding Variable Scope](https://adamtheautomator.com/wp-content/uploads/2019/09/wooden-bucket-3373505_1280.jpg)

# PowerShell Scopes: Understanding Variable Scope

[![](https://secure.gravatar.com/avatar/592cc421b96f8a3f79f030a608d24047fcc0ec05ba59b5b9110af4804a6774b8?s=192&d=mm&r=g)Tyler Muir](https://adamtheautomator.com/author/tyler/)27 September 201911 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Scopes: Kinda Like Buckets](#scopes-kinda-like-buckets)
*   [Scope Types](#scope-types)
*   [Global Scope](#global-scope)
*   [Script Scope](#script-scope)
*   [Private Scope](#private-scope)
*   [Local Scope](#local-scope)
*   [Referencing Scopes](#referencing-scopes)
*   [Named Scopes](#named-scopes)
*   [Numbered Scopes](#numbered-scopes)
*   [Scope Hierarchy and Inheritance](#scope-hierarchy-and-inheritance)
*   [Defining and Accessing Items in Scopes](#defining-and-accessing-items-in-scopes)
*   [Get/Set-Variable](#get-set-variable)
*   [Local Scopes](#local-scopes)
*   [Private/Script/Global Scopes](#private-script-global-scopes)
*   [Scope “Prefacing”](#scope-prefacing-)
*   [Local Scopes](#local-scopes-1)
*   [Private/Script/Global Scopes](#private-script-global-scopes-1)
*   [Scopes in Scriptblocks](#scopes-in-scriptblocks)
*   [Dot Sourcing Scripts (Swapping Local Scopes)](#dot-sourcing-scripts-swapping-local-scopes-)
*   [Using the AllScope Property (Option)](#using-the-allscope-property-option-)
*   [Function Scopes](#function-scopes)
*   [Keeping Items Private (Disabling Inheritance)](#keeping-items-private-disabling-inheritance-)
*   [Scoping Best Practices](#scoping-best-practices)
*   [Further Reading](#further-reading)

When you write a PowerShell script with no functions and no external dependencies on other scripts, the concept of PowerShell scopes isn’t of much concern. The concept of PowerShell global variables isn’t front and center. But as you begin to build functions, modules and learn to call scripts from other scripts, the topic becomes more important.

In this article, you’re going to get a deep lesson in what scopes in PowerShell are, how they work, and how you can write code with scopes in mind. By the time you’re done, you’ll understand PowerShell’s global variables and a lot more!

## **Scopes: Kinda Like Buckets**

Have you ever written a script where you define a variable and when you check the value of that variable, it’s something else? You may scratch your head at how that variable changed when you clearly defined it. One reason may be the variable’s value is getting overwritten in another scope.

Maybe you’ve wondered how certain PowerShell variables have values when you reference them in your console but don’t exist in your scripts. Chances are those variables are in another ‘bucket’ that’s not available at that time.

Scopes are like buckets. Scopes affect the way PowerShell isolates variables, aliases, functions, and PSDrives between different areas. A scope is like a bucket. It’s a place to collect all of these items together.

When PowerShell starts, it automatically creates these “buckets” for you. At that point, you’re already using scopes without realizing it. All scopes are defined by PowerShell and get created without any help on your part.

## **Scope Types**

When PowerShell fires up, it automatically creates four “buckets” or scopes for various items to be placed in. You cannot create scopes on your own. You can only add and remove items from these scopes defined below.

### **Global Scope**

Items defined when PowerShell opens are set at the global scope. These items include system-created objects like PowerShell drives and also anything you have defined in a [PowerShell profile](https://devblogs.microsoft.com/scripting/understanding-the-six-powershell-profiles/) since your profile runs at startup.

Items in the global scope are available everywhere. You can reference items in the global scope interactively on the console, in any script you run, and in any function. PowerShell’s Global variables are everywhere. For this reason, the common use of PowerShell global variables is to use PowerShell global variables between scripts.

There is only one global scope that rules overall.

### **Script Scope**

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.

Only items created in that particular script scope instance can reference each other.

### **Private Scope**

Typically, an item defined can be accessed from other scopes – not true with items in a private scope. Items in a private scope, contain objects that are hidden to other scopes. A private scope is used to create items with the same name as items in other scopes to prevent overlap.

### **Local Scope**

Unlike the other scopes, the local scope is a bit different. The local scope is a pointer to the global, script or private scope. The local scope is relative to whatever context the code runs in at the time.

If you create a variable, alias, function, or PSDrive without explicitly assigning it a scope (which we’ll cover later) it will go into the local scope.

## **Referencing Scopes**

Now that you have an idea on the four types of scopes that exist, you should also know there are two ways to reference those scopes.

In PowerShell, there are two ways to reference scopes – named or numbered. Both methods are referencing the same scopes but simply in a different way. These are two different ways of interacting with scopes.

### **Named Scopes**

Above in the Scope Type section, you learned about scopes referenced by name. Referencing a scope by name is, intuitively, called a named scope. The main purpose of referencing a scope by name is to assign an item to a scope. You’ll learn how to do this below.

### **Numbered Scopes**

Along with a name, each scope has a number starting at zero which will always be the local scope. Scopes are numbered dynamically in relation to the current local scope.

For example, as soon as you open a PowerShell session you are operating in the global scope. At this point, the global scope is the local scope (remember the local scope is just a pointer).

Since the local scope is always scope zero, at this point, the global scope is also currently scope zero. But, when you run a script from that same session, a script scope is created. When running, the local scope pointer has then changed to the script scope. Now the script scope is scope zero and the global scope is scope one.

Scopes are numbered This process repeats for as many scopes as you have where the local scope is 0. Scopes are dynamically numbered by scope hierarchy.

## **Scope Hierarchy and Inheritance**

As mentioned earlier, when you launch a PowerShell session, PowerShell creates some items for you in the global scope. These items can be functions, variables, aliases, or PSDrives. Anything you define in your PowerShell session will be defined in the global scope also.

Since you are in the global scope by default, if you do something that creates another scope like executing a script or running a function, a child scope will be created with the parent being the global scope. Scopes are like processes with parents and children.

Anything that is defined in a parent scope, the global scope, in this case, will be accessible in the child scope. But these items are only editable in the scope they were defined in.

Let’s say you have a script called _Test.ps1_. Inside of this script is a single line as shown below.

```powershell
$a = 'Hello world!'
```

When you run this script, `$a` is assigned a value in the local scope (script while the script is running). When _Test.ps1_ is run, you can see below that you’re unable to reference it after the script executes. Since `$a` was assigned while in the script scope, the global scope (at the interactive console) can’t see it.

![Global scope cannot see the variable](/wp-content/uploads/2019/09/powershell-scope-1.png)

Global scope cannot see the variable

Let’s take this example a step further and make the _Test.ps1_ script look like below. The script is now attempting to output the value of `$a` before setting it in the same scope.

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

Related:[Understanding How PowerShell Variables in Strings Work](https://adamtheautomator.com/powershell-variable-in-strings)

To demonstrate, assign a value to `$a` at the interactive console. This assigns the value at the global scope. Now, the script runs, it will inherit the parent scope (global) and should be able to see the value.

You can see below that when _Test.ps1_ is executed (creating a child scope of the global scope), it can see the value of `$a`. You can also see that the variable’s value is available at the global scope also since this scope is where it was set at. This means that `$a` is available both in the script (child) and parent (global) scopes.

![Variable is available in script and global scopes](/wp-content/uploads/2019/09/powershell-scope-2.png)

Variable is available in script and global scopes

> _Remember this scope inheritance behavior. By doing so will help you when troubleshooting occasions variable conflicts will occur such as variables in different scopes with the same name._

## **Defining and Accessing Items in Scopes**

Now that you know what a scope is and how they work, how do you access them? Let’s see how to use PowerShell to set a variable scope (and access them).

### **Get/Set-Variable**

In PowerShell, there are two cmdlets that allow you to set variables called `Get-Variable` and `Set-Variable`. These cmdlets allow you to retrieve the value of a variable or define a value.

Both cmdlets are similar with a `Name` and `Scope` parameter. Using these parameters, PowerShell allows you to set and retrieve variable values across all scopes.

#### **Local Scopes**

To set a variable in a local scope, use `Set-Variable` and provide it a local variable name and a value as shown below.

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

The local scope is always the default so not using the `Scope` parameter will always define the variable in the local scope.

To retrieve the value of a locally-scoped variable, use `Get-Variable` providing it the name.

```powershell
PS> Get-Variable -Name a

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

#### **Private/Script/Global Scopes**

You’ll use the same parameters (`Name` and `Value`) when working with private, script, and global variables as well. The only difference is this time you’ll use the Scope parameter to explicitly define the scope.

The methods for setting a private, script, or globally-scoped variable are the same. Simply replace the value passed to the `Scope` parameter as `Private`,  `Script`  `Global`.

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

To retrieve the value of a script or globally-scoped variable, use `Get-Variable` providing it the name and scope.

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

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

> _Note: You can also reference scopes using scope numbers instead of names with the `Get`/`Set-Variable` cmdlets._

### **Scope “Prefacing”**

You can also retrieve and set variables in scopes using a shortcut. Instead of using PowerShell cmdlets, you will preface the scope to the variable when referencing it.

#### **Local Scopes**

Since the local scope is always the default, simply defining a variable and referencing will set and retrieve a local scope variable

```powershell
PS> $a = 'foo'
PS> $a

foo
```

#### **Private/Script/Global Scopes**

If you’d like to define and reference script or global scopes, you can preface the variables with the scope name and a colon.

For example, to set the variable `$a` in the global scope, you can preface a with `$global:`.

```powershell
$global:a = ‘foo’
```

The same can be done for a script-scoped variable.

```powershell
$script:a = ‘foo’
```

Once the variables are set in the preferred scope, you’d then reference them the same way. Also, notice that you can exclude the scope preface if the defined scope is the local scope.

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

## **Scopes in Scriptblocks**

PowerShell has a handy construct called scriptblocks. Scriptblocks allow you to move around snippets of code and execute them just about anywhere.

Like a PS1 script, scriptblocks run in their own script scope. When you execute a scriptblock, you’re essentially executing a PS1 script.

Notice in the example below where a variable is defined in the global scope and then attempted to overwrite in a script scope. As you learned above, this won’t work because a child scope can’t reference a parent scope.

![A child scope cannot overwrite a parent scope](/wp-content/uploads/2019/09/powershell-scope-3.png)

A child scope cannot overwrite a parent scope

This example shows that when `$a` is changed in the scriptblock, the _global_ variable definition for `$a` is not changed because the scriptblock is a script child scope.

## **Dot Sourcing Scripts (Swapping Local Scopes)**

PowerShell has a concept called [dot-sourcing](https://mcpmag.com/articles/2017/02/02/exploring-dot-sourcing-in-powershell.aspx). This is a method that allows you to execute a PS1 script and bring everything that would be script-scoped into the local scope instead.

By putting a dot (.) before referencing a PS1 script and executing it, this “dot sources” the content of the script and brings everything into the local scope.

To demonstrate, I have a _Test.ps1_ script again which defines a variable as shown below.

```powershell
$a = 'Hello world!'
```

In a PowerShell console, set a value for an `$a` variable then dot source this script as shown below. Notice that the original variable was overwritten. PowerShell “merged” the two local scopes together.

![Original variable overwritten](/wp-content/uploads/2019/09/powershell-scope-4.png)

Original variable overwritten

## **Using the AllScope Property (Option)**

You have seen how to interact with items in specific scopes, but so far each item is still defined in a single scope. But what if you don’t know what scope a variable is defined in?

When defining a variable with the `Set-Variable` cmdlet, you can place the variable into all scopes at once. To do this, use the `AllScope` value for the `Option` parameter.

To demonstrate, the _Test.ps1_ script has been modified to set an a variable in all scopes. That variable is then output as shown below.

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

You can then see below that a value is being set for `$a` in the global scope and the _Test.ps1_ script is executed. However, instead of having no effect, `$a`’s value has been overwritten. Not only has it been defined in the script scope (`Write-Output $a`) but it’s also overwritten the global scope.

![Variable overwritten in global scope](/wp-content/uploads/2019/09/powershell-scope-5.png)

Variable overwritten in global scope

The `AllScope` option is handy but be careful. This option essentially does away with the concept of scopes and merges everything together.

## **Function Scopes**

When you execute a function, all code within that function is in its own child scope. Function scopes follow the same child/parent behavior as other scopes.

Related:[Your Getting Started Guide to Powershell Functions](https://adamtheautomator.com/powershell-functions/)

Having separate scopes for each function is a good idea. It allows better control over items not having to worry about items conflicting, It also gives the added benefit of automated cleanup of variables in a function. As soon as the function completes, all of the items defined in the function will be cleared.

To demonstrate, copy/paste the function below directly into the PowerShell console.

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

Once pasted, execute the function. Notice you cannot access the `$var` variable outside of the function.

```powershell
PS> Do-Thing
PS> $var
```

## **Keeping Items Private (Disabling Inheritance)**

Typically, if a variable is defined in a parent scope, that variable will be defined in the child scope. But perhaps you’d like to use a variable name but that variable name has already been defined in one of the scopes to be run in a session. In that case, you can either choose a different variable name or define the variable in a private scope making it a private variable.

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.

```powershell
Write-Output $a
```

You can see below I’m defining a privately-scoped variable at the global scope and then executing the _Test.ps1_ script. Usually, when you define a variable in a parent scope, that variable will be available in the child scope – not so with a privately-scoped variable.

In the below example, you can see that the script child scope created by executing the _Test.ps1_ script could not see the private-scoped `$a` variable defined in the parent scope.

![Script scope cannot see the private-scoped variable](/wp-content/uploads/2019/09/powershell-scope-6.png)

Script scope cannot see the private-scoped variable

Unlike global scopes or the `AllScope` option on the `Set-Variable` cmdlet, privately-scoped variables are an excellent way to compartmentalize items.

## **Scoping Best Practices**

Thinking that defining variables in the global scope or using the `AllScope` option is the way to go is common. After all, all variables are available everywhere. There’s no need to worry about the complications of scopes. While this does provide additional freedom for access to what is defined, it can quickly get out of hand and get difficult to troubleshoot.

Instead of trying to prevent using scopes follow these tips:

1.  Instead of specifying scopes in functions, use parameters to pass the required information to the function.
2.  Stay within the local scope as much as possible.
3.  Instead of defining global variables from a script, use the `Write-Output` cmdlet to output everything and save it to a variable when needed from the console.

The main point here is to embrace scopes and learn to use them to your advantage instead of trying to circumvent them.

## **Further Reading**

*   _**_**[_**About Advanced Functions and Function Parameters**_](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters?view=powershell-7.2)**_**_
*   _**_**[_**Using Environment Variables in PowerShell**_](https://adamtheautomator.com/powershell-environment-variables/)**_**_

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-scopes%2F&text=PowerShell%20Scopes%3A%20Understanding%20Variable%20Scope)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-scopes%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-scopes%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
