Azure / azure-cli

Azure Command-Line Interface
MIT License
4.03k stars 3.01k forks source link

Customer feedback | az vm run-command invoke with RunPowerShellScript does not fail with Exit 1 #29750

Open dbradish-microsoft opened 3 months ago

dbradish-microsoft commented 3 months ago

This customer suggestion is being moved from MicrosoftDocs 4542. Please route to VM engineering team.

Reference command

az vm run-command invoke

Customer request summary

  1. Show the exit code from my script returned in the json if that's possible.
  2. Allow the command to accept --fail-on-non-zero, to propogate the exit code of az vm run-command-invoke back to me
  3. document some best practice for error handling around az vm run-command invoke with both bash and powershell.**

Feedback

I'm using the following form to run a powershell script on a virtual machine in Azure.

az vm run-command invoke  --command-id RunPowerShellScript --name win-vm -g my-resource-group \
    --scripts @test/bad.ps1 --parameters "arg1=somefoo" "arg2=somebar"

The trouble is, the returned JSON doesn't tell me that my script has exited 1:

param(
    [string]$arg1,
    [string]$arg2
)
Write-Host "[$Env:COMPUTERNAME] This is script should fail with parameters $arg1 and $arg2"
Exit 1

Yields:

{
  "value": [
    {
      "code": "ComponentStatus/StdOut/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "[win-vm] This is script should fail with parameters somefoo and somebar",
      "time": null
    },
    {
      "code": "ComponentStatus/StdErr/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "",
      "time": null
    }
  ]
}

When I throw an exception, I do get some error information in the second value object returned by the CLI:

param(
    [string]$arg1,
    [string]$arg2
)
Write-Host "[$Env:COMPUTERNAME] This is script should fail with parameters $arg1 and $arg2"
# https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-exceptions?view=powershell-5.1#working-with-exceptions
# https://powershellexplained.com/2017-04-07-all-dotnet-exception-list/#systemargumentexception
Write-Error -Exception ([System.ArgumentException]::new("[$Env:COMPUTERNAME] I am not a happy script with parameters $arg1 and $arg2")) -ErrorAction Stop
Exit 1

Yields:

{
  "value": [
    {
      "code": "ComponentStatus/StdOut/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "[win-vm] This is script should fail with parameters somefoo and somebar",
      "time": null
    },
    {
      "code": "ComponentStatus/StdErr/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "C:\\Packages\\Plugins\\Microsoft.CPlat.Core.RunCommandWindows\\1.1.18\\Downloads\\script0.ps1 : [win-vm] I am not a \nhappy script with parameters somefoo and somebar\nAt C:\\Packages\\Plugins\\Microsoft.CPlat.Core.RunCommandWindows\\1.1.18\\Downloads\\script0.ps1:8 char:1\n+ Write-Error -Exception ([System.ArgumentException]::new(\"[$Env:COMPUT ...\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n    + CategoryInfo          : NotSpecified: (:) [Write-Error], ArgumentException\n    + FullyQualifiedErrorId : System.ArgumentException,script0.ps1\n ",
      "time": null
    }
  ]
}

**I think I'm asking for a few things:

šŸ’” It would be nice if I could see the exit code from my script returned in the json if that's possible. šŸ’” What would be super duper is if I could pass --fail-on-non-zero, to propogate the exit code of az vm run-command-invoke back to me šŸ“š I think it would be helpful to document some best practice for error handling around az vm run-command invoke with both bash and powershell.**

I am sure I can cobble something together like checking result.value[1].message.length === 0 && result.value[1].code ==="ComponentStatus/StdOut/succeeded" but it feels fragile.

Here's what I feel I can safely assume:

results="bad.json"
az vm run-command invoke --command-id RunPowerShellScript --name win-vm -g win-rg --scripts @test/bad.ps1 --parameters "arg1=somefoo" "arg2=somebar" > $results
#!/bin/bash
results=$1
if [ ! -f "$results" ]; then
    echo "##[error] could not find $results"
    exit 1
fi

stdout_output=$(cat $results | jq -r '.value[0].message')
stdout_result=$(cat $results | jq -r '.value[0].code')
if [ "$stdout_result" = "ComponentStatus/StdOut/failed" ]; then
    echo "##[error] could not read stdout"
elif [ "$stdout_result" = "ComponentStatus/StdOut/succeeded" ]; then
    if [[ -n $stdout_output ]]; then
        echo $stdout_output
    fi
fi

stderr_output=$(cat $results | jq -r '.value[1].message')
stderr_result=$(cat $results | jq -r '.value[1].code')
if [ "$stderr_result" = "ComponentStatus/StdErr/failed" ]; then
    echo "##[error] could not read stderr"
elif [ "$stderr_result" = "ComponentStatus/StdErr/succeeded" ]; then
    if [[ -n $stderr_output ]]; then
        echo "##[error]$stderr_output"
    fi
fi

Page URL

https://learn.microsoft.com/en-us/cli/azure/vm/run-command?view=azure-cli-latest

Content source URL

https://github.com/MicrosoftDocs/azure-docs-cli/blob/main/latest/docs-ref-autogen/vm/run-command.yml

yonzhan commented 3 months ago

Thank you for opening this issue, we will look into it.

github-actions[bot] commented 3 months ago

Here are some similar issues that might help you. Please check if they can solve your problem.