Skip to content

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

Getting started

PowerShell
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-MgGraph

How to convert a user mailbox to a shared mailboxExchange & Outlook

1. Check size and holds

PowerShell
Connect-ExchangeOnline
Get-MailboxStatistics leaver@contoso.com | Select-Object TotalItemSize
Get-Mailbox leaver@contoso.com | Format-List LitigationHoldEnabled,InPlaceHolds,ArchiveStatus,RecipientTypeDetails

3. Convert

PowerShell
Set-Mailbox leaver@contoso.com -Type Shared

4. Grant access

PowerShell
Add-MailboxPermission leaver@contoso.com -User successor@contoso.com -AccessRights FullAccess -AutoMapping $true
Add-RecipientPermission leaver@contoso.com -Trustee successor@contoso.com -AccessRights SendAs -Confirm:$false

How to put a mailbox on litigation holdExchange & Outlook

1. Confirm the licence

PowerShell
Connect-ExchangeOnline
Get-Mailbox user@contoso.com | Format-List RecipientTypeDetails,PersistedCapabilities,LitigationHoldEnabled

2. Enable the hold

PowerShell
Set-Mailbox user@contoso.com -LitigationHoldEnabled $true -LitigationHoldDuration 2555 `
  -LitigationHoldOwner legal@contoso.com -Comment "Matter 2026-014, per Legal 2026-09-03"

3. Bulk holds

PowerShell
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

1. Get the CNAME targets

PowerShell
Connect-ExchangeOnline
New-DkimSigningConfig -DomainName contoso.com -Enabled $false   # creates keys if missing
Get-DkimSigningConfig -Identity contoso.com | Format-List Selector1CNAME,Selector2CNAME

3. Enable signing

PowerShell
Set-DkimSigningConfig -Identity contoso.com -Enabled $true

Office 365 Message Encryption deep diveExchange & Outlook

Branding the OME portal

PowerShell
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"

Custom templates

PowerShell
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

Managing addresses

PowerShell
Set-Mailbox anna.svensson -EmailAddresses @{add="anna@contoso.com"}

Handling licence-count overrun surprisesMicrosoft 365 essentials

Step 1: measure the gap

PowerShell
Get-MgSubscribedSku | Select-Object SkuPartNumber, @{n="Enabled";e={$_.PrepaidUnits.Enabled}}, ConsumedUnits

Step 1: measure the gap

PowerShell
Get-MgUser -All -Filter "assignedLicenses/any(x:x/skuId eq 'sku-guid')" -ConsistencyLevel eventual -CountVariable c -Property DisplayName,UserPrincipalName,AccountEnabled,SignInActivity

How to offboard a user in Microsoft 365Microsoft 365 essentials

1. Block sign-in and revoke sessions (last day, at the agreed time)

PowerShell
Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.AccessAsUser.All"
Update-MgUser -UserId leaver@contoso.com -AccountEnabled:$false
Revoke-MgUserSignInSession -UserId leaver@contoso.com

2. Decide the mailbox path

PowerShell
Connect-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 $true

How to restore a deleted user in Microsoft 365Microsoft 365 essentials

1. Find the user

PowerShell
Connect-MgGraph -Scopes "User.ReadWrite.All"
Get-MgDirectoryDeletedItemAsUser -All | Where-Object UserPrincipalName -like "j.smith*" | Select-Object Id,UserPrincipalName,DeletedDateTime

3. Restore

PowerShell
Restore-MgDirectoryDeletedItem -DirectoryObjectId <object id>

Microsoft 365 cost optimisationMicrosoft 365 essentials

Reclaim inactive licences

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

Eliminate redundant SKUs

PowerShell
Get-MgUser -All -Property AssignedLicenses |
  Where-Object { $_.AssignedLicenses.Count -gt 1 } |
  # Detailed analysis of which SKUs overlap

Microsoft 365 reporting via PowerShellMicrosoft 365 essentials

Licence assignments

PowerShell
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, UserPrincipalName

Inactive users (no sign-in in 90 days)

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

Mailboxes over quota

PowerShell
Connect-ExchangeOnline
Get-EXOMailbox -ResultSize Unlimited |
  Get-EXOMailboxStatistics |
  Where-Object { $_.TotalItemSize -gt 49GB } |
  Select-Object DisplayName, TotalItemSize

Teams meeting recording locations

PowerShell
# 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 pattern

SharePoint site storage by site

PowerShell
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 -NoTypeInformation

Conditional Access policy assignments

PowerShell
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

PowerShell
Connect-MgGraph -Scopes "DeviceManagementManagedDevices.Read.All"
Get-MgDeviceManagementManagedDevice -All |
  Select-Object DeviceName, OperatingSystem, ComplianceState, LastSyncDateTime

Authentication patterns for production scripts

PowerShell
Connect-MgGraph -Scopes "User.Read.All"

Authentication patterns for production scripts

PowerShell
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

PowerShell
Get-MgDirectoryDeletedItemAsGroup -All | Select-Object DisplayName, Mail, DeletedDateTime, Id

Restore it

PowerShell
Restore-MgDirectoryDeletedItem -DirectoryObjectId "group-object-id"

Defender Threat IntelligenceMicrosoft Defender (Security)

Threat hunting with TI

KQL
// 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

KQL
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, ProcessCommandLine

Find PowerShell launching unusual scripts

KQL
DeviceProcessEvents
| where Timestamp > ago(1d)
| where FileName == "powershell.exe"
| where ProcessCommandLine has_any ("DownloadString", "FromBase64", "IEX", "Invoke-Expression")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine

Find unusual sign-in patterns

KQL
IdentityLogonEvents
| 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 desc

Find email URLs that were clicked

KQL
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 = Url

Find first-time-seen processes

KQL
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, FolderPath

How to block a compromised account in Microsoft 365Microsoft Defender (Security)

1. Block sign-in

PowerShell
Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.AccessAsUser.All"
Update-MgUser -UserId user@contoso.com -AccountEnabled:$false

2. Revoke sessions

PowerShell
Revoke-MgUserSignInSession -UserId user@contoso.com

5. Remove mailbox persistence

PowerShell
Connect-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.com

KQL primer for Defender XDRMicrosoft Defender (Security)

The basic shape

KQL
DeviceProcessEvents
| where Timestamp > ago(1d)
| where FileName == "powershell.exe"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
| order by Timestamp desc
| take 100

Time filtering

KQL
| where Timestamp > ago(1h)        // last hour
| where Timestamp > ago(7d)        // last 7 days
| where Timestamp between (datetime(2026-05-01) .. datetime(2026-05-05))

Counting and aggregation

KQL
DeviceLogonEvents
| where ActionType == "LogonFailed"
| where Timestamp > ago(1d)
| summarize count() by AccountName
| order by count_ desc

String operations

KQL
| 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"

Joining tables

KQL
DeviceProcessEvents
| where FileName == "rundll32.exe"
| where Timestamp > ago(1d)
| join DeviceNetworkEvents on DeviceId, Timestamp

Microsoft Sentinel analytic rulesMicrosoft Defender (Security)

Custom rule authoring

KQL
// 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 > 100

Cleaning up over-consented app permissionsMicrosoft Entra (Identity)

Two kinds of grant, two lists

PowerShell
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 -NoTypeInformation

Cleaning up unused enterprise apps in Entra IDMicrosoft Entra (Identity)

Step 1: get the whole list with signals

PowerShell
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 -NoTypeInformation

Cross-tenant calendar sharingMicrosoft Entra (Identity)

Exchange organisation relationships

PowerShell
# On Tenant A
New-OrganizationRelationship -Name "TenantB" `
    -DomainNames "tenantb.com" `
    -FreeBusyAccessEnabled $true `
    -FreeBusyAccessLevel AvailabilityOnly

How to assign licenses with group-based licensing in Entra IDMicrosoft Entra (Identity)

3. Assign the licence to the group

PowerShell
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

PowerShell
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)

6. Alert on every sign-in

KQL
SigninLogs
| where UserPrincipalName in~ ("svc-recovery-01@contoso.onmicrosoft.com","svc-recovery-02@contoso.onmicrosoft.com")
| project TimeGenerated, UserPrincipalName, IPAddress, ResultType, AppDisplayName

How to reset MFA for a user in Entra IDMicrosoft Entra (Identity)

2. Delete the method that is gone

PowerShell
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

PowerShell
$cred = Add-MgApplicationPassword -ApplicationId "app-object-id" -PasswordCredential @{ displayName = "rotation 2026-09"; endDateTime = (Get-Date).AddMonths(12) }
$cred.SecretText

Stop rotating by hand

PowerShell
Get-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

PowerShell
Install-Script -Name Get-WindowsAutopilotInfo -Force
Get-WindowsAutopilotInfo -OutputFile C:\hash.csv -GroupTag "KW-EU"

Intune scripts and proactive remediationsMicrosoft Intune (Devices)

Writing remediation pairs

PowerShell
# Detection
$svc = Get-Service -Name w32time -ErrorAction Stop
if ($svc.Status -eq 'Running') { exit 0 } else { exit 1 }

Writing remediation pairs

PowerShell
# Remediation
Start-Service -Name w32time
Set-Service -Name w32time -StartupType Automatic

The Office Deployment Tool deep diveMicrosoft Intune (Devices)

Running ODT

Command Prompt
:: 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.xml

Troubleshooting Microsoft 365 Apps activationMicrosoft Intune (Devices)

Activation token issues

PowerShell
# Windows
cd "C:\Program Files\Microsoft Office\root\Licensing16"
.\ospp.vbs /dstatus  # diagnose
.\ospp.vbs /unpkeyremove:LASTFIVE  # remove problematic keys
# Then sign back in

How to search the audit log in Microsoft PurviewMicrosoft Purview (Compliance)

5. PowerShell for scale and repeatability

PowerShell
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 -NoTypeInformation

Microsoft 365 audit log query patternsMicrosoft Purview (Compliance)

Mailbox compromise — what did the attacker do?

PowerShell
Search-UnifiedAuditLog `
    -StartDate (Get-Date).AddDays(-7) `
    -EndDate (Get-Date) `
    -UserIds compromised.user@yourcompany.com `
    -RecordType ExchangeItem,ExchangeAdmin

Suspicious file activity — mass downloads or shares

PowerShell
Search-UnifiedAuditLog `
    -StartDate (Get-Date).AddDays(-1) `
    -EndDate (Get-Date) `
    -UserIds suspect.user@yourcompany.com `
    -Operations FileDownloaded,FileSyncDownloadedFull,SharingSet

Admin changes — who did what to roles

PowerShell
Search-UnifiedAuditLog `
    -StartDate (Get-Date).AddDays(-30) `
    -EndDate (Get-Date) `
    -RecordType AzureActiveDirectoryAccountLogon,AzureActiveDirectory `
    -Operations "Add member to role.","Remove member from role."

OAuth consent grants

PowerShell
Search-UnifiedAuditLog `
    -StartDate (Get-Date).AddDays(-7) `
    -EndDate (Get-Date) `
    -RecordType AzureActiveDirectory `
    -Operations "Add OAuth2PermissionGrant.","Consent to application."

Sensitivity label changes

PowerShell
Search-UnifiedAuditLog `
    -StartDate (Get-Date).AddDays(-7) `
    -EndDate (Get-Date) `
    -Operations "SensitivityLabelApplied","SensitivityLabelChanged","SensitivityLabelRemoved"

Sharing audit

PowerShell
Search-UnifiedAuditLog `
    -StartDate (Get-Date).AddDays(-30) `
    -EndDate (Get-Date) `
    -Operations SharingInvitationCreated,AnonymousLinkCreated,SecureLinkCreated

Recovering a deleted Team and its dataMicrosoft Teams

Step 2: restore the group

PowerShell
Get-MgDirectoryDeletedItemAsGroup -All | Where-Object DisplayName -eq "Project Falcon"
Restore-MgDirectoryDeletedItem -DirectoryObjectId "group-id"

Teams meeting policies designMicrosoft Teams

Configuration via PowerShell

PowerShell
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

Update users

PowerShell
Get-Mailbox | ForEach-Object {
    $newEmail = $_.Alias + "@newcompany.com"
    Set-Mailbox $_ -EmailAddresses @{Add=$newEmail}
    Set-Mailbox $_ -PrimarySmtpAddress $newEmail
}

Handling an accidental external-sharing exposureSharePoint & OneDrive

Step 2: find every path

PowerShell
Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/Finance -Interactive
Get-PnPFileSharingLink -Identity "/sites/Finance/Shared Documents/Board" 
Get-PnPFolderSharingLink -Folder "Shared Documents/Board"

Handling an accidental mass delete of SharePoint filesSharePoint & OneDrive

Recycle bin: precise, manual, 93 days

PowerShell
Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/Finance -Interactive
Get-PnPRecycleBinItem -FirstStage | Where-Object DeletedByEmail -eq "user@contoso.com" | Where-Object DeletedDate -gt (Get-Date "2026-09-01 14:00") | Restore-PnPRecycleBinItem -Force

How to restrict external sharing for a SharePoint siteSharePoint & OneDrive

2. Restrict the site

PowerShell
Connect-SPOService -Url https://contoso-admin.sharepoint.com
Set-SPOSite -Identity https://contoso.sharepoint.com/sites/Finance -SharingCapability Disabled
# Or: ExistingExternalUserSharingOnly | ExternalUserSharingOnly | ExternalUserAndGuestSharing