Check if Azure VM name exists before deploying arm template - azure

I am trying to use Azure powershell to get VM name (Eg: demovm01, where the VM name is demovm and the suffix is 01.
I want to get the output and automatically append a new suffix of 02 if 01 already exists.
Sample script to get vm name:
$getvm = Get-AzVM -Name "$vmname" -ResourceGroupName "eodemofunction" -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent) {
Write-Output "VM not found. Creating now"
}
else {
Write-Output "VM exists."
return $true
}
I want to be able to inject this new vm name to an arm deploy to deploy

This should do it. Will increment until no VM is found and use a simple -replace to inject to your json file. Will also return all thr VM values that are already present in Azure
$i=1
$vmname_base = "vmserver"
$VMexists = #()
do {
#invert int value to double digit string
$int = $i.tostring('00')
$getvm = Get-AzVM -Name "$vmname_base$int" -ResourceGroupName "eodemofunction" -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent) {
Write-Output "VM not found. Creating now"
Write-Output "VM created name is $vmname_base$int"
#Set condition to end do while loop
VMcreated = "true"
#commands to inject to json here. I always find replace method the easiest
$JSON = Get-Content azuredeploy.parameters.json
$JSON = $JSON -replace ("Servername","$vmname_base$int")
$JSON | Out-File azuredeploy.parameters.json -Force
}
else {
Write-Output "VMexists."
# Add existing VM to array
$VMexists += "$vmname_base$int"
# Increment version, ie. 01 to 02 to 03 etc
$i++
}
} while ($VMcreated -ne "true")
return $VMexists

Your command could be like below, the $newvmname is that you want.
$vmname = "demovm01"
$getvm = Get-AzVM -Name "$vmname" -ResourceGroupName "<group name>" -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent) {
Write-Output "VM not found. Creating now"
}
else {
Write-Output "VM exists."
if($getvm.Name -like '*01'){
$newvmname = $vmname.TrimEnd('01')+"02"
}
Write-Output $newvmname
return $true
}

Related

Do we need to dispose azure powershell commands?

We have over 400 app services and we are creating a deployment tool to deploy to all of these instances as soon as possible.
We have 4 projects running in separate app service and each customer need to have all 4 projects up and running so we have distributed the instances by customer name and each instance deploy to 4 app services internally (See the code snippet below)
We've created a powershell function app with queue trigger that is calling azure powershell commands to do the deployment. The deployment steps are:
Create deployment slot
Publish to the deployment slot
Version check (Have an endpoint in all projects which returns assembly version)
Swap slot
Version check again
Delete slot
The steps are straight forward but when I deploy to single instance it runs pretty quickly but when I am trying to deploy to multiple instances (5+) then it starts becoming really slow and eventually stops execution. My assumption is that there is a memory issue. I am using premium (EP1) plan for my function so it shouldn't be that slow.
I am totally new to powershell so the question is do I need to dispose the azure powershell stuff? Or anything else to freed the memory. If yes, how can I call dispose to azure powershell commands?
Update
Adding the code snippets.
Some more context:
So the run.ps1 file has the code that downloads the ps1 script file from blob storage and dynamically executes it:
run.ps1
# Input bindings are passed in via param block.
param($QueueItem, $TriggerMetadata)
# Write out the queue message and insertion time to the information log.
Write-Host "PowerShell queue trigger function processed work item: $QueueItem"
Write-Host "Queue item insertion time: $($TriggerMetadata.InsertionTime)"
$currentContext = Get-AzContext -ListAvailable | Where-Object {$_.Name -contains 'Subscriptionname'}
$storageAccount = Get-AzStorageAccount -ResourceGroupName "<ResourceGroup>" -Name "<ResourceName>" -DefaultProfile $currentContext
$Context = $storageAccount.Context
$queue = Get-AzStorageQueue -Name logs -Context $Context
function Log {
param (
[string]$message, [string]$isDetailed, [string]$hasError = "false"
)
$jsonMessge = #"
{
"InstanceId": "$instanceId",
"TaskId": "$taskId",
"Note": "$message",
"IsDetailed": $isDetailed,
"HasError": $hasError
}
"#
# Create a new message using a constructor of the CloudQueueMessage class
$queueMessage = [Microsoft.Azure.Storage.Queue.CloudQueueMessage]::new($jsonMessge)
# # Add a new message to the queue
$queue.CloudQueue.AddMessageAsync($queueMessage)
}
try {
#Extracting data from Queue message
$queueMessage = $QueueItem
$instanceId = $queueMessage.instanceId
$taskId = $queueMessage.taskId
$siteName = $queueMessage.siteName
$buildNo = $queueMessage.buildNo
$pass = $queueMessage.password
$dbPassword = convertto-securestring "$pass" -asplaintext -force
$servicePlanName = $queueMessage.servicePlanName
$subscription = $queueMessage.subscription
$key = $queueMessage.key
$rg = $queueMessage.resourceGroup
$sqlServerName = $queueMessage.sqlServerName
Log -message "Deployment started for $($siteName)" -isDetailed "false"
$tempFolder = $env:temp
# $artifactFolderPath = "$($tempFolder)\$($siteName)\$($buildNo)"
#$artifactFilePath = "$($tempFolder)\$($siteName)\$($buildNo).zip"
$tempDownloadPath = "$($tempFolder)\$($siteName)"
$scriptFileName = "DeployScripts.ps1"
if (Test-Path $tempDownloadPath) {
Remove-Item $tempDownloadPath -Force -Recurse
}
$storageAccount = Get-AzStorageAccount -ResourceGroupName "KineticNorthEurope" -Name "KineticDeployment" -DefaultProfile $currentContext
New-Item -Path $tempFolder -Name $siteName -ItemType "directory"
$Context = $storageAccount.Context
$blobContent = #{
Blob = "DeployScripts.ps1"
Container = 'builds'
Destination = "$($tempDownloadPath)\$($scriptFileName)"
Context = $Context
}
Get-AzStorageBlobContent #blobContent -DefaultProfile $currentContext
#[System.IO.Compression.ZipFile]::ExtractToDirectory($artifactFilePath, $artifactFolderPath)
$arguments = "-rg $rg -site $siteName -buildNo $buildNo -dbPassword `$dbPassword -instanceId $instanceId -taskId $taskId -sqlServerName $sqlServerName -subscription $subscription"
$path = "$($tempDownloadPath)\$($scriptFileName)"
Unblock-File -Path $path
"$path $ScriptFilePath $arguments" | Invoke-Expression
if (Test-Path $tempDownloadPath) {
Remove-Item $tempDownloadPath -Force -Recurse
}
Log -message "Resources cleaned up" -isDetailed "false"
}
catch {
Log -message $_.Exception.message -isDetailed "false" -hasError "true"
if (Test-Path $tempDownloadPath) {
Remove-Item $tempDownloadPath -Force -Recurse
}
}
And here is the actual DeployScripts.ps1 file:
param($rg, $site, $buildNo, [SecureString] $dbPassword, $instanceId, $taskId, $sqlServerName, $subscription)
$siteNameWeb = "${site}"
$siteNamePortal = "${site}Portal"
$siteNamePortalService = "${site}PortalService"
$siteNameSyncService = "${site}SyncService"
$kineticNorthContext = Get-AzContext -ListAvailable | Where-Object {$_.Name -contains 'SubscriptionName'}
$storageAccount = Get-AzStorageAccount -ResourceGroupName "<ResourceGroup>" -Name "<ResourceName>" -DefaultProfile $kineticNorthContext
$Context = $storageAccount.Context
$queue = Get-AzStorageQueue -Name logs -Context $Context
Set-AzContext -SubscriptionName $subscription
Function CreateDeploymentSlots() {
Log -message "Creating deployment slots" -isDetailed "false"
Log -message "Creating deployment slot for web" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNameWeb -slot develop
Log -message "Creating deployment slot for portal" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNamePortal -slot develop
Log -message "Creating deployment slot for portal service" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNamePortalService -slot develop
Log -message "Creating deployment slot for sync service" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNameSyncService -slot develop
Log -message "Deployment slots created" -isDetailed "false"
}
Function DeleteDeploymentSlots() {
Log -message "Deleting deployment slots" -isDetailed "false"
Log -message "Deleting slot web" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNameWeb -Slot "develop"
Log -message "Deleting slot portal" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNamePortal -Slot "develop"
Log -message "Deleting slot portal service" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNamePortalService -Slot "develop"
Log -message "Deleting slot sync service" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNameSyncService -Slot "develop"
Log -message "Slots deployment deleted" -isDetailed "false"
}
Function SwapDeploymentSlots {
Log -message "Switching deployment slots" -isDetailed "false"
Log -message "Switch slot web" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNameWeb
Log -message "Switch slot portal" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNamePortal
Log -message "Switch slot portal service" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNamePortalService
Log -message "Switch slot sync service" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNameSyncService
Log -message "Deployment slots switched" -isDetailed "false"
}
function Log {
param (
[string]$message, [string]$isDetailed, [string]$isDeployed = "false", [string]$hasError = "false"
)
$jsonMessge = #"
{
"InstanceId": "$instanceId",
"TaskId": "$taskId",
"Note": "$message",
"IsDetailed": $isDetailed,
"IsDeployed": $isDeployed,
"HasError": $hasError
}
"#
# Create a new message using a constructor of the CloudQueueMessage class
$queueMessage = [Microsoft.Azure.Storage.Queue.CloudQueueMessage]::new($jsonMessge)
# # Add a new message to the queue
$queue.CloudQueue.AddMessageAsync($queueMessage)
}
function VersionCheckWeb() {
$tls = Invoke-WebRequest -URI "https://${site}.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortal() {
$tls = Invoke-WebRequest -URI "https://${site}portal.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortalService() {
$tls = Invoke-WebRequest -URI "https://${site}portalservice.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckSyncService() {
$tls = Invoke-WebRequest -URI "https://${site}syncservice.net/SyncService.svc/Info" -UseBasicParsing
$tls = $tls -replace '[?]', ""
$content = "$tls" | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheck() {
$versionCheckWeb = VersionCheckWeb
$versionCheckPortal = VersionCheckPortal
$versionCheckPortalService = VersionCheckPortalService
$versionCheckSyncService = VersionCheckSyncService
if (($versionCheckWeb -eq "True") -and ($versionCheckPortal -eq "True") -and ($versionCheckPortalService -eq "True") -and ($versionCheckSyncService -eq "True")) {
Log -message "Version correct" -isDetailed "false"
}
else {
Log -message "Version check failed, exception not thrown" -isDetailed "false"
}
}
function VersionCheckWebSlot() {
$tls = Invoke-WebRequest -URI "https://${site}-develop.azurewebsites.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortalSlot() {
$tls = Invoke-WebRequest -URI "https://${site}portal-develop.azurewebsites.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortalServiceSlot() {
$tls = Invoke-WebRequest -URI "https://${site}portalservice-develop.azurewebsites.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckSyncServiceSlot() {
$tls = Invoke-WebRequest -URI "https://${site}syncservice-develop.azurewebsites.net/SyncService.svc/Info" -UseBasicParsing
$tls = $tls -replace '[?]', ""
$content = "$tls" | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckSlot() {
$versionCheckWeb = VersionCheckWebSlot
$versionCheckPortal = VersionCheckPortalSlot
$versionCheckPortalService = VersionCheckPortalServiceSlot
$versionCheckSyncService = VersionCheckSyncServiceSlot
if (($versionCheckWeb -eq "True") -and ($versionCheckPortal -eq "True") -and ($versionCheckPortalService -eq "True") -and ($versionCheckSyncService -eq "True")) {
Log -message "Slot version correct" -isDetailed "false"
}
else {
Log -message "Slot version check failed, exception not thrown" -isDetailed "false"
}
}
function PublishToAzure() {
$webPublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNameWeb
$webXml = $webPublishProfile -as [Xml]
$webUserName = $webXml.publishData.publishProfile[0].userName
$webUserPwd = $webXml.publishData.publishProfile[0].userPWD
$webpair = "$($webUserName):$($webUserPwd)"
$webencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($webpair))
$webauthHeader = "Basic $webencodedCreds"
$webHeaders = #{
Authorization = $webauthHeader
}
$portalPublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNamePortal
$portalXml = $portalPublishProfile -as [Xml]
$portalUserName = $portalXml.publishData.publishProfile[0].userName
$portalUserPwd = $portalXml.publishData.publishProfile[0].userPWD
$portalpair = "$($portalUserName):$($portalUserPwd)"
$portalencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($portalpair))
$portalauthHeader = "Basic $portalencodedCreds"
$portalHeaders = #{
Authorization = $portalauthHeader
}
$portalServicePublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNamePortalService
$portalServiceXml = $portalServicePublishProfile -as [Xml]
$portalServiceUserName = $portalServiceXml.publishData.publishProfile[0].userName
$portalServiceUserPwd = $portalServiceXml.publishData.publishProfile[0].userPWD
$portalServicepair = "$($portalServiceUserName):$($portalServiceUserPwd)"
$portalServiceencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($portalServicepair))
$portalServiceauthHeader = "Basic $portalServiceencodedCreds"
$portalServiceHeaders = #{
Authorization = $portalServiceauthHeader
}
$syncServicePublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNameSyncService
$syncServiceXml = $syncServicePublishProfile -as [Xml]
$syncServiceUserName = $syncServiceXml.publishData.publishProfile[0].userName
$syncServiceUserPwd = $syncServiceXml.publishData.publishProfile[0].userPWD
$syncServicepair = "$($syncServiceUserName):$($syncServiceUserPwd)"
$syncServiceencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($syncServicepair))
$syncServiceauthHeader = "Basic $syncServiceencodedCreds"
$syncServiceHeaders = #{
Authorization = $syncServiceauthHeader
}
$bodyWeb = '{"packageUri": "<blobUrl>"}'
$bodyPortal = '{"packageUri": "blobUrl"}'
$bodyPortalService = '{"packageUri": "blobUrl"}'
$bodySyncService = '{"packageUri": "blobUrl"}'
$web = Invoke-RestMethod -URI "https://${siteNameWeb}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodyWeb -Headers $webHeaders -ContentType "application/json"
Log -message "Published to Web" -isDetailed "false"
$portal = Invoke-RestMethod -URI "https://${siteNamePortal}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodyPortal -Headers $portalHeaders -ContentType "application/json"
Log -message "Published to Portal" -isDetailed "false"
$portalService = Invoke-RestMethod -URI "https://${siteNamePortalService}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodyPortalService -Headers $portalServiceHeaders -ContentType "application/json"
Log -message "Published to PortalService" -isDetailed "false"
$syncService = Invoke-RestMethod -URI "https://${siteNameSyncService}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodySyncService -Headers $syncServiceHeaders -ContentType "application/json"
Log -message "Published to SyncService" -isDetailed "false"
}
try {
CreateDeploymentSlots
PublishToAzure
VersionCheckSlot
SwapDeploymentSlots
VersionCheck
DeleteDeploymentSlots
Log -message "Instance deployed successfully" -isDetailed "false" -isDeployed "true"
}
catch {
Log -message $_.Exception.message -isDetailed "false" -hasError "true"
}
I know the code is little mess right now and that's because I've changed the implementation to faster the process but no major luck.
Question2
I actually have another question as well. We've multiple subscriptions and appservices are distributed accordingly. So when function app tries to deploy to a instance exists in another subscription, it throws error. I'm setting AzContext before starting the processing and it seems to be working fine. But i also have to put message into a queue after each step and the queue exists in a storage account that belongs to same subscription as of the function app. Currently i'm getting the AzContent and passing it as -DefaultProfile while getting the storage account. Is there a better way to handle this?
Also I am writing powershell for the first time so any suggestion would be appreciated. Thanks.

Starting azure VM in parallel and validate after in PowerShell

Context : I am automating starting of 3 Azure VM through a PowerShell script, and each VM is taking 4-5min to start. I want to run the start command parallel and after 5-6min verify them whether they are started.
function restartLoadAgents ($AzuresecretValue,$AzureApplicationID,$AzureObjectID,$AzureDirectoryID,$AzureUserName,$AzureSubscriptionID) {
$password = ConvertTo-SecureString $AzuresecretValue -AsPlainText -Force;
$LoadAgentResourceGroup = "test-performance-rg01";
#Connecting to the Azure VM using the Service Principle
$pscredential = New-Object -TypeName System.Management.Automation.PSCredential($AzureApplicationID, $password);
Connect-AzAccount -ServicePrincipal -Tenant $AzureDirectoryID -Credential $pscredential | Out-null;
#List all the Load Agents
$VMList = Get-AzVm -ResourceGroupName $LoadAgentResourceGroup -Status;
ForEach($VM in $VMList) {
#Skipping the Master Machine and DB machine
if ($VM.Name -eq "test-load-appmachine01" -or $VM.Name -eq "test-load-appmachine02") {
continue;
}
$VMLoadAgentStatus = (Get-AzVm -ResourceGroupName $LoadAgentResourceGroup -Name $VM.Name -status).Statuses
$CurrentLoadAgentRunningStatus = $VMLoadAgentStatus[1].DisplayStatus;
if($CurrentLoadAgentRunningStatus -match "deallocated" -or $CurrentLoadAgentRunningStatus -match "VM deallocated"){
Start-AzVM -ResourceGroupName $LoadAgentResourceGroup -Name $VM.Name | Out-null
commandVerifier;
checkVMStatus($VM.Name);
}
else {
Write-Host $VM.Name " Current State is "$CurrentLoadAgentRunningStatus;
}
}
}
function commandVerifier() {
if ($?){
Write-Host "Successfully Started "$VM.Name;
}
else {
Write-Host "Start Unsuccessful "$VM.Name;
}
}
function checkVMStatus($VM_NAME) {
$VMLoadAgentStatus = (Get-AzVm -ResourceGroupName $LoadAgentResourceGroup -Name $$VM_NAME -status).Statuses
$VMRunningStatusAfterTriggered = $VMLoadAgentStatus[1].DisplayStatus;
if($VMRunningStatusAfterTriggered -eq "running" -or $VMRunningStatusAfterTriggered -eq "VM running"){
Write-Host "Successfully Started VM"
}
else{
Write-Host "Something went with starting VM and current status is"$VMRunningStatusAfterTriggered
}
}
function getServicePrincipleDetails () {
$AzuresecretValue = "<secretValue>";
$AzureApplicationID = "<app_id>";
$AzureObjectID = "<obj_id>";
$AzureDirectoryID = "<dir_id>";
$AzureUserName = "SVCUSER";
$AzureSubscriptionID = "<sub_id>";
restartLoadAgents $AzuresecretValue $AzureApplicationID $AzureObjectID $AzureDirectoryID $AzureUserName $AzureSubscriptionID
}
getServicePrincipleDetails
There are 5 VM in total and first two need not to be stopped or started. test-load-appmachine03,test-load-appmachine04 & test-load-appmachine05 are the target VM and I want to start them parallelly and check after.

How to get the list of azure servers having Auto-Shutdown disabled using PowerShell?

I want to get the list of azure servers having auto-shutdown disabled on them, I have the below script but the issue with the script is that it gets the list of RG's under the Subscription GUID but repeats the output after every loop.
Import-AzureRmContext -Path "$PSScriptRoot\AzureProfile.json"
Select-AzureRmSubscription -SubscriptionId {subscriptionId}
[array]$ResourceGroupArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId
foreach ($resourceGroup in $ResourceGroupArray){
$targetResourceId = (Get-AzureRmVM -ResourceGroupName $resourcegroup.ResourceGroupName -Name $resourceGroup.Name).Id
$shutdownInformation = (Get-AzureRmResource -ResourceGroupName $resourcegroup.ResourceGroupName -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
Write-Host "ID: " $targetResourceId
$shutdownInformation
The output for each VM is displayed in the following format,
What I want is simple, I want the VM name and its status of Auto-shutdown to be displayed on the screen so that its easy for me to find out which all VM have auto-shutdown currently disabled on them.
Any help related to this would be helpful.
You just need to get the microsoft.devtestlab/schedules resource ID using:
/subscriptions/{subscriptionId}/resourceGroups/{rgName}/providers/microsoft.devtestlab/schedules/shutdown-computevm-{vmName}
Then iterate over all your VMs using Get-AzVM, Get the microsoft.devtestlab/schedules resource using Get-AzResource, then output VM name and status into a table using Format-Table.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzVM) {
try {
$shutdownResource = Get-AzResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
To set the context to the correct subscription, we can use Set-AzContext.
The above however is using the latest Az modules. You can do the same using the equivalent AzureRm modules.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzureRmContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzureRmVM) {
try {
$shutdownResource = Get-AzureRmResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
Although I do recommend moving to the Az module since support for AzureRm is ending December 2020. You can read the documentation for more information about this.
The above code should give you an output similar to the following
VMName ShutdownStatus
------ --------------
vm1 Enabled
vm2 Disabled
Update
The Call operator & is used here to run the for loop as a script block. You can read more about this in about_Script_Blocks.
Try something like this to get the auto-shutdown status of all VMs. Instead of trying to get the schedules inside the loop, get all the ones in the subscription and match them based on the VM's full resource Id.
[array]$VMArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId, Id
$ShutdownInformation = (Get-AzureRmResource -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
foreach($vm in $VMArray) {
$ShutdownStatus = "Not Configured"
$Schedule = $ShutdownInformation | Where-Object { $_.targetResourceId -eq $vm.Id } | Select -First 1
if($Schedule -ne $null) {
$ShutdownStatus = $Schedule.status
}
Write-Host $vm.VmId $ShutdownStatus
}

Azure Automation Runbook missing mandatory parameters

I'm trying to set a Tag on all virtual machines in my subscription but I keep getting errors when running the Runbook.
The error is the following:
Get-AzureRmVM : Cannot process command because of one or more missing mandatory parameters: ResourceGroupName. At line:30
Here is my Runbook:
$azureConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
#Authenticate
try {
Clear-Variable -Name params -Force -ErrorAction Ignore
$params = #{
ServicePrincipal = $true
Tenant = $azureConnection.TenantID
ApplicationId = $azureConnection.ApplicationID
CertificateThumbprint = $azureConnection.CertificateThumbprint
}
$null = Add-AzureRmAccount #params
}
catch {
$errorMessage = $_
Throw "Unable to authenticate with error: $errorMessage"
}
# Discovery of all Azure VM's in the current subscription.
$azurevms = Get-AzureRmVM | Select-Object -ExpandProperty Name
Write-Host "Discovering Azure VM's in the following subscription $SubscriptionID Please hold...."
Write-Host "The following VM's have been discovered in subscription $SubscriptionID"
$azurevms
foreach ($azurevm in $azurevms) {
Write-Host "Checking for tag $vmtagname on $azurevm"
$tagRGname = Get-AzureRmVM -Name $azurevm | Select-Object -ExpandProperty ResourceGroupName
$tags = (Get-AzureRmResource -ResourceGroupName $tagRGname -Name $azurevm).Tags
If ($tags.UpdateWindow){
Write-Host "$azurevm already has the tag $vmtagname."
}
else
{
Write-Host "Creating Tag $vmtagname and Value $tagvalue for $azurevm"
$tags.Add($vmtagname,$tagvalue)
Set-AzureRmResource -ResourceGroupName $tagRGname -ResourceName $azurevm -ResourceType Microsoft.Compute/virtualMachines -Tag $tags -Force `
}
}
Write-Host "All tagging is done"
I tried importing the right modules but this doesn't seem to affect the outcome.
Running the same commands in Cloud Shell does work correctly.
I can reproduce your issue, the error was caused by this part Get-AzureRmVM -Name $azurevm, when running this command, the -ResourceGroupName is needed.
You need to use the Az command Get-AzVM -Name $azurevm, it will work.
Running the same commands in Cloud Shell does work correctly.
In Cloud shell, azure essentially uses the new Az module to run your command, you can understand it runs the Enable-AzureRmAlias before the command, you could check that via debug mode.
Get-AzureRmVM -Name joyWindowsVM -debug
To solve your issue completely, I recommend you to use the new Az module, because the AzureRM module was deprecated and will not be updated.
Please follow the steps below.
1.Navigate to your automation account in the portal -> Modules, check if you have imported the modules Az.Accounts, Az.Compute, Az.Resources, if not, go to Browse Gallery -> search and import them.
2.After import successfully, change your script to the one like below, then it should work fine.
$azureConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
#Authenticate
try {
Clear-Variable -Name params -Force -ErrorAction Ignore
$params = #{
ServicePrincipal = $true
Tenant = $azureConnection.TenantID
ApplicationId = $azureConnection.ApplicationID
CertificateThumbprint = $azureConnection.CertificateThumbprint
}
$null = Connect-AzAccount #params
}
catch {
$errorMessage = $_
Throw "Unable to authenticate with error: $errorMessage"
}
# Discovery of all Azure VM's in the current subscription.
$azurevms = Get-AzVM | Select-Object -ExpandProperty Name
Write-Host "Discovering Azure VM's in the following subscription $SubscriptionID Please hold...."
Write-Host "The following VM's have been discovered in subscription $SubscriptionID"
$azurevms
foreach ($azurevm in $azurevms) {
Write-Host "Checking for tag $vmtagname on $azurevm"
$tagRGname = Get-AzVM -Name $azurevm | Select-Object -ExpandProperty ResourceGroupName
$tags = (Get-AzResource -ResourceGroupName $tagRGname -Name $azurevm).Tags
If ($tags.UpdateWindow){
Write-Host "$azurevm already has the tag $vmtagname."
}
else
{
Write-Host "Creating Tag $vmtagname and Value $tagvalue for $azurevm"
$tags.Add($vmtagname,$tagvalue)
Set-AzResource -ResourceGroupName $tagRGname -ResourceName $azurevm -ResourceType Microsoft.Compute/virtualMachines -Tag $tags -Force `
}
}
Write-Host "All tagging is done"

Automate deployment of JSON map

I have a Logic App in Azure which use a Liquid map, to transform JSON content. I am trying to deploy the map using New-AzureRmIntegrationAccountMap commandlet and the Set-AzureRmIntegrationAccountMap commandlet.
I get the following error when calling the Set-AzureRmIntegrationAccountMap commandlet:
Set-AzureRmIntegrationAccountMap : Unable to deserialize the response.
With this script:
Try
{
Write-Host -ForegroundColor Green "Creating $baseName..."
$mapContent = Get-Content -Path $fullName | Out-String
Write-Host -ForegroundColor Cyan "$mapContent"
New-AzureRmIntegrationAccountMap -ResourceGroupName $resourceGroupName -Name $iacName -MapName $baseName -MapDefinition $mapContent -ErrorAction Stop
Write-Host -ForegroundColor Green "Successfully created $baseName"
}
Catch
{
Write-Host -ForegroundColor Red "Error creating $baseName, trying update..."
Set-AzureRmIntegrationAccountMap -ResourceGroupName $resourceGroupName -Name $iacName -MapName $baseName -MapDefinition $mapContent -Force
if ($?) {
Write-Host -ForegroundColor Green "Successfully updated $baseName"
} else {
Write-Host -ForegroundColor Red "Error updating $baseName"
exit 1
}
}
After some searches, the two commandlets accept the MapType parameter, but only one value is allowed (XSLT).
Is there a way to automate the deployment of Liquid maps in an integration account in Azure (powershell, ARM template...) ?
Is there a way to automate the deployment of Liquid maps in an integration account in Azure (powershell, ARM template...) ?
Yes, I could create Liquid map with PowerShell on my side with the following code.
Login-AzureRmAccount
$IntegrationAccountName = "Integration Account name"
$ResouceGroupname = "ResourcegroupName"
$ResourceLocation = "West US" # location
$ResourceName = "liquid name"
$Content = Get-Content -Path "C:\Tom\simple.liquid" | Out-String
Write-Host $Content
$PropertiesObject = #{
mapType = "liquid"
content = "$Content"
contentType = "text/plain"
}
New-AzureRmResource -Location $ResourceLocation -PropertyObject $PropertiesObject -ResourceGroupName $ResouceGroupname -ResourceType Microsoft.Logic/integrationAccounts/maps -ResourceName " $IntegrationAccountName/$ResourceName" -ApiVersion 2016-06-01 -Force
Check it from azure portal.

Resources