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.