PowerShell Script Template
Published on May 16, 2022
A comprehensive PowerShell script template that incorporates best practices, proper error handling, logging, and parameter validation.
Complete Script Template
<#
.SYNOPSIS
Brief description of what the script does
.DESCRIPTION
Detailed description of the script's functionality, purpose, and usage scenarios
.PARAMETER ComputerName
Specifies the computer name(s) to target
.PARAMETER Path
Specifies the path for input/output operations
.PARAMETER Credential
Specifies credentials for authentication
.PARAMETER LogPath
Specifies the path for log file output
.EXAMPLE
.\ScriptTemplate.ps1 -ComputerName "SERVER01" -Path "C:\Data"
.EXAMPLE
.\ScriptTemplate.ps1 -ComputerName @("SERVER01","SERVER02") -LogPath "C:\Logs\script.log"
.NOTES
Author: Your Name
Version: 1.0
Created: Date
Modified: Date
.LINK
https://your-documentation-link.com
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "Specify computer name(s) to target")]
[ValidateNotNullOrEmpty()]
[Alias("CN", "Computer")]
[string[]]$ComputerName,
[Parameter(Mandatory = $false)]
[ValidateScript({Test-Path $_ -IsValid})]
[string]$Path = "C:\Temp",
[Parameter(Mandatory = $false)]
[PSCredential]$Credential,
[Parameter(Mandatory = $false)]
[ValidateScript({Test-Path (Split-Path $_ -Parent) -PathType Container})]
[string]$LogPath = "$env:TEMP\ScriptLog_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
)
#Requires -Version 5.1
#Requires -RunAsAdministrator
# Script variables
$ErrorActionPreference = "Stop"
$VerbosePreference = if ($PSBoundParameters.Verbose) { "Continue" } else { "SilentlyContinue" }
$ScriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
$ScriptVersion = "1.0"
$StartTime = Get-Date
# Initialize logging
if (!(Test-Path (Split-Path $LogPath -Parent))) {
New-Item -ItemType Directory -Path (Split-Path $LogPath -Parent) -Force | Out-Null
}
# Logging function
function Write-LogEntry {
param(
[Parameter(Mandatory = $true)]
[string]$Message,
[Parameter(Mandatory = $false)]
[ValidateSet("Information", "Warning", "Error")]
[string]$Level = "Information"
)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogEntry = "[$Timestamp] [$Level] $Message"
# Write to console with appropriate color
switch ($Level) {
"Information" { Write-Host $LogEntry -ForegroundColor Green }
"Warning" { Write-Warning $LogEntry }
"Error" { Write-Error $LogEntry }
}
# Write to log file
Add-Content -Path $LogPath -Value $LogEntry -ErrorAction SilentlyContinue
}
# Error handling function
function Handle-Error {
param(
[Parameter(Mandatory = $true)]
[System.Management.Automation.ErrorRecord]$ErrorRecord,
[Parameter(Mandatory = $false)]
[string]$CustomMessage
)
$ErrorMessage = if ($CustomMessage) {
"$CustomMessage - $($ErrorRecord.Exception.Message)"
} else {
$ErrorRecord.Exception.Message
}
Write-LogEntry -Message "ERROR: $ErrorMessage" -Level "Error"
Write-LogEntry -Message "ERROR DETAILS: Line $($ErrorRecord.InvocationInfo.ScriptLineNumber) - $($ErrorRecord.InvocationInfo.Line.Trim())" -Level "Error"
}
# Function to test prerequisites
function Test-Prerequisites {
Write-LogEntry -Message "Testing prerequisites..."
# Test PowerShell version
if ($PSVersionTable.PSVersion.Major -lt 5) {
throw "PowerShell 5.1 or higher is required"
}
# Test if running as administrator
$CurrentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw "This script must be run as Administrator"
}
# Test network connectivity for remote operations
if ($ComputerName -ne $env:COMPUTERNAME) {
foreach ($Computer in $ComputerName) {
if (-not (Test-Connection -ComputerName $Computer -Count 1 -Quiet)) {
throw "Cannot connect to computer: $Computer"
}
}
}
Write-LogEntry -Message "Prerequisites check passed"
}
# Main processing function
function Invoke-MainProcess {
param(
[string]$TargetComputer
)
Write-LogEntry -Message "Processing computer: $TargetComputer"
try {
# Your main script logic goes here
# Example: Get system information
$SystemInfo = if ($TargetComputer -eq $env:COMPUTERNAME) {
Get-ComputerInfo
} else {
Invoke-Command -ComputerName $TargetComputer -Credential $Credential -ScriptBlock {
Get-ComputerInfo
}
}
# Example: Process the information
$Result = [PSCustomObject]@{
ComputerName = $TargetComputer
OperatingSystem = $SystemInfo.WindowsProductName
Version = $SystemInfo.WindowsVersion
LastBootTime = $SystemInfo.LastBootUpTime
ProcessedTime = Get-Date
}
Write-LogEntry -Message "Successfully processed $TargetComputer"
return $Result
} catch {
Handle-Error -ErrorRecord $_ -CustomMessage "Failed to process computer $TargetComputer"
return $null
}
}
# Cleanup function
function Invoke-Cleanup {
Write-LogEntry -Message "Performing cleanup operations..."
# Clean up temporary files, connections, etc.
# Remove-Item $TempFiles -ErrorAction SilentlyContinue
$EndTime = Get-Date
$Duration = $EndTime - $StartTime
Write-LogEntry -Message "Script execution completed in $($Duration.TotalSeconds) seconds"
Write-LogEntry -Message "Log file saved to: $LogPath"
}
# Main execution block
try {
# Script header
Write-LogEntry -Message "=== $ScriptName v$ScriptVersion Started ==="
Write-LogEntry -Message "Parameters: ComputerName=$($ComputerName -join ','), Path=$Path"
# Test prerequisites
Test-Prerequisites
# Initialize results collection
$Results = @()
# Process each computer
foreach ($Computer in $ComputerName) {
if ($PSCmdlet.ShouldProcess($Computer, "Process Computer")) {
$Result = Invoke-MainProcess -TargetComputer $Computer
if ($Result) {
$Results += $Result
}
}
}
# Output results
if ($Results.Count -gt 0) {
Write-LogEntry -Message "Successfully processed $($Results.Count) computer(s)"
$Results | Format-Table -AutoSize
# Export results if needed
$OutputPath = Join-Path $Path "Results_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$Results | Export-Csv -Path $OutputPath -NoTypeInformation
Write-LogEntry -Message "Results exported to: $OutputPath"
} else {
Write-LogEntry -Message "No results to display" -Level "Warning"
}
} catch {
Handle-Error -ErrorRecord $_ -CustomMessage "Script execution failed"
exit 1
} finally {
Invoke-Cleanup
}
Template Features
Parameter Validation
- Mandatory parameters with proper validation
- Pipeline support for input objects
- Parameter aliases for flexibility
- Help messages for user guidance
- Path validation to ensure valid file paths
Error Handling
- Try-catch blocks around critical operations
- Custom error handling function
- Detailed error logging with line numbers
- Graceful error recovery where possible
Logging System
- Structured logging with timestamps and levels
- Console output with color coding
- File-based logging for audit trails
- Log rotation considerations
Best Practices Implementation
- Requires statements for version and privilege checks
- SupportsShouldProcess for WhatIf scenarios
- Proper variable scoping
- Comment-based help documentation
- Version information tracking
Modular Design
- Separate functions for different operations
- Reusable components across scripts
- Easy maintenance and updates
- Unit testing friendly structure
Usage Examples
Basic Execution
.\ScriptTemplate.ps1 -ComputerName "SERVER01"
Multiple Computers
.\ScriptTemplate.ps1 -ComputerName @("SERVER01", "SERVER02", "SERVER03")
With Custom Parameters
.\ScriptTemplate.ps1 -ComputerName "SERVER01" -Path "C:\Output" -LogPath "C:\Logs\custom.log"
WhatIf Testing
.\ScriptTemplate.ps1 -ComputerName "SERVER01" -WhatIf
Customization Guidelines
- Replace placeholder logic with your specific requirements
- Modify parameter definitions based on your needs
- Update help documentation with accurate descriptions
- Adjust error handling for your specific scenarios
- Customize logging levels and output formats
Benefits
- Consistency across all your PowerShell scripts
- Reliability through proper error handling
- Maintainability with modular design
- Debuggability with comprehensive logging
- Professional quality with proper documentation
This template provides a solid foundation for creating robust PowerShell scripts that follow industry best practices and can be easily maintained and extended.