With organizations moving more workloads into Azure, administrators now have more options for running PowerShell commands and scripts across virtual machines. In this post, you will learn multiple ways to execute PowerShell remotely on your Azure virtual machines.
Latest posts by Jeff Brown (see all)

While there are many methods for deploying PowerShell scripts against Azure VMs, this article focuses on two: Run Command and Custom Script Extension. Each technique offers different opportunities and obstacles for executing a PowerShell script.

Prerequisites

To follow along with this tutorial, you will need:

  • An Azure tenant and subscription with sufficient privileges, such as Owner or Contributor.
  • PowerShell command line and Microsoft Azure PowerShell Az Modules.
  • Bash console and Microsoft Azure CLI.
  • One or more Windows virtual machines in Azure. This tutorial uses Windows Server Datacenter 2019.

Using Run Command via the Virtual Machine Agent

The first option is to use the Run Command feature. This feature uses the virtual machine agent to execute PowerShell scripts in an Azure Windows VM. Using an agent does not require direct network access to the VM, so you can run scripts for general server management or diagnose network issues. This method is also helpful if the virtual machine does not have the RDP or SSH port open due to security or improper configuration.

There are a few restrictions when using Run Command on an Azure VM:

  • Output is limited to the last 4,096 bytes.
  • The script will time out after 90 minutes of runtime.
  • The agent runs the script as System on Windows operating systems.
  • The agent can only run one script at a time.
  • The script cannot be interactive or prompt for information.
  • You cannot cancel a running script once it has started.
  • VM outbound connectivity is required to return the script results.
  • The VM agent status must be in a ready state, and the script should not stop or update the VM agent. This action puts the extension in a transition state and leads to a timeout.

There are multiple commands available for Windows VMs when using Run Command. This article focuses on the RunPowerShellScript command, which instructs the agent to run a PowerShell script. However, there are several others, such as EnableAdminAccount, IPConfig, and SetRDPPort. You can read more about the available commands here on Microsoft Docs.

Let's focus on three methods for using Run Command: Azure portal, Azure CLI, and Azure PowerShell.

Run Command in Azure Portal

To run a PowerShell script using Run Command on an Azure Windows VM:

  1. In the Azure portal, navigate to the virtual machine resource.
  2. Navigate to Operations > Run Command. Select RunPowerShellScript from the list of commands.
    Navigating to Run Command on an Azure virtual machine

    Navigating to Run Command on an Azure virtual machine

  3. Type the PowerShell script content you want to run on the server in the Run Command Script pane. The example below sets the time zone, installs IIS, and modifies the default IIS document. When complete, click Run.
    Entering the PowerShell script content for Run Command

    Entering the PowerShell script content for Run Command

  4. Azure displays a banner indicating that the script execution is in progress. An output window appears below the script contents section, showing the script output. This example output shows that the script successfully installed IIS.
    Output of the Run Command script action

    Output of the Run Command script action

Run Command in Azure PowerShell

You can also use Run Command via PowerShell, using the Invoke-AzVmRunCommand command. This command is part of the Az.Compute set of Azure PowerShell modules. To use this command to run a PowerShell script:

  1. Open a PowerShell window.
  2. Log into your Azure tenant using the Connect-AzAccount command.
  3. If necessary, select a default subscription using the Set-AzContext command.
  4. Use the Invoke-AzVmRunCommand and specify the -ResourceGroupName and -VMName of the virtual machine. Use the -CommandId value of RunPowerShellScript along with the path to the script. In this example, the Install-IIS.ps1 script contains the same code run in the previous Azure portal example.
Invoke-AzVmRunCommand `
     -ResourceGroupName "rg-azpsremote" `
     -VMName "server1" `
     -CommandId "RunPowerShellScript" `
     -ScriptPath "C:\ps\Install-IIS.ps1"
  1. PowerShell displays any script output (to the limits mentioned earlier) and indicates that the script exited successfully.
    Invoke AzVmRunCommand command and script output

    Invoke AzVmRunCommand command and script output

Unlike the Azure portal, the Run Command in PowerShell supports the use of parameters that enable customizing script input for each server.

In the example below, the Install-IIS.ps1 script accepts two parameters for TimeZone and WebsiteMessage. You pass the parameters as a hash table, using the parameter name as the key and associating the value. This example sets TimeZone to "Pacific Standard Time" and WebsiteMessage to "Hello, World!"

Invoke-AzVmRunCommand `
     -ResourceGroupName "rg-azpsremote" `
     -VMName "server1" `
     -CommandId "RunPowerShellScript" `
     -ScriptPath "C:\ps\Install-IIS.ps1" `
     -Parameter @{
        TimeZone = "Pacific Standard Time";
        WebsiteMessage = "Hello, World!"
     }

Run Command in Azure CLI

The Azure CLI uses az vm run-command invoke to run PowerShell scripts on Azure VMs. To use this command to run a PowerShell script:

  1. Open a Bash terminal.
  2. Log in to your Azure tenant using the az login command.
  3. If necessary, select a default subscription using the az account set command.
  4. Use the az vm run-command invoke and specify the --resource-group and --name of the virtual machine. Use the --command-id of RunPowerShellScript, and specify the script file name using an At (@) sign. Note the use of double backslashes (\\) in the path name. In this example, the Install-IIS.ps1 script contains the same code run in the previous examples.
az vm run-command invoke \
  --resource-group 'rg-azpsremote' \
  --name 'server2' \
  --command-id 'RunPowerShellScript' \
  --scripts @C:\\ps\\Install-IIS.ps1
Using az vm run command invoked in Azure CLI

Using az vm run command invoked in Azure CLI

Using az vm run-command invoked in Azure CLI

  1. The shell console displays any script output (to the limits mentioned earlier) and indicates that the script exited successfully.
    Run Command output in Azure CLI

    Run Command output in Azure CLI

Just like Azure PowerShell, Azure CLI accepts parameters as input for a PowerShell script. Use --parameters followed by key/value assignments that use an equal sign (=) in quotes. Enclose individual key/value pairs within double quotes and separate multiple parameters using spaces.

az vm run-command invoke \
  --resource-group 'rg-azpsremote' \
  --name 'server2' \
  --command-id 'RunPowerShellScript' \
  --scripts @C:\\ps\\Install-IIS.ps1 \
  --parameters "TimeZone=Pacific Standard Time" "WebsiteMessage=Hello, World!"

One advantage Azure CLI has over PowerShell is its ability to run individual commands instead of scripts. Instead of specifying a script in the --scripts argument, you can pass individual PowerShell commands. This example sets the time zone and the website message using two commands enclosed in single quotes and separated by a space.

az vm run-command invoke \
  --resource-group 'rg-azpsremote' \
  --name 'server2' \
  --command-id 'RunPowerShellScript' \
  --scripts 'Set-TimeZone -Name "Pacific Standard Time"' \
    'Set-Content -Path "C:\inetpub\wwwroot\iisstart.htm" -Value "Hello, World!"'

Using Azure VM Custom Script Extension

Another option is to use the Custom Script Extension on a virtual machine. The Custom Script Extension downloads and executes scripts on Azure virtual machines and is helpful for post-deployment configurations.

You place the PowerShell scripts in a location that the Azure virtual machine can route to, such as GitHub, Azure Blog storage, or an internal file server. This connectivity requirement may mean you need to add firewall rules or Network Security Group exceptions for the VM to access the file.

When working with a Custom Script Extension, there are a few things to consider.

  • Verify that the script is successful by manually running it on a test system. This action eliminates failures or timeouts when you run the script through the extension.
  • The extension allows 90 minutes for the script to run. Any longer-running scripts will time out and fail.
  • Don't include reboots within the script, as reboots cause issues with other extensions being installed. If needed, schedule a reboot from within the script for later.
  • Custom Script Extension runs under the LocalSystem account.

Let's take a look at two examples of downloading scripts from a GitHub repository and an Azure storage account container. Both examples save all settings to the ProtectedSettings section of the Custom Script Extension.

GitHub repository

This example shows downloading a PowerShell script from a public GitHub repository. You will need the raw URL of the PowerShell script. Here is an example raw URL for the Install-IIS.ps1 script used in earlier examples:

https://raw.githubusercontent.com/JeffBrownTech/azure_psremote_demo_script/main/Install-IIS.ps1

Save this raw URL to an array variable named $fileUris. Next, create a hash table named $protectedSettings that includes two keys named fileUris and commandToExecute. The execution command should open PowerShell and run the file name of the downloaded file.

$fileUris = @("https://raw.githubusercontent.com/JeffBrownTech/azure_psremote_demo_script/main/Install-IIS.ps1")
$protectedSettings = @{
    "fileUris" = $fileUris
    "commandToExecute" = "powershell -ExecutionPolicy Unrestricted -File Install-IIS.ps1"    
}

Next, use the Set-AzVMExtension command to create the Custom Script Extension for the VM. You will need to specify the resource group name, VM name, and VM location. Give the Custom Script Extension a name such as "InstallIIS." Next, enter all the properties for the extension, such as the Publisher, ExtensionType, and TypeHandlerVersion. Finally, set ProtectedSettings to the $protectedSettings variable.

Be sure to update the resource group name, server name, and location specific to your deployment.

Set-AzVMExtension `
    -ResourceGroupName "rg-azpsremote" `
    -Location "westus" `
    -VMName "server1" `
    -Name "InstallIIS" `
    -Publisher "Microsoft.Compute" `
    -ExtensionType "CustomScriptExtension" `
    -TypeHandlerVersion "1.10" `
    -ProtectedSettings $protectedSettings

Storage Account Blob

This example shows how to download the PowerShell script file from a storage account container. Downloading from a storage account container requires additional properties, such as the storage account blob URL, the container name, and the storage account key.

First, create the same $fileUris array variable, this time containing the blob URL representing the PowerShell script. Next, create the $protectedSettings hash table again, this time with values for storageAccountName and storageAccountKey.

Finally, run the Set-AzVMExtension command again, using the same values as in the previous example. Be sure to update the resource group name, server name, and location specific to your deployment.

Subscribe to 4sysops newsletter!

$fileUris = @("https://jbtstgacct9283.blob.core.windows.net/scripts/Install-IIS.ps1")
$protectedSettings = @{
    "fileUris" = $fileUris
    "storageAccountName" = "jbtstgacct9283"
    "storageAccountKey" = "xnZDaK9Fr2hYRRaH9nqJiHb/3Q=="
    "commandToExecute" = "powershell -ExecutionPolicy Unrestricted -File Install-IIS.ps1"
}

Set-AzVMExtension `
    -ResourceGroupName "rg-azpsremote" `
    -Location "westus" `
    -VMName "server0" `
    -Name "InstalIIS" `
    -Publisher "Microsoft.Compute" `
    -ExtensionType "CustomScriptExtension" `
    -TypeHandlerVersion "1.10" `
    -ProtectedSettings $protectedSettings

Closing

This article introduced how to run a PowerShell script against Azure Windows virtual machines. Both methods have pros and cons; it's up to you to determine the best workflow to meet your needs. How will you use these methods to run PowerShell scripts on your VMS?

avataravataravatar
2 Comments
  1. kevin 7 months ago

    Thanks for the info.
    Since you can’t run powershell from within Power BI to pull data into Power BI, would like to run a powershell script from within Azure (automate running the script and import data into azure storage – Azure SQL, blob storage, etc.) Which methods can I try ? Will Logic Apps work ?

Leave a reply

Please enclose code in pre tags

Your email address will not be published.

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account