Using Remote PowerShell on Azure

When we have hundreds of Virtual Machines to manage, manual tasks just don’t cut it. they’re error prone and can be quite boring to carry out.

On Azure, there are two approaches to automation for Windows Virtual Machines. The first is PowerShell Desired State Configuration (DSC). This approach is well suited for the initial configuration of complex environments. The second is Remote PowerShell, and this blog post will focus on this approach.

Remote PowerShell is great for executing commands and performing maintenance on existing Virtual Machines. It uses the WinRM protocol over HTTPS to secure the communication transport layer. By default, if we don’t specify a certificate, the provisioning agent will automatically generate a self-signed certificate and configure the SSL listener.

In order to connect to a Virtual Machine that uses a self-signed certificate, we need to download and install it to the Azure Automation Instance that executes our runbook. Failure to do so, forces us to use the -SkipCACheck PowerShell session option that leaves us vulnerable to a man in the middle attack.

The Challenge

The goal of this post is to walk through what is required to execute commands through Remote PowerShell from Azure Automation.

The exit criteria for this example, is to be able to create a text file on an existing Azure Virtual Machine.

The Solution

We need to start by Configuring Azure Automation. This requires us to create a new Azure Active Directory user to manage our Azure subscription.

The credentials for this new user, are securely stored in Azure Automation Credential Assets. In order to authorize Azure Automation to interact with our Azure Subscription, we use the Get-AutomationPSCredential CmdLet to retrieve user credentials and the Add-AzureAccount Azure CmdLet to Authenticate against the Azure Management APIs.

To secure the Remote PowerShell Session we use an InlineScript block to fetch the default WinRM Certificate from the Classic Azure Virtual Machine. Then we install it to the Local Machine Certificate Store.

The URI used by the Invoke-Command CmdLet is secured via HTTPS and contains the public WinRM port configured on the Azure Virtual Machine.

Note: On Azure Classic Compute, the port information is configured through Endpoints. On Azure Resource Manager driven Compute, it is defined in the Network Security Groups (NSG).

Ok, now we’re almost ready. We need to store the Virtual Machine user credentials in an Azure Automation Credential Asset.

Using the Virtual Machine user credentials and the WinRM URI, we can now use the Invoke-Command CmdLet to open a Remote PowerShell Session and execute commands on out Virtual Machine.

The Runbook

workflow Invoke-AzureVMCommand
{
    # Get the Azure Management Credentials
    $creds = Get-AutomationPSCredential -Name 'runbook'
              
    #Connect to your Azure Account
    $Account = Add-AzureAccount -Credential $creds
    if(!$Account) {
        Throw "Could not authenticate to Azure using the credential asset '${CredentialAssetName}'. Make sure the user name and password are correct."
    }
            
    InlineScript 
    {  
        # Get the Azure certificate for remoting into this VM 
        $winRMCert = (Get-AzureVM -ServiceName 'trial-brisebois' `
                                  -Name 'trial-brisebois' `
                        | select -ExpandProperty vm)
                     .DefaultWinRMCertificateThumbprint    
        
        $AzureX509cert = Get-AzureCertificate -ServiceName 'trial-brisebois' `
                                              -Thumbprint $winRMCert `
                                              -ThumbprintAlgorithm sha1 
              
        # Add the VM certificate into the LocalMachine 
        if ((Test-Path Cert:\LocalMachine\Root\$winRMCert) -eq $false) 
        { 
            Write-Progress "VM certificate is not in local machine certificate store - adding it" 
            $certByteArray = [System.Convert]::fromBase64String($AzureX509cert.Data) 
            $CertToImport = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$certByteArray) 
            $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine" 
            $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) 
            $store.Add($CertToImport) 
            $store.Close() 
        } 
    }             
    
    # Build the connection URI with the WinRM port configured on the VM          
    $uri = 'https://trial-brisebois.cloudapp.net:5986/'
    
    # Get the VM Admin Credentials                         
    $admin = Get-AutomationPSCredential -Name 'Brisebois'             
                             
    # Run a command on the Azure VM 
    InlineScript {         
        Invoke-command -ConnectionUri $Using:uri -credential $Using:admin -ScriptBlock { 
           
            # This script executes on the remote VM
            New-Item c:\trial-brisebois.txt -type file
        
        } 
    }         
}

Resources

5 responses to Azure Automation, Remote PowerShell And a Virtual Machine

  1. 

    Very nice and useful it helped me alot

    Like

  2. 

    Very nice and useful, it helped me a lot. Please add a ` at the end of line 17 and it run fine!
    Thanks!

    Like

  3. 

    Hi guys… How can we implement this on AzureRM vms?

    Like

Trackbacks and Pingbacks:

  1. Build it, Use it, Destroy it! « Alexandre Brisebois ☁ - October 17, 2015

    […] with PowerShell to provision a new Windows Virtual Machine and use Remote PowerShell to bring it to a desired […]

    Like

  2. Deploying Nano Server to Microsoft Azure « Alexandre Brisebois ☁ - February 19, 2016

    […] a previous blog post about using remote PowerShell on Azure I demonstrated how to execute PowerShell on a distant Virtual Machine (VM) from Azure Automation. […]

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.