Migrating the Exchange Management Shell (5.1 → 7.x)
The Exchange snap-in (Microsoft.Exchange.Management.PowerShell.SnapIn,
.E2010, .Admin) is a binary snap-in that cannot load in PowerShell 7.
This is the single most common — and hardest — blocker in Exchange-heavy repos.
The fix is to stop loading a snap-in and instead connect to an Exchange
endpoint, which works from any PowerShell edition.
On-premises Exchange → implicit remoting
# 5.1 (remove this)
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn
# 7.x — connect to the Exchange remoting endpoint instead
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://<exchange-server>/PowerShell/" -Authentication Kerberos # or Negotiate
Import-PSSession $session -DisableNameChecking -AllowClobber
# ... run Exchange cmdlets exactly as before ...
Remove-PSSession $session
The imported cmdlets keep the same names and parameters, so most script bodies
are unchanged. Objects come back deserialized — properties survive, methods
do not; rewrite any $mbx.SomeMethod() calls to use cmdlets.
Exchange Online → EXO REST module
For Exchange Online, do not use WinRM remoting; use the REST-based module (works natively on PS7):
Install-Module ExchangeOnlineManagement # once
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
# ... Exchange Online cmdlets ...
Disconnect-ExchangeOnline -Confirm:$false
Prefer the -REST-backed cmdlets (Get-EXOMailbox, Get-EXORecipient, …) where
available — they are faster and paginate better than the classic aliases.
Migration steps per script
- Delete the
Add-PSSnapin Microsoft.Exchange...line(s). - Insert the correct connect block (on-prem remoting vs EXO) near the top.
- Add the matching disconnect/cleanup at the end (and in a
finally). - Parameterize the endpoint/credentials — do not hardcode servers or secrets.
- Replace method calls on returned objects with cmdlet equivalents.
Validation (Rung 4c — the honest limit)
Full behavioral parity needs a live Exchange/EXO environment, which this agent does not own. Do:
- Rung 1/2: parse + PSScriptAnalyzer clean (no snap-in remains).
- Prove the command surface matches after connecting:
Diff against the 5.1 parameter set.Get-Command Get-Mailbox | Select-Object -ExpandProperty Parameters - Use
-WhatIfin a staging org for mutating cmdlets where supported. - Otherwise record
needs-live-env/manual-signoff. Do not claim runtime validation that requires infrastructure you cannot reach.