PowerShell Playbook: 15 Real Scripts That Save Hours of Admin Work in 2026

[For IT Pros]

If you work in IT in 2026 and you're still doing repetitive admin tasks by hand, you're burning time you’ll never get back. PowerShell is still the easiest way to take back your day – but most people never get past a few one-liners.

This is a practical script pack, not theory. Use these examples as copy-paste starters, then adapt them to your environment (Azure AD / Entra ID, M365, Intune, on-prem AD, hybrid).

1. Bulk Onboard Users with a Single CSV (Hybrid or Cloud-Only)

New starters should not require 20 minutes of clicking in three portals. Drive it from HR’s CSV and let PowerShell handle the plumbing.

1.1. Sample CSV format

UserPrincipalName,DisplayName,GivenName,Surname,Department,JobTitle,UsageLocation,LicenseSku
[email protected],Jane Doe,Jane,Doe,Finance,Accountant,GB,ENTERPRISEPREMIUM

1.2. Entra ID (Azure AD) user creation with licensing

Connect-MgGraph -Scopes User.ReadWrite.All,Directory.ReadWrite.All
Select-MgProfile -Name beta

$users = Import-Csv .\new-users.csv

$skus = Get-MgSubscribedSku | Group-Object SkuPartNumber -AsHashTable -AsString

foreach ($u in $users) {
    $passwordProfile = @{ forceChangePasswordNextSignIn = $true; password = [System.Web.Security.Membership]::GeneratePassword(14,3) }

    $userParams = @{
        AccountEnabled   = $true
        DisplayName      = $u.DisplayName
        MailNickname     = $u.GivenName + $u.Surname
        UserPrincipalName= $u.UserPrincipalName
        GivenName        = $u.GivenName
        Surname          = $u.Surname
        Department       = $u.Department
        JobTitle         = $u.JobTitle
        UsageLocation    = $u.UsageLocation
        PasswordProfile  = $passwordProfile
    }

    $user = New-MgUser @userParams

    if ($u.LicenseSku -and $skus.ContainsKey($u.LicenseSku)) {
        Set-MgUserLicense -UserId $user.Id -AddLicenses @{SkuId = $skus[$u.LicenseSku].SkuId} -RemoveLicenses @()
    }

    Write-Host "Created: $($u.UserPrincipalName)" -ForegroundColor Green
}

Why this matters: This replaces the classic dance of creating the user, setting attributes, then jumping to M365 admin for licensing.

2. Quick Health Checks You Can Run Before a Ticket Storm

These are the scripts you run when something "feels off". They give you signal before users start shouting.

2.1. Check Domain Controllers for obvious problems (on-prem)

$dcs = Get-ADDomainController -Filter *

foreach ($dc in $dcs) {
    Write-Host "=== $($dc.HostName) ===" -ForegroundColor Cyan

    Test-ComputerSecureChannel -Server $dc.HostName -Verbose

    Get-WinEvent -ComputerName $dc.HostName -LogName System -MaxEvents 200 |
        Where-Object { $_.LevelDisplayName -in 'Error','Critical' } |
        Select-Object -First 10 TimeCreated, Id, LevelDisplayName, Message

    repadmin /replsummary | Out-Host
}

2.2. M365 service connectivity test from a server or jump box

$urls = @(
  'https://outlook.office365.com',
  'https://login.microsoftonline.com',
  'https://graph.microsoft.com',
  'https://teams.microsoft.com'
)

foreach ($u in $urls) {
    try {
        $r = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 15
        Write-Host "OK  - $u ($($r.StatusCode))" -ForegroundColor Green
    }
    catch {
        Write-Host "BAD - $u ($($_.Exception.Message))" -ForegroundColor Red
    }
}

Use case: You’ll quickly see if this is a local firewall / proxy problem or a genuine upstream outage.

3. Intune & Endpoint: Real-World Maintenance Scripts

In 2026, Intune is at the centre of most endpoint strategies, but there are still a lot of gaps that scripts can close. Use these for compliance, cleanup, and remote troubleshooting.

3.1. Clean up old Intune devices that haven't checked in

Connect-MgGraph -Scopes Device.ReadWrite.All
Select-MgProfile -Name beta

$cutoff = (Get-Date).AddDays(-45)

$staleDevices = Get-MgDevice -All | Where-Object {
    $_.ApproximateLastSignInDateTime -lt $cutoff -and
    $_.DeviceTrustType -eq 'AzureAD'
}

Write-Host "Found $($staleDevices.Count) stale devices." -ForegroundColor Yellow

$staleDevices | Select-Object DisplayName, Id, ApproximateLastSignInDateTime |
    Format-Table -AutoSize

$confirm = Read-Host "Type YES to delete these devices from Entra ID"
if ($confirm -eq 'YES') {
    foreach ($d in $staleDevices) {
        Remove-MgDevice -DeviceId $d.Id -Confirm:$false
        Write-Host "Deleted: $($d.DisplayName)" -ForegroundColor Green
    }
}

3.2. Remote log collector for Windows endpoints (via Intune script)

Drop this as an Intune Proactive Remediation or script to quickly gather logs when something breaks at scale.

$root = "C:\SupportLogs"
New-Item -Path $root -ItemType Directory -Force | Out-Null

$items = @(
  'C:\Windows\CCM\Logs',
  'C:\Windows\Logs',
  'C:\ProgramData\Microsoft\IntuneManagementExtension\Logs'
)

foreach ($i in $items) {
  if (Test-Path $i) {
    Copy-Item $i -Destination $root -Recurse -Force -ErrorAction SilentlyContinue
  }
}

$zipPath = "C:\SupportLogs-$(($env:COMPUTERNAME) + '-' + (Get-Date -Format yyyyMMddHHmm)).zip"
Compress-Archive -Path $root -DestinationPath $zipPath -Force
Write-Host "LOG_PACKAGE=$zipPath"

How to use: Trigger this script, ask the user for the resulting ZIP path printed in the console (or harvest via Log Analytics if you tie it in).

4. Stronger Security Defaults in Minutes, Not Months

You don’t need a full Zero Trust project plan to improve security this afternoon. These PowerShell snippets help you standardise across Entra ID and M365.

4.1. Baseline conditional access export (for change tracking)

Connect-MgGraph -Scopes Policy.Read.All
Select-MgProfile -Name beta

$policies = Get-MgIdentityConditionalAccessPolicy -All

$timestamp = Get-Date -Format 'yyyyMMdd-HHmm'
$policies | ConvertTo-Json -Depth 10 | 
    Out-File ".\CA-Backup-$timestamp.json" -Encoding UTF8

Write-Host "Exported $($policies.Count) CA policies" -ForegroundColor Green

Why: Before anyone starts "tidying" CA policies, have a JSON backup you can diff or restore from.

4.2. Find users with no MFA and high-risk configuration

Connect-MgGraph -Scopes AuditLog.Read.All,Directory.Read.All
Select-MgProfile -Name beta

# Note: by 2026, most orgs are on combined security info registration
$authMethods = Get-MgReportAuthenticationMethodUserRegistrationDetail -All

$atRisk = $authMethods | Where-Object {
    -not $_.IsMfaRegistered -or
    ($_.IsMfaRegistered -and $_.DefaultMfaMethod -eq 'sms')
}

$atRisk | Select-Object UserPrincipalName, IsMfaRegistered, DefaultMfaMethod |
    Export-Csv .\Users-Weak-MFA.csv -NoTypeInformation

Write-Host "Exported $($atRisk.Count) risky accounts to Users-Weak-MFA.csv" -ForegroundColor Yellow

This does not fix anything by itself, but it gives you a priority list to feed into conditional access, training, or targeted campaigns.

5. Everyday Admin: File Servers, Shares, and Reports

Not everything lives in the cloud yet. These are the little scripts that save you from RDP-ing into a file server 50 times a week.

5.1. Report NTFS perms on a share in a readable way

$path = "D:\Shares\Finance"
$out  = ".\Finance-NTFS-Permissions.csv"

$results = @()

Get-ChildItem -Path $path -Recurse | ForEach-Object {
    $acl = Get-Acl $_.FullName
    foreach ($ace in $acl.Access) {
        $results += [pscustomobject]@{
            Path       = $_.FullName
            Identity   = $ace.IdentityReference
            Rights     = $ace.FileSystemRights
            Inherited  = $ace.IsInherited
            Type       = $ace.AccessControlType
        }
    }
}

$results | Export-Csv $out -NoTypeInformation
Write-Host "Exported NTFS report to $out" -ForegroundColor Green

5.2. Quick stale file cleanup with a safety report first

$path = "D:\Shares\Temp"
$days = 30
$cutoff = (Get-Date).AddDays(-$days)

$stale = Get-ChildItem $path -Recurse -File | Where-Object {
    $_.LastWriteTime -lt $cutoff
}

$report = ".\Temp-StaleFiles-$((Get-Date -Format yyyyMMdd)).csv"
$stale | Select-Object FullName, Length, LastWriteTime |
    Export-Csv $report -NoTypeInformation

Write-Host "Found $($stale.Count) stale files. Report: $report" -ForegroundColor Yellow

$confirm = Read-Host "Type DELETE to remove these files"
if ($confirm -eq 'DELETE') {
    $stale | Remove-Item -Force
    Write-Host "Deleted stale files" -ForegroundColor Green
}

Tip: Run this on a test folder first and send the report to the data owner before deleting anything.

6. Self-Defence: Audit Logs & Change Tracking

When something goes wrong – a misconfig, suspected insider activity, or just a fat-finger – PowerShell gives you the fastest view of "who did what when".

6.1. Quick Entra ID audit search for risky changes

Connect-MgGraph -Scopes AuditLog.Read.All
Select-MgProfile -Name beta

$since = (Get-Date).AddDays(-3)

$ops = Get-MgAuditLogDirectoryAudit -Filter "activityDateTime ge $($since.ToString('o'))" -All

$risky = $ops | Where-Object {
    $_.ActivityDisplayName -match 'Add member to role' -or
    $_.ActivityDisplayName -match 'Update conditional access policy' -or
    $_.ActivityDisplayName -match 'Reset password'
}

$risky | Select-Object ActivityDateTime, InitiatedBy, ActivityDisplayName, TargetResources |
    Export-Csv .\Entra-RiskyChanges.csv -NoTypeInformation

Write-Host "Exported risky changes to Entra-RiskyChanges.csv" -ForegroundColor Yellow

6.2. Local admin membership drift detector (for servers or critical endpoints)

$baselinePath = "C:\Baselines\LocalAdmins.json"
$group = 'Administrators'

$members = Get-LocalGroupMember -Group $group | Select-Object Name, ObjectClass

if (-not (Test-Path $baselinePath)) {
    $members | ConvertTo-Json | Out-File $baselinePath -Encoding UTF8
    Write-Host "Baseline created at $baselinePath" -ForegroundColor Green
    return
}

$baseline = Get-Content $baselinePath | ConvertFrom-Json

$added   = Compare-Object -ReferenceObject $baseline -DifferenceObject $members -PassThru | 
           Where-Object { $_.SideIndicator -eq '=>' }
$removed = Compare-Object -ReferenceObject $baseline -DifferenceObject $members -PassThru | 
           Where-Object { $_.SideIndicator -eq '<=' }

Write-Host "Added:" -ForegroundColor Yellow
$added | Format-Table

Write-Host "Removed:" -ForegroundColor Yellow
$removed | Format-Table

Usage pattern: Run once to set a baseline on a gold image or critical server, then on a schedule to detect silent changes.

7. Turn This into Your Own Script Toolkit

The biggest win is not any single script above – it is building your own repeatable toolkit. Create a private Git repo (or DevOps project), drop these scripts in logical folders (Onboarding, Intune, Security, FileServers, Reports), and standardise how your team runs them.

Pick one pain point this week – maybe user onboarding, Intune cleanup, or MFA reporting – and turn it into a script you can run in under 30 seconds. Once you’ve done that once, keep iterating; in 6 months, you’ll have a library that quietly saves you several hours every single week.