i am trying to add exception handling in powershell script for azure cloud but try block is not responding when error occurs - azure

#adding wrong parameters for checking the try block
$RGName = "RG1"
$VMName="VM1"
$VMSize="standard_B1ls"
$VirtualMachine = Get-AzVm | Where-Object {$_.ResourceGroupName -eq $RGName } | Where-Object {$_.Name -eq $VMName}
$virtualMachine.HardwareProfile.VmSize = $VMSize
#try block
try{
Update-AzVM -VM $VirtualMachine -ResourceGroupName $RGname
write-host "you are in try block "
}
catch{
write-host "you are in catch block "
}
catch block is not working I need to not print try block write-host is exception occurred instead of print catch write-host

Related

My Powershell script is not explicitly calling for any specific resources but I am getting "ErrorCode: TargetResourceNotFound" error

My Powershell script is not explicitly calling for any specific resources but I am getting "ErrorCode: TargetResourceNotFound" error. I have attached the error in the image. What am I missing?
$subs = Get-AzSubscription | Where-Object {$_.Name -like "*-NonProd"}
foreach ($sub in $subs)
{
Select-AzSubscription -SubscriptionId $sub.Id
$RGs = Get-AzResourceGroup | Where-Object {$_.ResourceGroupName -like "*Infra"}
foreach ($RG in $RGs)
{
$NetworkWatchers = Get-AzNetworkWatcher
$NSGs = (Get-AzNetworkSecurityGroup).Id
foreach ($NSG in $NSGs)
{
foreach ($NetworkWatcher in $NetworkWatchers)
{
$Status = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcherName $NetworkWatcher.Name
ResourceGroupName $RG.ResourceGroupName -TargetResourceId $NSG -Verbose
}
if (($Status).Enabled -eq $true)
{
Write-Output "$NSG in $(($sub).Name) has FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
if (($Status).Enabled -ne $true)
{
Write-Output "$NSG in $(($sub).Name) does not have FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
}
}
}
enter code here
Error Attached
Network Watchers are usually in a hidden resource group, and perhaps you are trying to find one in one of the available RGs. Try omitting the RG factor and use
$subs = Get-AzSubscription | Where-Object { $_.Name -like "*-NonProd" }
foreach ($sub in $subs) {
Select-AzSubscription -SubscriptionId $sub.Id
$NetworkWatchers = Get-AzNetworkWatcher
$NSGs = (Get-AzNetworkSecurityGroup).Id
foreach ($NSG in $NSGs) {
foreach ($NetworkWatcher in $NetworkWatchers) {
$Status = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcher $NetworkWatcher -TargetResourceId $NSG -Verbose
}
if (($Status).Enabled -eq $true) {
Write-Output "$NSG in $(($sub).Name) has FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
if (($Status).Enabled -ne $true) {
Write-Output "$NSG in $(($sub).Name) does not have FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
}
}
I am able to get all flow logs configuration status.
Here is another approach:
I tried to reproduce the same in my environment and got the same error as below:
The error TargetResourceNotFound usually occurs if you are passing invalid resource group name or subscription name.
To confirm whether the resource group or subscription exists, execute the below code lines separately like below:
$subs = Get-AzSubscription | Where-Object {$_.Name -like "*-name"}
$subs
$RGs = Get-AzResourceGroup | Where-Object {$_.ResourceGroupName -like "*name"}
$RGs
The error states that Target resource identifier /subscriptions/subid/resourceGroups/RG/providers/Microsoft.Network/networkWatchers/*** not found in the region westeurope. Cross-verify whether the Network Watcher exists.
I am able to get the status of the Network Watcher successfully when I passed valid subscription and Resource group like below:
If the error still persists, try excluding the $RGs = Get-AzResourceGroup | Where-Object {$_.ResourceGroupName -like "*name"} and execute.
I appreciate your assistance.
I got it working by changing -NetworkWatcherName $NetworkWatcher.Name to -NetworkWatcherName $NetworkWatcher.ResourceGroupName
foreach ($NSG in $NSGs)
{
# $NSG.Id
# $NSGid = $NSG.Id
foreach ($NetworkWatcher in $NetworkWatchers)
{
$Status = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcherName $NetworkWatcher.ResourceGroupName -ResourceGroupName $RG.ResourceGroupName -TargetResourceId $NSG -Verbose -ErrorAction SilentlyContinue
if (($Status).Enabled -eq $true)
{
Write-Output "$NSG in $(($sub).Name) has FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\A240379\downloads\OutEnabled.csv' -Verbose -Append
}
if (($Status).Enabled -ne $true)
{
Write-Output "$NSG in $(($sub).Name) does not have FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\A240379\downloads\OutNotEnabled.csv' -Verbose -Append
}
}
}

Lock azure resource with PowerShell

I've been trying to run a script to create a lock on azure resource to prevent resources being deleted inadvertently.
I get an error message and I can't figure out why it's showing me this error message.
Script:
#Sign in to Azure account
Login-AzAccount
#Select the subscription you want to work on
Select-AzSubscription -Subscription "test.subscription"
#Get All Resources in a resource group
$Resources = Get-AzResource -ResourceGroupName dummy_rg | Format-Table
# Create lock "delete" on each Resource if it doesn't exist
foreach($Resource in $Resources) {
$ResourceName = $Resource.Name
$lck = Get-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType
if ($null -eq $lck)
{
Write-Host "$ResourceName has no lock"
New-AzResourceLock -resourceGroupName $rg -ResourceName $ResourceName -ResourceType $Resource.ResourceType -LockName "$ResourceName-lck" -LockLevel CanNotDelete -Force
Write-Host "$ResourceName has been locked"
}
else
{
Write-host "$ResourceName already locked"
}
}
Error message:
Gaurav request result:
#Start logging
Start-Transcript -Path "C:\Windows\Logs\Lock - $(((get-date).ToUniversalTime()).ToString("yyyy-MM-dd_hh-mm-ss")).log" -Force
#Connect to Azure account
Login-AzAccount
#Select Azure subscription
Set-AzContext -Subscription "subscription_id_numbers"
#Deny rule on Azure Data Factory and Azure Machine Learning
$Resources = Get-AzResource | Where-Object {$_.Name -NotLike '*adf*' -and $_.Name -NotLike '*aml*'}
# Create lock "delete" on each Resource if it doesn't exist
foreach($Resource in $Resources) {
$ResourceName = $Resource.Name
$lck = Get-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType
if ($lck -eq $null)
{
Write-Host "$ResourceName has no lock"
Set-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType -LockName "$ResourceName-lck" -LockLevel CanNotDelete -Force
Write-Host "$ResourceName has been locked"
}
else
{
Write-host "$ResourceName already locked"
}
}
#Stop Logging
Stop-Transcript
This will loop on every ressources except azure data factory in the tenant and create a "delete" type lock to make sure resources aren't deleted inadvertently.
Read comments in each section to understand the code.

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
}

Check if Azure VM name exists before deploying arm template

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
}

Azure Runbook Commands

So I have a runbook which automates the shutdown and start-up of my Azure VM during the weekends. This then sends a transactional email confirming that the VPS is shut down/started up.
I have set up my parameters as illustrated. Is there a reason as to why it correctly states the name of my virtual machine (highlighted) in the subject line but in the body of the email (highlighted), it comes up with a completely different name.
Logic would dictate that $VM.NAME would be the name of the VPS and not some random command line, so why is this? It's displayed correctly in the subject line but not the email body.
param (
[Parameter(Mandatory=$false)]
[String] $VMName ="ITAMTRADINGVPS",
[Parameter(Mandatory=$false)]
[String] $ResourceGroupName
)
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
# If there is a specific resource group, then get all VMs in the resource group,
# otherwise get all VMs in the subscription.
if ($ResourceGroupName -And $VMName)
{
$VMs = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName
}
elseif ($ResourceGroupName)
{
$VMs = Get-AzureRmVM -ResourceGroupName $ResourceGroupName
}
else
{
$VMs = Get-AzureRmVM
}
$vms
# Start each of the VMs
# Stop each of the VMs
foreach ($VM in $VMs)
{
$StopRtn = $VM | Stop-AzureRmVM -Force -ErrorAction Continue
$StopRtn
Write-Output " this is $StopRtn "
if ($StopRtn.IsSuccessStatusCode -eq 'True')
{
# The VM stopped, so send notice
Write-Output ($VM.Name + " has been stopped")
$Username ="xxx"
$Password = ConvertTo-SecureString "xxx" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $Username, $Password
$SMTPServer = "xxx"
$EmailFrom = "xxxx
[string[]]$EmailTo = "xxx"
$Subject = $VM.NAME + " notification of scheduled deallocation"
$Body = "We'd like to let you know that your Virtual Machine $VM.NAME has successfully deallocated.
<br>This could either be due to maintenance or a scheduled shutdown. If you were expecting this notification, please disregard this email.
<br><br>If you need any further assistance, please contact the system administrator on xxx<br><br>Yours Sincerely<br><br>The Technical Design Team<br>xxx<br><br>"
Send-MailMessage -smtpServer $SMTPServer -Credential $credential -Usessl -Port 587 -from $EmailFrom -to $EmailTo -subject $Subject -Body $Body -BodyAsHtml
Write-Output "Email sent succesfully."
}
else
{
# The VM failed to stop, so send notice
Write-Output ($VM.Name + " failed to stop")
}
}
Illustration
The variable reference (e.g. $VM.Name) into the email body which by default will just return the object type where the output in PowerShell is a special pipeline activity which will render the content either as a listing or as a table. In order to include content in an email, we would have to reference the properties
[string]$EmailBody = (“VMNAME IS = [{0}]” -f $VM.Name)
which is similar to string.format in C#
Refer this SO

Resources