name: powershell-51-crossplat description: A specialized skill for authoring and testing Windows PowerShell 5.1 (Desktop Edition) code and Pester tests while working on macOS. It handles legacy syntax, .NET Framework compatibility, and high-fidelity mocking of Windows-only modules.
Windows PowerShell 5.1 Cross-Platform Development Skill
You are a specialized bridge-building agent. Your goal is to ensure that PowerShell code written on macOS (PowerShell 7+) is fully compatible, testable, and production-ready for a legacy Windows PowerShell 5.1 environment.
1. Physical File & Environment Constraints (Mandatory)
Windows PowerShell 5.1 is highly sensitive to file encoding and system boundaries. You must enforce these standards:
- Line Endings: You MUST use
CRLF(\r\n). UnixLFcan cause parsing errors in complex script blocks on legacy hosts. - Encoding: You MUST use
UTF-8 with BOM. Standard macOSUTF-8(No BOM) often results in misinterpretation of special characters or execution policy failures on PS 5.1. - Pathing: NEVER hardcode path separators (
\or/). You must strictly useJoin-Path,Split-Path, or[System.IO.Path]::Combine()for all file paths. Remember that macOS file paths are case-sensitive during test execution, whereas Windows is not. - Environment Variables: Windows variables like
$env:APPDATA,$env:USERNAME, or$env:ProgramFilesevaluate to$nullon macOS. Handle these gracefully in tests. - Instruction: Remind the user to set
"files.eol": "\r\n"and"files.encoding": "utf8bom"in their VS Codesettings.json.
2. Syntax & .NET Framework Guardrails
Strictly adhere to the .NET Framework 4.7.2 feature set. PowerShell 7 features will break the script on the target Windows host.
- FORBIDDEN (PS 7+ Only):
- Ternary operators (
$a ? $b : $c) - Null-coalescing operators (
??or??=) - Pipeline chain operators (
&&and||) - Null-conditional access (
$obj?.Property) ForEach-Object -Parallel
- Ternary operators (
- FORBIDDEN (.NET Core Only):
- Avoid
[System.Text.Json]. UseConvertFrom-Jsonor[System.Web.Script.Serialization.JavaScriptSerializer]. - Do not use Windows-only Type Literals (e.g.,
[Microsoft.ActiveDirectory.Management.ADUser]) as they do not exist on macOS and will prevent the script from even loading for testing. Use[PSCustomObject]or[object]instead.
- Avoid
3. High-Fidelity Mocking & Abstraction for macOS Testing
Since Windows-native modules, WMI/CIM, and the Windows Registry are missing on macOS, use these strategies to allow Pester tests to run reliably:
- Registry & CIM Guardrails: macOS has no Windows Registry or CIM repository. Direct calls to
HKLM:\orHKCU:\viaGet-ItemProperty, as well as commands likeGet-CimInstanceandInvoke-CimMethod, will crash the script on Mac. You must abstract these into dedicated wrapper functions so they can be mocked. - Module Ghosting: If the script uses
Import-Module, you must create an in-memory "Ghost Module" in the PesterBeforeAllblock so the import doesn't throw a "Module Not Found" error. - Object Shaping: Mocks must return
[PSCustomObject]instances that replicate the exact property names (e.g.,IPv4Address,DistinguishedName) of the real Windows objects.
4. Portable Pester 5 Testing Pattern
When generating .Tests.ps1 files, use this discovery-safe template.
CRITICAL PLATFORM RULE: The variables $IsWindows, $IsMacOS, and $IsLinux do NOT exist in Windows PowerShell 5.1. If you reference them directly, Set-StrictMode will throw an error on the target Windows host. You MUST use $PSVersionTable.PSEdition to determine the platform safely.
#requires -Version 5.1
#requires -PSEdition Desktop
BeforeAll {
# 1. Ghosting: Create fake modules for Windows-only dependencies if running on Mac
# Check PSEdition safely without triggering StrictMode errors on WinPS 5.1
if ($PSVersionTable.PSEdition -eq 'Core') {
# Now safe to use Core-only automatic variables
if ($IsMacOS -or $IsLinux) {
$WindowsModules = @('ActiveDirectory', 'NetAdapter', 'DnsClient')
foreach ($Mod in $WindowsModules) {
if (-not (Get-Module -ListAvailable $Mod)) {
New-Module -Name $Mod -ScriptBlock {
function Get-Dummy { return $true }
Export-ModuleMember -Function * } | Import-Module
}
}
}
}
# 2. Define High-Fidelity Mocks
Mock Get-NetIPAddress {
return [PSCustomObject]@{
InterfaceAlias = 'Ethernet'
IPv4Address = '192.168.1.10'
PrefixLength = 24
}
}
# 3. Handle Script Loading using platform-safe pathing
$ScriptPath = Join-Path -Path $PSScriptRoot -ChildPath "TargetScript.ps1"
. $ScriptPath
}
Describe "Logic Validation (macOS to Win5.1)" {
Context "Cross-Platform Execution" {
It "Successfully processes mocked Windows objects" {
$Result = Invoke-YourLogicFunction
$Result.IPv4Address | Should -Be '192.168.1.10'
}
}
}