How to run remote PowerShell to Azure VM


This post will demo how to run remote PowerShell to an Azure vm. It’s either can from Azure Automation Portal or from a vm that running in Azure. This includes set up the connection to an Azure VM as well as call a command inside of an Azure API.

Before you get started, you need to make sure to install two modules from Azure Runbook Gallery (Thanks to the System Center Automation Team)
One is Connect-AzureVM, the other is Invoke-PSCommandSample.

Install and publish those two modules, and then run a command like below:

1
2
3
4
5
6
    Invoke-PSCommandSample -AzureSubscriptionName "Visual Studio Premium with MSDN" `
-ServiceName "DEMO" `
-VMName "DC01" `
-VMCredentialName "VMDomainCred" `
-PSCommand "Get-WindowsFeature" `
-AzureOrgIdCredential $Cred

If you cannot find the module, please use the following:

Connect-AzureVM:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<#
.SYNOPSIS
Sets up the connection to an Azure VM

.DESCRIPTION
This runbook sets up a connection to an Azure virtual machine. It requires the Azure virtual machine to
have the Windows Remote Management service enabled, which is the default. It sets up a connection to the Azure
subscription and then imports the certificate used for the Azure VM so remote PowerShell calls can be made to it.

.PARAMETER AzureSubscriptionName
Name of the Azure subscription to connect to

.PARAMETER AzureOrgIdCredential
A credential containing an Org Id username / password with access to this Azure subscription.

If invoking this runbook inline from within another runbook, pass a PSCredential for this parameter.

If starting this runbook using Start-AzureAutomationRunbook, or via the Azure portal UI, pass as a string the
name of an Azure Automation PSCredential asset instead. Azure Automation will automatically grab the asset with
that name and pass it into the runbook.

.PARAMETER ServiceName
Name of the cloud service where the VM is located.

.PARAMETER VMName
Name of the virtual machine that you want to connect to

.EXAMPLE
Connect-AzureVM -AzureSubscriptionName "Visual Studio Ultimate with MSDN" -ServiceName "Finance" -VMName "WebServer01" -AzureOrgIdCredential $cred

.NOTES
AUTHOR: System Center Automation Team
LASTEDIT: Dec 18, 2014
#>
workflow Connect-AzureVM
{
[OutputType([System.Uri])]

Param
(
[parameter(Mandatory=$true)]
[String]
$AzureSubscriptionName,

[parameter(Mandatory=$true)]
[PSCredential]
$AzureOrgIdCredential,

[parameter(Mandatory=$true)]
[String]
$ServiceName,

[parameter(Mandatory=$true)]
[String]
$VMName
)

Add-AzureAccount -Credential $AzureOrgIdCredential | Write-Verbose

# Select the Azure subscription we will be working against
Select-AzureSubscription -SubscriptionName $AzureSubscriptionName | Write-Verbose

InlineScript {
# Get the Azure certificate for remoting into this VM
$winRMCert = (Get-AzureVM -ServiceName $Using:ServiceName -Name $Using:VMName | select -ExpandProperty vm).DefaultWinRMCertificateThumbprint
$AzureX509cert = Get-AzureCertificate -ServiceName $Using:ServiceName -Thumbprint $winRMCert -ThumbprintAlgorithm sha1

# Add the VM certificate into the LocalMachine
if ((Test-Path Cert:LocalMachineRoot$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()
}

# Return the WinRM Uri so that it can be used to connect to this VM
Get-AzureWinRMUri -ServiceName $Using:ServiceName -Name $Using:VMName
}
}

Invoke-PSCommandSample:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<#
.SYNOPSIS
This runbook calls a command inside of an Azure VM

.DESCRIPTION
This runbook connects into an Azure virtual machine and runs the PowerShell command passed in.
It has a dependency on the Connect-AzureVM runbook to set up the connection to the virtual machine
before the command can be run.

.PARAMETER AzureSubscriptionName
Name of the Azure subscription to connect to

.PARAMETER AzureOrgIdCredential
A credential containing an Org Id username / password with access to this Azure subscription.

If invoking this runbook inline from within another runbook, pass a PSCredential for this parameter.

If starting this runbook using Start-AzureAutomationRunbook, or via the Azure portal UI, pass as a string the
name of an Azure Automation PSCredential asset instead. Azure Automation will automatically grab the asset with
that name and pass it into the runbook.

.PARAMETER ServiceName
Name of the cloud service where the VM is located.

.PARAMETER VMName
Name of the virtual machine that you want to connect to

.PARAMETER VMCredentialName
Name of a PowerShell credential asset that is stored in the Automation service.
This credential should have access to the virtual machine.

.PARAMETER PSCommand
PowerShell command that you want to run inside the Azure virtual machine.

.EXAMPLE
Invoke-PSCommandSample -AzureSubscriptionName "Visual Studio Ultimate with MSDN" -ServiceName "Finance" -VMName "WebServer01" -VMCredentialName "FinanceCredentials" -PSCommand "ipconfig /all" -AzureOrgIdCredential $cred

.NOTES
AUTHOR: System Center Automation Team
LASTEDIT: Aug 14, 2014
#>
Workflow Invoke-PSCommandSample
{
Param
(
[parameter(Mandatory=$true)]
[String]
$AzureSubscriptionName,

[parameter(Mandatory=$true)]
[PSCredential]
$AzureOrgIdCredential,

[parameter(Mandatory=$true)]
[String]
$ServiceName,

[parameter(Mandatory=$true)]
[String]
$VMName,

[parameter(Mandatory=$true)]
[String]
$VMCredentialName,

[parameter(Mandatory=$true)]
[String]
$PSCommand
)

# Get credentials to Azure VM
$Credential = Get-AutomationPSCredential -Name $VMCredentialName
if ($Credential -eq $null)
{
throw "Could not retrieve '$VMCredentialName' credential asset. Check that you created this asset in the Automation service."
}

# Set up Azure connection by calling the Connect-Azure runbook. You should call this runbook after
# every CheckPoint-WorkFlow to ensure that the management certificate is available if this runbook
# gets interrupted and starts from the last checkpoint
$Uri = Connect-AzureVM -AzureSubscriptionName $AzureSubscriptionName -AzureOrgIdCredential $AzureOrgIdCredential -ServiceName $ServiceName -VMName $VMName

# Run a command on the Azure VM
$PSCommandResult = InlineScript {
Invoke-command -ConnectionUri $Using:Uri -credential $Using:Credential -ScriptBlock {
Invoke-Expression $Args[0]
} -Args $Using:PSCommand

}

$PSCommandResult
}