Windows Server 2025 / How to Handle PowerShell Errors and Write Run Logs
A completed command is not necessarily a successful administrative task. PowerShell try, catch, finally, explicit error handling, and per-run logs help identify failures and show when only part of a task finished.
Make failures visible
This exercise reads a file without changing server roles. A real installation or account-management script must also record changes left by an intermediate failure. Entering catch does not automatically undo earlier actions.
Some PowerShell errors allow execution to continue. Merely placing a command inside try does not make every error catchable; -ErrorAction Stop promotes supported errors to terminating errors. Review PowerShell error handling for the distinction.
Prepare an input file and the complete script
Create C:\LabScripts\input.txt containing one line, lab ready. Save the complete code below as Read-LabFile.ps1 in the same folder using UTF-8. The Windows PowerShell 5.1 example reads files and writes logs; it does not change server services or networking.
param(
[Parameter(Mandatory=$true)]
[string]$InputPath
)
$logDirectory = 'C:\LabLogs'
New-Item -ItemType Directory -Path $logDirectory -Force -ErrorAction Stop | Out-Null
$runLabel = (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + ([guid]::NewGuid().ToString('N').Substring(0,6))
$logPath = Join-Path $logDirectory ($runLabel + '.json')
$result = [ordered]@{
StartedAt = (Get-Date).ToString('o')
ComputerName = $env:COMPUTERNAME
InputPath = $InputPath
Success = $false
LineCount = $null
ErrorId = $null
ErrorMessage = $null
}
$exitStatus = 0
try {
$lines = @(Get-Content -LiteralPath $InputPath -ErrorAction Stop)
$result.LineCount = $lines.Count
$result.Success = $true
}
catch {
$result.ErrorId = $_.FullyQualifiedErrorId
$result.ErrorMessage = $_.Exception.Message
$exitStatus = 1
Write-Warning $result.ErrorMessage
}
finally {
$result.FinishedAt = (Get-Date).ToString('o')
$result | ConvertTo-Json | Set-Content -LiteralPath $logPath -Encoding UTF8 -ErrorAction Stop
}
Write-Output $logPath
exit $exitStatus
Compare success and failure under the same conditions
The first invocation reads the existing file. The second uses missing-input.txt, which must genuinely be absent. You do not need to delete the input or modify a system file to create a failure:
powershell.exe -NoProfile -File 'C:\LabScripts\Read-LabFile.ps1' -InputPath 'C:\LabScripts\input.txt' $LASTEXITCODE powershell.exe -NoProfile -File 'C:\LabScripts\Read-LabFile.ps1' -InputPath 'C:\LabScripts\missing-input.txt' $LASTEXITCODE
Immediately inspect each exit code. The expected success case returns 0 with Success=true. The missing file returns 1 with Success=false and error details. Each invocation creates a different JSON file; open the reported paths and compare InputPath and ErrorId.
If script policy blocks execution, follow the organization’s policy and signing requirements rather than weakening global settings for this example.
Understand each error-handling section
| Section | Purpose in this script |
|---|---|
| try | Read the file and record its line count |
| catch | Record the handled error identifier and message; select a failure exit code |
| finally | Attempt to save the run result regardless of read success |
Microsoft’s try, catch, and finally reference explains terminating-error handling. A finally block cannot guarantee a writable log disk. Full storage or denied access can still prevent saving, so log writes also use -ErrorAction Stop. Do not report success simply because no log exists.
External programs return their own exit codes. In Windows PowerShell 5.1, do not assume a nonzero exit automatically enters catch. Inspect $LASTEXITCODE immediately and throw when appropriate; another external command can replace that value.
Add safe rerun criteria to operational scripts
- Record the server, target, and start and finish times.
- Query existing state to avoid duplicate creation or unintended overwrite.
- Track successful and failed steps separately.
- Keep passwords, tokens, and unnecessary user-file contents out of logs.
- If implementing rollback, record its supported scope and any recovery failure.
Restore the valid input path and run again to confirm a new successful result. Preserve needed evidence before removing only the temporary files from this lab. Adding SilentlyContinue everywhere hides failures rather than making administration reliable.









