Install
$ agentstack add skill-galaxyruler-galactic-skills-powershell-safe-vars ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README — it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
PowerShell: Safe Variables, Quoting, and One-Liners
When to use
Use this when writing or editing PowerShell (pwsh) commands/scripts inside Codex tool calls, especially for automations and one-liner scripts.
Problems this prevents
PowerShell has automatic variables (some are read-only / constant), and variable names are case-insensitive. Accidentally assigning to one of these (e.g. $HOME, $Host) can cause a script to fail with errors like “Cannot overwrite variable … because it is read-only or constant.”
PowerShell also parses quoting, pipes, redirection, and command substitution differently than Bash. Copying Bash snippets directly can produce ParserError, Missing file specification after redirection operator, The term 'from' is not recognized, or An empty pipe element is not allowed.
Workflow
1) Pick “safe” variable names
- Prefer descriptive names like
$userHome,$codexHome,$installRoot,$sessionDir. - Avoid short/common names that collide with automatic variables, including:
$HOME(often constant) → use$userHome$Host(automatic variable) → use$hostInfo/$hostProc$PID,$PSVersionTable,$Error,$Matches,$Profile,$PSScriptRoot,$PSCommandPath- Remember:
$homeand$HOMEare the same variable.
2) If you must reuse a risky name, change it immediately
- Rename the local variable to a safe name and update all references.
3) Keep “tool-call scripts” failure-loud
- Start scripts with:
$ErrorActionPreference='Stop' - Set timeouts explicitly in the tool call (e.g.
timeout_ms) for long operations.
4) Avoid string-interpolation parsing traps
- If a variable is immediately followed by
:, PowerShell can treat it like a scoped variable reference and throw: “Variable reference is not valid. ':' was not followed by a valid variable name character.” - Fix by using one of:
"${var}:suffix"(brace the variable)("{0}:{1}" -f $var, $suffix)(format operator)
5) Treat optional env vars as optional
- Some environments won’t set expected variables like
$env:CODEX_HOME. - Prefer defensive fallbacks, e.g.:
$codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $env:USERPROFILE '.codex' }
6) Guard method calls on optional strings and process state
Get-Content -Rawcan return$nullfor an empty file or missing optional output path, so calling.Trim(),.Substring(),.Length, or regex methods directly can fail with "You cannot call a method on a null-valued expression."- Coerce optional text to
[string]before string methods:
$stdoutText = if (Test-Path -LiteralPath $outPath) { [string](Get-Content -Raw -LiteralPath $outPath) } else { '' }
$stderrText = if (Test-Path -LiteralPath $errPath) { [string](Get-Content -Raw -LiteralPath $errPath) } else { '' }
$cleanStdout = $stdoutText.Trim()
- Do not read
$process.ExitCodeuntil the process has exited; prefer direct invocation plus$LASTEXITCODEwhen no timeout is needed, or wait withWaitForExit()and precompute$exitCodebefore building result objects. - Compute possibly-null fields before
[ordered]@{}or[pscustomobject]@{}literals so failures are isolated and easier to diagnose. - Do not pass live PowerShell objects such as
[pscredential]through a nested nativepowershell.exe -File ...call. Invoke the script in the current session with& .\script.ps1 -Credential $cred; otherwise the object is stringified and downstream authentication may fail even when the password is correct.
7) Avoid $PSScriptRoot in parameter default expressions
- In Windows PowerShell and some invocation styles,
$PSScriptRootcan be empty while parameter default values are being evaluated, causingJoin-Path $PSScriptRoot ...to fail. - Prefer computing defaults after
param()runs, e.g.: if (!$ConfigPath) { $ConfigPath = Join-Path $PSScriptRoot 'runner-config.json' }- Or pass
-ConfigPathexplicitly from the caller.
8) Do not paste Bash heredocs into PowerShell
- Bad in PowerShell:
python - <<'PY' - Use a PowerShell here-string piped to the command:
@'
print("hello")
'@ | python -
- Here-string headers and terminators must each be alone on their own line. Do not write
@'{"json":true}on one line.
9) Quote native-command regexes and globs PowerShell-first
- Prefer single quotes for regex/search arguments that contain
",|,$,--,[,],*,?, or backslashes. - Also single-quote native glob flags such as
rg -g '*.ts'; otherwise PowerShell can parse[as indexing or*as multiplication before the native command receives it. - Backslash does not escape a double quote in PowerShell. Use single quotes, or escape PowerShell double quotes with a backtick.
- If a native command argument keeps being parsed by PowerShell, reduce the expression, single-quote it, or pass the pattern from a variable.
10) Compute conditionals before interpolation
- Do not use Bash-style
$((...))in strings for command substitution or conditionals. - Prefer a separate variable:
$codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $env:USERPROFILE '.codex' }
"CodexHome=$codexHome"
11) Compute conditionals before object literals
- PowerShell
ifis a statement, not an expression. Do not putif (...) { ... }directly inside[pscustomobject]@{}values. - Prefer precomputed variables:
$childCount = if (Test-Path -LiteralPath $repoRaw) { (Get-ChildItem -LiteralPath $repoRaw).Count } else { 0 }
[pscustomobject]@{ Path = $repoRaw; ChildCount = $childCount }
12) Pipe control-flow output safely
- Do not pipe directly after a closing brace from
foreach,if, or similar control-flow statements in one-liners. - Capture rows first, then pipe the variable:
$rows = foreach ($item in $items) { [pscustomobject]@{ Name = $item.Name } }
$rows | Format-Table -AutoSize
Verification checklist
- Script runs without
WriteError/ “Cannot overwrite variable …”. - No assignments to automatic variables (scan for
=$patterns on$HOME,$Host, etc.). - Variables used for paths are built from
$env:USERPROFILE/$env:LOCALAPPDATAas needed, with safe defaults when env vars are missing. - No Bash heredoc/redirection syntax like
<<'PY'remains in PowerShell commands. - Optional file, command, or process output is coerced to
[string]before string methods like.Trim(). - External-process exit code fields are precomputed before object literals.
- Here-string headers and terminators are on their own lines.
- Regex/search/glob args containing pipes, embedded quotes, character classes, or wildcards are single-quoted, variable-backed, or PowerShell-escaped.
- Complex conditionals are computed before interpolation or object literals.
foreach/ifstatement output is assigned to a variable before piping.
Common failure modes
- Using
$home = ...or$host = ...in a script (case-insensitive collision). - Copy/pasting variable names from other shells (Bash
$HOME) without adjusting for PowerShell semantics. - Building strings like
"$path:$line"without bracing (use"${path}:$line"or-f). - Using
Join-Path $PSScriptRoot ...inside a parameter default value (move it into the function/script body). - Running
python - <<'PY'or similar Bash heredocs in PowerShell; use a here-string piped to the command. - Putting JSON or code on the same line as a here-string header (
@'or@"). - Calling
.Trim(),.Length,.Substring(), or similar methods on optionalGet-Content -Rawoutput without coercing it to[string]first. - Reading
$process.ExitCodebefore a launched process has exited, or embedding that read directly inside a result-object literal. - Writing regex arguments with
\"inside PowerShell double-quoted strings; use single quotes or backtick-escaped quotes. - Running commands like
rg -n "foo[0-9]" . -g "*.ts"and letting PowerShell parse[or*; userg -n 'foo[0-9]' . -g '*.ts'. - Embedding Bash-style
$((if ...))in strings; compute the value first. - Embedding
if (...) { ... }directly inside a[pscustomobject]@{}value; compute the value first. - Piping directly from
foreach (...) { ... } | Format-Table; assign the rows first.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: GalaxyRuler
- Source: GalaxyRuler/Galactic-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.