Mund
Mund

Reputation: 157

Invoke-AzVMRunCommand log output, error handling

Once we run command "Invoke-AzVMRunCommand" to execute a PS script on a remote VM, it always succeeds even it actually fails. I know remote VM has the log file there:

"C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandWindows\1.1.3\Status"

The problem:

But how to retrieve the error on a local powershell, try-catch etc. does not show it. What is a proper error handling using "Invoke-AzVMRunCommand", ideally getting results in .txt, something like:

| Out-File -Filepath xxx.txt

thank you.

Upvotes: 1

Views: 3892

Answers (2)

Luke
Luke

Reputation: 16

As this is one of the top results I got when looking for this question, I thought I would add some extra information on how to get the output of jobs when using the -AsJob parameter with Invoke-AzVMRunCommand (often used for parallelism or status tracking.)

When you use -AsJob with Invoke-AzVMRunCommand, it creates a PowerShell job object to track the status of the task. You can then use Get-Job to retrieve the job information. However, the 'output' of the task does not appear in those results. You need to pass the job's object over to the Receive-Job cmdlet to get the output information. This cmdlet returns more information and has a 'Values' property which contains at least two (by my observation) items. The index of [0] which contains the standard output stream message, and the index of [1] which contains the standard error output stream message.

So all together, it would look something like this:

$VM = Get-AzVM -Name 'SomeVM'

Invoke-AzVMRunCommand -AsJob -VM $VM -CommandId 'RunPowerShellScript' -ScriptPath ".\MyScript.ps1"

#Use whatever method you want for waiting - a loop to check the job status or a delay (when using -AsJob, Invoke-AzRunCommand is asynchronous)

#Recevives the standard output stream for all jobs
(Get-Job -IncludeChildJob | Receive-Job -Keep).Value[0].Message

#Recevives the standard error stream for all jobs
(Get-Job -IncludeChildJob | Receive-Job -Keep).Value[1].Message

You could specify the job name or ID if you want a particular job.

Note that once you perform 'Receive-Job' on a job object, its results are cleared from memory so store them in a variable if you wish to re-use them.

Also note that 'Invoke-AzVMRunCommand' works similarly to 'Invoke-Command' - however with Invoke-Command, the 'Output' property does contain some of the output information from the task. You can use Receive-Job to get the individual output streams as well.

Edit: the behaviour seems odd but if you run Receive-Job even once for a specific job it seems to clear the results for all jobs. I have added the -Keep switch in in the example for this.

Upvotes: 0

Mund
Mund

Reputation: 157

Eventually after long testing, I end up with this solution, which throws an error from remote script execution and logs it in .txt file:

$result = Invoke-AzVMRunCommand -ErrorAction Stop -ResourceGroupName "MyRg" -Name "MyVM" -CommandId 'RunPowerShellScript' -ScriptPath MyScript.ps1
Remove-Item -path script.ps1 

if ($result.value.Message -like '*error*') 
{  

    Write-Output "Failed. An error occurred: `n $($result.value.Message)" | Out-File -Filepath C:\OutputLog.txt -Append
    throw $($result.value.Message)        
}
else
{
    Write-Output "Success" | Out-File -Filepath C:\OutputLog.txt -Append
} 

Upvotes: 3

Related Questions