Cloud Scripts

Ready-to-run PowerShell scripts for Exchange Online, Microsoft 365, and Entra ID. Edit variables inline, copy to clipboard, or download as a .ps1 file.

Get Mailbox Rules & Descriptions
Lists all inbox rules for a mailbox including name, enabled state, conditions, and actions. Useful for spotting auto-forward or deletion rules.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
Mailbox email
Get-InboxRule -Mailbox "##MAILBOX##" |
    Select-Object Name, Enabled, Description,
        @{N="Conditions";E={$_.Conditions | Out-String}},
        @{N="Actions";E={$_.Actions | Out-String}} |
    Format-List
Get All External Forwarding Rules
Finds all mailboxes that are forwarding email externally — either via ForwardingSmtpAddress or inbox rules. Critical for security audits.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
# Mailbox-level forwarding
Get-Mailbox -ResultSize Unlimited |
    Where-Object { $_.ForwardingSmtpAddress -ne $null } |
    Select-Object DisplayName, UserPrincipalName, ForwardingSmtpAddress, DeliverToMailboxAndForward |
    Format-Table -AutoSize

# Inbox rule forwarding
Get-Mailbox -ResultSize Unlimited | ForEach-Object {
    $rules = Get-InboxRule -Mailbox $_.UserPrincipalName -ErrorAction SilentlyContinue |
        Where-Object { $_.ForwardTo -or $_.RedirectTo -or $_.ForwardAsAttachmentTo }
    if ($rules) {
        Write-Host "Mailbox: $($_.UserPrincipalName)" -ForegroundColor Yellow
        $rules | Select-Object Name, ForwardTo, RedirectTo | Format-List
    }
}
List Shared Mailboxes & Permissions
Lists all shared mailboxes along with who has FullAccess and SendAs permissions on each.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
$sharedMailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited

foreach ($mailbox in $sharedMailboxes) {
    Write-Host "`n=== $($mailbox.DisplayName) ($($mailbox.PrimarySmtpAddress)) ===" -ForegroundColor Cyan

    $fullAccess = Get-MailboxPermission -Identity $mailbox.Identity |
        Where-Object { $_.AccessRights -like "*FullAccess*" -and $_.IsInherited -eq $false -and $_.User -notlike "NT AUTHORITY*" }

    $sendAs = Get-RecipientPermission -Identity $mailbox.Identity |
        Where-Object { $_.Trustee -notlike "NT AUTHORITY*" }

    Write-Host "  Full Access:" -ForegroundColor Green
    $fullAccess | Select-Object User, AccessRights | Format-Table -AutoSize

    Write-Host "  Send As:" -ForegroundColor Green
    $sendAs | Select-Object Trustee, AccessControlType | Format-Table -AutoSize
}
Get Mailbox Size & Item Count
Reports mailbox size, item count, and quota status for all mailboxes or a specific user. Sorted by size descending.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
Get-Mailbox -ResultSize Unlimited |
    Get-MailboxStatistics |
    Select-Object DisplayName,
        @{N="Size (MB)"; E={[math]::Round($_.TotalItemSize.Value.ToMB(), 2)}},
        ItemCount,
        @{N="Deleted (MB)"; E={[math]::Round($_.TotalDeletedItemSize.Value.ToMB(), 2)}},
        LastLogonTime |
    Sort-Object "Size (MB)" -Descending |
    Format-Table -AutoSize
Convert Mailbox to Shared
Converts a user mailbox to a shared mailbox and removes the assigned licence. The user account is left enabled for delegation purposes.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
User to convert
Remember to remove the licence in M365 admin after converting
$upn = "##USER_UPN##"

# Convert to shared mailbox
Set-Mailbox -Identity $upn -Type Shared
Write-Host "Converted $upn to shared mailbox" -ForegroundColor Green

# Verify
Get-Mailbox -Identity $upn | Select-Object DisplayName, RecipientTypeDetails, PrimarySmtpAddress
Get All Email Aliases (Proxy Addresses)
Lists every email address and alias across all mailboxes. Useful for finding alias conflicts or auditing email addresses in use.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
Get-Mailbox -ResultSize Unlimited | ForEach-Object {
    $mb = $_
    $mb.EmailAddresses | Where-Object { $_ -like "smtp:*" } | ForEach-Object {
        [PSCustomObject]@{
            DisplayName  = $mb.DisplayName
            UPN          = $mb.UserPrincipalName
            Type         = $mb.RecipientTypeDetails
            EmailAddress = $_ -replace "smtp:", ""
            IsPrimary    = $_ -clike "SMTP:*"
        }
    }
} | Sort-Object DisplayName | Format-Table -AutoSize
Remove User From All Groups
Removes a departing user from all distribution lists and mail-enabled security groups in Exchange Online.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
Departing user
$upn = "##USER_UPN##"

$groups = Get-Recipient -ResultSize Unlimited -RecipientTypeDetails MailUniversalDistributionGroup, MailUniversalSecurityGroup |
    Where-Object { (Get-DistributionGroupMember -Identity $_.Identity -ResultSize Unlimited).PrimarySmtpAddress -contains $upn }

if ($groups.Count -eq 0) {
    Write-Host "No groups found for $upn" -ForegroundColor Yellow
} else {
    foreach ($group in $groups) {
        Remove-DistributionGroupMember -Identity $group.Identity -Member $upn -Confirm:$false
        Write-Host "Removed from: $($group.DisplayName)" -ForegroundColor Green
    }
    Write-Host "`nTotal groups removed from: $($groups.Count)" -ForegroundColor Cyan
}
Get Mailbox Delegate Permissions
Reports all non-default FullAccess, SendAs, and SendOnBehalf permissions across all mailboxes.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
$report = @()
$mailboxes = Get-Mailbox -ResultSize Unlimited

foreach ($mb in $mailboxes) {
    # FullAccess
    Get-MailboxPermission -Identity $mb.Identity |
        Where-Object { $_.AccessRights -like "*FullAccess*" -and !$_.IsInherited -and $_.User -notlike "NT AUTHORITY*" } |
        ForEach-Object {
            $report += [PSCustomObject]@{
                Mailbox    = $mb.PrimarySmtpAddress
                Delegate   = $_.User
                Permission = "FullAccess"
            }
        }
    # SendAs
    Get-RecipientPermission -Identity $mb.Identity |
        Where-Object { $_.Trustee -notlike "NT AUTHORITY*" } |
        ForEach-Object {
            $report += [PSCustomObject]@{
                Mailbox    = $mb.PrimarySmtpAddress
                Delegate   = $_.Trustee
                Permission = "SendAs"
            }
        }
    # SendOnBehalf
    $mb.GrantSendOnBehalfTo | ForEach-Object {
        $report += [PSCustomObject]@{
            Mailbox    = $mb.PrimarySmtpAddress
            Delegate   = $_
            Permission = "SendOnBehalf"
        }
    }
}
$report | Sort-Object Mailbox | Format-Table -AutoSize
Block User Sign-In
Disables a user account to prevent sign-in. Use for leavers or compromised accounts. Does not delete the account or affect their mailbox.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.ReadWrite.All'
User UPN to block
$upn = "##USER_UPN##"

# Block sign-in
Update-MgUser -UserId $upn -AccountEnabled:$false

# Revoke all active sessions
Revoke-MgUserSignInSession -UserId $upn

Write-Host "Blocked sign-in and revoked sessions for: $upn" -ForegroundColor Green

# Verify
Get-MgUser -UserId $upn | Select-Object DisplayName, UserPrincipalName, AccountEnabled
Get MFA Status for All Users
Reports the MFA registration status for all users, including authentication methods registered. Uses Microsoft Graph.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'UserAuthenticationMethod.Read.All', 'User.Read.All'
$users = Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled

$report = foreach ($user in $users) {
    $methods = Get-MgUserAuthenticationMethod -UserId $user.Id
    $methodTypes = $methods.AdditionalProperties."@odata.type" -replace "#microsoft.graph.", ""

    [PSCustomObject]@{
        DisplayName       = $user.DisplayName
        UPN               = $user.UserPrincipalName
        AccountEnabled    = $user.AccountEnabled
        MFAMethodCount    = $methods.Count
        Methods           = ($methodTypes | Where-Object { $_ -ne "passwordAuthenticationMethod" }) -join ", "
        HasMFA            = ($methods.Count -gt 1)
    }
}

$report | Sort-Object HasMFA, DisplayName | Format-Table -AutoSize

Write-Host "`nUsers without MFA: $(($report | Where-Object { !$_.HasMFA }).Count)" -ForegroundColor Yellow
Write-Host "Users with MFA:    $(($report | Where-Object { $_.HasMFA }).Count)" -ForegroundColor Green
Get Last Sign-In Date for All Users
Reports the last interactive sign-in for every user. Useful for identifying inactive accounts.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.Read.All', 'AuditLog.Read.All'
Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled, SignInActivity |
    Select-Object DisplayName, UserPrincipalName, AccountEnabled,
        @{N="LastSignIn"; E={$_.SignInActivity.LastSignInDateTime}},
        @{N="DaysSinceSignIn"; E={
            if ($_.SignInActivity.LastSignInDateTime) {
                (New-TimeSpan -Start $_.SignInActivity.LastSignInDateTime -End (Get-Date)).Days
            } else { "Never" }
        }} |
    Sort-Object LastSignIn -Descending |
    Format-Table -AutoSize
Find Inactive Users (No Sign-In)
Lists users who have not signed in within a specified number of days. Useful for licence cleanup and security audits.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.Read.All', 'AuditLog.Read.All'
Days of inactivity
Users who have not signed in for this many days
$inactiveDays = ##DAYS##
$cutoff = (Get-Date).AddDays(-$inactiveDays)

Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled, SignInActivity |
    Where-Object {
        $_.AccountEnabled -eq $true -and (
            $_.SignInActivity.LastSignInDateTime -lt $cutoff -or
            $null -eq $_.SignInActivity.LastSignInDateTime
        )
    } |
    Select-Object DisplayName, UserPrincipalName,
        @{N="LastSignIn"; E={$_.SignInActivity.LastSignInDateTime ?? "Never"}},
        @{N="DaysInactive"; E={
            if ($_.SignInActivity.LastSignInDateTime) {
                (New-TimeSpan -Start $_.SignInActivity.LastSignInDateTime -End (Get-Date)).Days
            } else { "Never signed in" }
        }} |
    Sort-Object LastSignIn |
    Format-Table -AutoSize
Get All Licensed Users
Lists all users with assigned licences, showing which licence SKUs are assigned to each account.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.Read.All'
# Get friendly SKU name mapping
$skuMap = @{}
Get-MgSubscribedSku | ForEach-Object { $skuMap[$_.SkuId] = $_.SkuPartNumber }

Get-MgUser -All -Property DisplayName, UserPrincipalName, AccountEnabled, AssignedLicenses |
    Where-Object { $_.AssignedLicenses.Count -gt 0 } |
    Select-Object DisplayName, UserPrincipalName, AccountEnabled,
        @{N="Licences"; E={
            ($_.AssignedLicenses | ForEach-Object { $skuMap[$_.SkuId] ?? $_.SkuId }) -join ", "
        }} |
    Sort-Object DisplayName |
    Format-Table -AutoSize

$total = (Get-MgUser -All -Filter "assignedLicenses/`$count ne 0" -ConsistencyLevel eventual -CountVariable c; $c)
Write-Host "`nTotal licensed users: $total" -ForegroundColor Cyan
Force Password Reset at Next Sign-In
Forces a user to change their password the next time they sign in. Does not change the current password.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.ReadWrite.All'
User UPN
$upn = "##USER_UPN##"

Update-MgUser -UserId $upn -PasswordProfile @{
    ForceChangePasswordNextSignIn = $true
}

Write-Host "Password reset flag set for: $upn" -ForegroundColor Green
Write-Host "User will be prompted to change password on next sign-in." -ForegroundColor Yellow
Get All Admin Role Members
Lists every admin role in the tenant and all users assigned to each role. Useful for access reviews and privilege audits.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'RoleManagement.Read.Directory', 'User.Read.All'
$roles = Get-MgDirectoryRole -All

foreach ($role in $roles | Sort-Object DisplayName) {
    $members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id
    if ($members.Count -gt 0) {
        Write-Host "`n=== $($role.DisplayName) ===" -ForegroundColor Cyan
        $members | ForEach-Object {
            $user = Get-MgUser -UserId $_.Id -ErrorAction SilentlyContinue
            if ($user) {
                Write-Host "  $($user.DisplayName) <$($user.UserPrincipalName)>"
            }
        }
    }
}
Get All Guest Users
Lists all guest (external) accounts in the tenant with their invite status and last sign-in date.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.Read.All', 'AuditLog.Read.All'
Get-MgUser -All -Filter "userType eq 'Guest'" -Property DisplayName, UserPrincipalName, Mail, CreatedDateTime, SignInActivity |
    Select-Object DisplayName, UserPrincipalName, Mail,
        @{N="Created";      E={$_.CreatedDateTime}},
        @{N="LastSignIn";   E={$_.SignInActivity.LastSignInDateTime ?? "Never"}} |
    Sort-Object Created -Descending |
    Format-Table -AutoSize
Revoke All User Sessions
Immediately invalidates all active sign-in sessions and refresh tokens for a user. Use for compromised accounts.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.ReadWrite.All'
User UPN
$upn = "##USER_UPN##"

Revoke-MgUserSignInSession -UserId $upn

Write-Host "All sessions revoked for: $upn" -ForegroundColor Green
Write-Host "The user will be signed out of all apps and devices immediately." -ForegroundColor Yellow

# Also block sign-in if this is a security incident
# Update-MgUser -UserId $upn -AccountEnabled:$false
Get All Conditional Access Policies
Lists all Conditional Access policies with their state, included/excluded users, and conditions.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'Policy.Read.All'
Get-MgIdentityConditionalAccessPolicy -All |
    Select-Object DisplayName, State,
        @{N="IncludeUsers";  E={$_.Conditions.Users.IncludeUsers -join ", "}},
        @{N="ExcludeUsers";  E={$_.Conditions.Users.ExcludeUsers -join ", "}},
        @{N="IncludeApps";   E={$_.Conditions.Applications.IncludeApplications -join ", "}},
        @{N="GrantControls"; E={$_.GrantControls.BuiltInControls -join ", "}} |
    Format-List
M365 Licence Usage Summary
Shows each subscribed SKU, total seats, consumed seats, and remaining seats. Handy for licence capacity checks.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'Organization.Read.All'
Get-MgSubscribedSku |
    Select-Object SkuPartNumber,
        @{N="Total"; E={$_.PrepaidUnits.Enabled}},
        ConsumedUnits,
        @{N="Available"; E={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}} |
    Sort-Object SkuPartNumber |
    Format-Table -AutoSize
Get Disabled Cloud Users
Lists disabled Entra user accounts with UPN and creation date. Useful for leaver and stale-account reviews.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'User.Read.All'
Get-MgUser -All -Property DisplayName,UserPrincipalName,AccountEnabled,CreatedDateTime |
    Where-Object { $_.AccountEnabled -eq $false } |
    Select-Object DisplayName, UserPrincipalName, CreatedDateTime |
    Sort-Object DisplayName |
    Format-Table -AutoSize
Get User Authentication Methods
Lists registered authentication methods for a user (Authenticator app, phone, FIDO2, etc).
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'UserAuthenticationMethod.Read.All', 'User.Read.All'
User UPN
$upn = "##USER_UPN##"
$user = Get-MgUser -UserId $upn -ErrorAction SilentlyContinue

if (-not $user) {
    Write-Host "User not found: $upn" -ForegroundColor Red
    return
}

Get-MgUserAuthenticationMethod -UserId $user.Id |
    Select-Object Id,
        @{N="MethodType"; E={$_.AdditionalProperties."@odata.type" -replace "#microsoft.graph.",""}} |
    Format-Table -AutoSize
Get Mailbox Auto-Reply Status
Reports automatic reply (out-of-office) configuration for all user mailboxes.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited |
    ForEach-Object {
        $ar = Get-MailboxAutoReplyConfiguration -Identity $_.UserPrincipalName
        [PSCustomObject]@{
            DisplayName      = $_.DisplayName
            UserPrincipalName= $_.UserPrincipalName
            AutoReplyState   = $ar.AutoReplyState
            InternalMessage  = $ar.InternalMessage
            ExternalMessage  = $ar.ExternalMessage
        }
    } |
    Sort-Object DisplayName |
    Format-Table -AutoSize
Get Locked Out AD Accounts
Finds all currently locked-out Active Directory accounts with the lockout time and source DC.
Active Directory ActiveDirectory
Install-WindowsFeature RSAT-AD-PowerShell # Server&#10;# Or for Windows 10/11: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Run on a Domain Controller or machine with RSAT installed
Search-ADAccount -LockedOut |
    Get-ADUser -Properties LockedOut, BadLogonCount, BadPasswordTime, LastBadPasswordAttempt |
    Select-Object Name, SamAccountName, LockedOut, BadLogonCount, LastBadPasswordAttempt |
    Format-Table -AutoSize
Unlock AD Account
Unlocks a locked Active Directory user account.
Active Directory ActiveDirectory
Install-WindowsFeature RSAT-AD-PowerShell # Server&#10;# Or for Windows 10/11: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Run on a Domain Controller or machine with RSAT installed
SAM account name
$samAccount = "##SAM_ACCOUNT##"

Unlock-ADAccount -Identity $samAccount
Write-Host "Unlocked account: $samAccount" -ForegroundColor Green

# Verify
Get-ADUser -Identity $samAccount -Properties LockedOut, BadLogonCount |
    Select-Object Name, SamAccountName, LockedOut, BadLogonCount
Find Inactive AD Users
Lists enabled AD user accounts that have not logged on within a specified number of days.
Active Directory ActiveDirectory
Install-WindowsFeature RSAT-AD-PowerShell # Server&#10;# Or for Windows 10/11: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Run on a Domain Controller or machine with RSAT installed
Days of inactivity
$inactiveDays = ##DAYS##
$cutoff = (Get-Date).AddDays(-$inactiveDays)

Get-ADUser -Filter { Enabled -eq $true } -Properties LastLogonDate, Description |
    Where-Object { $_.LastLogonDate -lt $cutoff -or $_.LastLogonDate -eq $null } |
    Select-Object Name, SamAccountName, LastLogonDate, Description |
    Sort-Object LastLogonDate |
    Format-Table -AutoSize
Get AD Group Members
Lists all members of a specified Active Directory group, including nested group resolution.
Active Directory ActiveDirectory
Install-WindowsFeature RSAT-AD-PowerShell # Server&#10;# Or for Windows 10/11: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Run on a Domain Controller or machine with RSAT installed
Group name
$groupName = "##GROUP_NAME##"

# Direct members
Write-Host "Direct members of: $groupName" -ForegroundColor Cyan
Get-ADGroupMember -Identity $groupName | Get-ADUser -Properties EmailAddress |
    Select-Object Name, SamAccountName, EmailAddress | Format-Table -AutoSize

# All members including nested
Write-Host "`nAll members (including nested groups):" -ForegroundColor Cyan
Get-ADGroupMember -Identity $groupName -Recursive | Get-ADUser -Properties EmailAddress |
    Select-Object Name, SamAccountName, EmailAddress | Format-Table -AutoSize
Reset AD Password & Force Change
Resets an Active Directory user password and forces them to change it at next logon.
Active Directory ActiveDirectory
Install-WindowsFeature RSAT-AD-PowerShell # Server&#10;# Or for Windows 10/11: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Run on a Domain Controller or machine with RSAT installed
SAM account name
Temporary password
Must meet your domain password policy
$samAccount = "##SAM_ACCOUNT##"
$newPassword = ConvertTo-SecureString "##TEMP_PASSWORD##" -AsPlainText -Force

Set-ADAccountPassword -Identity $samAccount -NewPassword $newPassword -Reset
Set-ADUser -Identity $samAccount -ChangePasswordAtLogon $true

Write-Host "Password reset for: $samAccount" -ForegroundColor Green
Write-Host "User must change password at next logon." -ForegroundColor Yellow
Get Recently Created AD Accounts
Lists AD user accounts created within the last N days. Useful for onboarding audits.
Active Directory ActiveDirectory
Install-WindowsFeature RSAT-AD-PowerShell # Server&#10;# Or for Windows 10/11: Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Run on a Domain Controller or machine with RSAT installed
Created in last N days
$days = ##DAYS##
$cutoff = (Get-Date).AddDays(-$days)

Get-ADUser -Filter { WhenCreated -ge $cutoff } -Properties WhenCreated, EmailAddress, Description |
    Select-Object Name, SamAccountName, WhenCreated, EmailAddress, Description |
    Sort-Object WhenCreated -Descending |
    Format-Table -AutoSize
Get Local Disk Free Space
Shows local fixed drives with total size, free space, and free percentage. Great for proactive storage checks.
Local Windows Built-in
# No module install required (built into Windows PowerShell)
# Run in an elevated PowerShell session on the target machine
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
    Select-Object DeviceID,
        @{N="Size (GB)"; E={[math]::Round($_.Size / 1GB, 2)}},
        @{N="Free (GB)"; E={[math]::Round($_.FreeSpace / 1GB, 2)}},
        @{N="Free %"; E={[math]::Round(($_.FreeSpace / $_.Size) * 100, 1)}} |
    Sort-Object "Free %" |
    Format-Table -AutoSize
Get Local Administrators Group Members
Lists all members of the local Administrators group. Useful for privilege auditing on endpoints and servers.
Local Windows Built-in
# No module install required (built into Windows PowerShell)
# Run in an elevated PowerShell session on the target machine
Get-LocalGroupMember -Group "Administrators" |
    Select-Object Name, ObjectClass, PrincipalSource |
    Sort-Object Name |
    Format-Table -AutoSize
Get Top CPU Processes (Live Sample)
Samples process CPU usage over a short interval and returns the top CPU consumers.
Local Windows Built-in
# No module install required (built into Windows PowerShell)
# Run in PowerShell on the target machine
Sample duration (seconds)
$sampleSeconds = ##SECONDS##

$before = Get-Process | Select-Object Id, ProcessName, CPU
Start-Sleep -Seconds $sampleSeconds
$after = Get-Process | Select-Object Id, ProcessName, CPU

$report = foreach ($p in $after) {
    $old = $before | Where-Object { $_.Id -eq $p.Id }
    if ($old -and $p.CPU -ne $null -and $old.CPU -ne $null) {
        [PSCustomObject]@{
            ProcessName = $p.ProcessName
            Id          = $p.Id
            CpuSeconds  = [math]::Round(($p.CPU - $old.CPU), 2)
        }
    }
}

$report | Sort-Object CpuSeconds -Descending | Select-Object -First 15 | Format-Table -AutoSize
Get Automatic Services Not Running
Finds services set to Automatic startup that are currently stopped.
Local Windows Built-in
# No module install required (built into Windows PowerShell)
# Run in PowerShell on the target machine
Get-Service |
    Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
    Select-Object Name, DisplayName, Status, StartType |
    Sort-Object DisplayName |
    Format-Table -AutoSize
Find Suspicious Mailbox Rules
Scans all mailboxes for potentially malicious inbox rules — rules that forward externally, delete messages, or redirect silently. Common indicator of compromise.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
$suspicious = @()

Get-Mailbox -ResultSize Unlimited | ForEach-Object {
    $mbx = $_
    Get-InboxRule -Mailbox $mbx.UserPrincipalName -ErrorAction SilentlyContinue |
        Where-Object {
            $_.ForwardTo -or $_.RedirectTo -or $_.ForwardAsAttachmentTo -or
            $_.DeleteMessage -eq $true -or $_.MoveToFolder -ne $null
        } | ForEach-Object {
            $suspicious += [PSCustomObject]@{
                Mailbox     = $mbx.UserPrincipalName
                RuleName    = $_.Name
                Enabled     = $_.Enabled
                ForwardTo   = $_.ForwardTo -join "; "
                RedirectTo  = $_.RedirectTo -join "; "
                DeleteMsg   = $_.DeleteMessage
                MoveToFolder = $_.MoveToFolder
            }
        }
}

if ($suspicious.Count -eq 0) {
    Write-Host "No suspicious rules found." -ForegroundColor Green
} else {
    Write-Host "WARNING: $($suspicious.Count) suspicious rule(s) found!" -ForegroundColor Red
    $suspicious | Format-List
}
Search M365 Unified Audit Log
Searches the Microsoft 365 unified audit log for admin and user activity. Results are limited to 5000 records; narrow your date range for large tenants.
Exchange Online ExchangeOnlineManagement
Install-Module ExchangeOnlineManagement -Force
Connect-ExchangeOnline -UserPrincipalName ##ADMIN_UPN##
Admin UPN
Look back (days)
$startDate = (Get-Date).AddDays(-##DAYS##).ToString("yyyy-MM-dd")
$endDate   = (Get-Date).ToString("yyyy-MM-dd")

$results = Search-UnifiedAuditLog `
    -StartDate $startDate `
    -EndDate   $endDate `
    -ResultSize 500

$results |
    Select-Object CreationDate, UserIds, Operations, AuditData |
    Sort-Object CreationDate -Descending |
    Format-Table -AutoSize

Write-Host "`nTotal records: $($results.Count)" -ForegroundColor Cyan
Get App Registrations & Permissions
Lists all Azure AD app registrations and their assigned API permissions. Important for security audits and app inventory.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'Application.Read.All'
$apps = Get-MgApplication -All

foreach ($app in $apps | Sort-Object DisplayName) {
    Write-Host "`n=== $($app.DisplayName) ===" -ForegroundColor Cyan
    Write-Host "  App ID:  $($app.AppId)"
    Write-Host "  Created: $($app.CreatedDateTime)"

    if ($app.RequiredResourceAccess) {
        Write-Host "  API Permissions:" -ForegroundColor Yellow
        foreach ($resource in $app.RequiredResourceAccess) {
            Write-Host "    Resource: $($resource.ResourceAppId)"
            $resource.ResourceAccess | ForEach-Object {
                Write-Host "      $($_.Type): $($_.Id)"
            }
        }
    }
}
Get Recent Sign-In Failures
Retrieves failed sign-in events from Entra ID logs. Useful for detecting brute-force attacks or account compromise attempts.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'AuditLog.Read.All'
Look back (hours)
$startTime = (Get-Date).AddHours(-##HOURS##).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")

Get-MgAuditLogSignIn -Filter "status/errorCode ne 0 and createdDateTime ge $startTime" -All |
    Select-Object CreatedDateTime, UserPrincipalName,
        @{N="Error";        E={$_.Status.FailureReason}},
        @{N="IP";           E={$_.IpAddress}},
        @{N="Location";     E={"$($_.Location.City), $($_.Location.CountryOrRegion)"}},
        @{N="AppName";      E={$_.AppDisplayName}} |
    Sort-Object CreatedDateTime -Descending |
    Format-Table -AutoSize
Get All Teams & Owners
Lists all Microsoft Teams in the tenant with their owners, member count, and visibility setting.
Entra ID / M365 Microsoft.Graph
Install-Module Microsoft.Graph -Force
Connect-MgGraph -Scopes 'Group.Read.All', 'User.Read.All'
$teams = Get-MgGroup -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" -All `
    -Property Id, DisplayName, Description, Visibility, CreatedDateTime

foreach ($team in $teams | Sort-Object DisplayName) {
    $owners = Get-MgGroupOwner -GroupId $team.Id
    $members = Get-MgGroupMember -GroupId $team.Id -All

    [PSCustomObject]@{
        Team        = $team.DisplayName
        Visibility  = $team.Visibility
        Members     = $members.Count
        Owners      = ($owners | ForEach-Object {
            (Get-MgUser -UserId $_.Id -ErrorAction SilentlyContinue).UserPrincipalName
        }) -join "; "
        Created     = $team.CreatedDateTime
    }
} | Format-Table -AutoSize
No scripts match your search.

Frequently asked questions

How do I use these scripts?
Fill in any variables shown above the script, then click Copy or Download .ps1. Run the script in PowerShell 5.1+ or PowerShell 7. Most scripts require a module to be installed first — the required module and install command are shown on each card.
Do I need to connect before running each script?
Yes. Each script group shows a Connect command at the top. For Exchange Online, run Connect-ExchangeOnline first. For Microsoft Graph, run Connect-MgGraph with the required scopes. For Azure AD legacy, run Connect-AzureAD.
Are these scripts safe to run in production?
All scripts are read-only (Get-* commands) unless explicitly described as making changes. Scripts that modify settings or block accounts are clearly labelled. Always test in a non-production environment first and ensure you have appropriate permissions.