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
                                }
                        }