Practices
Test first
Test first
Always run scripts in a non-production or development environment before executing against live systems. Even small configuration differences between environments can produce unexpected outcomes.Create a dedicated test OU in Active Directory, a non-production vSphere cluster, or a Microsoft 365 developer tenant to validate behavior safely.
Review before running
Review before running
Read every line of a script and understand what it does before executing it. Pay attention to:
- What objects are targeted (all users, a specific OU, all VMs)
- Whether the script makes changes or only reads data
- Any hardcoded paths, credentials, or environment-specific values
Use appropriate permissions
Use appropriate permissions
Run scripts with the minimum privilege required to complete the task. Avoid running everything as a Domain Admin or Global Administrator.Check what roles and permissions each script needs and use a dedicated service account or just-in-time (JIT) elevation where your organization supports it.
Backup data before making changes
Backup data before making changes
Before running any script that modifies or deletes data, create a backup or export of the current state.For Exchange Online, export mailbox configurations. For vSphere, take a snapshot. For SharePoint, export site contents. The cost of a backup is always lower than the cost of recovery.
Customize scripts for your environment
Customize scripts for your environment
Scripts in this toolkit are starting points, not plug-and-play solutions. Customize them for your organization before running:
- Update Distinguished Names (DNs) and OUs to match your AD structure
- Replace example server names, tenant IDs, and domain names
- Adjust filter parameters to match your naming conventions
- Remove or add fields in export reports to match your reporting needs
Follow change management procedures
Follow change management procedures
Treat PowerShell scripts as changes to your environment, because they are. Before running a script in production:
- Open a change request in your ITSM system
- Document what the script does, why it is being run, and what the rollback plan is
- Schedule execution during an approved maintenance window
- Notify affected teams or end users as required by your change process
Use -WhatIf to preview changes
Use -WhatIf to preview changes
Many PowerShell cmdlets support the Run the script with Only remove
-WhatIf parameter, which shows what the command would do without actually doing it. Always check for -WhatIf support before running a destructive operation.-WhatIf first to verify the scope:-WhatIf once the output confirms the correct set of objects will be affected.Enable logging with Start-Transcript
Enable logging with Start-Transcript
Start-Transcript captures everything printed to the console — commands, output, and errors — to a log file. Start a transcript at the beginning of any significant script run.Use try/catch for error handling
Use try/catch for error handling
Wrap operations that can fail in Use
try/catch blocks so that a single error does not silently abort the rest of the script.-ErrorAction Stop on cmdlets inside try blocks so that non-terminating errors are promoted to exceptions and caught correctly.Set an appropriate execution policy
Set an appropriate execution policy
PowerShell’s execution policy controls which scripts are allowed to run. The default policy on most Windows systems is
Use
Restricted, which blocks all scripts.| Policy | Description |
|---|---|
Restricted | No scripts allowed (default) |
AllSigned | All scripts must be signed by a trusted publisher |
RemoteSigned | Local scripts run freely; downloaded scripts must be signed |
Unrestricted | All scripts run; downloaded scripts prompt for confirmation |
Bypass | Nothing is blocked — use only in controlled automation contexts |
RemoteSigned or AllSigned in production environments. Avoid Bypass outside of tightly controlled automation pipelines.Safe scripting template
The following template combines logging, error handling, and-WhatIf support in a single reusable pattern:
-WhatIf to preview, then without to execute:
