Entra / Microsoft 365 · Users & guests
Report hard deleted user accounts
Example of an Azure Automation runbook to report Entra ID hard-deleted user accounts.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -Identity -NoWelcome
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
Connect-MgGraph -Identity -NoWelcome# Find hard-deleted user accounts from the last 30 days[array]$DeletedUserRecords = Get-MgAuditLogDirectoryAudit -Filter "ActivityDisplayName eq 'Hard Delete user'" -All -Sort 'ActivityDateTime'If (!$DeletedUserRecords) {Write-Host "No hard deleted user records found"; break}$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($Record in $DeletedUserRecords) {$DataLine = [PSCustomObject][Ordered]@{TimeStamp = (Get-Date $Record.ActivityDateTime -format 'dd-MMM-yyyy HH:mm:ss')DeletionInitiatedBy = $Record.InitiatedBy.User.UserPrincipalNameDeletedUser = $Record.TargetResources.UserPrincipalName.Substring(32,($Record.TargetResources.UserPrincipalName.length-32))}$Report.Add($DataLine)}Write-Output "The following accounts were hard-deleted in the last 30 days"$Report | Format-Table TimeStamp, DeletionInitiatedBy, DeletedUser -AutoSize# Define the target SharePoint document library to create the report in. Make sure to update this value to match your tenant$SiteUri = "https://office365itpros.sharepoint.com/sites/Office365Questions"$SiteId = $SiteUri.Split('//')[1].split("/")[0] + ":/sites/" + $SiteUri.Split('//')[1].split("/")[2]$Site = Get-MgSite -SiteId $SiteIdIf (!$Site) {Write-Output ("Unable to connect to site {0} with id {1}" -f $Uri, $SiteId)Exit}[array]$Drives = Get-MgSiteDrive -SiteId $Site.Id# Locate the default document library$DocumentsDrive = $Drives | Where-Object {$_.Name -eq "Documents"}# Generate Excel worksheet - this needs the ImportExcel module - see https://office365itpros.com/2022/05/10/importexcel-powershell/If (Get-Module ImportExcel) {# Generate Excel worksheet if we canImport-Module ImportExcel# Make sure that we have a unique file name so that we don't overwrite any existing file$OutputFile = ("HardDeletedUsers-{0}.xlsx" -f (Get-Date -format yyyyMMdd-HHmm))$Report | Export-Excel -Path $OutputFile -WorksheetName "Hard Deleted User Accounts" -Title "Hard Deleted Accounts" `-TableName "HardDeletedAccounts"} Else {# Generate CSV file if ImportExcel module is not available$OutputFile = ("HardDeletedUsers-{0}.csv" -f (Get-Date -format yyyyMMdd-HHmm))$Report | Export-Csv -Path $OutputFile -NoTypeInformation -Encoding UTF8}# This works interactively but not in an Azure Automation runbook# $TargetFile = "root:/General/" + $OutputFile + ":"# $NewFile = Set-MgDriveItemContent -DriveId $DocumentsDrive.Id -DriveItemId $TargetFile -InFile $File# So we use the URI method instead$Uri = ("https://graph.microsoft.com/V1.0/sites/{0}/drive/items/root:/General/{1}:/content" -f $Site.Id, $OutputFile)$NewFile = Invoke-MgGraphRequest -Uri $Uri -Method PUT -InputFilePath $OutputFileIf ($NewFile) {Write-Output ("File {0} uploaded to {1} with size {2} MB" -f $NewFile.Name, $DocumentsDrive.Name, ([math]::Round($NewFile.Size/ 1MB, 2)))}# Update the document metadata to include a title and description. Note that if the Sites.Selected Graph permission# is used to gain access to the target site, the Manage rather than Write role is required.$Uri = ("https://graph.microsoft.com/V1.0/sites/{0}/drive/items/root:/General/{1}:/listItem/fields" -f $Site.Id, $OutputFile)$Body = @{}$Body.Add("Title", "Hard Deleted Users Report (Created by Azure Automation)")$Body.Add("_ExtendedDescription", "This report is generated by an Azure Automation runbook")# Custom fields added to the target site# $Body.Add("MoreInfo", "Report listing hard-deleted Entra ID user accounts")# $Body.Add("NumberofAccounts", $Report.Count)$ItemUpdate = Invoke-MgGraphRequest -Uri $Uri -Method PATCH -Body $BodyIf ($ItemUpdate) {Write-Output ("Updated document metadata for item {0} with title {1}" -f $OutputFile, $Body.Title)}
Attribution
Author
Office365itpros