Admin cheat sheet
73 PowerShell, KQL, Command Prompt snippets, lifted verbatim from 37 guides on this site. Nothing here is written for the cheat sheet itself — every block links back to the runbook that explains the why, the prerequisites, and how to roll it back.
Read the surrounding guide before running anything in production. Placeholders like <groupId> and example UPNs are intentional.
73 of 73 snippets from 37 guides
The Microsoft Graph PowerShell SDKDeveloper & APIs
Install-Module Microsoft.Graph -Scope CurrentUser
Connect-MgGraph -Scopes "User.Read.All","Group.Read.All"
Get-MgUser -Top 10
Get-MgGroup -Filter "displayName eq 'Marketing'"
Disconnect-MgGraphHow to put a mailbox on litigation holdExchange & Outlook
Connect-ExchangeOnline
Get-Mailbox user@contoso.com | Format-List RecipientTypeDetails,PersistedCapabilities,LitigationHoldEnabledSet-Mailbox user@contoso.com -LitigationHoldEnabled $true -LitigationHoldDuration 2555 `
-LitigationHoldOwner legal@contoso.com -Comment "Matter 2026-014, per Legal 2026-09-03"Import-Csv .\custodians.csv | ForEach-Object {
Set-Mailbox $_.UPN -LitigationHoldEnabled $true -Comment "Matter 2026-014"
}How to set up DKIM for a custom domain in Microsoft 365Exchange & Outlook
Connect-ExchangeOnline
New-DkimSigningConfig -DomainName contoso.com -Enabled $false # creates keys if missing
Get-DkimSigningConfig -Identity contoso.com | Format-List Selector1CNAME,Selector2CNAMESet-DkimSigningConfig -Identity contoso.com -Enabled $trueOffice 365 Message Encryption deep diveExchange & Outlook
Set-OMEConfiguration -Identity "OME Configuration" `
-EmailText "Encrypted message from Contoso" `
-PortalText "Contoso secure messages" `
-DisclaimerText "This message is confidential..." `
-OTPEnabled $true `
-SocialIdSignIn $true `
-BackgroundColor "#003366"New-RMSTemplate -Name "Legal Privilege" `
-DepartmentName "Legal" `
-RightsDefinitions @(
New-Object Microsoft.Online.Administration.RightsDefinition `
-Property @{
EmailAddress = "everyone@contoso.com"
Rights = "VIEW","REPLY","REPLYALL","EDIT","EXPORT","EXTRACT","FORWARD"
}
)Proxy addresses and email aliases in Exchange OnlineExchange & Outlook
Set-Mailbox anna.svensson -EmailAddresses @{add="anna@contoso.com"}Handling licence-count overrun surprisesMicrosoft 365 essentials
Get-MgSubscribedSku | Select-Object SkuPartNumber, @{n="Enabled";e={$_.PrepaidUnits.Enabled}}, ConsumedUnitsGet-MgUser -All -Filter "assignedLicenses/any(x:x/skuId eq 'sku-guid')" -ConsistencyLevel eventual -CountVariable c -Property DisplayName,UserPrincipalName,AccountEnabled,SignInActivityHow to offboard a user in Microsoft 365Microsoft 365 essentials
1. Block sign-in and revoke sessions (last day, at the agreed time)
Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.AccessAsUser.All"
Update-MgUser -UserId leaver@contoso.com -AccountEnabled:$false
Revoke-MgUserSignInSession -UserId leaver@contoso.comConnect-ExchangeOnline
Set-MailboxAutoReplyConfiguration leaver@contoso.com -AutoReplyState Enabled -ExternalAudience All `
-InternalMessage "This person has left. Contact successor@contoso.com." -ExternalMessage "This person has left. Contact successor@contoso.com."
Set-Mailbox leaver@contoso.com -ForwardingAddress successor@contoso.com -DeliverToMailboxAndForward $trueHow to restore a deleted user in Microsoft 365Microsoft 365 essentials
Connect-MgGraph -Scopes "User.ReadWrite.All"
Get-MgDirectoryDeletedItemAsUser -All | Where-Object UserPrincipalName -like "j.smith*" | Select-Object Id,UserPrincipalName,DeletedDateTimeRestore-MgDirectoryDeletedItem -DirectoryObjectId <object id>Microsoft 365 cost optimisationMicrosoft 365 essentials
$cutoff = (Get-Date).AddDays(-90).ToString("o")
Get-MgUser -All -Property UserPrincipalName,SignInActivity,AccountEnabled |
Where-Object {
$_.AccountEnabled -and
$_.SignInActivity.LastSignInDateTime -lt $cutoff
} |
Select-Object UserPrincipalName, @{N="LastSignIn";E={$_.SignInActivity.LastSignInDateTime}}Get-MgUser -All -Property AssignedLicenses |
Where-Object { $_.AssignedLicenses.Count -gt 1 } |
# Detailed analysis of which SKUs overlapMicrosoft 365 reporting via PowerShellMicrosoft 365 essentials
Connect-MgGraph -Scopes "User.Read.All,Organization.Read.All"
# Active licences in the tenant
Get-MgSubscribedSku |
Select-Object SkuPartNumber, PrepaidUnits, ConsumedUnits
# Users with a specific licence
$skuId = (Get-MgSubscribedSku -Filter "SkuPartNumber eq 'SPE_E5'").SkuId
Get-MgUser -All -Filter "assignedLicenses/any(x:x/skuId eq $skuId)" |
Select-Object DisplayName, UserPrincipalNameInactive users (no sign-in in 90 days)
$cutoff = (Get-Date).AddDays(-90).ToString("o")
Get-MgUser -All -Property UserPrincipalName,SignInActivity |
Where-Object { $_.SignInActivity.LastSignInDateTime -lt $cutoff } |
Select-Object UserPrincipalName, @{N="LastSignIn";E={$_.SignInActivity.LastSignInDateTime}}Connect-ExchangeOnline
Get-EXOMailbox -ResultSize Unlimited |
Get-EXOMailboxStatistics |
Where-Object { $_.TotalItemSize -gt 49GB } |
Select-Object DisplayName, TotalItemSizeTeams meeting recording locations
# Channel meeting recordings - in the team's SharePoint site
# Non-channel meeting recordings - in the organiser's OneDrive
# Query via Graph for files matching meeting-recording patternSharePoint site storage by site
Connect-SPOService -Url https://yourtenant-admin.sharepoint.com
Get-SPOSite -Limit All |
Sort-Object StorageUsageCurrent -Descending |
Select-Object Url, @{N="StorageMB";E={$_.StorageUsageCurrent}}, Owner |
Export-Csv site-storage.csv -NoTypeInformationConditional Access policy assignments
Connect-MgGraph -Scopes "Policy.Read.All"
Get-MgIdentityConditionalAccessPolicy |
Select-Object DisplayName, State,
@{N="UsersIncluded";E={($_.Conditions.Users.IncludeUsers + $_.Conditions.Users.IncludeGroups) -join ","}},
@{N="UsersExcluded";E={($_.Conditions.Users.ExcludeUsers + $_.Conditions.Users.ExcludeGroups) -join ","}},
@{N="Apps";E={$_.Conditions.Applications.IncludeApplications -join ","}}Defender for Endpoint device inventory
Connect-MgGraph -Scopes "DeviceManagementManagedDevices.Read.All"
Get-MgDeviceManagementManagedDevice -All |
Select-Object DeviceName, OperatingSystem, ComplianceState, LastSyncDateTimeAuthentication patterns for production scripts
Connect-MgGraph -Scopes "User.Read.All"Authentication patterns for production scripts
Connect-MgGraph -ClientId "app-id" -TenantId "tenant-id" -CertificateThumbprint "thumbprint"Restoring a deleted Microsoft 365 group and its resourcesMicrosoft 365 essentials
Confirm what you are restoring
Get-MgDirectoryDeletedItemAsGroup -All | Select-Object DisplayName, Mail, DeletedDateTime, IdRestore-MgDirectoryDeletedItem -DirectoryObjectId "group-object-id"Defender Threat IntelligenceMicrosoft Defender (Security)
// Hunt for connections to known C2 IPs from a TI feed
let MaliciousIPs = ThreatIntelligenceIndicator
| where Action == "block"
| where IsActive == true
| project NetworkIP;
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where RemoteIP in (MaliciousIPs)Defender XDR advanced hunting workshopMicrosoft Defender (Security)
Find processes spawned by Office apps
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in ("winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe")
| where FileName in ("cmd.exe", "powershell.exe", "wscript.exe", "cscript.exe", "mshta.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLineFind PowerShell launching unusual scripts
DeviceProcessEvents
| where Timestamp > ago(1d)
| where FileName == "powershell.exe"
| where ProcessCommandLine has_any ("DownloadString", "FromBase64", "IEX", "Invoke-Expression")
| project Timestamp, DeviceName, AccountName, ProcessCommandLineIdentityLogonEvents
| where Timestamp > ago(7d)
| where ActionType == "LogonSuccess"
| summarize Sources = make_set(IPAddress), LogonCount = count() by AccountName, bin(Timestamp, 1d)
| where array_length(Sources) > 5 // 5+ distinct IPs in a day
| order by LogonCount descFind email URLs that were clicked
EmailEvents
| where Timestamp > ago(7d)
| where ThreatTypes has "phish"
| join kind=inner (EmailUrlInfo) on NetworkMessageId
| join kind=inner (EmailPostDeliveryEvents | where Action == "Click") on NetworkMessageId
| project Timestamp, Recipient, Subject, Url, ClickedUrl = UrlFind first-time-seen processes
DeviceProcessEvents
| where Timestamp > ago(1d)
| join kind=leftanti (
DeviceProcessEvents
| where Timestamp between (ago(30d) .. ago(1d))
| distinct FileName, SHA256
) on FileName, SHA256
| where FileName endswith ".exe"
| project Timestamp, DeviceName, FileName, SHA256, FolderPathHow to block a compromised account in Microsoft 365Microsoft Defender (Security)
Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.AccessAsUser.All"
Update-MgUser -UserId user@contoso.com -AccountEnabled:$falseRevoke-MgUserSignInSession -UserId user@contoso.comConnect-ExchangeOnline
# Inbox rules — look for delete/move/forward rules with innocuous names like "."
Get-InboxRule -Mailbox user@contoso.com | Format-List Name,Description,Enabled
# Forwarding
Get-Mailbox user@contoso.com | Format-List ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward
Set-Mailbox user@contoso.com -ForwardingAddress $null -ForwardingSmtpAddress $null
# Delegates and Send As granted during the compromise window
Get-MailboxPermission user@contoso.com | Where-Object {$_.User -notlike "NT AUTHORITY*"}
Get-RecipientPermission user@contoso.comKQL primer for Defender XDRMicrosoft Defender (Security)
DeviceProcessEvents
| where Timestamp > ago(1d)
| where FileName == "powershell.exe"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
| order by Timestamp desc
| take 100| where Timestamp > ago(1h) // last hour
| where Timestamp > ago(7d) // last 7 days
| where Timestamp between (datetime(2026-05-01) .. datetime(2026-05-05))DeviceLogonEvents
| where ActionType == "LogonFailed"
| where Timestamp > ago(1d)
| summarize count() by AccountName
| order by count_ desc| where ProcessCommandLine has "Invoke-Expression" // case-insensitive contains
| where ProcessCommandLine contains "iex" // also contains
| where ProcessCommandLine matches regex @"\bIEX\b" // regex
| where FileName startswith "powershell"DeviceProcessEvents
| where FileName == "rundll32.exe"
| where Timestamp > ago(1d)
| join DeviceNetworkEvents on DeviceId, TimestampMicrosoft Sentinel analytic rulesMicrosoft Defender (Security)
// Detect unusual data export by departing employees
let HRData = externaldata(UserPrincipalName:string, DepartureDate:datetime)
[@"https://your-data-source/hr.csv"] with(format="csv");
let DepartingUsers =
HRData
| where DepartureDate between (now() .. now()+30d);
SignInLogs
| where TimeGenerated > ago(7d)
| where UserPrincipalName in (DepartingUsers | project UserPrincipalName)
| join kind=inner OfficeActivity on $left.UserPrincipalName == $right.UserId
| where Operation in ("FileDownloaded", "SyncDownloadedFiles")
| summarize TotalDownloads = count() by UserPrincipalName, bin(TimeGenerated, 1h)
| where TotalDownloads > 100Cleaning up over-consented app permissionsMicrosoft Entra (Identity)
Connect-MgGraph -Scopes "Application.Read.All","DelegatedPermissionGrant.Read.All","Directory.Read.All"
# Delegated grants
Get-MgOauth2PermissionGrant -All | Select-Object ClientId, ConsentType, PrincipalId, ResourceId, Scope | Export-Csv .\delegated.csv -NoTypeInformation
# Application permissions on Microsoft Graph
$graph = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'"
Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $graph.Id -All | Select-Object PrincipalDisplayName, PrincipalId, AppRoleId | Export-Csv .\application.csv -NoTypeInformationCleaning up unused enterprise apps in Entra IDMicrosoft Entra (Identity)
Step 1: get the whole list with signals
Connect-MgGraph -Scopes "Application.Read.All","AuditLog.Read.All","Directory.Read.All"
Get-MgServicePrincipal -All -Property Id,DisplayName,AppId,ServicePrincipalType,AccountEnabled,CreatedDateTime,AppOwnerOrganizationId,Tags,PasswordCredentials,KeyCredentials |
Select-Object DisplayName, AppId, ServicePrincipalType, AccountEnabled, CreatedDateTime, AppOwnerOrganizationId,
@{n="Creds";e={$_.PasswordCredentials.Count + $_.KeyCredentials.Count}} |
Export-Csv .\sps.csv -NoTypeInformationCross-tenant calendar sharingMicrosoft Entra (Identity)
Exchange organisation relationships
# On Tenant A
New-OrganizationRelationship -Name "TenantB" `
-DomainNames "tenantb.com" `
-FreeBusyAccessEnabled $true `
-FreeBusyAccessLevel AvailabilityOnlyHow to assign licenses with group-based licensing in Entra IDMicrosoft Entra (Identity)
3. Assign the licence to the group
Connect-MgGraph -Scopes "Group.ReadWrite.All","Organization.Read.All"
$sku = Get-MgSubscribedSku | Where-Object SkuPartNumber -eq "SPE_E3"
Set-MgGroupLicense -GroupId <groupId> -AddLicenses @{SkuId = $sku.SkuId; DisabledPlans = @()} -RemoveLicenses @()How to bulk-assign Intune configuration profilesMicrosoft Entra (Identity)
3. Script it for many profiles
Connect-MgGraph -Scopes "DeviceManagementConfiguration.ReadWrite.All"
$policyId = "<configurationPolicy id>"
$filterId = "<filter id>"
$excludeId = "<exclusion group id>"
$body = @{
assignments = @(
@{ target = @{
"@odata.type" = "#microsoft.graph.allDevicesAssignmentTarget"
deviceAndAppManagementAssignmentFilterId = $filterId
deviceAndAppManagementAssignmentFilterType = "include" } },
@{ target = @{
"@odata.type" = "#microsoft.graph.exclusionGroupAssignmentTarget"
groupId = $excludeId } }
)
} | ConvertTo-Json -Depth 6
Invoke-MgGraphRequest -Method POST -Body $body -ContentType "application/json" `
-Uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$policyId/assign"How to create a break-glass account in Entra IDMicrosoft Entra (Identity)
SigninLogs
| where UserPrincipalName in~ ("svc-recovery-01@contoso.onmicrosoft.com","svc-recovery-02@contoso.onmicrosoft.com")
| project TimeGenerated, UserPrincipalName, IPAddress, ResultType, AppDisplayNameHow to reset MFA for a user in Entra IDMicrosoft Entra (Identity)
2. Delete the method that is gone
Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All"
Get-MgUserAuthenticationMethod -UserId user@contoso.com
# then, for the Authenticator entry you want gone:
Remove-MgUserAuthenticationMicrosoftAuthenticatorMethod -UserId user@contoso.com -MicrosoftAuthenticatorAuthenticationMethodId <id>Rotating an app registration secret without downtimeMicrosoft Entra (Identity)
Step 2: add the new credential alongside the old
$cred = Add-MgApplicationPassword -ApplicationId "app-object-id" -PasswordCredential @{ displayName = "rotation 2026-09"; endDateTime = (Get-Date).AddMonths(12) }
$cred.SecretTextGet-MgApplication -All -Property DisplayName,PasswordCredentials,KeyCredentials |
ForEach-Object { $app = $_; $app.PasswordCredentials + $app.KeyCredentials |
Where-Object EndDateTime -lt (Get-Date).AddDays(60) |
Select-Object @{n="App";e={$app.DisplayName}}, DisplayName, EndDateTime, KeyId }How to register devices for Windows AutopilotMicrosoft Intune (Devices)
2. Manual registration by hardware hash
Install-Script -Name Get-WindowsAutopilotInfo -Force
Get-WindowsAutopilotInfo -OutputFile C:\hash.csv -GroupTag "KW-EU"Intune scripts and proactive remediationsMicrosoft Intune (Devices)
# Detection
$svc = Get-Service -Name w32time -ErrorAction Stop
if ($svc.Status -eq 'Running') { exit 0 } else { exit 1 }# Remediation
Start-Service -Name w32time
Set-Service -Name w32time -StartupType AutomaticThe Office Deployment Tool deep diveMicrosoft Intune (Devices)
:: Download the installation files
setup.exe /download configuration.xml
:: Install Office using the downloaded files
setup.exe /configure configuration.xml
:: Uninstall existing Office
setup.exe /configure uninstall.xmlTroubleshooting Microsoft 365 Apps activationMicrosoft Intune (Devices)
# Windows
cd "C:\Program Files\Microsoft Office\root\Licensing16"
.\ospp.vbs /dstatus # diagnose
.\ospp.vbs /unpkeyremove:LASTFIVE # remove problematic keys
# Then sign back inHow to search the audit log in Microsoft PurviewMicrosoft Purview (Compliance)
5. PowerShell for scale and repeatability
Connect-ExchangeOnline
$start = (Get-Date).AddDays(-7); $end = Get-Date
$sessionId = "inv-2026-014"
$all = @()
do {
$batch = Search-UnifiedAuditLog -StartDate $start -EndDate $end -Operations FileDeleted,FileDeletedFirstStageRecycleBin `
-UserIds user@contoso.com -SessionId $sessionId -SessionCommand ReturnLargeSet -ResultSize 5000
$all += $batch
} while ($batch.Count -eq 5000)
$all | Select-Object CreationDate,UserIds,Operations,@{n="Object";e={($_.AuditData|ConvertFrom-Json).ObjectId}} |
Export-Csv .\deleted-files.csv -NoTypeInformationMicrosoft 365 audit log query patternsMicrosoft Purview (Compliance)
Mailbox compromise — what did the attacker do?
Search-UnifiedAuditLog `
-StartDate (Get-Date).AddDays(-7) `
-EndDate (Get-Date) `
-UserIds compromised.user@yourcompany.com `
-RecordType ExchangeItem,ExchangeAdminSuspicious file activity — mass downloads or shares
Search-UnifiedAuditLog `
-StartDate (Get-Date).AddDays(-1) `
-EndDate (Get-Date) `
-UserIds suspect.user@yourcompany.com `
-Operations FileDownloaded,FileSyncDownloadedFull,SharingSetAdmin changes — who did what to roles
Search-UnifiedAuditLog `
-StartDate (Get-Date).AddDays(-30) `
-EndDate (Get-Date) `
-RecordType AzureActiveDirectoryAccountLogon,AzureActiveDirectory `
-Operations "Add member to role.","Remove member from role."Search-UnifiedAuditLog `
-StartDate (Get-Date).AddDays(-7) `
-EndDate (Get-Date) `
-RecordType AzureActiveDirectory `
-Operations "Add OAuth2PermissionGrant.","Consent to application."Search-UnifiedAuditLog `
-StartDate (Get-Date).AddDays(-7) `
-EndDate (Get-Date) `
-Operations "SensitivityLabelApplied","SensitivityLabelChanged","SensitivityLabelRemoved"Search-UnifiedAuditLog `
-StartDate (Get-Date).AddDays(-30) `
-EndDate (Get-Date) `
-Operations SharingInvitationCreated,AnonymousLinkCreated,SecureLinkCreatedRecovering a deleted Team and its dataMicrosoft Teams
Get-MgDirectoryDeletedItemAsGroup -All | Where-Object DisplayName -eq "Project Falcon"
Restore-MgDirectoryDeletedItem -DirectoryObjectId "group-id"Teams meeting policies designMicrosoft Teams
Connect-MicrosoftTeams
# Create a custom policy
New-CsTeamsMeetingPolicy -Identity "Executive" `
-AllowCloudRecording $false `
-AllowMeetWatermark $true `
-DesignatedPresenterRoleMode "OrganizerOnlyUserOverride"
# Assign to a user
Grant-CsTeamsMeetingPolicy -Identity exec@yourcompany.com -PolicyName "Executive"Microsoft 365 tenant rebrandingMigration & Tenants
Get-Mailbox | ForEach-Object {
$newEmail = $_.Alias + "@newcompany.com"
Set-Mailbox $_ -EmailAddresses @{Add=$newEmail}
Set-Mailbox $_ -PrimarySmtpAddress $newEmail
}