PowerShell Script Tips & Tricks

I think most of this is doubled up in other notes but fuck it we publish.

Patterns and techniques for making scripts more reusable and user-friendly.


Ask for input instead of hardcoding

Use Read-Host to prompt for a value at runtime — no more swapping emails in Notepad.

$mailbox = Read-Host "Enter mailbox"

Or inline:

Get-Mailbox -Identity (Read-Host "Enter mailbox") | Select ArchiveQuota

Auto-connect to Exchange Online

Add this to the top of any EXO script. Connects only if not already connected.

if (-not (Get-ConnectionInformation)) {
    Connect-ExchangeOnline
}

Requires: ExchangeOnlineManagement module


Auto-connect to Microsoft Graph

Add this to the top of any Graph script. Connects only if not already connected.

if (-not (Get-MgContext)) {
    Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All"
}

Requires: Microsoft.Graph.Identity.SignIns module

Check if installed:

Get-Module Microsoft.Graph.Identity.SignIns -ListAvailable

Install if missing:

Install-Module Microsoft.Graph.Identity.SignIns

Check if connected to MgGraph

Get-MgContext

Environment Variables in Paths

PowerShell does not expand CMD-style environment variables like %USERPROFILE% inside strings. That syntax only works in Command Prompt and batch files.

In PowerShell, environment variables are accessed via $env:VARIABLENAME:

# Wrong — PowerShell treats this as a literal string
"$%USERPROFILE%\Desktop\file.csv"
 
# Right
"$env:USERPROFILE\Desktop\file.csv"

Common ones:

CMDPowerShell
%USERPROFILE%$env:USERPROFILE
%APPDATA%$env:APPDATA
%TEMP%$env:TEMP
%COMPUTERNAME%$env:COMPUTERNAME
%USERNAME%$env:USERNAME

Example — export CSV to desktop regardless of who’s logged in:

$results | Export-Csv -Path "$env:USERPROFILE\Desktop\LicensedUsers.csv" -NoTypeInformation

This works on any machine without hardcoding C:\Users\Rick\...


Write-Host — printing messages to the terminal

Use Write-Host to print status messages, section headers, or confirmations. It outputs directly to the terminal and doesn’t affect the pipeline.

# Basic message
Write-Host "Done."
 
# With a leading blank line for readability
Write-Host "`nDone."
 
# With a variable
Write-Host "`nExported to $env:USERPROFILE\Desktop\LicensedUsers.csv"

The backtick ` is PowerShell’s escape character. `n is a newline — handy for spacing output between sections.


Force immediate output formatting

PowerShell sometimes buffers pipeline output and prints it out of order. Add | Format-Table to force it to print immediately.

Get-MailboxStatistics $mailbox -Archive | Select DisplayName, TotalItemSize, ItemCount | Format-Table

Comparison Operators

PowerShell can’t use >, <, >= etc. directly in conditionals — it uses text-based operators instead:

OperatorMeaning
-eqEqual to
-neNot equal to
-gtGreater than
-geGreater than or equal to
-ltLess than
-leLess than or equal to
if ($hour -ge 8 -and $hour -lt 18) { ... }

Also useful for day-of-week checks — DayOfWeek returns the full day name as a string:

$day = (Get-Date).DayOfWeek
 
if ($day -ne 'Saturday' -and $day -ne 'Sunday') { ... }

Scripts

checkarchive.ps1

Check archive size and quota for a mailbox.

if (-not (Get-ConnectionInformation)) {
    Connect-ExchangeOnline
}
 
$mailbox = Read-Host "Enter mailbox"
 
Write-Host "`n--- Archive Stats ---"
Get-MailboxStatistics $mailbox -Archive | Select DisplayName, TotalItemSize, ItemCount | Format-Table
 
Write-Host "`n--- Archive Quota ---"
Get-Mailbox -Identity $mailbox | Select ArchiveQuota, ArchiveWarningQuota, AutoExpandingArchiveEnabled | Format-Table

newtap.ps1

Generate a Temporary Access Pass for a user.

if (-not (Get-MgContext)) {
    Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All"
}
 
New-MgUserAuthenticationTemporaryAccessPassMethod -UserId (Read-Host "Enter UPN") -LifetimeInMinutes 60 | Select TemporaryAccessPass

removetaps.ps1

Remove all Temporary Access Passes for a user.

if (-not (Get-MgContext)) {
    Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All"
}
 
$upn = Read-Host "Enter UPN"
Get-MgUserAuthenticationTemporaryAccessPassMethod -UserId $upn | ForEach-Object {
    Remove-MgUserAuthenticationTemporaryAccessPassMethod -UserId $upn -TemporaryAccessPassAuthenticationMethodId $_.Id
}

setpasswordneverexpires.ps1

Set password never expires on all enabled local accounts. Safe to run as system — only affects local accounts, not Entra/domain accounts.

Get-LocalUser | Where-Object {$_.Enabled -eq $true} | Set-LocalUser -PasswordNeverExpires $true

Notes

  • Scripts live at C:\Users\Rick\Scripts — symlinked to OneDrive - Coytis\Scripts so they sync across both PCs automatically
  • Always use Read-Host instead of hardcoded emails/UPNs in scripts that will be reused or published in KBs
  • Connection checks mean scripts are safe to run standalone or after an existing session — no double auth prompts