How to execute PowerShell scripts inside Azure VMs from external
There are some ways to execute PowerShell scripts inside Azure VMs such like PowerShell remoting. Recently, it comes up cool feature to execute scripts inside Azure VMs easily. This article introduces how to manage that.
Execute PowerShell scripts inside Azure VMs from Azure Portal
Go to Azure Portal and choose an Azure VM among your VMs, so you can find "Run command" menu from left menus. Next, choose "RunPowerShellScript" menu, so you can execute PowerShell scripts like below.
I have already located a text file into "F;\temp\hello.txt" path on Azure VM before executing above scripts to take this screenshot. This means you can manage files inside Azure VMs.
Here is diagram for this scenario. We send HTTP requests as REST API call to VM Agent and the agent execute your PowerShell scripts inside the VM.
Execute PowerShell scripts inside Azure VMs from client machines
You can execute the scripts with PowerShell command named Invoke-AzureRmVMRunCommand. Here is diagram for this scenario.
Follow commands snippet below in your local machine PowerShell ISE to execute your scripts inside VM.
$rgname = 'your vm resource group' $vmname = 'your vm name' $localmachineScript = 'PowerShell script file on your local machine like script-test.ps1' Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname -CommandId 'RunPowerShellScript' -ScriptPath $localmachineScript -Parameter @{"arg1" = "var1";"arg2" = "var2"} -Debug
Confirm your Azure PowerShell module version and authentication if the script doesn't work well.
Execute PowerShell scripts inside Azure VMs from Azure Automation
At first, update Azure Automation modules for your Azure Automation account. Go to your Azure Automation account and choose "Modules" menu from left menu and click "Update Azure Modules" to be latest versions like below.
Next, It's needed to locate your script into downloadable place such like Azure Storage, because we can't locate any files into Azure Automation runtime environment. In this case, I have located a script file into "https://change-your-storage-account-name.blob.core.windows.net/scripts/script-test.ps1" and the content is same with above. Here is diagram for this scenario.
Finally, create a Runbook for the script like below and execute it. This need to authenticate to Azure AD.
$connection = Get-AutomationConnection -Name "AzureRunAsConnection" Write-Output $connection Add-AzureRMAccount -ServicePrincipal -Tenant $connection.TenantID -ApplicationId $connection.ApplicationID -CertificateThumbprint $connection.CertificateThumbprint $rgname = 'your vm resource group' $vmname = 'your vm name' $localmachineScript = 'PowerShell script file on your local machine like script-test.ps1' wget "https://automationbackupstorage.blob.core.windows.net/scripts/$localmachineScript" -outfile $localmachineScript Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname -CommandId 'RunPowerShellScript' -ScriptPath $localmachineScript -Parameter @{"arg1" = "var1";"arg2" = "var2"} -Debug
How to handle exceptions for the scripts inside Azure VMs
It's needed to handle errors when you will integrate this scripts execution into your workflow. I have updated 'script-test.ps1' script like below,
cd F:\temp type hello.txt throw "Error trying to do a task @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
Here is a result of the script execution.
PS D:\temp> $rgname = 'your vm resource group' $vmname = 'your vm name' $localmachineScript = 'script-test.ps1' $result = Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname -CommandId 'RunPowerShellScript' -ScriptPath $localmachineScript -Parameter @{"arg1" = "var1";"arg2" = "var2"} -Debug DEBUG: 6:28:11 PM - InvokeAzureRmVMRunCommand begin processing with ParameterSet 'DefaultParameter'. ... DEBUG: ============================ HTTP REQUEST ============================ HTTP Method: POST Absolute Uri: ... Headers: x-ms-client-request-id : f0edfe29-5abf-4d7f-9d83-8c98b3e59891 accept-language : en-US Body: { "commandId": "RunPowerShellScript", "script": [ "cd F:\\temp", "type hello.txt", "throw \"Error trying to do a task @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\"" ], "parameters": [ { "name": "arg1", "value": "var1" }, { "name": "arg2", "value": "var2" } ] } DEBUG: ============================ HTTP RESPONSE ============================ Status Code: OK ... Body: { "startTime": "2018-06-26T18:28:14.5508701-07:00", "endTime": "2018-06-26T18:28:36.3646186-07:00", "status": "Failed", "error": { "code": "VMExtensionProvisioningError", "message": "VM has reported a failure when processing extension 'RunCommandWindows'. Error message: \"Finished executing command\"." }, "name": "bc901040-54ad-4ff1-a8ee-c9794b7a34cb" } DEBUG: AzureQoSEvent: CommandName - Invoke-AzureRmVMRunCommand; IsSuccess - True; Duration - 00:00:33.0677753; Exception - ; DEBUG: Finish sending metric. DEBUG: 6:28:45 PM - InvokeAzureRmVMRunCommand end processing. DEBUG: 6:28:45 PM - InvokeAzureRmVMRunCommand end processing. Invoke-AzureRmVMRunCommand : Long running operation failed with status 'Failed'. Additional Info:'VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command".' ErrorCode: VMExtensionProvisioningError ErrorMessage: VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command". StartTime: 6/26/2018 6:28:14 PM EndTime: 6/26/2018 6:28:36 PM OperationID: bc901040-54ad-4ff1-a8ee-c9794b7a34cb Status: Failed At line:1 char:1 + Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname - ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Invoke-AzureRmVMRunCommand], ComputeCloudException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.Automation.InvokeAzureRmVMRunCommand DEBUG: AzureQoSEvent: CommandName - Invoke-AzureRmVMRunCommand; IsSuccess - False; Duration - 00:00:33.0677753; Exception - Microsoft.Azure.Commands.Compute.Common.ComputeCloudException: Long running operation failed with status 'Failed'. Additional Info:'VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command".' ErrorCode: VMExtensionProvisioningError ErrorMessage: VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command". StartTime: 6/26/2018 6:28:14 PM EndTime: 6/26/2018 6:28:36 PM OperationID: bc901040-54ad-4ff1-a8ee-c9794b7a34cb Status: Failed ---> Microsoft.Rest.Azure.CloudException: Long running operation failed with status 'Failed'. Additional Info:'VM has reported a failure when processing extension 'RunCommandWi ndows'. Error message: "Finished executing command".' at Microsoft.Rest.ClientRuntime.Azure.LRO.AzureLRO`2.CheckForErrors() at Microsoft.Rest.ClientRuntime.Azure.LRO.AzureLRO`2.<StartPollingAsync>d__17.MoveNext() ... --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Azure.Management.Compute.VirtualMachinesOperationsExtensions.RunCommand(IVirtualMachinesOperations operations, String resourceGroupName, String vmName, RunCommandInput paramet ers) at Microsoft.Azure.Commands.Compute.Automation.InvokeAzureRmVMRunCommand.<ExecuteCmdlet>b__0_0() at Microsoft.Azure.Commands.Compute.ComputeClientBaseCmdlet.ExecuteClientAction(Action action) --- End of inner exception stack trace --- at Microsoft.Azure.Commands.Compute.ComputeClientBaseCmdlet.ExecuteClientAction(Action action) at Microsoft.WindowsAzure.Commands.Utilities.Common.AzurePSCmdlet.ProcessRecord(); DEBUG: Finish sending metric. DEBUG: 6:28:47 PM - InvokeAzureRmVMRunCommand end processing. DEBUG: 6:28:47 PM - InvokeAzureRmVMRunCommand end processing. PS D:\temp> $result
It seems to be difficult to handle the errors, because there are no contents including message of "Error trying to do a task @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@". In this case, -ErrorVariable option should be useful. Update the script again and execute it like below.
PS D:\temp> $rgname = 'your vm resource group' $vmname = 'your vm name' $localmachineScript = 'script-test.ps1' Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname -CommandId 'RunPowerShellScript' -ScriptPath $localmachineScript -Parameter @{"arg1" = "var1";"arg2" = "var2"} -ErrorVariable result echo "=============================" $result.Count echo "=============================" $result echo "=============================" $result[1] Invoke-AzureRmVMRunCommand : Long running operation failed with status 'Failed'. Additional Info:'VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command".' ErrorCode: VMExtensionProvisioningError ErrorMessage: VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command". StartTime: 6/26/2018 6:35:02 PM EndTime: 6/26/2018 6:35:17 PM OperationID: 2ea46d42-2523-4f23-9135-9a595f62f656 Status: Failed At line:1 char:1 + Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname - ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Invoke-AzureRmVMRunCommand], ComputeCloudException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.Automation.InvokeAzureRmVMRunCommand ============================= 1 ============================= Invoke-AzureRmVMRunCommand : Long running operation failed with status 'Failed'. Additional Info:'VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command".' ErrorCode: VMExtensionProvisioningError ErrorMessage: VM has reported a failure when processing extension 'RunCommandWindows'. Error message: "Finished executing command". StartTime: 6/26/2018 6:35:02 PM EndTime: 6/26/2018 6:35:17 PM OperationID: 2ea46d42-2523-4f23-9135-9a595f62f656 Status: Failed At line:1 char:1 + Invoke-AzureRmVMRunCommand -ResourceGroupName $rgname -Name $vmname - ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Invoke-AzureRmVMRunCommand], ComputeCloudException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.Automation.InvokeAzureRmVMRunCommand ============================= PS D:\temp> $result
Unfortunately, we can't take error messages from inside PowerShell scripts but we can find there are errors or not. We should use both Azure Automation logs and logs inside Azure VMs.
References
- https://www.petri.com/execute-scripts-inside-azure-vms-portal
- https://docs.microsoft.com/en-us/azure/virtual-machines/windows/run-command
- https://docs.microsoft.com/en-us/powershell/module/azurerm.compute/invoke-azurermvmruncommand?view=azurermps-6.3.0
- https://blogs.msdn.microsoft.com/powershell/2006/11/02/erroraction-and-errorvariable/