How to output Subscription name with Get-AzVM - azure

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

Related

Find/list the Unused storage accounts in azure using powershell

Trying to get the list of unused/inactive storage accounts in azure using powershell. Below is my script which im trying it will provide the storage account name and last modified date of your Azure storage accounts, but i need to list only the unused storage accounts names not all the storage accounts, for that some condition/filter i need to provide to achieve the same. Please assist me to solve this. Thanks in Advance
It will output the results into a table detailing the name and last modified date of your Azure storage accounts.
& {
foreach ($storageAccount in Get-AzStorageAccount) {
$storageAccountName = $storageAccount.StorageAccountName
$resourceGroupName = $storageAccount.ResourceGroupName
# Get storage account key
$storageAccountKey = (Get-AzStorageAccountKey -Name $storageAccountName -ResourceGroupName $resourceGroupName).Value[0]
# Create storage account context using above key
$context = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
# Get the last modified date
$lastModified = Get-AzStorageContainer -Context $context | Sort-Object -Property #{Expression = {$_.LastModified.DateTime}} | Select-Object -Last 1 -ExpandProperty LastModified
# Collect the information to output to a table when the for loop has completed
New-Object psobject -Property #{
Name = $storageAccountName;
LastModified = $lastModified.DateTime;
ResourceGroupName = $resourceGroupName
}
}
} | Format-Table Name, LastModified, ResourceGroupName -autosize
I tried to reproduce the same in my environment and got the same result as below:
By using the same script, I got the storage account name and last modified date of the Azure storage accounts.
To get only the unused/inactive storage accounts in azure using PowerShell, I modified the script like below:
I agree with #Niclas, you need make use of get-date command.
& {
foreach ($storageAccount in Get-AzStorageAccount) {
$storageAccountName = $storageAccount.StorageAccountName
$resourceGroupName = $storageAccount.ResourceGroupName
$storageAccountKey = (Get-AzStorageAccountKey -Name $storageAccountName -ResourceGroupName $resourceGroupName).Value[0]
$context = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
$lastModified = Get-AzStorageContainer -Context $context | Sort-Object -Property #{Expression = {$_.LastModified.DateTime}} | Select-Object -Last 1 -ExpandProperty LastModified
$unusedacc = (Get-Date).AddDays(-10)
if ($lastModified.DateTime -lt $unusedacc) {
New-Object psobject -Property #{
Name = $storageAccountName;
LastModified = $lastModified.DateTime;
ResourceGroupName = $resourceGroupName
}
}
}
} | Format-Table Name, LastModified, ResourceGroupName -autosize
Note: Based on your requirement you can change the number of days in this line $unusedacc = (Get-Date).AddDays(-10).
If there are no unused Storage accounts, then it will return blank results like below:
Use get-date
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-date
and use the Where-Object.
# ADD THIS
$lastModDate = (get-date).AddDays(-5).Date
$lastMod = $lastModified | Where-Object { ($_.DateTime).Date -lt $lastModDate}
# If $lastMod.DateTime is NOT empty, then:
if ($lastMod.DateTime) {
# Write-Host "variable is NOT null " + $storageAccountName # For testing purpose
# Collect the information to output to a table when the for loop has completed
New-Object psobject -Property #{
Name = $storageAccountName;
LastModified = $lastMod.DateTime; # CHANGE THIS
ResourceGroupName = $resourceGroupName
}
}
https://www.techielass.com/find-unused-storage-accounts-in-azure/
With your script:
With my changes:

Azure Powershell Question for Virtual Machine

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

Formatting the Powershell script object output?

The script does is to Go to each of the Azure Subscription and then list the VM properties and then create the PSObjects to capture the output in a meaningful and useful format.
Get-AzSubscription | ForEach-Object {
$subscriptionId = $_.Id
$subscriptionName = $_.Name
Set-AzContext -SubscriptionId $subscriptionId
$VM = Get-AzVM
# Get NIC id
$NICId = $VM.NetworkProfile.NetworkInterfaces[0].id
# Get NIC
$NIC = Get-AzNetworkInterface -ResourceId $NICId
# Get public ip id
$PIPId = $NIC.IpConfigurations.PublicIpAddress.id
# Get public ip
$PIP = Get-AzResource -ResourceId $PIPId
# Output
[pscustomobject]#{
Subscription = $subscriptionName
VMName = $VM.Name
VMRG = $VM.ResourceGroupName
VMLocation = $VM.Location
IpAddress = $PIP.Properties.ipAddress
PublicIPAllocationMethod = $PIP.Properties.publicIPAllocationMethod
FQDN = $pip.Properties.dnsSettings.fqdn
}
} | Out-GridView
However, the result is mixed up and not in the correct format like the below:
Out-GridView
Format-Table -Autosize
Subscription : Corp-Azure-Dev-subs
VMName : {prod1-build, corpbuild-image, corpplus-build-server, u2api...}
VMRG : {corp-prod1-BUILD, corp-PLUS-BUILD-SETUP, corp-PLUS-BUILD-SETUP, ERP-Acorp-DEV...}
VMLocation : {eastus, east, centralus, westus...}
IpAddress : 52.44.66.198
PublicIPAllocationMethod : Static
FQDN :
I think you're outputting multiple object types. From the looks of it the line:
Set-AzContext -SubscriptionId $subscriptionId
Might be causing the issue. Remember anything you output is fed down the pipe. So, the likely problem is Out-Griview doesn't know what to do with a multi-typed array. Try sending that like to Out-Null to see if it rights the Out-GridView result.

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!

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