Azure CLI run-command invoke RunPowerShellScript with parameters - azure

I've been trying to run a script on an Azure VM that requires parameters passed to it like so;
az vm run-command invoke -g <resource group> -n <vm name> --command-id RunPowerShellScript --scripts "#....\Desktop\write-host.ps1" --parameters First Second
I have done this succesfully using the AzureRM modules in the following way;
Invoke-AzureRmVMRunCommand -ResourceGroupName <resource group> -VMName <vm name> -CommandId "RunPowerShellScript" -ScriptPath "....\Desktop\write-host.ps1" -Parameter #{ "first" = "First"; "second" = "Second; }
The write-host.ps1 script is very simple and is as follows;
param(
[string]
$first,
[string]
$second
)
Write-Host "$first and $second"
I cannot get the Azure CLI command to find the parameters. I've tried reading the documentation here, I've tried passing it in in a whole manner of different ways, some of which involve;
--parameters [first=]First [second=]Second
--parameters "[first=]First [second=]Second"
--parameters "`"First`" `"Second`""
--parameters #{"First" = "first"; "second" = "Second"}
The only time I can get it to semi work is when I pass in the variables like follows;
--parameters "`First`" `"Second`" `"Third`""
--parameters "First Second Third"
In which case it only prints out "Second and Third", it seems to ignore "First"
I want to execute these in a PowerShell script using AzureCLI commands but I've failed to execute it both in a Command window and in PowerShell.
Is any one able to tell me how to successfully pass in parameters, named or otherwise, into a PowerShell script using the AzureCLI run-command command?

in this case using the second suggested notation worked:
--parameters first=xxx second=yyy
although according to the docs both ways should be fine

Related

Executing Powershell script on Remote VM on Azure with Parameters

I have a simple script such that
Param(
[string] $test
)
Write-Output "Hello $test"
and when I run it from my pipeline, this is the command I am running:
az vm run-command invoke --command-id RunPowerShellScript --name my-vm-win -g myRG --scripts "C:\test.ps1" --parameters test=Peter
My output:
{
"code": "ComponentStatus/StdOut/succeeded",
"displayStatus": "Provisioning succeeded",
"level": "Info",
"message": "Hello \n",
"time": null
}
Clearly, I am not able to pass the parameter test and this is stopping me from going forward. I have tried the suggestion in this question as you can see but it is not working.
I have reproduced in my environment and I have got expected results as below and I followed Microsoft-Document:
In VM i have stored this ps1 file:
test.ps1 :
param(
[string]$arg1,
[string]$arg2
)
Write-Host This is a sample script with parameters $arg1 and $arg2
Now run the below command:
az vm run-command invoke --command-id RunPowerShellScript --name "vm-name" -g "resourcegrp-name" --scripts "C:\test.ps1 rithwik bojja"
Output:
Here in scripts parameter give the string you want to pass as an argument as I did and you will get output as I got.
[Here rithwik in command is argument 1 and bojja is the argument 2.]

How to filter resources using more than one tag using azure CLI?

I can able to get the resource details by using the tag using the Azure CLI command
az resource list --tag AppID=XXXX --query [].name
However, how can filter resources use more than one tag? Could you please help?
Example:
az resource list --tag AppID=XXXX, Region=DEV --query [].name
Based on the above requirement we have created a script using both Azure CLI cmdlets & PowerShell cmdlet to filter the resources using more than one Tag.
Script using PowerShell Cmdlet:
connect-azaccount
$resource = Get-AzResource -ResourceGroupName <resourcegroupName> -TagName env -TagValue prod |Select-Object -Property ResourceId
$resourcearray=$resource
foreach ( $resource in $resourcearray){
$Tagvalue=(Get-AzTag -ResourceId $resource.ResourceId)
if ($Tagvalue.Properties.TagsProperty.Count -gt 1)
{
$Tagvalue.Id -replace "/providers/Microsoft.Resources/tags/default",""
}
}
Here is the output for reference :
Script using Azure CLI cmdlets:
$re= az resource list --tag env=prod
$rearray = $re |ConvertFrom-Json
foreach ( $re in $rearray)
{
$tagcount=$(az tag list --resource-id $re.id --query "properties.tags|length(#)")
if ($tagcount -ge 1)
{
$re.id
}
Here is the output for reference :

OS Type Conflict running Azure CLI command from PowerShell

I am running an Azure CLI command in a Windows 10 Professional PowerShell script and I receive this error:
(Conflict) Run command OS type 'Windows' does not match the target OS Linux.
PowerShell version:
Major Minor Build Revision
----- ----- ----- --------
5 1 19041 1237
The failing PowerShell script:
$ResourceGroup= "Development"
$VmName = "ubuntu-test"
az vm run-command invoke `
--resource-group $ResourceGroup `
--name $VmName `
--command-id RunPowerShellScript `
--scripts "ufw disable"
Note: The ` character is the backtick. The one on the same key as the tilde ~
The same command without line continuation backticks works:
az vm run-command invoke --resource-group Development --name ubuntu-test --command-id RunShellScript --scripts "ufw disable"
If I do a Write-Host the output is a single line with the correct arguments minus the quotes around the --script command.
Write-Host az vm run-command invoke `
--resource-group $ResourceGroup `
--name $VmName `
--command-id RunPowerShellScript `
--scripts "ufw disable"
az vm run-command invoke --resource-group Development --name ubuntu-test --command-id RunPowerShellScript --scripts ufw disable
The documentation for the AZ CLI invoke command mentions nothing about setting the OS Type.
az VM run-command invoke
I think the use of line-continuations (` at the very end of lines) is incidental to your problem.
Apart from the use of variables vs. literals, the crucial difference between your multi-line command and your working single-line command is:
--command-id RunPowerShellScript vs. --command-id RunShellScript.
It looks like the VM you're targeting is a Linux machine, and that --command-id RunPowerShellScript isn't supported there, whereas --command-id RunShellScript is.
az vm run-command list ... can apparently be used to discover supported --command-id values.

Run statement with multiple lines in azure cli

I am new to ARM templates and Azure CLI
This may seem a really stupid question, but I am using the tutorial here
It contains the following command
templateFile="my template file"
az deployment group create \
--name blanktemplate \
--resource-group myResourceGroup \
--template-file $templateFile
I am running Azure Cli via a command prompt
How can I run this? As there are multiple lines
Paul
Replace the backslashs ( \ ) with backticks ( ` ) at the end of each line and you should be able to run it. Your sample code with the backticks:
templateFile="my template file" `
az deployment group create `
--name blanktemplate `
--resource-group myResourceGroup `
--template-file $templateFile
for example, the following code will execute in the cloud shell if you just copy paste
Write-Host `
Hello, `
World!
There's another way. You can create a temporary PowerShell script file in cloud shell. Paste all the commands there as necessary and run the script file from the cloud shell.

Azure CLI how to check if a resource exists

I'm starting to write a bash script to provision a VM in a new or existing resource group so that we can enforce naming convention and configuration.
In a bash script how can I check that a resource already exists so I don't try to create it again?
# 1. If a new resource group is desired, create it now. Microsoft Docs
az group create --name $RESOURCEGROUPNAME --location $LOCATION
# 2. Create a virtual network and subnet if one has not already been created. Microsoft Docs
# Consider a separate VNet for each resource group.
# az network vnet list -output table
az network vnet create \
--resource-group $RESOURCEGROUPNAME \
--name $RESOURCEGROUPNAME-vnet \
--address-prefix 10.0.x.0/24 \
--subnet-name default \
--subnet-prefix 10.0.x.0/24
# x is the next available 3rd octet value
# 3. Create a public IP Address. Microsoft Docs
az network public-ip create \
--resource-group $RESOURCEGROUPNAME \
--name $VMNAME-ip \
--dns-name $DNSNAME
# 4. Create a network security group. Microsoft Docs
az network nsg create \
--resource-group $RESOURCEGROUPNAME \
--name $VMNAME-nsg
# 5. Create a rule to allow SSH to the machine. Microsoft Docs
az network nsg rule create \
--resource-group $RESOURCEGROUPNAME \
--nsg-name $VMNAME-nsg \
--name allow-ssh \
--protocol tcp \
--priority 1000 \
--destination-port-range 22 \
--access allow
# 6. Create a virtual NIC. Microsoft Docs
az network nic create \
--resource-group $RESOURCEGROUPNAME \
--name $VMNAME-nic \
--vnet-name $RESOURCEGROUPNAME-vnet \
--subnet default \
--public-ip-address $VMNAME-ip \
--network-security-group $VMNAME-nsg
# 7. Create an availability set, if redundancy is required. Microsoft Docs
az vm availability-set create \
--resource-group $RESOURCEGROUPNAME \
--name $AVSETNAME-as
# 8. Create the VM. Microsoft Docs
az vm create \
--resource-group $RESOURCEGROUPNAME \
--location $LOCATION \
--name $VMNAME \
--image UbuntuLTS \
--size $VMSIZE \
--availability-set $AVSETNAME-as \
--nics $VMNAME-nic \
--admin-username $ADMINUSERNAME \
--authentication-type ssh
--ssh-key-value #$SSHPUBLICKEYFILE \
--os-disk-name $VMNAME-osdisk
This should work in bash script:
if [ $(az group exists --name $RESOURCEGROUPNAME) = false ]; then
az group create --name $RESOURCEGROUPNAME --location $LOCATION
fi
In a bash script how can I check that a resource already exists so I
don't try to create it again?
We can use CLI 2.0 command az group exists to test the resource group exist or not, like this:
C:\Users\user>az group exists -n jasontest
false
In this way, before we create it, we can test the name available or not. In new resource group, we can create new Vnet and other resources.
For now, there is no CLI 2.0 command to test other resource exist or not. If you want to create resource in an existing resource group, maybe we should use CLI 2.0 command to list the resources, and use bash to make sure the resource exist or not.
You can use JMESPath queries to do this. All resource types support this, AFAIK.
For example, for VMs:
az vm list --resource-group $RESOURCEGROUPNAME --query "[?name=='$VMNAME'] | length(#)"
This will output the number of matching VMs - either 1 or 0.
You can use this to create if/else logic in bash as follows.
if [[ $(az vm list --resource-group $RESOURCEGROUPNAME --query "[?name=='$VMNAME'] | length(#)") > 0 ]]
then
echo "VM exists"
else
echo "VM doesn't exist"
fi
If a resource show command returns an empty string and a success status code (0), then the resource does not exist.
Edit: ChrisWue pointed out that this is no longer true. It must have changed since I left the Azure CLI team (it used to be a requirement that all commands worked like this). Or it may be that there is a bug for the key vault commands he mentioned below.
this work for my batch commands
call az webapp show --subscription <yoursubs> --resource-group <yourrg> --name <yourappname> -query name
if %errorlevel% == 1 (
az webapp create ...
)
As mentioned in another answer - there is no generic "exists" command. One line of reasoning I've found was that "create" is meant to be idem potent - therefor if you have a script that creates resources (for example as part of a build pipeline) it doesn't matter how often you execute it since "it will do the right thing".
If you still need to do this you can do it in shell like this (the example is for keyvault but it should work for all resource types that have a show command)
if az keyvault show -n my-keyvault -o none; then
echo "keyvault exists"
else
echo "keyvault doesn't exist"
fi
It should be noted that az will output an error message to stderr if the resource doesn't exists - this doesn't affect the check but if it bothers you then you can redirect stderr to /dev/null
In our case we needed this because we don't run the infra scripts if the setup hasn't changed (cuts our build time in half). We dectect this by creating a hash of the infra-scripts and store it in a keyvault. When the script runs it creates the keyvault (to make sure it exists) and then tries to check the secret that contains the hash. If the hash is still the same then don't run the rest of the script.
Catch is that keyvault create nukes the access policies which also includes the web-app managed identity access policy which won't get added if the rest of the script doesn't run ... so the fix is to check if the keyvault exists first and to not create it if it does.

Resources