Skip to content
AgileLogics
5 min read

Best Practices for Production Scripts

Prerequisites: Building production modules

A checklist that pulls the course together — use it to review scripts before they run unattended or are shared with a team.

Structure

  • Put reusable logic in advanced functions inside modules; keep scripts as thin entry points.
  • One function, one job. Verb-Noun names with approved verbs.
  • #Requires -Version 7.4 and #Requires -Modules Az.Accounts at the top of scripts document and enforce dependencies.

Input and output

  • Typed, validated parameters; Mandatory where required; no prompts in automation.
  • Accept pipeline input where natural; output objects, one per item.
  • No Write-Host for data; Write-Verbose for progress.

Safety

  • SupportsShouldProcess on anything that changes state; test with -WhatIf.
  • Set-StrictMode -Version Latest and $ErrorActionPreference = 'Stop'.
  • try/catch with logging and meaningful exit codes; finally for cleanup.
  • No Invoke-Expression on input; -LiteralPath for user-supplied paths.
  • Secrets from a vault or managed identity — never in code or logs.

Quality

  • Comment-based help with examples on every public function.
  • Pester tests for logic, run in CI, with PSScriptAnalyzer clean.
  • Source control, code review, semantic versioning, and a changelog.

A final example

#Requires -Version 7.0
function Get-StaleFile {
  <#
  .SYNOPSIS
    Finds files not modified for a given number of days.
  .EXAMPLE
    Get-StaleFile -Path ./logs -Days 30
  #>
  [CmdletBinding()]
  [OutputType([System.IO.FileInfo])]
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })]
    [string]$Path,

    [ValidateRange(1, 3650)]
    [int]$Days = 30
  )
  begin   { $cutoff = (Get-Date).AddDays(-$Days) }
  process {
    Write-Verbose "Scanning $Path for files older than $cutoff"
    Get-ChildItem -LiteralPath $Path -File -Recurse |
      Where-Object LastWriteTime -lt $cutoff
  }
}

New-Item -ItemType Directory logs | Out-Null
'a.log', 'b.log' | ForEach-Object { New-Item "logs/$_" | Out-Null }
(Get-Item logs/a.log).LastWriteTime = (Get-Date).AddDays(-60)
Get-StaleFile -Path logs -Days 30 | Select-Object -ExpandProperty Name
'logs' | Get-StaleFile -Days 90 | Measure-Object | Select-Object -ExpandProperty Count
a.log
0

Help, validation, pipeline input, verbose output, and object output — in about twenty lines.

What's next

Try the Advanced Projects, then read What You Should Know Now — and What's Next for where to go from here.