Get-AzVMDeletionActivity.ps1
#requires -Version 5.0 -Module Az.Monitor,Az.Accounts <#PSScriptInfo .VERSION 0.6 .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. PFB expected output.Some details might be blank if the VM was created before 90 days. AzVMname Hostname AzVMId OSType CreatedUTC CreatedBy IP Subscription SubscriptionId Location -------- -------- ------ ------ ---------- --------- -- ------------ -------------- -------- ACE2T30050AP001 <Sub name> <Sub Id> ACE2T30050FS001 <Sub name> <Sub Id> ACE2T30050SQ001 <Sub name> <Sub Id> ACE2T30050SQ002 <Sub name> <Sub Id> AzPETest1VM <Sub name> <Sub Id> IndVM IndVM 0c904716-ffab-4fe5-a83a-db95860c7b7e Windows 5/1/2022 4:18:50 AM <username> 10.2.0.4 <Sub name> <Sub Id> southindia NvStateTstJmpVM Windows 10.2.0.4 <Sub name> <Sub Id> southindia NvStateTstVM Windows 10.2.0.4 <Sub name> <Sub Id> southindia testvm testvm d7228860-c155-419c-9189-8a046a709945 Windows 6/2/2022 1:09:56 AM <username> 10.2.0.4 <Sub name> <Sub Id> northcentralus .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 } } |