Search code examples
azurepowershellazure-automation

Azure Automation Account Powershell runbook exception errors with Azure Snapshots


I am trying to write a script that automatically start or stop Azure VMs in a resource group by finding their tags with the authentication part done by a managed identity. Also, as a VM starts the script will take a snapshot of its OS disk. Everything worked fine until I added everything linked to the snapshot part.

You will find below the entire script that I used :

Param(
[Parameter(Mandatory=$true)]
[Boolean]
$Shutdown,
[Parameter(Mandatory=$true)]
[String]
$ResourceGroup,
[Parameter(Mandatory=$true)]
[String]
$TagName,
[Parameter(Mandatory=$true)]
[String]
$TagValue,
[Parameter(Mandatory=$true)]
[String]
$ManagedIdentityId
) 

$location = 'West Europe'
$datetime = Get-Date -Format "dd-MM-yyyy"

try
{
# Logging into Azure using Managed Identity
    Connect-AzAccount -Identity -AccountId $ManagedIdentityId
}
catch 
{ 
    Write-Error -Message $_.Exception 
    throw $_.Exception 
}
"Getting VMs with appropriate tags"
# We get all azure resources inside a specific resource group having a specific tag (Key and value). After that we apply a filter to get only virtual machines.     
$vms =  Get-AzResource -ResourceGroupName $ResourceGroup -TagName $TagName -TagValue $TagValue | where {$_.ResourceType -like "Microsoft.Compute/virtualMachines"}

# Test if the script has to stop or start these virtual machines that we previously got. This test is based on the parameter Shutdown ( Shutdown == true -> Stop VMs | Shutdown == false -> start VMs) 
foreach ($vm in $vms) {     
    if($Shutdown){
        Write-Output "Stopping $($vm.Name)";     
        Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force;
    }
    else {    
        $snapshotConfig =  New-AzSnapshotConfig -SourceUri $vm.StorageProfile.OsDisk.ManagedDisk.Id -Location $location -CreateOption copy -SkuName Standard_LRS
        $snapshotName = $vm.Name + 'OsDisk_snapshot_' + $datetime"  
        Write-Output "Taking Snapshots of the $($vm.Name) OS disk";
        New-AzSnapshot `
            -SnapshotName $snapshotName `
            -Snapshot $snapshotConfig `
            -ResourceGroupName $ResourceGroup
        Write-Output "Starting $($vm.Name)"; 
        Start-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name;
    }
}

As I try to launch the script I get the following error :

At line:44 char:66 + $snapshotName = $vm.Name + 'OsDisk_snapshot_' + $datetime" + ~ Unexpected token '" Write-Output "' in expression or statement. At line:45 char:23 + Write-Output "Taking Snapshots of the $($vm.Name) OS disk"; + ~~~~~~ Unexpected token 'Taking' in expression or statement. At line:50 char:43 + Write-Output "Starting $($vm.Name)"; + ~~ The string is missing the terminator: ". At line:42 char:10 + else { + ~ Missing closing '}' in statement block or type definition. At line:37 char:23 + foreach ($vm in $vms) { + ~ Missing closing '}' in statement block or type definition.

I don't quite understand these errors as it worked fine (the VMs could start and stop without problem) before I added this block of code :

        $snapshotConfig =  New-AzSnapshotConfig -SourceUri $vm.StorageProfile.OsDisk.ManagedDisk.Id -Location $location -CreateOption copy -SkuName Standard_LRS
        $snapshotName = $vm.Name + 'OsDisk_snapshot_' + $datetime"  
        Write-Output "Taking Snapshots of the $($vm.Name) OS disk";
        New-AzSnapshot `
            -SnapshotName $snapshotName `
            -Snapshot $snapshotConfig `
            -ResourceGroupName $ResourceGroup

Am I missing something here ?

I tried deleting the Write-Output commands but as I did it I got other Exception errors with missing characters of unexpected token for other lines of code that I didn't change so I'm don't really understand.


Solution

  • Error is related to the extra double quotes (") added after $datetime in the provided code.

    Remove the double quote at the end of below line and execute it as shown below.

    $snapshotName = $vm.Name + 'OsDisk_snapshot_' + $datetime 
    

    Modified PS script:

    Param(
    [Parameter(Mandatory=$true)]
    [Boolean]
    $Shutdown,
    [Parameter(Mandatory=$true)]
    [String]
    $ResourceGroup,
    [Parameter(Mandatory=$true)]
    [String]
    $TagName,
    [Parameter(Mandatory=$true)]
    [String]
    $TagValue
    ) 
    
    $location = 'eastus'
    $datetime = Get-Date -Format "dd-MM-yyyy"
         
    $vms =  Get-AzResource -ResourceGroupName $ResourceGroup -TagName $TagName -TagValue $TagValue | where {$_.ResourceType -like "Microsoft.Compute/virtualMachines"}
    
    foreach ($vm in $vms) {     
        if($Shutdown){
            Write-Output "Stopping $($vm.Name)";     
            Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force
        }
        else{    
            $snapshotConfig =  New-AzSnapshotConfig -SourceUri $vm.StorageProfile.OsDisk.ManagedDisk.Id -Location $location -CreateOption copy -SkuName Standard_LRS
            $snapshotName = $vm.Name + 'OsDisk_snapshot_' + $datetime
            Write-Output "Taking Snapshots of the $($vm.Name) OS disk"
            New-AzSnapshot `
                -SnapshotName $snapshotName `
                -Snapshot $snapshotConfig `
                -ResourceGroupName $ResourceGroup
            Write-Output "Starting $($vm.Name)"
            Start-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
        }
    }
    

    Output:

    enter image description here

    Updated code:

    $VMs = Get-AzVM
    foreach ($VM in $VMs)
    {
        [Hashtable]$VMTags = (Get-AzVM -ResourceGroupName $VM.ResourceGroupName -Name  $VM.Name).Tags
        foreach ($hash in $VMTag.GetEnumerator()) {
        if (($hash.Name -eq "Reason") -and ($hash.value -eq "Repro"))
            {
                Write-host "VM with given tags are" $VM.Name
            }
        }
    }
    

    enter image description here