# Powershell Safe Invocation

Use when writing or running PowerShell on Windows, especially native programs, quoted...

- Repository: https://github.com/OpenBMB/PilotDeck (4947 stars)
- Category: Writing
- License: AGPL-3.0
- Last updated: 2026-10-29
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add OpenBMB/PilotDeck --skill powershell-safe-invocation -g -a claude-code -y`
Codex: `npx skills add OpenBMB/PilotDeck --skill powershell-safe-invocation -g -a codex -y`
Cursor: `npx skills add OpenBMB/PilotDeck --skill powershell-safe-invocation -g -a cursor -y`
Gemini CLI: `npx skills add OpenBMB/PilotDeck --skill powershell-safe-invocation -g -a gemini-cli -y`

## Description

Use when writing or running PowerShell on Windows, especially native programs, quoted paths, escaping, pwsh, Start-Process, file operations, or shell troubleshooting.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# PowerShell Safe Invocation

## Shell

Use PowerShell 7 through `pwsh.exe` unless Windows PowerShell 5.1 is explicitly required.

When the active shell is uncertain, verify:

```powershell
$PSVersionTable.PSVersion
$PSNativeCommandArgumentPassing
```

Do not assume installing PowerShell 7 makes `powershell.exe` use PowerShell 7:

- `pwsh.exe` = PowerShell 7
- `powershell.exe` = Windows PowerShell 5.1

## Native Programs

Never construct one large command string when arguments can be passed separately.

Use:

```powershell
$exe = 'C:\Path With Spaces\tool.exe'
$args = @(
    '--input'
    'C:\Data Folder\input.json'
    '--flag'
)

& $exe @args

$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
    throw "$exe failed with exit code $exitCode"
}
```

Rules:

- Treat every native argument as one array item.
- Invoke executable paths stored in variables with `&`.
- Capture `$LASTEXITCODE` immediately.
- Do not use `Invoke-Expression`.
- Do not add a `cmd.exe /c` layer merely to launch an executable.
- Do not use Bash-style `\"` escaping in PowerShell.

## Cmdlets

Use hashtable splatting for PowerShell cmdlets:

```powershell
$params = @{
    LiteralPath = 'C:\Data[1]\input.txt'
    Destination = 'C:\Output'
    Force       = $true
    ErrorAction = 'Stop'
}

Copy-Item @params
```

Use `-LiteralPath` for real paths unless wildcard expansion is intentional.

Do not use `$LASTEXITCODE` to test a PowerShell cmdlet. Use terminating errors:

```powershell
$ErrorActionPreference = 'Stop'
```

## Complex Commands

Avoid deeply quoted commands such as:

```text
cmd.exe /c pwsh.exe -Command "..."
```

For multiline code, nested quotes, JSON, XML, regular expressions, pipelines, redirection, or non-ASCII paths:

1. Write a temporary `.ps1` file.
2. Execute it with:

```text
pwsh.exe -NoLogo -NoProfile -NonInteractive -File script.ps1
```

Prefer `-File` over `-Command` for anything beyond a short, simple expression.

The rest: https://github.com/OpenBMB/PilotDeck/blob/HEAD/src/extension/plugins/builtin/windows-skills/skills/powershell-safe-invocation/SKILL.md
