Azure Powershell Question for Virtual Machine - azure

I am reviewing a script that is supposed to delete a vm along with all of the resources attributed to the vm
Write-Host -NoNewline -ForegroundColor Green "Please enter the VM name you would like to remove:"
$VMName = Read-Host
$vm = Get-AzVm -Name $VMName
if ($vm) {
$RGName=$vm.ResourceGroupName
Write-Host -ForegroundColor Cyan 'Resource Group Name is identified as-' $RGName
#boot diagnostics container auto generated in storage account. Auto delete this storageURI property
$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\.').groups[1].value
Write-Host -ForegroundColor Cyan 'Marking Disks for deletion...'
$tags = #{"VMName"=$VMName; "Delete Ready"="Yes"}
$osDiskName = $vm.StorageProfile.OSDisk.Name
$datadisks = $vm.StorageProfile.DataDisks
$ResourceID = (Get-Azdisk -Name $osDiskName).id
New-AzTag -ResourceId $ResourceID -Tag $tags | Out-Null
if ($vm.StorageProfile.DataDisks.Count -gt 0) {
foreach ($datadisks in $vm.StorageProfile.DataDisks){
$datadiskname=$datadisks.name
$ResourceID = (Get-Azdisk -Name $datadiskname).id
New-AzTag -ResourceId $ResourceID -Tag $tags | Out-Null
}
}
if ($vm.Name.Length -gt 9){
$i = 9
}
else
{
$i = $vm.Name.Length - 1
}
$azResourceParams = #{
'ResourceName' = $VMName
'ResourceType' = 'Microsoft.Compute/virtualMachines'
'ResourceGroupName' = $RGName
}
$vmResource = Get-AzResource #azResourceParams
$vmId = $vmResource.Properties.VmId
$diagContainerName = ('bootdiagnostics-{0}-{1}' -f $vm.Name.ToLower().Substring(0, $i), $vmId)
$diagSaRg = (Get-AzStorageAccount | where { $_.StorageAccountName -eq $diagSa }).ResourceGroupName
$saParams = #{
'ResourceGroupName' = $diagSaRg
'Name' = $diagSa
}
Write-Host -ForegroundColor Cyan 'Removing Boot Diagnostic disk..'
if ($diagSa){
Get-AzStorageAccount #saParams | Get-AzStorageContainer | where {$_.Name-eq $diagContainerName} | Remove-AzStorageContainer -Force
}
else {
Write-Host -ForegroundColor Green "No Boot Diagnostics Disk found attached to the VM!"
}
Write-Host -ForegroundColor Cyan 'Removing Virtual Machine-' $VMName 'in Resource Group-'$RGName '...'
$null = $vm | Remove-AzVM -Force
Write-Host -ForegroundColor Cyan 'Removing Network Interface Cards, Public IP Address(s) used by the VM...'
foreach($nicUri in $vm.NetworkProfile.NetworkInterfaces.Id) {
$nic = Get-AzNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $nicUri.Split('/')[-1]
Remove-AzNetworkInterface -Name $nic.Name -ResourceGroupName $vm.ResourceGroupName -Force
foreach($ipConfig in $nic.IpConfigurations) {
if($ipConfig.PublicIpAddress -ne $null){
Remove-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name $ipConfig.PublicIpAddress.Id.Split('/')[-1] -Force
}
}
}
Write-Host -ForegroundColor Cyan 'Removing OS disk and Data Disk(s) used by the VM..'
Get-AzResource -tag $tags | where{$_.resourcegroupname -eq $RGName}| Remove-AzResource -force | Out-Null
Write-Host -ForegroundColor Green 'Azure Virtual Machine-' $VMName 'and all the resources associated with the VM were removed sucessfully...'
}
else{
Write-Host -ForegroundColor Red "The VM name entered doesn't exist in your connected Azure Tenant! Kindly check the name entered and restart the script with correct VM name..."
}
I had a question: what does this block of code exactly do:
$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\.').groups[1].value
I know it matches the storage uri, but how? And why is this needed? I am not sure what the .groups[1].value is referring to either

$diagSa =
[regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri,
'^http[s]?://(.+?).').groups[1].value
I know it matches the storage uri, but how?
You are using the [regex] type accelerator & match method () in the above expression.
The Match() method is a way to instruct PowerShell to attempt to match a string inside of another string. The Match() method has two parameters; the string you'd like to match on and the regular expression you'd like to test against.
Whenever a match is found and a regex group is used; (), the [regex] type accelerator has a Captures property. This Captures property then has a property called Groups. This is a collection that contains lots of attributes of what was matched. The second element in that collection contains the actual value that was matched.
what the .groups[1].value is referring to either
groups[1].values returns the storage account name where the boot diagnostics container resides.
And why is this needed?
When creating an Azure VM, you always have the option of creating a boot diagnostics container. This is useful to troubleshooting VM boot issues but doesn’t get removed when a VM is deleted. Let’s remedy that.
To remove the boot diagnostics container, you first need to figure out the name of the storage account the container resides on. To find that storage account, you’ll have to do some parsing of the storageUri property that’s exists in the DiagnosticsProfile object on the VM.
for more information about [regex]::match().group[1].value expression refer the below blog :
https://mcpmag.com/articles/2015/09/30/regex-groups-with-powershell.aspx

Related

How to output Subscription name with Get-AzVM

I am currently trying to output a list of VMs that are not compliant with a policy, all is working except I cant figure out how to output the subscription the VM lives in, since its not a property of Get-AzVm. If someone can please help me out, I am embarrassed I cant figure it out since it seems pretty simple. The current output will use the last subscription context for all the VMs, even though I have multiple subscriptions. Thanks a lot!
$vmsNotBackedUp = #()
$vms_results = #()
$subscriptions = Get-AzSubscription
#set policy definition
$poldef = '013e242c-8828-4970-87b3-ab247555486d'
#Get VMs resource ID that are not backed up from Azure Policy, store in $resourceIDs variable
foreach ($sub in $subscriptions) {
Set-AzContext -Subscription $sub.Id
$resourceIDs =(Get-AzPolicyState -Filter "PolicyDefinitionName eq '$poldef' and ComplianceState eq 'NonCompliant'").ResourceId
$vmsNotBackedUp += Get-AzVM | Where-Object{$_.Id -in $resourceIDs}
$currentContext = $sub.Name
$currentContext
}
Write-Output("The Following VMs were not able to be backed up, may need investigation")
#$vmsNotBackedUp|Select-Object -Property Name,ResourceGroupName,Location
foreach ($vm in $vmsNotBackedUp) {
$output_data = [PSCustomObject]#{
vmName = $vm.Name
ResourceGroup = $vm.ResourceGroupName
vmLocation = $vm.Location
vmOS = $vm.StorageProfile.OsDisk.OsType
vmSub = $currentContext
}
$vms_results += $output_data
}
Since you already have the subscription ID in $sub.Id, you could add this as a property to the VMs you enumerate in your script. Something like this:
$vmsNotBackedUp += Get-AzVM |
Where-Object{$_.Id -in $resourceIDs} |
Add-Member -MemberType NoteProperty -Name 'Subscription' -Value $sub.id -PassThru

Validate Azure Resource Group Exist or not

I am trying to write to a powershell script to validate the Resource Group is exist or not.
Conditions-
Check the resource group (myrg) is already exist in azure subscription.
If "condition 1" is FALSE then Create a Resource Group (myrg) Else append 2 digits to the Resource Group name. e.g. (myrg01)
Check the (myrg01)resource group exist in azure subscription.
If "condition 3" is FALSE then Create a Resource Group (myrg01) Else increment the last digit by one for Resource Group name. e.g. (myrg02)
Check the (myrg02) resource group exist in azure subscription.
If "condition 5" is FALSE then Create a Resource Group (myrg02) Else increment the last digit by one for Resource Group name. e.g. (myrg03)
and so on.........
Below is the code which i have written so far and unable to create a desired loop.
$rgname= "myrg"
Get-AzResourceGroup -Name $rgname -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent){
Write-Host "ResourceGroup doesn't exist, Creating resource group"
$createRG= New-AzResourceGroup -Name $rgname -Location $region -Tag $tag
Write-Host $rgname
}
else{
$countcontent = $countcontent + 1
$counter = [int]$countcontent
++$counter
$countString = "{0:d2}" -f ($counter)
Write-Host "ResourceGroup $rgname already exist, Generating a new name for Resource Group"
$rgname= $rgname + $countString
Get-AzResourceGroup -Name $rgname -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notpresent){
$createRG= New-AzResourceGroup -Name $rgname -Location $region -Tag $tag
Write-Host $rgname
Clear-Variable countcontent
Clear-Variable counter
Clear-Variable countString
}
}
Got a workaround
$rg="myrg"
$Subscriptions = Get-AzSubscription
$Rglist=#()
foreach ($Subscription in $Subscriptions){
$Rglist +=(Get-AzResourceGroup).ResourceGroupName
}
$rgfinal=$rg
$i=1
while($rgfinal -in $Rglist){
$rgfinal=$rg +"0" + $i++
}
Write-Output $rgfinal
Set-AzContext -Subscription "Subscription Name"
$createrg= New-AzResourceGroup -Name $rgfinal -Location "location"

How can I simply get the powerstate from within a powershell workflow automation runbook in Azure?

I have a Powershell workflow runbook that automates starting and shutting down VMs in Azure, I updated the modules in an automation account (so I could use it for other things) and it has stopped the script working. I have fixed most of the broken stuff but the bit that is not now working is obtaining the power state eg: PowerState/deallocated so that it can be shutdown/started up. Here is my code:
$vmFullStatus = Get-AzureRmVM -ResourceGroupName test1 -Name test1 -Status
$vmStatusJson = $vmFullStatus | ConvertTo-Json -depth 100
$vmStatus = $vmStatusJson | ConvertFrom-Json
$vmStatusCode = $vmStatus.Statuses[1].code
Write-Output " VM Status Code: $vmStatusCode"
The Write-Output VM Status Code is now blank in the output of the runbook, but it outputs fine in standard shell. I only have limited experiences in workflow runbooks but I believe it needs to be converted to Json so the Workflow can use it.
I think the issue may lie with the statuses as when it is converted to Json it displays:
"Statuses": [
"Microsoft.Azure.Management.Compute.Models.InstanceViewStatus",
"Microsoft.Azure.Management.Compute.Models.InstanceViewStatus"
],
Which doesn't now show the PowerState. How can I get the powerstate of a vm from within a powershell workflow runbook so it can used? Thanks
I have tried an inline script and it does work if you specify a vm name:
$vmStatusCode = InlineScript {
$vmFullStatus = Get-AzureRmVM -ResourceGroupName test1 -Name test1 -Status
$vmStatusJson = $vmFullStatus | ConvertTo-Json -depth 100
$vmStatus = $vmStatusJson | ConvertFrom-Json
$vmStatus.Statuses[1].code
}
But it doesn't work when you pass variables:
$vmFullStatus = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
Get-AzureRmVM : Cannot validate argument on parameter 'ResourceGroupName'. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
it needs to be run without an inline script - any ideas?
forgot to add $using:
$vmStatusCode = InlineScript {
$vmFullStatus = Get-AzureRmVM -ResourceGroupName $using:vm.ResourceGroupName -Name $using:vm.Name -Status
$vmStatusJson = $vmFullStatus | ConvertTo-Json -depth 100
$vmStatus = $vmStatusJson | ConvertFrom-Json
$vmStatus.Statuses[1].code
}
This now works!

Azure Powershell Script

I have written a PowerShell script to print VM names with unmanaged disks however it's giving me an error. Appreciate any help on this -
$location=Read-Host -Prompt 'Input location for VMs'
$azuresubscription=Read-Host -Prompt 'Input Subscription Id'
$rmvms=Get-AzurermVM
# Add info about VM's from the Resource Manager to the array
foreach ($vm in $rmvms)
{
# Get status (does not seem to be a property of $vm, so need to call Get-AzurevmVM for each rmVM)
$vmstatus = Get-AzurermVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Status | where Location -like $location
# Add values to the array:
$vmarray += New-Object PSObject -Property #{`
# Subscription=$Subscription.SubscriptionName; `
Subscription=$azuresubscription.SubscriptionName; `
AzureMode="Resource_Manager"; `
Name=$vm.Name; PowerState=(get-culture).TextInfo.ToTitleCase(($vmstatus.statuses)[1].code.split("/")[1]); `
Size=$vm.HardwareProfile.VirtualMachineSize}
}
foreach ($vm in $vmarray)
{
$vmdiskstatus = (Get-AzurermVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName).StorageProfile.OsDisk.ManagedDisk
if (!$vmdiskstatus) {Write-Host $vm.Name}
}
Error Message:
($vmarray is resulting in Null array) -
Cannot index into a null array.
Expected Output - $vmarray should have one VM as there is a running
instance in eastus (that's what I am using as value for $location)
As requested by Victor Silva to add my comment as answer, here goes:
You need to define the $vmarray as array before entering the loop to add objects to it.
Then, after that loop, the foreach ($vm in $vmarray) does have an array to index into, even if empty:
$location=Read-Host -Prompt 'Input location for VMs'
$azuresubscription=Read-Host -Prompt 'Input Subscription Id'
$rmvms=Get-AzurermVM
###################################################
# create an array variable to collect the result(s)
###################################################
$vmarray = #()
# Add info about VM's from the Resource Manager to the array
foreach ($vm in $rmvms)
{
# rest of your code
}

How to get all Azure Resources without tags in a Azure Resource Group

In my Azure dev/test lab (DTL), there are many resources which were not tagged. How can I get a list of all untagged resources under DTL/resource group?
Here's a simple PowerShell loop to get untagged resources.
$resources = Get-AzureRmResource
foreach($resource in $resources)
{
if ($resource.Tags -eq $null)
{
echo $resource.Name, $resource.ResourceType
}
}
Other ways to query this information and also set tags programmatically or as part of resource deployments are described here.
If you want to avoid the situation of ending up with untagged resources, you could enforce a customized policy that all resources should have a value for a particular tag.
Here is the idiomatic PowerShell to supplement #huysmania's answer which is expressed in procedural language mindset (and updated for the new PowerShell Az cmdlets):
Get-AzResource | Where-Object Tags -eq $null | Select-Object -Property Name, ResourceType
and the terse (alias) form:
Get-AzResource | ? Tags -eq $null | select Name, ResourceType
I usually just run this command to output a table of untagged resources using Get-AzResource. It filters Azure resources with tags that are $null or empty using Where-Object.
Get-AzResource `
| Where-Object {$null -eq $_.Tags -or $_.Tags.Count -eq 0} `
| Format-Table -AutoSize
If you want to list untagged resources for a specific resource group, you can just add the -ResourceGroupName switch to Get-AzResource.
$resourceGroupName = "My Resource Group"
Get-AzResource -ResourceGroupName $resourceGroupName `
| Where-Object {$null -eq $_.Tags -or $_.Tags.Count -eq 0} `
| Format-Table -AutoSize
Note: The above uses the newer Azure PowerShell Az module, which is replacement for AzureRM.
<#Bellow is PowerShell script to locate untagged resources -
you may change the script out put as per your requirement.
Hope must be helpful. Thanks!#>
Write-Host "List all resource where Tag value is not Set"
Write-Host "********************************************"
#Fetch all resource details
$resources=get-AzureRmResource
foreach ($resource in $resources) {
$tagcount=(get-AzureRmResource | where-object {$_.Name -match $resource.Name}).Tags.count
if($tagcount -eq 0) {
Write-Host "Resource Name - "$resource.Name
Write-Host "Resource Type and RG Name : " $resource.resourcetype " & " $resource.resourcegroupname "`n"
}
}
This link has the solution for this question. It beautifully explains assigning and querying tags using powershell.
$resourceGroupName = 'InternalReportingRGDev'
$azureRGInfo = Get-AzureRmResourceGroup -Name $resourceGroupName
foreach ($item in $azureRGInfo)
{
Find-AzureRmResource -ResourceGroupNameEquals $item.ResourceGroupName | ForEach-Object {Set-AzureRmResource -ResourceId $PSItem.ResourceId -Tag $item.Tags -Force }
}

Resources