PowerShell is a cross-platform task automation solution made up of a command-line shell, a scripting language, and a configuration management framework. PowerShell runs on Windows, Linux, and macOS. [1]

Commands for PowerShell are known as cmdlets (pronounced command-lets). In addition to cmdlets, PowerShell allows you to run any command available on your system. [2]

  • Cmdlets are native PowerShell commands, not stand-alone executables.

  • Cmdlets are collected into PowerShell modules that can be loaded on demand.

  • Cmdlets can be written in any compiled .NET language or in the PowerShell scripting language itself.

  • PowerShell uses a Verb-Noun name pair to name cmdlets.

PowerShell includes cmdlets that help you discover PowerShell. Using these three cmdlets, you can discover what commands available, what they do, and what types they operate on. [3]

  • Get-Verb. Running this command returns a list of verbs that most commands adhere to. The response includes a description of what these verbs do. Since most commands follow this naming convention, it sets expectations on what a command does. This helps you select the appropriate command and what to name a command, should you be creating one.

  • Get-Command. This command retrieves a list of all commands installed on your machine.

  • Get-Member. It operates on object based output and is able to discover what object, properties and methods are available for a command.

  • Get-Help. Invoking this command with the name of a command as an argument displays a help page describing various parts of a command.

Using these commands, you can discover almost anything you need to know about PowerShell.

Get-Command -Name Get-Process
Get-Command -Name *-Process | Select-Object -First 2
Get-Command -Verb Get | Select-Object -First 2
Get-Command -Noun Process | Select-Object -First 2

Get-Process | Get-Member | Select-Object -First 3
Get-Process | Get-Member -MemberType Method | Select-Object -First 3
Get-Command -ParameterType Process | Select-Object -First 3

Get-Help -Name Get-Command -Full
Get-Help -Name Get-Command -Detailed
Get-Help -Name Get-Command -Examples
Get-Help -Name Get-Command -Online
Get-Help -Name Get-Command -Parameter Noun
Get-Help -Name Get-Command -ShowWindow

1. Getting Started with PowerShell

All modern versions of Windows operating systems ship with PowerShell installed. If you’re running a version older than 5.1, you should install the latest version.

1.1. What version of PowerShell am I running?

There are a number of automatic variables in PowerShell that store state information. One of these variables is $PSVersionTable, which contains a hashtable that can be used to display the relevant PowerShell version information:

PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.19041.3031
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.3031
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

1.2. Execution Policy

Contrary to popular belief, the execution policy in PowerShell is not a security boundary. It’s designed to prevent a user from unknowingly running a script.

Regardless of the execution policy setting, any PowerShell command can be run interactively. The execution policy only affects commands running in a script.

The Get-ExecutionPolicy cmdlet is used to determine what the current execution policy setting is and the Set-ExecutionPolicy cmdlet is used to change the execution policy.

PS C:\> Get-ExecutionPolicy
RemoteSigned
PS C:\> Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser    RemoteSigned
 LocalMachine       Undefined

It’s recommended to use the RemoteSigned policy, which requires downloaded scripts to be signed by a trusted publisher in order to be run.

PowerShell scripts can’t be run at all when the execution policy is set to Restricted. This is the default setting on all Windows client operating systems.

PS C:\> Set-ExecutionPolicy -Scope CurrentUser Restricted
PS C:\> Get-Service -Name W32Time | Stop-Service -PassThru

Status   Name               DisplayName
------   ----               -----------
Stopped  W32Time            Windows Time


PS C:\> echo 'Get-Service -Name W32Time | Stop-Service -PassThru' > Stop-TimeService.ps1
PS C:\> .\Stop-TimeService.ps1
.\Stop-TimeService.ps1 : File C:\Stop-TimeService.ps1 cannot be loaded because running scripts is disabled on this system. For more
information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\Stop-TimeService.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
PS C:\> Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
PS C:\> .\Stop-TimeService.ps1

Status   Name               DisplayName
------   ----               -----------
Stopped  W32Time            Windows Time

1.3. The Help System

Compiled commands in PowerShell are called cmdlets. Cmdlet is pronounced "command-let" (not CMD-let). Cmdlets names have the form of singular "Verb-Noun" commands to make them easily discoverable.

1.3.1. Get-Help

Get-Help is a multipurpose command. Get-Help helps you learn how to use commands once you find them. Get-Help can also be used to help locate commands, but in a different and more indirect way when compared to Get-Command.

When Get-Help is used to locate commands, it first searches for wildcard matches of command names based on the provided input. If it doesn’t find a match, it searches through the help topics themselves, and if no match is found an error is returned. Contrary to popular belief, Get-Help can be used to find commands that don’t have help topics.

Get-Help -Name Get-Help

Help is a function that pipes Get-Help to a function named more, which is a wrapper for the more.com executable file in Windows.

Get-Help -Name Get-Help -Full
help -Name Get-Help -Full
help Get-Help -Full

Get-Help -Name Get-Command -Full
Get-Help -Name Get-Command -Detailed
Get-Help -Name Get-Command -Examples
Get-Help -Name Get-Command -Online
Get-Help -Name Get-Command -Parameter Noun
Get-Help -Name Get-Command -ShowWindow

1.3.2. Get-Command

Get-Command is designed to help you locate commands. Running Get-Command without any parameters returns a list of all the commands on your system.

Get-Command -Name *service* -CommandType Cmdlet, Function, Alias

Use Get-Command with the Module parameter to determine what commands were added as part of the ActiveDirectory PowerShell module when the remote server administration tools were installed.

Get-Command -Module ActiveDirectory

1.3.3. Get-Member

Get-Member helps you discover what objects, properties, and methods are available for commands. Any command that produces object-based output can be piped to Get-Member.

Get-Service -Name w32time
Get-Service -Name w32time | Get-Member
Get-Command -ParameterType ServiceController
Get-Service -Name w32time | Select-Object -Property *
Get-Service -Name w32time | Select-Object -Property Status, Name, DisplayName, ServiceType
Get-Service -Name w32time | Select-Object -Property Status, DisplayName, Can*
Get-Service -Name w32time | Get-Member -MemberType Method
(Get-Service -Name w32time).Stop()

1.4. Formatting, aliases, providers, comparison

The most common format commands are Format-Table and Format-List. Format-Wide and Format-Custom can also be used, but are less common.

PS C:\> Get-Service -Name w32time | Select-Object -Property Status, DisplayName, Can*

Status              : Running
DisplayName         : Windows Time
CanPauseAndContinue : False
CanShutdown         : True
CanStop             : True

PS C:\> Get-Service -Name w32time | Select-Object -Property Status, DisplayName, Can* | Format-Table

 Status DisplayName  CanPauseAndContinue CanShutdown CanStop
 ------ -----------  ------------------- ----------- -------
Running Windows Time               False        True    True

PS C:\> Get-Service -Name w32time | Format-List

Name                : w32time
DisplayName         : Windows Time
Status              : Running
DependentServices   : {}
ServicesDependedOn  : {}
CanPauseAndContinue : False
CanShutdown         : True
CanStop             : True
ServiceType         : Win32OwnProcess, Win32ShareProcess

An alias in PowerShell is a shorter name for a command. PowerShell includes a set of built-in aliases and you can also define your own aliases.

The Get-Alias cmdlet is used to find aliases. If you already know the alias for a command, the Name parameter is used to determine what command the alias is associated with.

PS C:\> Get-Alias -Name gcm

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           gcm -> Get-Command

PS C:\> Get-Alias -Name gcm, gm

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           gcm -> Get-Command
Alias           gm -> Get-Member

A provider in PowerShell is an interface that allows file system like access to a datastore. There are a number of built-in providers in PowerShell.

PS C:\> Get-PSProvider

Name                 Capabilities                                                  Drives
----                 ------------                                                  ------
Registry             ShouldProcess, Transactions                                   {HKLM, HKCU}
Alias                ShouldProcess                                                 {Alias}
Environment          ShouldProcess                                                 {Env}
FileSystem           Filter, ShouldProcess, Credentials                            {C, D}
Function             ShouldProcess                                                 {Function}
Variable             ShouldProcess                                                 {Variable}
Certificate          ShouldProcess                                                 {Cert}
WSMan                Credentials                                                   {WSMan}

The actual drives that these providers use to expose their datastore can be determined with the Get-PSDrive cmdlet. The Get-PSDrive cmdlet not only displays drives exposed by providers, but it also displays Windows logical drives including drives mapped to network shares.

PS C:\> Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root                                                                       CurrentLocation
----           ---------     --------- --------      ----                                                                       ---------------
Alias                                  Alias
C                 138.14        131.16 FileSystem    C:\
Cert                                   Certificate   \
D                 205.78          0.33 FileSystem    D:\
Env                                    Environment
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
Variable                               Variable
WSMan                                  WSMan

Third-party modules such as the Active Directory PowerShell module and the SQLServer PowerShell module both add their own PowerShell provider and PSDrive.

PS C:\> Import-Module SqlServer
PS C:\> Get-PSProvider

Name                 Capabilities                                                  Drives
----                 ------------                                                  ------
Registry             ShouldProcess                                                 {HKLM, HKCU}
Alias                ShouldProcess                                                 {Alias}
Environment          ShouldProcess                                                 {Env}
FileSystem           Filter, ShouldProcess, Credentials                            {C, D, Temp}
Function             ShouldProcess                                                 {Function}
Variable             ShouldProcess                                                 {Variable}
SqlServer            Credentials                                                   {SQLSERVER}
Certificate          ShouldProcess                                                 {Cert}
WSMan                Credentials                                                   {WSMan}

PS C:\> Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root                                                                       CurrentLocation
----           ---------     --------- --------      ----                                                                       ---------------
Alias                                  Alias
C                 138.14        131.16 FileSystem    C:\
Cert                                   Certificate   \
D                 205.78          0.33 FileSystem    D:\
Env                                    Environment
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
SQLSERVER                              SqlServer     SQLSERVER:\
Temp              138.14        131.16 FileSystem    C:\Users\xuqiang3\AppData\Local\Te…
Variable                               Variable
WSMan                                  WSMan

PSDrives can be accessed just like a traditional file system.

PS C:\> Get-ChildItem -Path Cert:\LocalMachine\CA

   PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\CA

Thumbprint                                Subject              EnhancedKeyUsageList
----------                                -------              --------------------
FEE449EE0E3965A5246F000E87FDE2A065FD89D4  CN=Root Agency
D559A586669B08F46A30A133F8A9ED3D038E2EA8  OU=www.verisign.com… {Server Authentication, Client Authentication, $null, $null}
D4FFDB19BA590FFFAA34DB5F4B568706A2978436  CN=Microsoft TPM Ro…
5E94211AC5D477F157230E6E316AA923E521AF2C  CN=NCU-INTC-KEYID-B… {$null, Attestation Identity Key Certificate}
109F1CAED645BB78B3EA2B94C0697C740733031C  CN=Microsoft Window… {Code Signing, Windows Hardware Driver Verification}

PowerShell contains a number of comparison operators that are used to compare values or find values that match certain patterns. Table 5-1 contains a list of comparison operators in PowerShell.

Table 1. All of the operators listed are case-insensitive. Place a c in front of the operator listed to make it case-sensitive. For example, -ceq is the case-sensitive version of the -eq comparison operator.
Operator Definition

-eq

Equal to

-ne

Not equal to

-gt

Greater than

-ge

Greater than or equal to

-lt

Less than

-le

Less than or equal to

-Like

Match using the * wildcard character

-NotLike

Does not match using the * wildcard character

-Match

Matches the specified regular expression

-NotMatch

Does not match the specified regular expression

-Contains

Determines if a collection contains a specified value

-NotContains

Determines if a collection does not contain a specific value

-In

Determines if a specified value is in a collection

-NotIn

Determines if a specified value is not in a collection

-Replace

Replaces the specified value

2. The PowerShellGet module

The PowerShellGet module contains cmdlets for discovering, installing, updating, and publishing PowerShell packages from the PowerShell Gallery. These packages can contain artifacts such as Modules, DSC Resources, and Scripts.

Use the following command to see what version is installed.

PS C:\> Get-Module PowerShellGet, PackageManagement

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     1.0.0.1    PackageManagement                   {Find-Package, Find-PackageProvider, Get-Package, Get-PackageProvider...}
Script     1.0.0.1    PowerShellGet                       {Find-Command, Find-DscResource, Find-Module, Find-RoleCapability...}

To install the latest versions of these modules run the following:

Install-Module PowerShellGet -Force -AllowClobber

Windows PowerShell 5.1 comes with version 1.0.0.1 of the PowerShellGet and PackageManagement preinstalled. This version of PowerShellGet has a limited features and must be updated to work with the PowerShell Gallery. To be supported, you must update to the latest version.

Windows PowerShell 5.1 comes with PowerShellGet version 1.0.0.1, which doesn’t include the NuGet provider. The provider is required by PowerShellGet when working with the PowerShell Gallery.

There are two ways to install the NuGet provider:

  • Use Install-PackageProvider to install NuGet before installing other modules

    Run the following command to install the NuGet provider.

    Install-PackageProvider -Name NuGet -Force

    After you have installed the provider you should be able to use any of the PowerShellGet cmdlets with the PowerShell Gallery.

  • Let Install-Module prompt you to install the NuGet provider

    The following command attempts to install the updated PowerShellGet module without the NuGet provider.

    Install-Module PowerShellGet -AllowClobber -Force

After you have installed the new version of PowerShellGet, you should open a new PowerShell session. PowerShell automatically loads the newest version of the module when you use a PowerShellGet cmdlet.

It’s also recommended to register the PowerShell Gallery as a trusted repository. Use the following command:

Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

3. Scripting language

As a scripting language, PowerShell is commonly used for automating the management of systems. It’s also used to build, test, and deploy solutions, often in CI/CD environments. PowerShell is built on the .NET Common Language Runtime (CLR). All inputs and outputs are .NET objects. No need to parse text output to extract information from output. The PowerShell scripting language includes the following features:

  • Extensible through functions, classes, scripts, and modules

  • Extensible formatting system for easy output

  • Extensible type system for creating dynamic types

  • Built-in support for common data formats like CSV, JSON, and XML

3.1. How to run a script

Before you can run a script on Windows, you need to change the default PowerShell execution policy. Execution policy does not apply to PowerShell running on non-Windows platforms.

The default execution policy, Restricted, prevents all scripts from running, including scripts that you write on the local computer. For more information, see about_Execution_Policies.

The execution policy is saved in the registry, so you need to change it only once on each computer.

To change the execution policy, use the following procedure.

At the command prompt, type:

Set-ExecutionPolicy AllSigned

or

Set-ExecutionPolicy RemoteSigned

The change is effective immediately.

To run a script, type the full name and the full path to the script file.

For example, to run the Get-ServiceLog.ps1 script in the C:\Scripts directory, type:

C:\Scripts\Get-ServiceLog.ps1

To run a script in the current directory, type the path to the current directory, or use a dot to represent the current directory, followed by a path backslash (.\).

For example, to run the ServicesLog.ps1 script in the local directory, type: PowerShell

.\Get-ServiceLog.ps1

If the script has parameters, type the parameters and parameter values after the script filename.

For example, the following command uses the ServiceName parameter of the Get-ServiceLog script to request a log of WinRM service activity.

.\Get-ServiceLog.ps1 -ServiceName WinRM

As a security feature, PowerShell does not run scripts when you double-click the script icon in File Explorer or when you type the script name without a full path, even when the script is in the current directory.

Beginning in PowerShell 3.0, you can run scripts from File Explorer.

  • To use the "Run with PowerShell" feature: Run File Explorer, right-click the script filename and then select "Run with PowerShell".

  • The "Run with PowerShell" feature is designed to run scripts that do not have required parameters and do not return output to the command prompt.

3.2. How to write a script

A script can contain any valid PowerShell commands, including single commands, commands that use the pipeline, functions, and control structures such as If statements and For loops.

To write a script, open a new file in a text editor, type the commands, and save them in a file with a valid filename with the .ps1 file extension.

To define parameters in a script, use a Param statement. The Param statement must be the first statement in a script, except for comments and any #Require statements.

Script parameters work like function parameters. The parameter values are available to all of the commands in the script. All of the features of function parameters, including the Parameter attribute and its named arguments, are also valid in scripts.

# Test-Remote.ps1
param ($ComputerName = $(throw "ComputerName parameter is required."))

function CanPing {
   $error.clear()
   $tmp = test-connection $computername -erroraction SilentlyContinue

   if (!$?)
       {write-host "Ping failed: $ComputerName."; return $false}
   else
       {write-host "Ping succeeded: $ComputerName"; return $true}
}

function CanRemote {
    $s = new-pssession $computername -erroraction SilentlyContinue

    if ($s -is [System.Management.Automation.Runspaces.PSSession])
        {write-host "Remote test succeeded: $ComputerName."}
    else
        {write-host "Remote test failed: $ComputerName."}
}

if (CanPing $computername) {CanRemote $computername}

3.3. Functions

A function is a list of PowerShell statements that has a name that you assign. When you run a function, you type the function name. The statements in the list run as if you had typed them at the command prompt.

Functions can be as simple as:

function Get-PowerShellProcess { Get-Process PowerShell }

Like cmdlets, functions can have parameters. The parameters can be named, positional, switch, or dynamic parameters. Function parameters can be read from the command line or from the pipeline.

Functions can return values that can be displayed, assigned to variables, or passed to other functions or cmdlets. You can also specify a return value using the return keyword. The return keyword doesn’t affect or suppress other output returned from your function. However, the return keyword exits the function at that line.

The function’s statement list can contain different types of statement lists with the keywords begin, process, end, and clean. These statement lists handle input from the pipeline differently.

The filter keyword is used to create a type of function that runs on each object in the pipeline. A filter resembles a function with all its statements in a process block.

The following are the syntax for a function:

function [<scope:>]<name> [([type]$parameter1[,[type]$parameter2])]
{
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
  clean {<statement list>}
}
function [<scope:>]<name>
{
  param([type]$parameter1 [,[type]$parameter2])
  dynamicparam {<statement list>}
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
  clean {<statement list>}
}

A function includes the following items:

  • A function keyword

  • A scope (optional)

  • A name that you select

  • Any number of named parameters (optional)

  • One or more PowerShell commands enclosed in braces {}

Functions don’t have to be complicated to be useful. The simplest functions have the following format:

function <function-name> {statements}

For example, the following function starts PowerShell with the Run as Administrator option.

function Start-PSAdmin {Start-Process PowerShell -Verb RunAs}

4. Manage Microsoft 365 with PowerShell

PowerShell for Microsoft 365 enables you to manage your Microsoft 365 settings from the command line. To connect to PowerShell, just install the required software and then connect to your Microsoft 365 organization. [4]

There are two versions of the PowerShell module that you can use to connect to Microsoft 365 and administer user accounts, groups, and licenses:

Currently, the Azure Active Directory PowerShell for Graph module doesn’t completely replace the functionality of the Microsoft Azure Active Directory Module for Windows PowerShell module for user, group, and license administration. In some cases, you need to use both versions. You can safely install both versions on the same computer.

The Azure Active Directory Module is being replaced by the Microsoft Graph PowerShell SDK. You can use the Microsoft Graph PowerShell SDK to access all Microsoft Graph APIs.

4.1. Azure Active Directory PowerShell for Graph

Azure AD Powershell is planned for deprecation on March 30, 2024. For more details on the deprecation plans, see the deprecation update. We encourage you to continue migrating to Microsoft Graph PowerShell, which is the recommended module for interacting with Azure AD. In addition, Microsoft Graph PowerShell allows you access to all Microsoft Graph APIs and is available on PowerShell 7. For answers to frequent migration queries, see the Migration FAQ.

You can use the Azure Active Directory PowerShell module version for Graph for Azure AD administrative tasks such as user management, domain management and for configuring single sign-on.

The Azure AD PowerShell module is not compatible with PowerShell 7. It is only supported in PowerShell 5.1.

To install the General Availability version of the module, run:

Install-Module AzureAD

To connect to Azure Active Directory (Azure AD) for your Microsoft 365 subscription with an account name and password or with multi-factor authentication, run one of these commands from a Windows PowerShell command prompt. [4]

Office 365 cloud Command

Office 365 Worldwide (+GCC)

Connect-AzureAD

Office 365 operated by 21 Vianet

Connect-AzureAD -AzureEnvironmentName AzureChinaCloud

Office 365 Germany

Connect-AzureAD -AzureEnvironmentName AzureGermanyCloud

Office 365 U.S. Government DoD and Office 365 U.S. Government GCC High

Connect-AzureAD -AzureEnvironmentName AzureUSGovernment

4.2. Azure Active Directory Module (MSOnline) for Windows PowerShell

MSOnline is planned for deprecation on March 30, 2024. For more details on the deprecation plans, see the deprecation update. We encourage you to continue migrating to Microsoft Graph PowerShell, which is the recommended module for interacting with Azure AD. In addition, Microsoft Graph PowerShell allows you access to all Microsoft Graph APIs and is available on PowerShell 7. For answers to frequent migration queries, see the Migration FAQ.

Follow these steps to install and import the Microsoft Azure Active Directory Module for Windows PowerShell:

  • Open an elevated Windows PowerShell command prompt (run Windows PowerShell as an administrator).

  • Run the Install-Module MSOnline command.

  • If you’re prompted to install the NuGet provider, type Y and press Enter.

  • If you’re prompted to install the module from PSGallery, type Y and press Enter.

  • Run the Import-Module MSOnline command to import the module.

To connect to Azure AD for your Microsoft 365 subscription with an account name and password or with multi-factor authentication, run one of these commands from a Windows PowerShell command prompt. (It doesn’t have to be elevated.)

Office 365 cloud Command

Office 365 Worldwide (+GCC)

Connect-MsolService

Office 365 operated by 21 Vianet

Connect-MsolService -AzureEnvironmentName AzureChinaCloud

Office 365 Germany

Connect-MsolService -AzureEnvironmentName AzureGermanyCloud

Office 365 U.S. Government DoD and Office 365 U.S. Government GCC High

Connect-MsolService -AzureEnvironmentName AzureUSGovernment

4.3. Microsoft Graph PowerShell SDK

The Microsoft Graph PowerShell SDK acts as an API wrapper for the Microsoft Graph APIs, exposing the entire API set for use in PowerShell. It contains a set of cmdlets that helps you manage identities at scale from automating tasks to managing users in bulk using Azure Active Directory (Azure AD). It will help administer every Azure AD feature that has an API in Microsoft Graph. [5]

The Microsoft Graph PowerShell SDK provides the following benefits:

  • Access to all Microsoft Graph APIs: Microsoft Graph PowerShell is based on Microsoft Graph API. In addition to Azure AD, the Microsoft Graph API includes APIs from other Microsoft services like SharePoint, Exchange, and Outlook, all accessed through a single endpoint with a single access token.

  • Supports PowerShell 7: Microsoft Graph PowerShell works with PowerShell 7 and later. It’s also compatible with Windows PowerShell 5.1.

  • Cross-platform support: Microsoft Graph PowerShell works on all platforms including Windows, macOS, and Linux.

  • Supports modern authentication: Microsoft Graph PowerShell supports the Microsoft Authentication Library (MSAL) which offers more security. For example, you can use passwordless sign-in experiences.

  • Supports external identities: Users from other Azure AD tenants can authenticate to services in your tenant with Microsoft Graph PowerShell.

  • Uses least privilege: Microsoft Graph PowerShell permissions are not pre-authorized and users must perform one-time request for app permissions depending on their needs.

  • Advanced queries: Microsoft Graph PowerShell supports rich, advanced queries via eventual consistency. For example, you can get a near-instant count of all users using advanced queries.

  • Open source: Feature teams and the community can create great PowerShell experiences and share them with everyone.

  • Receives regular updates: Microsoft Graph PowerShell commands are updated regularly to support the latest Graph API updates.

4.3.1. Installation

The Microsoft Graph PowerShell SDK comes in 2 modules, Microsoft.Graph and Microsoft.Graph.Beta, that you will install separately. These modules call the Microsoft Graph v1.0 and Microsoft Graph beta endpoints, respectively. You can install the 2 modules on the same PowerShell version.

Using the Install-Module cmdlet is the preferred installation method for the Microsoft Graph PowerShell modules.

To install the v1 module of the SDK in PowerShell Core or Windows PowerShell, run the following command.

Install-Module Microsoft.Graph -Scope CurrentUser

Optionally, you can change the scope of the installation using the -Scope parameter. This requires admin permissions.

Install-Module Microsoft.Graph -Scope AllUsers

To install the beta module, run the following command.

Install-Module Microsoft.Graph.Beta

After the installation is completed, you can verify the installed version with the following command.

Get-InstalledModule Microsoft.Graph

To verify the installed sub-modules and their versions, run:

Get-InstalledModule

The version in the output should match the latest version published on the PowerShell Gallery. Now you’re ready to use the SDK.

4.3.2. Use PowerShell SDK

The PowerShell SDK supports two types of authentication: delegated access, and app-only access.

Each API in the Microsoft Graph is protected by one or more permission scopes. The user logging in must consent to one of the required scopes for the APIs you plan to use.

The Find-MgGraphCommand cmdlet can be used to discover the required permissions for another cmdlet. For example, to see all permissions that can be used to call Get-MgUser, run;

Find-MgGraphCommand -command Get-MgUser | Select -First 1 -ExpandProperty Permissions
PS C:\> Find-MgGraphCommand -Command Get-MgUser


   APIVersion: v1.0

Command    Module Method URI              OutputType          Permissions
-------    ------ ------ ---              ----------          -----------
Get-MgUser Users  GET    /users           IMicrosoftGraphUser {DeviceManagementApps.Read.All, DeviceManagementApps.ReadWrite.All, DeviceMana...
Get-MgUser Users  GET    /users/{user-id} IMicrosoftGraphUser {DeviceManagementApps.Read.All, DeviceManagementApps.ReadWrite.All, DeviceMana...


PS C:\> Find-MgGraphCommand -Command Get-MgUser | Select -First 1 -ExpandProperty Permissions

Name                                         IsAdmin Description                                                       FullDescription
----                                         ------- -----------                                                       ---------------
DeviceManagementApps.Read.All                True    Read Microsoft Intune apps                                        Allows the app to rea...
DeviceManagementApps.ReadWrite.All           True    Read and write Microsoft Intune apps                              Allows the app to rea...
DeviceManagementConfiguration.Read.All       True    Read Microsoft Intune Device Configuration and Policies           Allows the app to rea...
DeviceManagementConfiguration.ReadWrite.All  True    Read and write Microsoft Intune Device Configuration and Policies Allows the app to rea...
DeviceManagementManagedDevices.Read.All      True    Read devices Microsoft Intune devices                             Allows the app to rea...
DeviceManagementManagedDevices.ReadWrite.All True    Read and write Microsoft Intune devices                           Allows the app to rea...
DeviceManagementServiceConfig.Read.All       True    Read Microsoft Intune configuration                               Allows the app to rea...
DeviceManagementServiceConfig.ReadWrite.All  True    Read and write Microsoft Intune configuration                     Allows the app to rea...
Directory.Read.All                           True    Read directory data                                               Allows the app to rea...
Directory.ReadWrite.All                      True    Read and write directory data                                     Allows the app to rea...
User.Read.All                                True    Read all users' full profiles                                     Allows the app to rea...
User.ReadBasic.All                           False   Read all users' basic profiles                                    Allows the app to rea...
User.ReadWrite.All                           True    Read and write all users' full profiles                           Allows the app to rea...

Use the Connect-MgGraph command to sign in with the required scopes. You’ll need to sign in with an admin account to consent to the required scopes.

Connect-MgGraph -Scopes "User.Read.All","Group.ReadWrite.All"

The command prompts you to go to a web page to sign in with your credentials. Once you’ve done that, the command indicates success with a Welcome To Microsoft Graph! message. You only need to sign in once per session.

You can add additional permissions by repeating the Connect-MgGraph command with the new permission scopes.

Use the Disconnect-MgGraph command to sign out.

Disconnect-MgGraph

4.3.3. Using authentication cmdlets

Microsoft Graph PowerShell supports two types of authentication: delegated and app-only access. There are a number of cmdlets that can be used to manage the different parameters required during authentication, for example, environment, application ID, and certificate. [6]

4.3.3.1. Using Connect-MgGraph

You must invoke Connect-MgGraph before any commands that access Microsoft Graph. This cmdlet gets the access token using the Microsoft Authentication Library.

  • Delegated access

    There are three ways to allow delegated access using Connect-MgGraph:

    • Using interactive authentication, where you provide the scopes that you require during your session:

      Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All"
    • Using device code flow:

      Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -UseDeviceAuthentication
    • Using your own access token:

      Connect-MgGraph -AccessToken $AccessToken
  • App-only access

    • Using client credential with a certificate

      To use app-only access, the certificate is loaded from either Cert:\CurrentUser\My\ or Cert:\LocalMachine\My\ when -CertificateThumbprint or -CertificateName is specified. Make sure that the certificate you’re using is present in either certificate store before calling Connect-MgGraph.

      • Using Certificate Thumbprint:

        Connect-MgGraph -ClientId "YOUR_APP_ID" -TenantId "YOUR_TENANT_ID" -CertificateThumbprint "YOUR_CERT_THUMBPRINT"
      • Using Certificate name:

        Connect-MgGraph -ClientId "YOUR_APP_ID" -TenantId "YOUR_TENANT_ID" -CertificateName "YOUR_CERT_SUBJECT"
      • Using a certificate:

        $Cert = Get-ChildItem Cert:\LocalMachine\My\$CertThumbprint
        Connect-MgGraph -ClientId "YOUR_APP_ID" -TenantId "YOUR_TENANT_ID" -Certificate $Cert

        To use a certificate stored in your machine’s certificate store or another location when connecting to Microsoft Graph, specify the certificate’s location.

    • Using client secret credentials

      If you need interactions in the background, without a user to sign in, this type of grant will help you. Support for client secret credentials was added by adding -ClientSecretCredential parameter to Connect-MgGraph.

      $ClientSecretCredential = Get-Credential -Username "Client_Id"
      # Enter client_secret in the password prompt.
      Connect-MgGraph -TenantId "Tenant_Id" -ClientSecretCredential $ClientSecretCredential
    • Using managed identity

      A common challenge when writing automation scripts is the management of secrets, credentials, certificates, and keys used to secure communication between services. Eliminate the need to manage credentials by allowing the module to obtain access tokens for Azure resources that are protected by Azure AD. The identity is managed by the Azure platform and does not require you to provision or rotate any secrets.

      • System-assigned managed identity:

        Uses an automatically managed identity on a service instance. The identity is tied to the lifecycle of a service instance.

        Connect-MgGraph -Identity
      • User-assigned managed identity:

        Uses a user created managed identity as a standalone Azure resource.

        Connect-MgGraph -Identity -ClientId "User_Assigned_Managed_identity_Client_Id"
4.3.3.2. Using Get-MgEnvironment: Connecting to an environment or cloud

When you use Connect-MgGraph, you can choose to target other environments. By default, Connect-MgGraph targets the global public cloud.

To get a list of all clouds that you can choose from, run:

Get-MgEnvironment
Name     AzureADEndpoint                   GraphEndpoint                           Type
----     ---------------                   -------------                           ----
China    https://login.chinacloudapi.cn    https://microsoftgraph.chinacloudapi.cn Built-in
Global   https://login.microsoftonline.com https://graph.microsoft.com             Built-in
USGov    https://login.microsoftonline.us  https://graph.microsoft.us              Built-in
USGovDoD https://login.microsoftonline.us  https://dod-graph.microsoft.us          Built-in
Germany  https://login.microsoftonline.de  https://graph.microsoft.de              Built-in

To explicitly target other clouds, for example, US Government and Azure China, use the -Environment parameter.

Connect-MgGraph -Environment USGov
Globally registered apps don’t replicate to Azure China. You’ll need to register your own applications in Azure China and use them when connecting to Microsoft Graph.
4.3.3.3. Connecting to an environment as a different identity

To connect as a different identity other than CurrentUser, specify the -ContextScope parameter with the value Process.

Connect-MgGraph -ContextScope Process -ForceRefresh
4.3.3.4. Using Disconnect-MgGraph

Once you’re signed in, you’ll remain signed in until you invoke Disconnect-MgGraph. Microsoft Graph PowerShell automatically refreshes the access token for you and sign-in persists across PowerShell sessions because Microsoft Graph PowerShell securely caches the token.

Use Disconnect-MgGraph to sign out.

Disconnect-MgGraph
4.3.3.5. Using Get-MgContext

Get-MgContext is used to retrieve the details about your current session, which include:

  • ClientID

  • TenantID

  • Certificate Thumbprint

  • Scopes consented to

  • AuthType: Delegated or app-only

  • AuthProviderType

  • CertificateName

  • Account

  • AppName

  • ContextScope

  • Certificate

  • PSHostVersion

  • ClientTimeOut.

To retrieve the session details, run:

Get-MgContext

To retrieve all the scopes that you’ve consented to, expand the Scopes property using the -ExpandProperty parameter.

Get-MgContext | Select -ExpandProperty Scopes
4.3.3.6. Using Invoke-MgGraphRequest

Invoke-MgGraphRequest issues REST API requests to the Graph API. It works for any Graph API if you know the REST URI, method and optional body parameter. This command is especially useful for accessing APIs for which there isn’t an equivalent cmdlet yet.

To retrieve the details of the signed-in user, run:

Invoke-MgGraphRequest -Method GET https://graph.microsoft.com/v1.0/me

4.3.4. Using Find-MgGraphCommand cmdlet

Find-MgGraphCommand aims to make it easier for you to discover which API path a command calls, by providing a URI or a command name.

The Find-MgGraphCommand allows to:

  • Pass a Microsoft Graph URL (relative and absolute) and get an equivalent Microsoft Graph PowerShell command.

  • Pass a command and get the URL it calls.

  • Pass a command or URI wildcard (.*) to find all commands that match it.

Find-MgGraphCommand -Uri <String[]> [-Method <String>] [-ApiVersion <String>] [<CommonParameters>]
Find-MgGraphCommand -Uri .*searchstring.* [-ApiVersion <String>] [<CommonParameters>] [-Method <String>]

Find-MgGraphCommand -Command <String[]> [-ApiVersion <String>] [<CommonParameters>]
Find-MgGraphCommand -Command .*searchstring.* [-ApiVersion <String>] [<CommonParameters>]
# Use a URI to get all related cmdlets
Find-MgGraphCommand -Uri '/users/{id}'

# Search for commands using URI wildcard
Find-MgGraphCommand -Uri ".*users.*" -Method 'Get' -ApiVersion 'v1.0'

# Pass a command and get the URI it calls
Find-MgGraphCommand -Command 'Get-MgUser'

# Pass a command and get the permissions required
Find-MgGraphCommand -command Get-MgUser | Select -First 1 -ExpandProperty Permissions

# Search for commands using a command wildcard
Find-MgGraphCommand -Command .*UserToDo.* -APIVersion 'v1.0'

4.3.5. Using Find-MgGraphPermission cmdlet

The Microsoft Graph PowerShell SDK application requires users to have domain knowledge of both the semantics and syntax of Microsoft Graph API permissions used to authorize access to the API. This cmdlet helps to answer the following questions:

  • How do I find the values to supply to the permission-related parameters of commands like New-MgApplication and other application and consent related commands?

  • What permissions are applicable to a certain domain, for example, application, directory? To use Microsoft Graph PowerShell SDK to access Microsoft Graph, users must sign in to an Azure AD application using the Connect-MgGraph command.

# Find permissions related to a given domain
Find-MgGraphPermission application

# Find the identifier for a specific permission
Find-MgGraphPermission application.Read | Format-List

# Pass a command and get the permissions required
Find-MgGraphCommand New-MgApplication | Select -ExpandProperty Permissions

4.3.6. View Microsoft 365 licenses and services with PowerShell

Every Microsoft 365 subscription consists of the following elements: [7]

  • Licensing plans These are also known as license plans or Microsoft 365 plans. Licensing plans define the Microsoft 365 services that are available to users. Your Microsoft 365 subscription may contain multiple licensing plans. An example licensing plan would be Microsoft 365 E3.

  • Services These are also known as service plans. Services are the Microsoft 365 products, features, and capabilities that are available in each licensing plan, for example, Exchange Online and Microsoft 365 Apps for enterprise (previously named Office 365 ProPlus). Users can have multiple licenses assigned to them from different licensing plans that grant access to different services.

  • Licenses Each licensing plan contains the number of licenses that you purchased. You assign licenses to users so they can use the Microsoft 365 services that are defined by the licensing plan. Every user account requires at least one license from one licensing plan so they can log on to Microsoft 365 and use the services.

Reading subscription license plans requires the Organization.Read.All permission scope or one of the other permissions listed in the 'List subscribedSkus' Graph API reference page.

Connect-Graph -Scopes Organization.Read.All
  • To view summary information about your current licensing plans and the available licenses for each plan, run this command:

    Get-MgSubscribedSku | Select -Property Sku*, ConsumedUnits -ExpandProperty PrepaidUnits | Format-List

    The results contain:

    • SkuPartNumber: Shows the available licensing plans for your organization. For example, ENTERPRISEPACK is the license plan name for Office 365 Enterprise E3.

    • Enabled: Number of licenses that you’ve purchased for a specific licensing plan.

    • ConsumedUnits: Number of licenses that you’ve assigned to users from a specific licensing plan.

  • To view details about the Microsoft 365 services that are available in all of your license plans, first display a list of your license plans.

    Get-MgSubscribedSku

    Next, store the license plans information in a variable.

    $licenses = Get-MgSubscribedSku

    Next, display the services in a specific license plan.

    $licenses[<index>].ServicePlans

    <index> is an integer that specifies the row number of the license plan from the display of the Get-MgSubscribedSku | Select SkuPartNumber command, minus 1.

    For example, if the display of the Get-MgSubscribedSku | Select SkuPartNumber command is this:

    SkuPartNumber
    -------------
    WIN10_VDA_E5
    EMSPREMIUM
    ENTERPRISEPREMIUM
    FLOW_FREE
    -------------

    Then the command to display the services for the ENTERPRISEPREMIUM license plan is this:

    $licenses[2].ServicePlans

    ENTERPRISEPREMIUM is the third row. Therefore, the index value is (3 - 1), or 2.

    For a complete list of license plans (also known as product names), their included service plans, and their corresponding friendly names, see Product names and service plan identifiers for licensing.

4.3.7. View licensed and unlicensed Microsoft 365 users with PowerShell

User accounts in your Microsoft 365 organization may have some, all, or none of the available licenses assigned to them from the licensing plans that are available in your organization. [8]

Reading user properties including license details requires the User.Read.All permission scope or one of the other permissions listed in the 'Get a user' Graph API reference page.

The Organization.Read.All permission scope is required to read the licenses available in the tenant.

Connect-Graph -Scopes User.Read.All, Organization.Read.All
  • To view the license details of a specific user account, run the following command:

    Get-MgUserLicenseDetail -UserId "<user sign-in name (UPN)>"
  • To view the list of all user accounts in your organization that have NOT been assigned any of your licensing plans (unlicensed users), run the following command:

    Get-MgUser -Filter 'assignedLicenses/$count eq 0' -ConsistencyLevel eventual -CountVariable unlicensedUserCount -All
    
    Write-Host "Found $unlicensedUserCount unlicensed users."
  • To view the list of all member user accounts (excluding guests) in your organization that have NOT been assigned any of your licensing plans (unlicensed users), run the following command:

    Get-MgUser -Filter "assignedLicenses/`$count eq 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable unlicensedUserCount -All
    
    Write-Host "Found $unlicensedUserCount unlicensed users (excluding guests)."
  • To view the list of all user accounts in your organization that have been assigned any of your licensing plans (licensed users), run the following command:

    Get-MgUser -Filter 'assignedLicenses/$count ne 0' -ConsistencyLevel eventual -CountVariable licensedUserCount -All -Select UserPrincipalName,DisplayName,AssignedLicenses | Format-Table -Property UserPrincipalName,DisplayName,AssignedLicenses
    
    Write-Host "Found $licensedUserCount licensed users."
  • To view the list of all user accounts in your organization that have an E5 license assigned, run the following command:

    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    
    Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($e5sku.SkuId) )" -ConsistencyLevel eventual -CountVariable e5licensedUserCount -All
    
    Write-Host "Found $e5licensedUserCount E5 licensed users."

4.3.8. Assign Microsoft 365 licenses to user accounts with PowerShell

Users can’t use any Microsoft 365 services until their account has been assigned a license from a licensing plan. You can use PowerShell to quickly assign licenses to unlicensed accounts. [9]

User accounts must first be assigned a location. Specifying a location is a required part of creating a new user account in the Microsoft 365 admin center.

Accounts synchronized from your on-premises Active Directory Domain Services do not by default have a location specified. You can configure a location for these accounts from:

  • The Microsoft 365 admin center

  • PowerShell

  • The Azure portal

Assigning and removing licenses for a user requires the User.ReadWrite.All permission scope or one of the other permissions listed in the 'Assign license' Microsoft Graph API reference page.

The Organization.Read.All permission scope is required to read the licenses available in the tenant.

Connect-MgGraph -Scopes User.ReadWrite.All, Organization.Read.All

Run the Get-MgSubscribedSku command to view the available licensing plans and the number of available licenses in each plan in your organization. The number of available licenses in each plan is ActiveUnits - WarningUnits - ConsumedUnits.

  • To find the unlicensed accounts in your organization, run this command.

    Get-MgUser -Filter 'assignedLicenses/$count eq 0' -ConsistencyLevel eventual -CountVariable unlicensedUserCount -All
  • To find the unlicensed synchronized users in your organization, run this command.

    Get-MgUser -Filter 'assignedLicenses/$count eq 0 and OnPremisesSyncEnabled eq true' -ConsistencyLevel eventual -CountVariable unlicensedUserCount -All -Select UserPrincipalName

    You can only assign licenses to user accounts that have the UsageLocation property set to a valid ISO 3166-1 alpha-2 country code. For example, US for the United States, and FR for France. Some Microsoft 365 services aren’t available in certain countries.

  • To find accounts that don’t have a UsageLocation value, run this command.

    Get-MgUser -Select Id,DisplayName,Mail,UserPrincipalName,UsageLocation,UserType | where { $_.UsageLocation -eq $null -and $_.UserType -eq 'Member' }
  • To set the UsageLocation value on an account, run this command.

    $userUPN="<user sign-in name (UPN)>"
    $userLoc="<ISO 3166-1 alpha-2 country code>"
    
    Update-MgUser -UserId $userUPN -UsageLocation $userLoc

    For example:

    Update-MgUser -UserId "belindan@litwareinc.com" -UsageLocation US

    If you use the Get-MgUser cmdlet without using the -All parameter, only the first 100 accounts are returned.

  • To assign a license to a user, use the following command in PowerShell.

    Set-MgUserLicense -UserId $userUPN -AddLicenses @{SkuId = "<SkuId>"} -RemoveLicenses @()

    This example assigns a license from the SPE_E5 (Microsoft 365 E5) licensing plan to the unlicensed user belindan@litwareinc.com:

    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    Set-MgUserLicense -UserId "belindan@litwareinc.com" -AddLicenses @{SkuId = $e5Sku.SkuId} -RemoveLicenses @()

    This example assigns SPE_E5 (Microsoft 365 E5) and EMSPREMIUM (ENTERPRISE MOBILITY + SECURITY E5) to the user belindan@litwareinc.com:

    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    $e5EmsSku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'EMSPREMIUM'
    $addLicenses = @(
        @{SkuId = $e5Sku.SkuId},
        @{SkuId = $e5EmsSku.SkuId}
    )
    
    Set-MgUserLicense -UserId "belinda@litwareinc.com" -AddLicenses $addLicenses -RemoveLicenses @()

    This example assigns SPE_E5 (Microsoft 365 E5) with the MICROSOFTBOOKINGS (Microsoft Bookings) and LOCKBOX_ENTERPRISE (Customer Lockbox) services turned off:

    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    $disabledPlans = $e5Sku.ServicePlans | `
        Where ServicePlanName -in ("LOCKBOX_ENTERPRISE", "MICROSOFTBOOKINGS") | `
        Select -ExpandProperty ServicePlanId
    
    $addLicenses = @(
        @{
            SkuId = $e5Sku.SkuId
            DisabledPlans = $disabledPlans
        }
    )
    
    Set-MgUserLicense -UserId "belinda@litwareinc.com" -AddLicenses $addLicenses -RemoveLicenses @()

    This example updates a user with SPE_E5 (Microsoft 365 E5) and turns off the Sway and Forms service plans while leaving the user’s existing disabled plans in their current state:

    $userLicense = Get-MgUserLicenseDetail -UserId "belinda@litwareinc.com"
    $userDisabledPlans = $userLicense.ServicePlans | `
        Where ProvisioningStatus -eq "Disabled" | `
        Select -ExpandProperty ServicePlanId
    
    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    $newDisabledPlans = $e5Sku.ServicePlans | `
        Where ServicePlanName -in ("SWAY", "FORMS_PLAN_E5") | `
        Select -ExpandProperty ServicePlanId
    
    $disabledPlans = ($userDisabledPlans + $newDisabledPlans) | Select -Unique
    
    $addLicenses = @(
        @{
            SkuId = $e5Sku.SkuId
            DisabledPlans = $disabledPlans
        }
    )
    
    Set-MgUserLicense -UserId "belinda@litwareinc.com" -AddLicenses $addLicenses -RemoveLicenses @()

    This example updates a user with SPE_E5 (Microsoft 365 E5) and turns off the Sway and Forms service plans while leaving the user’s existing disabled plans in all other subscriptions in their current state:

    $userLicense = Get-MgUserLicenseDetail -UserId belinda@litwareinc.com
    
    $userDisabledPlans = $userLicense.ServicePlans | Where-Object ProvisioningStatus -eq "Disabled" | Select -ExpandProperty ServicePlanId
    
    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    
    $newDisabledPlans = $e5Sku.ServicePlans | Where ServicePlanName -in ("SWAY", "FORMS_PLAN_E5") | Select -ExpandProperty ServicePlanId
    
    $disabledPlans = ($userDisabledPlans + $newDisabledPlans) | Select -Unique
    
    $result=@()
    $allPlans = $e5Sku.ServicePlans | Select -ExpandProperty ServicePlanId
    
    foreach($disabledPlan in $disabledPlans)
    {
        foreach($allPlan in $allPlans)
        {
            if($disabledPlan -eq $allPlan)
            {
                $property = @{
                    Disabled = $disabledPlan
                }
            }
         }
         $result += New-Object psobject -Property $property
    }
    
    $finalDisabled = $result | Select-Object -ExpandProperty Disabled
    
    $addLicenses = @(
        @{
            SkuId = $e5Sku.SkuId
            DisabledPlans = $finalDisabled
        }
    )
    
    Set-MgUserLicense -UserId belinda@litwareinc.com -AddLicenses $addLicenses -RemoveLicenses @()
  • Assign licenses to a user by copying the license assignment from another user

    This example assigns jamesp@litwareinc.com with the same licensing plan that has been applied to belindan@litwareinc.com:

    $mgUser = Get-MgUser -UserId "belindan@litwareinc.com" -Property AssignedLicenses
    Set-MgUserLicense -UserId "jamesp@litwareinc.com" -AddLicenses $mgUser.AssignedLicenses -RemoveLicenses @()
  • Move a user to a different subscription (license plan)

    • This example upgrades a user from the SPE_E3 (Microsoft 365 E3) licensing plan to the SPE_E5 (Microsoft 365 E5) licensing plan:

      $e3Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E3'
      $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
      
      # Unassign E3
      Set-MgUserLicense -UserId "belindan@litwareinc.com" -AddLicenses @{} -RemoveLicenses @($e3Sku.SkuId)
      # Assign E5
      Set-MgUserLicense -UserId "belindan@litwareinc.com" -AddLicenses @{SkuId = $e5Sku.SkuId} -RemoveLicenses @()

      You can verify the change in subscription for the user account with this command.

      Get-MgUserLicenseDetail -UserId "belindan@litwareinc.com"
    • This example upgrades all users from TEAMS_EXPLORATORY (Microsoft Teams Exploratory) to STANDARDPACK (Office 365 E1):

      Connect-MgGraph -Scopes Organization.Read.All,User.ReadWrite.All
      $teamsExploratorySku = Get-MgSubscribedSku | Where SkuPartNumber -eq 'TEAMS_EXPLORATORY'
      $e1Sku = Get-MgSubscribedSku | Where SkuPartNumber -eq 'STANDARDPACK'
      
      $disabledPlans = $e1Sku.ServicePlans | Where ServicePlanName -in ("EXCHANGE_S_STANDARD") | Select -ExpandProperty ServicePlanId
      $addLicenses = @(
          @{
              SkuId = $e1Sku.SkuId
              DisabledPlans = $disabledPlans
          }
      )
      $removeLicenses = @($teamsExploratorySku.SkuId)
      
      $filter = "assignedLicenses/any(u:u/skuId eq $($teamsExploratorySku.SkuId))"
      $teamsExploratoryUserIds = Get-MgUser -Property UserPrincipalName -Filter $filter | Select -Property UserPrincipalName
      
      Write-Host $teamsExploratoryUserIds.Count
      foreach ($userId in $teamsExploratoryUserIds) {
          Set-MgUserLicense -UserId $userId.UserPrincipalName -AddLicenses $addLicenses -RemoveLicenses $removeLicenses
      }

4.3.9. View Microsoft 365 account license and service details with PowerShell

In Microsoft 365, licenses from licensing plans (also called SKUs or Microsoft 365 plans) give users access to the Microsoft 365 services that are defined for those plans. However, a user might not have access to all the services that are available in a license that’s currently assigned to them. You can use PowerShell for Microsoft 365 to view the status of services on user accounts. [10]

Reading user properties including license details requires the User.Read.All permission scope or one of the other permissions listed in the 'Get a user' Graph API reference page.

The Organization.Read.All permission scope is required to read the licenses available in the tenant.

Connect-Graph -Scopes User.ReadWrite.All, Organization.Read.All

Next, list the license plans for your tenant with this command.

Get-MgSubscribedSku
  • Use these commands to list the services that are available in each licensing plan.

    $allSKUs = Get-MgSubscribedSku -Property SkuPartNumber, ServicePlans
    $allSKUs | ForEach-Object {
        Write-Host "Service Plan:" $_.SkuPartNumber
        $_.ServicePlans | ForEach-Object {$_}
    }
  • Use these commands to list the licenses that are assigned to a user account.

    Get-MgUserLicenseDetail -UserId "<user sign-in name (UPN)>"

    For example:

    Get-MgUserLicenseDetail -UserId "belindan@litwareinc.com"
  • To view all the Microsoft 365 services that a user has access to, use the following syntax:

    (Get-MgUserLicenseDetail -UserId <user account UPN> -Property ServicePlans)[<LicenseIndexNumber>].ServicePlans

    This example shows the services to which the user BelindaN@litwareinc.com has access. This shows the services that are associated with all licenses that are assigned to her account.

    (Get-MgUserLicenseDetail -UserId belindan@litwareinc.com -Property ServicePlans).ServicePlans

    This example shows the services that user BelindaN@litwareinc.com has access to from the first license that’s assigned to her account (the index number is 0).

    (Get-MgUserLicenseDetail -UserId belindan@litwareinc.com -Property ServicePlans)[0].ServicePlans
  • To view all the services for a user who has been assigned multiple licenses, use the following syntax:

    $userUPN="<user account UPN>"
    $allLicenses = Get-MgUserLicenseDetail -UserId $userUPN -Property SkuPartNumber, ServicePlans
    $allLicenses | ForEach-Object {
        Write-Host "License:" $_.SkuPartNumber
        $_.ServicePlans | ForEach-Object {$_}
    }

4.3.10. Remove Microsoft 365 licenses from user accounts with PowerShell

Assigning and removing licenses for a user requires the User.ReadWrite.All permission scope or one of the other permissions listed in the 'Assign license' Graph API reference page. [11]

The Organization.Read.All permission scope is required to read the licenses available in the tenant.

Connect-Graph -Scopes User.ReadWrite.All, Organization.Read.All
  • To remove licenses from an existing user account, use the following syntax:

    Set-MgUserLicense -UserId "<Account>" -RemoveLicenses @("<AccountSkuId1>") -AddLicenses @{}

    This example removes the SPE_E5 (Microsoft 365 E5) licensing plan from the user BelindaN@litwareinc.com:

    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    Set-MgUserLicense -UserId "belindan@litwareinc.com" -RemoveLicenses @($e5Sku.SkuId) -AddLicenses @{}
  • To remove all licenses from a group of existing licensed users, use the following syntax:

    $licensedUsers = Get-MgUser -Filter 'assignedLicenses/$count ne 0' `
        -ConsistencyLevel eventual -CountVariable licensedUserCount -All `
        -Select UserPrincipalName,DisplayName,AssignedLicenses
    
    foreach($user in $licensedUsers)
    {
        $licencesToRemove = $user.AssignedLicenses | Select -ExpandProperty SkuId
        $user = Set-MgUserLicense -UserId $user.UserPrincipalName -RemoveLicenses $licencesToRemove -AddLicenses @{}
    }

    Another way to free up a license is by deleting the user account.

4.3.11. Disable access to Microsoft 365 services with PowerShell

When a Microsoft 365 account is assigned a license from a licensing plan, Microsoft 365 services are made available to the user from that license. However, you can control the Microsoft 365 services that the user can access. For example, even though the license allows access to the SharePoint Online service, you can disable access to it. You can use PowerShell to disable access to any number of services for a specific licensing plan for:

  • An individual account.

  • A group of accounts.

  • All accounts in your organization.

Assigning and removing licenses for a user requires the User.ReadWrite.All permission scope or one of the other permissions listed in the 'Assign license' Graph API reference page.

The Organization.Read.All permission scope is required to read the licenses available in the tenant.

Connect-Graph -Scopes User.ReadWrite.All, Organization.Read.All

Next, use this command to view your available licensing plans, also known as SkuPartNumber:

Get-MgSubscribedSku | Select SkuId, SkuPartNumber, ServicePlans | Sort SkuPartNumber
  • Disable specific Microsoft 365 services for specific users for a specific licensing plan

    First list the licensing plans available in your tenant using the following command.

    Get-MgSubscribedSku | Select SkuPartNumber

    Next, use the SkuPartNumber from the command above, list the service plans available for a given license plan (Sku).

    Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5' |  select -ExpandProperty ServicePlans

    The following example assigns SPE_E5 (Microsoft 365 E5) with the MICROSOFTBOOKINGS (Microsoft Bookings) and LOCKBOX_ENTERPRISE (Customer Lockbox) services turned off:

    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    $disabledPlans = $e5Sku.ServicePlans | `
        Where ServicePlanName -in ("LOCKBOX_ENTERPRISE", "MICROSOFTBOOKINGS") | `
        Select -ExpandProperty ServicePlanId
    
    $addLicenses = @(
        @{
            SkuId = $e5Sku.SkuId
            DisabledPlans = $disabledPlans
        }
    )
    
    Set-MgUserLicense -UserId "belinda@litwareinc.com" -AddLicenses $addLicenses -RemoveLicenses @()

    The DisabledPlans property of the AddLicenses parameter in Set-MgUserLicense will overwrite the user’s existing DisabledPlans value. To preserve the state of existing service plans, the user’s current state of service plans must be merged with the new plans that are going to be disabled.

    Failing to include the existing DisabledPlans will result in the user’s previously disabled plan being enabled.

    The following example updates a user with SPE_E5 (Microsoft 365 E5) and turns off the Sway and Forms service plans while leaving the user’s existing disabled plans in their current state:

    ## Get the services that have already been disabled for the user.
    $userLicense = Get-MgUserLicenseDetail -UserId "belinda@fdoau.onmicrosoft.com"
    $userDisabledPlans = $userLicense.ServicePlans | `
        Where ProvisioningStatus -eq "Disabled" | `
        Select -ExpandProperty ServicePlanId
    
    ## Get the new service plans that are going to be disabled
    $e5Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'SPE_E5'
    $newDisabledPlans = $e5Sku.ServicePlans | `
        Where ServicePlanName -in ("SWAY", "FORMS_PLAN_E5") | `
        Select -ExpandProperty ServicePlanId
    
    ## Merge the new plans that are to be disabled with the user's current state of disabled plans
    $disabledPlans = ($userDisabledPlans + $newDisabledPlans) | Select -Unique
    
    $addLicenses = @(
        @{
            SkuId = $e5Sku.SkuId
            DisabledPlans = $disabledPlans
        }
    )
    ## Update user's license
    Set-MgUserLicense -UserId "belinda@litwareinc.onmicrosoft.com" -AddLicenses $addLicenses -RemoveLicenses @()

4.4. Exchange Online PowerShell

Exchange Online PowerShell is the administrative interface that enables you to manage your Microsoft Exchange Online organization from the command line. For example, you can use Exchange Online PowerShell to configure mail flow rules (also known as transport rules) and connectors. [9]

The Exchange Online PowerShell module uses modern authentication and works with multi-factor authentication (MFA) for connecting to all Exchange-related PowerShell environments in Microsoft 365: Exchange Online PowerShell, Security & Compliance PowerShell, and standalone Exchange Online Protection (EOP) PowerShell.

To install the latest public version of the module, run one of the the following commands:

  • In an elevated PowerShell window (all users):

    Install-Module -Name ExchangeOnlineManagement
  • Only for the current user account:

    Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser

After you’ve installed the module, open a PowerShell window and load the module by running the following command:

Import-Module ExchangeOnlineManagement
If the module is already installed, you can typically skip this step and run Connect-ExchangeOnline without manually loading the module first.

Use the Connect-ExchangeOnline command to sign in.

Connect-ExchangeOnline -UserPrincipalName <UPN> [-UseRPSSession] [-ExchangeEnvironmentName <Value>] [-ShowBanner:$false] [-DelegatedOrganization <String>] [-PSSessionOption $ProxyOptions]

Be sure to disconnect the session when you’re finished. If you close the PowerShell window without disconnecting the session, you could use up all the sessions available to you, and you need to wait for the sessions to expire. To disconnect the session, run the following command:

Disconnect-ExchangeOnline

To silently disconnect without a confirmation prompt, run the following command:

Disconnect-ExchangeOnline -Confirm:$false

4.4.1. AutoDiscover of Outlook, Exchange, and Exchange Online (EXO)

Autodiscover is a feature that simplifies the configuration process for email clients like Outlook by automatically discovering the required settings for connecting to Exchange mailboxes, whether they are hosted on-premises (Exchange Server) or in the cloud (Exchange Online).

Here’s a summary of Autodiscover for Outlook, Exchange, and Exchange Online (EXO):

  1. Outlook: When configuring an email account in Outlook, it uses the Autodiscover process to find the appropriate settings for the user’s mailbox. Outlook first attempts to connect to Exchange Online by querying the default Office 365 Autodiscover endpoint. If it fails to find an Exchange Online mailbox, Outlook will try to discover settings for an on-premises Exchange mailbox using various methods, such as querying custom Autodiscover URLs or performing an SCP (Service Connection Point) lookup in Active Directory.

  2. Exchange (On-premises): For on-premises Exchange environments, the Autodiscover service is hosted on the Exchange server. You need to configure Autodiscover DNS records (such as an "A" or "CNAME" record for autodiscover.yourdomain.com) that point to your Exchange server’s IP address or hostname. This will enable Outlook to discover the on-premises mailbox settings automatically when it fails to find an Exchange Online mailbox.

  3. Exchange Online (EXO): In Office 365, the Autodiscover service is automatically configured for Exchange Online. Outlook can discover Exchange Online mailboxes using the default Office 365 Autodiscover endpoint. However, it’s a good practice to configure the recommended DNS records for your domain, including the Autodiscover CNAME record that points to autodiscover.outlook.com. This ensures optimal performance, compatibility, and helps avoid potential issues in the future.

    If you haven’t configured an Autodiscover DNS record for your domain, but Outlook still connects to Exchange Online (EXO) automatically, it’s likely due to Outlook’s built-in capability to find the Exchange Online mailbox using the default Office 365 Autodiscover service.

    Outlook has a pre-defined list of endpoints it checks during the Autodiscover process. If Outlook is unable to find a custom Autodiscover DNS record for your domain, it will try the default Office 365 Autodiscover endpoint at https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml.

    Since Exchange Online is part of Office 365, its Autodiscover information is already available at this default endpoint. When Outlook queries this URL, it will receive the necessary configuration settings to connect to the Exchange Online mailbox automatically.

By properly configuring Autodiscover for both on-premises Exchange and Exchange Online environments, you can ensure a seamless user experience and simplify the process of connecting to mailboxes using Outlook and other email clients.

Here’s the order of the Autodiscover process in Outlook:

  1. Outlook first checks for an Office 365 mailbox (Exchange Online) by querying the Office 365 Autodiscover service at “https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml”;.

  2. the mailbox is not found in Office 365, Outlook will then try to discover the mailbox settings from the on-premises Exchange server using the following methods:

    1. Querying the “https://autodiscover.yourdomain.com/autodiscover/autodiscover.xml”; URL, where "yourdomain.com" is the user’s email domain.

    2. Performing an SCP (Service Connection Point) lookup in Active Directory (only applicable for domain-joined computers in the same AD forest as the Exchange server).

    3. Querying the “https://yourdomain.com/autodiscover/autodiscover.xml”; URL.

  3. If the on-premises Exchange server is discovered and the mailbox settings are retrieved, Outlook will connect to the on-premises Exchange server.

It is important to ensure that your organization’s Autodiscover DNS records and configuration are set up correctly for both Exchange Online and on-premises Exchange server. This will allow Outlook to discover the correct mailbox settings and ensure a seamless user experience.

4.4.2. How to bypass the Autodiscover process in Outlook

Disabling Autodiscover in Office 365 (Microsoft 365) Exchange Online is not recommended, as it is an essential service for automatically configuring email clients and maintaining connections with Exchange Online mailboxes. However, if you want to prevent Outlook from automatically connecting to Exchange Online, you can use a registry modification on the client-side to bypass the Autodiscover process.

Please note that modifying the registry can cause issues if not done correctly, so proceed with caution and create a backup of your registry before making any changes.

To bypass the Autodiscover process in Outlook:

  1. Press Win + R to open the Run dialog box, type regedit, and press Enter.

  2. Navigate to the following registry key, depending on your version of Outlook:

    • Outlook 2016, 2019, or Outlook for Office 365:

      HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\AutoDiscover
    • Outlook 2013:

      HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Outlook\AutoDiscover

    If the AutoDiscover key does not exist, you can create it by right-clicking on the Outlook key, selecting "New" > "Key," and naming it "AutoDiscover."

  3. Right-click on the AutoDiscover key, choose "New" > "DWORD (32-bit) Value," and name it "ExcludeExplicitO365Endpoint."

  4. Double-click the "ExcludeExplicitO365Endpoint" value, set the "Value data" to 1, and click "OK."

  5. Close the Registry Editor and restart Outlook.

This registry modification tells Outlook to bypass the Office 365 Autodiscover process, allowing you to manually configure your email clients to connect to other Exchange servers, such as on-premises deployments.

Please keep in mind that this method disables the Autodiscover process for Office 365 on the client-side and may lead to issues with email client configuration and connectivity. Use this approach only if you understand the risks and potential consequences.

Here’s a PowerShell script and a batch script that will automatically detect the operating system version, Outlook version, and add or update the necessary registry key to bypass the Office 365 Autodiscover process.

PowerShell Script (AutodiscoverBypass.ps1):
# Detect the Outlook version
$OutlookVersion = (Get-ItemProperty -Path "HKLM:\Software\Microsoft\Office\ClickToRun\Configuration" -Name "ClientVersionToReport" -ErrorAction SilentlyContinue) -replace '[^\d\.]'
if (-not $OutlookVersion) { $OutlookVersion = (Get-ItemProperty -Path "HKLM:\Software\Microsoft\Office\16.0\Common\InstallRoot" -Name "Path" -ErrorAction SilentlyContinue) }
if (-not $OutlookVersion) { $OutlookVersion = (Get-ItemProperty -Path "HKLM:\Software\Microsoft\Office\15.0\Common\InstallRoot" -Name "Path" -ErrorAction SilentlyContinue) }

# Set the registry key based on the Outlook version
if ($OutlookVersion) {
    $AutoDiscoverPath = "HKCU:\Software\Microsoft\Office\$($OutlookVersion.Split('.')[0]).0\Outlook\AutoDiscover"
    if (-not (Test-Path $AutoDiscoverPath)) { New-Item -Path $AutoDiscoverPath -Force }
    Set-ItemProperty -Path $AutoDiscoverPath -Name "ExcludeExplicitO365Endpoint" -Value 1 -Type DWord
}

To run the PowerShell script:

  1. Save the script as AutodiscoverBypass.ps1.

  2. Open PowerShell as Administrator.

  3. Execute the script: .\AutodiscoverBypass.ps1

Batch Script (AutodiscoverBypass.bat):
@echo off
setlocal enabledelayedexpansion

rem Detect the Outlook version
for /f "tokens=2*" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Office\ClickToRun\Configuration" /v "ClientVersionToReport" 2^>nul') do set OutlookVersion=%%b
if not defined OutlookVersion for /f "tokens=2*" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Office\16.0\Common\InstallRoot" /v "Path" 2^>nul') do set OutlookVersion=16
if not defined OutlookVersion for /f "tokens=2*" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Office\15.0\Common\InstallRoot" /v "Path" 2^>nul') do set OutlookVersion=15

rem Set the registry key based on the Outlook version
if defined OutlookVersion (
    set MajorVersion=!OutlookVersion:~0,2!
    reg add "HKCU\Software\Microsoft\Office\!MajorVersion!.0\Outlook\AutoDiscover" /v "ExcludeExplicitO365Endpoint" /t REG_DWORD /d 1 /f
)

To run the batch script:

  1. Save the script as AutodiscoverBypass.bat.

  2. Right-click the file and select "Run as Administrator".

Both scripts will detect the operating system and Outlook version, and then add or update the ExcludeExplicitO365Endpoint registry key accordingly.

5. Azure PowerShell

Azure PowerShell is a set of cmdlets for managing Azure resources directly from PowerShell. Azure PowerShell is designed to make it easy to learn and get started with, but provides powerful features for automation. [10]

The Az PowerShell module is the replacement of AzureRM and is the recommended version to use for interacting with Azure.

5.1. Install Azure PowerShell on Windows

The Azure PowerShell Az module is a rollup module. Installing the Az PowerShell module downloads the generally available modules and makes their cmdlets available for use. [11]

The recommended installation method and PowerShell version for the Az PowerShell module:

  • Install from the PowerShell Gallery

  • Use with PowerShell version 7 or higher

5.1.1. Prerequisites

  • Run the following command from PowerShell to determine your PowerShell version:

    $PSVersionTable.PSVersion
  • Determine if you have the AzureRM PowerShell module installed:

    Get-Module -Name AzureRM -ListAvailable
If you have the AzureRM PowerShell module installed, see Az and AzureRM coexistence before proceeding.
Windows PowerShell
  • Update to Windows PowerShell 5.1

  • Install .NET Framework 4.7.2 or later

  • Update PowerShellGet

    Launch Windows PowerShell 5.1 elevated as an administrator and run the following command to update PowerShellGet:

    Install-Module -Name PowerShellGet -Force
  • Set the PowerShell execution policy to remote signed or less restrictive

    • Check the PowerShell execution policy:

    Get-ExecutionPolicy -List
    • Set the PowerShell execution policy to remote signed:

      Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

5.1.2. Installation

  • Use the Install-Module cmdlet to install the Az PowerShell module:

    Install-Module -Name Az -Repository PSGallery -Force
  • Use Update-Module to update to the latest version of the Az PowerShell module:

    Update-Module -Name Az -Force

    Updating the Az PowerShell module using Update-Module doesn’t remove old versions of the Az PowerShell module from your system.

5.1.3. Sign in with Azure PowerShell

Azure PowerShell supports several authentication methods. [12]

  • The easiest way to get started is with Azure Cloud Shell, which automatically logs you in.

  • With a local install, you can sign in interactively through your browser.

  • When writing scripts for automation, the recommended approach is to use a service principal with the necessary permissions.

When you restrict sign-in permissions as much as possible for your use case, you help keep your Azure resources secure.

Initially, you’re signed into the first subscription Azure returns if you have access to more than one subscription. Commands are run against this subscription by default.

  • To change your active subscription for a session, use the Set-AzContext cmdlet.

  • To change your active subscription and have it persist between sessions on the same system, use the Select-AzContext cmdlet.

5.1.3.1. Sign in interactively
  • To sign in interactively, use the Connect-AzAccount cmdlet.

    Connect-AzAccount

    This cmdlet presents an interactive browser based login prompt by default.

5.1.3.2. Device code authentication
  • You can specify the UseDeviceAuthentication parameter to use device code authentication instead of a browser control.

    Connect-AzAccount -UseDeviceAuthentication
5.1.3.3. Sign in using a managed identity

Managed identities are a feature of Azure Active Directory. Managed identities are service principals assigned to resources that run in Azure. You can use a managed identity service principal for sign-in, and an app-only access token to access other resources. Managed identities are only available on resources running in an Azure cloud.

This example connects using a system-assigned managed identity of the host environment. For example, if executed on a VirtualMachine with an assigned Managed Service Identity, this allows the code to sign in using that assigned identity.

Connect-AzAccount -Identity
5.1.3.4. Sign in with a non-default tenant or as a Cloud Solution Provider (CSP)

If your account is associated with more than one tenant, sign-in requires the Tenant parameter to be specified when connecting. This parameter works with any sign-in method. When logging in, this parameter value can either be the Azure object ID of the tenant (Tenant ID) or the fully qualified domain name of the tenant.

If you’re a Cloud Solution Provider (CSP), the value for the Tenant parameter must be a tenant ID.

Connect-AzAccount -Tenant '00000000-0000-0000-0000-000000000000'
5.1.3.5. Sign in to another Cloud

Azure cloud services offer environments compliant with regional data-handling laws. For accounts in a regional cloud, set the environment when you sign in with the Environment parameter. This parameter works with any sign-in method. For example, if your account is in Azure China 21Vianet:

Connect-AzAccount -Environment AzureChinaCloud

The following command returns a list of available environments:

Get-AzEnvironment | Select-Object -Property Name

5.1.4. Credential contexts

Azure PowerShell uses Azure PowerShell context objects (Azure contexts) to hold subscription and authentication information. If you have more than one subscription, Azure contexts let you select the subscription to run Azure PowerShell cmdlets on. Azure contexts are also used to store sign-in information across multiple PowerShell sessions and run background tasks.

Azure contexts are PowerShell objects representing your active subscription to run commands against, and the authentication information needed to connect to an Azure cloud. With Azure contexts, Azure PowerShell doesn’t need to reauthenticate your account each time you switch subscriptions. An Azure context consists of:

  • The account that was used to sign in to Azure with Connect-AzAccount. Azure contexts treat users, application IDs, and service principals the same from an account perspective.

  • The active subscription, a service agreement with Microsoft to create and run Azure resources, which are associated with a tenant. Tenants are often referred to as organizations in documentation or when working with Active Directory.

  • A reference to a token cache, a stored authentication token for accessing an Azure cloud. Where this token is stored and how long it persists for is determined by the context autosave settings.

Get Azure contexts
# List the available contexts
Get-AzContext -ListAvailable

# Or get a context by name
Get-AzContext -Name 'mycontext'
5.1.4.1. Change the active Azure context

Both Set-AzContext and Select-AzContext can be used to change the active Azure context.

Set-AzContext creates a new Azure context for a subscription if one doesn’t exist, and then switches the active context to that one.

Select-AzContext is meant to be used only with existing Azure contexts and works similarly to using Set-AzContext -Context, but is designed for use with piping:

Set-AzContext -Context $(Get-AzContext -Name 'mycontext') # Set a context with an inline Azure context object
Get-AzContext -Name 'mycontext' | Select-AzContext # Set a context with a piped Azure context object

Like many other account and context management commands in Azure PowerShell, Set-AzContext and Select-AzContext support the Scope parameter so that you can control how long the context is active. Scope lets you change a single session’s active context without changing your default:

Get-AzContext -Name 'mycontext' | Select-AzContext -Scope Process

To avoid switching contexts for a whole PowerShell session, Azure PowerShell commands with an AzContext parameter can be run against a given context:

$context = Get-AzContext -Name "mycontext"
New-AzVM -Name ExampleVM -AzContext $context

In order to change subscriptions associated with your current Azure session, you use the Set-AzContext cmdlet to change the current context.

Set-AzContext -Subscription <subscription name or id>

You can use the Get-AzSubscription cmdlet to retrieve a list of your Azure subscriptions.

5.1.4.2. Save Azure contexts across PowerShell sessions

By default, Azure contexts are saved for use between PowerShell sessions. You change this behavior in the following ways:

  • Sign in using -Scope Process with Connect-AzAccount.

    Connect-AzAccount -Scope Process

    The Azure context returned as part of this sign in is valid for the current session only and won’t be saved automatically, regardless of the Azure PowerShell context autosave setting.

  • Disable context autosave in Azure PowerShell with the Disable-AzContextAutosave cmdlet. Disabling context autosave doesn’t clear any stored tokens.

    To remove stored information, use the Clear-AzContext cmdlet.
  • Explicitly enable Azure context autosave can be enabled with the Enable-AzContextAutosave cmdlet. With autosave enabled, a user’s contexts are stored locally for later PowerShell sessions.

  • Manually save contexts with Save-AzContext to be used in future PowerShell sessions, where they can be loaded with Import-AzContext:

    Save-AzContext -Path current-context.json # Save the current context
    Save-AzContext -Profile $profileObject -Path other-context.json # Save a context object
    Import-AzContext -Path other-context.json # Load the context from a file and set it to the current context
5.1.4.3. Remove Azure contexts and stored credentials

To clear Azure contexts and credentials:

  • Sign out of an account with Disconnect-AzAccount. You can sign out of any account either by account or context:

    Disconnect-AzAccount # Disconnect active account
    Disconnect-AzAccount -Username 'user@contoso.com' # Disconnect by account name
    
    Disconnect-AzAccount -ContextName 'subscription2' # Disconnect by context name
    Disconnect-AzAccount -AzureContext $contextObject # Disconnect using context object information

    Disconnecting always removes stored authentication tokens and clears saved contexts associated with the disconnected user or context.

  • Use Clear-AzContext. This cmdlet always removes stored contexts, authentication tokens, and signs you out.

  • Remove a context with Remove-AzContext:

    Remove-AzContext -Name 'mycontext' # Remove by name
    Get-AzContext -Name 'mycontext' | Remove-AzContext # Remove by piping Azure context object

    If you remove the active context, you’ll be disconnected from Azure and need to reauthenticate with Connect-AzAccount.

5.2. Find commands

Azure PowerShell cmdlets follow a standard naming convention for PowerShell, Verb-Noun. The verb describes the action (examples include New, Get, Set, Remove) and the noun describes the resource type (examples include AzVM, AzKeyVaultCertificate, AzFirewall, AzVirtualNetworkGateway). Nouns in Azure PowerShell always start with the prefix Az.

Knowing the nouns, verbs, and the Azure PowerShell modules available helps you find commands with the Get-Command cmdlet. For example, to find all VM-related commands that use the Get verb:

Get-Command -Verb Get -Noun AzVM* -Module Az.Compute

References