Get-AzVMDeletionActivity.ps1
#requires -Version 5.0 -Module Az.Monitor,Az.Accounts <#PSScriptInfo .VERSION 0.5 .GUID aaa68dab-9130-4c5d-83cc-f5f19b61b12f .DESCRIPTION This is a script to find the basic details of Azure VM's that have been deleted from a subscription. .AUTHOR Ayan Mullick .COMPANYNAME Ayan Mullick LLC .TAGS AzCompute AzVM Infra-Report .LICENSEURI https://choosealicense.com/licenses/mit/ .PROJECTURI https://dev.azure.com/ayn/PowerShell/_git/AzIaaS?path=%2FGet-AzVMDeletionActivity.ps1&version=GBmain #> <# .Synopsis This is a script to find the basic details of Azure VM's that have been deleted from a subscription. It iterates for each unique VM deletion activity and tries to locate the VM and NIC creation activity log if the VM was created within 90 days.One needs read access to a subscription to run this script. .EXAMPLE Login-AzAccount -Tenant <Tenantid> -Subscription <Subscriptionid> Get-AzVMDeletionActivity This will log you into the desired subscription and get the list of Azure VM's deleted from the default context. .EXAMPLE Get-AzVMDeletionActivity.ps1 -SubscriptionId <Subscription Id> -WarningAction SilentlyContinue One can specify the subscription id in the -SubscriptionId parameter and suppress any warnings related to upcoming changes in the Azure PowerShell cmdlets. .EXAMPLE '<Subscription Id>'|Get-AzVMDeletionActivity.ps1 One can pipe a subscription id to the cmdlet too. .EXAMPLE (Get-AzSubscription).id|ForEach-Object {Get-AzVMDeletionActivity.ps1 -SubscriptionId $PSItem -WarningAction SilentlyContinue} One can use the Foreach-Object cmdlet to get the VM deletion list from all the subscriptions one has access to. .EXAMPLE $VMdeletion=(Get-AzSubscription).id|ForEach-Object -Parallel {Get-AzVMDeletionActivity.ps1 -SubscriptionId $PSItem -WarningAction SilentlyContinue} $VMdeletion|? OsType -NE 'Linux'|Export-Csv -Path C:\Temp\Vmdeletion.csv This will query all the subscriptions in the tenant for the list of deleted VM's in parallel, filter for OSType and export the list to a CSV file. .NOTES One can IM ayan@mullick.in on Teams if one needs to add parameters to it. #> [CmdletBinding()] param([Parameter(ValueFromPipeline=$true)] [ArgumentCompleter({return $(Get-AzSubscription).Id} )] [string] $SubscriptionId = $(Get-AzContext).Subscription.Id) $Params = @{DefaultProfile = $($Context=Set-AzContext -SubscriptionId $SubscriptionId;$Context); StartTime = $($Starttime=(Get-Date).AddDays(-90); $Starttime); ErrorAction='Stop'} #Splatting DefaultProfile etc to avoid errors during parallel execution. if ($Context) {$DeletionActivity=(Get-AzActivityLog @Params -ResourceProvider Microsoft.Compute).Where{$_.OperationName -EQ 'Delete Virtual Machine'}|Sort-Object ResourceId,CorrelationId -Unique} #Gets unique VM deletion activity by resource id and CorrelationId[specific time] $DeletionActivity.ForEach{$RId = $_.ResourceId $Creation=(Get-AzActivityLog @Params -ResourceId $RId).Where{($_.ResourceId -eq $RId -and $_.substatus -match 'Created')}|Select-Object -Last 1 #Locates record for creation of the VM if ( $Creation ) {$Responsebody=(New-Object PSObject -Property ([hashtable]$($Creation.Properties.Content))).responseBody|ConvertFrom-Json $CreationProp=$Responsebody.properties} if ( $CreationProp) {$NicCreation=(((Get-AzActivityLog @Params -EndTime $Creation.EventTimestamp -ResourceId $CreationProp.networkProfile.networkInterfaces.id).Where{$PSItem.Properties.Content.Keys -match 'responsebody'})[0]) #Locates record for creation of its NIC if ($NicCreation) {$PIP= ((New-Object PSObject -Property ([hashtable]$NicCreation.Properties.Content)).responsebody|ConvertFrom-Json).properties.ipConfigurations.properties.privateIPAddress} #Get IP from the NIC creation log } [PSCustomObject]@{ AzVMname = $RId.Split("/")[8] Hostname = $CreationProp.osProfile.computerName AzVMId = $CreationProp.VMId OSType = $CreationProp.storageprofile.osdisk.ostype CreatedUTC = $Creation.EventTimestamp CreatedBy = $Creation.Caller IP = $PIP Subscription = ($Context.Name).Substring(0,$Context.Name.IndexOf('(')) SubscriptionId= $_.SubscriptionId Location = $Responsebody.location ResourceGroup = $_.resourceGroupName DeletedUTC = $_.eventTimestamp DeletedBy = $_.Caller Operation = $_.operationName } } |