Skip to content

Mechanisms

POSIX builtins absent in PowerShell (command -v) parse as argument noise and fail silently instead of erroring.

Cases: command-v-noop

folder lookup answers empty instead of failing

Section titled “folder lookup answers empty instead of failing”

A known-folder lookup verifies the directory before answering and returns an empty string rather than an error when it is absent, and that empty string is a valid argument to every path function downstream, so the failure becomes a relative path instead of an exception.

Cases: known-folder-empty-not-error

Windows permissions are changed by a sequence of separate mutations with no atomic replace, and removing inheritance takes effect immediately, so an interrupted restrict-then-grant order leaves an empty DACL that denies everyone including the owner.

Cases: icacls-inheritance-r-empty-dacl

Built-in aliases (curl, wget) and PATH shims shadow the binaries users intend to run.

Cases: curl-alias · ps51-vs-7-split

Windows implements right Alt as Ctrl plus Alt, so a character typed with AltGr arrives carrying both modifiers and any handler treating Ctrl as a shortcut prefix silently consumes real text, but only on layouts that need AltGr to produce it.

Cases: altgr-reports-as-ctrl-alt

WindowsApps store aliases are zero-byte IO_REPARSE_TAG_APPEXECLINK files that pass stat probes but EPERM on spawn.

Cases: windowsapps-alias-eperm

Windows PowerShell 5.1 decides a script file’s encoding by BOM presence; no BOM means the legacy ANSI code page.

Cases: bom-less-ps1-cp949

Bun 1.3.14 Windows spawn fails outright when powershell.exe argv contains the -WindowStyle Hidden pair.

Cases: bun-ps-windowstyle-argv

case-insensitive filesystem, case-sensitive containers

Section titled “case-insensitive filesystem, case-sensitive containers”

NTFS matches paths without regard to case while preserving the casing written, so two spellings name one file, but every ordinary string container treats them as distinct keys and the same lowercasing fix would be wrong on a case-sensitive filesystem.

Cases: path-case-sensitive-map

Node CVE-2024-27980 hardening: spawning .bat/.cmd without shell errors EINVAL (18.20.2/20.12.2/21.7.3+).

Cases: spawn-npm-enoent-einval

Any command line routed through cmd.exe is re-tokenized; metacharacters and newlines inside arguments become command syntax.

Cases: get-command-where-disagree · cmd-shim-reparses-argv · cmd-start-ampersand-splits · shell-true-fallback-injects

PowerShell unrolls pipelines: zero items become null, one item loses its array, many become Object[] — types change with count.

Cases: if-nativecmd-truthiness · return-does-not-mean-return · get-content-scalar-collapse

CreateProcess command line capped at 32767

Section titled “CreateProcess command line capped at 32767”

CreateProcess limits the whole assembled command line to 32767 characters and reports the overflow with the same Win32 code used for an over-long path, so a payload passed as an argument fails under an error that describes filenames.

Cases: createprocess-cmdline-32767

Comparison operators against a collection FILTER it (returning matching elements) instead of returning a boolean.

Cases: ne-filters-instead-of-compares

Console-subsystem binaries get a new console at CreateProcess when the parent has none — before any flag is parsed.

Cases: windowstyle-hidden-vs-windowshide

Windows tools end lines with CRLF, so splitting text on LF alone leaves a trailing CR on every line; exact comparisons and anchored patterns then fail against a character that is invisible in editors, diffs, and terminal output.

Cases: lf-pure-transform-mixes-eol · split-n-leaves-cr · cmd-lf-drops-first-byte

Numeric/date casts honor the host culture; comma-decimal locales parse differently than invariant culture.

Cases: culture-comma-decimal-cast

5.1 cmdlets default to UTF-16LE or ANSI when writing; 7 defaults to BOM-less UTF-8 — same code, different bytes.

Cases: bomless-bat-oem-codepage · redirected-ps-output-mojibake · oss-outfile-bom · tee-object-utf16 · utf8-bom-still-breaks-grep · bom-less-ps1-cp949 · ps51-vs-7-split

CI runners pick a default shell per OS (pwsh on windows-latest); unmarked run: steps inherit it.

Cases: npm-script-runs-under-cmd · actions-default-shell

MS-DOS device names reserved in every directory

Section titled “MS-DOS device names reserved in every directory”

Win32 path parsing recognizes legacy device names such as CON, NUL, and COM1 as their own path type and rewrites them into the NT device namespace before any directory applies, with or without an extension, so opening one succeeds as a device rather than creating a file.

Cases: reserved-dos-device-names

A Windows absolute path begins with a drive letter and colon, so any API that parses its input as a URL reads that letter as the protocol, while an absolute POSIX path coincidentally parses as root-relative and works.

Cases: dynamic-import-needs-file-url

Windows env names are case-insensitive but JS objects are not; Path and PATH can coexist and fight.

Cases: env-path-vs-PATH-casing

USERDOMAIN/USERNAME env vars are writable, unreliable identity sources; workgroup machines put the computer name in USERDOMAIN.

Cases: env-domain-principal · wslenv-shared-with-host

Formatting an ErrorRecord (Out-String) renders multi-line error views including position/script text, multiplying one line into many.

Cases: out-string-multiplies-stderr

Execution policy gates script FILES (.ps1, -File) while in-memory command text bypasses it.

Cases: execution-policy-file-block · npm-ps1-not-comspec

Exit codes cross process/host boundaries by convention, not guarantee: hosts, wrappers, and CI steps each apply their own rule.

Cases: startup-artifact-is-not-a-process · start-process-no-lastexitcode · explorer-exits-one · exit-code-vs-dollar-q · pwsh-leaks-lastexitcode

powershell/pwsh -File dispatches on filename extension; non-.ps1 files are rejected before parsing.

Cases: ps-file-extension-dispatch

An immediate process exit tears the runtime down without waiting for libuv to finish closing handles; a handle still in the closing state trips an assertion, which Windows surfaces as a fastfail while POSIX teardown absorbs the same race silently.

Cases: process-exit-fastfail-0xc0000409

Write-Host and return semantics: host output bypasses the success pipeline, and functions emit every uncaptured value.

Cases: start-process-no-lastexitcode · write-host-not-success-stream · return-does-not-mean-return

Invoke-Expression runs text in the CURRENT session: exit kills the caller’s host, and parameters cannot be forwarded.

Cases: irm-iex-kills-host · piped-iex-drops-params

ConvertTo-Json defaults to -Depth 2, replacing deeper data with type names; 5.1/7.0 truncate silently, 7.1+ warn.

Cases: convertto-json-depth-two

locale preferred encoding is the ANSI codepage

Section titled “locale preferred encoding is the ANSI codepage”

Python text mode without an explicit encoding decodes with the locale preferred encoding, which on Windows is the ANSI codepage rather than UTF-8, and UTF-8 mode changes what that function reports without changing what native children emit.

Cases: python-subprocess-locale-encoding

Windows built-in command-line tools translate their column headings, status words, and error messages to the system UI language, so only structure and exit codes are stable; matching English substrings tests the machine’s language rather than its state.

Cases: localized-cli-output-parsing

Windows enforces file locks at the OS level: a handle opened without FILE_SHARE_DELETE blocks deletes and renames until it closes, where POSIX unlink only removes a name and lets the data outlive its last reference.

Cases: atomic-rename-loses-to-scanner · unlink-while-open-ebusy

MAX_PATH is an API ceiling, not a filesystem limit

Section titled “MAX_PATH is an API ceiling, not a filesystem limit”

Win32 caps a pathname at 260 characters including drive, separators, and the terminating NUL, and directory creation reserves twelve more, so a path NTFS would store is refused by the API unless the caller uses the extended-length prefix or opts in with both the registry value and a long-path-aware manifest.

Cases: max-path-260

PowerShell historically rebuilds one command-line string for native processes, re-quoting heuristically; quotes and empty args are lost.

Cases: backslash-quote-ends-span · oss-native-arg-quoting · prose-as-unknown-flags

Windows offers termination of one process or of a live parent-PID tree, with no group you opted into, so killing a child orphans its descendants while a tree kill sweeps up any caller that happens to descend from the target.

Cases: kill-hits-one-pid-or-the-whole-tree

A native command in a PowerShell expression evaluates to its captured OUTPUT; if() branches on output presence, not exit code.

Cases: if-nativecmd-truthiness

PATH list separator is host-dependent (‘;’ Windows, ‘:’ POSIX); colon-joined lists corrupt drive-letter entries.

Cases: path-colon-not-delimiter · node-path-host-delimiter

Windows resolves extensionless command names by walking PATH entries and PATHEXT extensions in order; results differ from POSIX execvp and between resolvers.

Cases: get-command-where-disagree · spawn-npm-enoent-einval · npm-ps1-not-comspec · pathext-bare-name-enoent · path-dot-hijacks-bare-npm · pathext-exe-beats-cmd

&& and || are PowerShell 7.0+ pipeline chain operators; 5.1 treats them as parser errors.

Cases: ps51-no-and-and

/dev/null is a POSIX device path; Windows treats it as a relative file path under the current drive.

Cases: dev-null-redirect

VAR=value cmd per-command environment is POSIX shell syntax; cmd.exe executes the literal token instead.

Cases: cmd-posix-env-prefix

English connectors like ‘and’ between commands parse as positional arguments of the first command.

Cases: english-and-not-separator

A Windows PATH entry may be wrapped in quotes so a directory name can contain a semicolon, which forces correct parsers to be quote-aware; an unmatched quote then opens a span that swallows every later entry into one fictional path.

Cases: path-unmatched-quote-swallows

Environment variables live in the registry; a process gets a merge snapshot at creation and never sees later writes.

Cases: envpath-pollutes-user · session-path-stale

A general-purpose URL type percent-encodes a backslash because it is an ordinary path character rather than a separator; only implementations following the WHATWG special-scheme rule convert it, so the same conversion is correct in one language and broken in another.

Cases: file-url-encodes-backslash

‘;’ terminates a PowerShell statement; joining fragments of ONE call with ‘;’ splits it into broken statements.

Cases: cmd-c-newline-not-separator · join-semicolon-splits-startprocess

5.1 wraps redirected native stderr lines in ErrorRecord objects, converting output into error-stream objects.

Cases: native-stderr-errorrecord · out-string-multiplies-stderr

Set-StrictMode changes property access on missing members from returning null to throwing.

Cases: strictmode-missing-property

Double-quoted PowerShell strings interpolate $tokens; backslash is not an escape — backtick is.

Cases: dollar-backslash-vars · prose-as-unknown-flags · dq-regex-interpolates

Windows retains the transmission control block for a closed socket so the endpoint stays unbindable, and its SO_REUSEADDR waives that state by also permitting an active listener to be hijacked, so runtimes refuse to set it and the POSIX escape hatch is unavailable rather than merely ineffective.

Cases: tcp-tcb-survives-listener

cmd.exe cannot hold a UNC current directory

Section titled “cmd.exe cannot hold a UNC current directory”

The current directory is drive-relative in cmd.exe’s model, so a UNC path cannot be one; started in a UNC directory it warns and silently relocates to the Windows directory, and every batch shim that hops through it inherits the wrong working directory.

Cases: cmd-unc-cwd-not-supported

a UNC path may be served by a non-NTFS provider

Section titled “a UNC path may be served by a non-NTFS provider”

A UNC root can be backed by a provider with entirely different semantics from NTFS, such as the WSL 9P filesystem, so operations that assume a Windows security descriptor fail with access-denied on a path that reads and lists normally.

Cases: wsl-unc-rejects-nt-acl

CPython text I/O applies universal newlines when writing as well as reading, so a lone line feed becomes the platform terminator wherever a TextIOWrapper sits in the path, including inside a subprocess pipe opened in text mode.

Cases: python-textio-newline-translation

Win32 trims trailing dots/spaces from paths at the API boundary; different runtimes normalize differently, so existence checks disagree.

Cases: esm-is-main-file-url · test-path-trailing-whitespace · basename-split-slash-only · zip-entry-drive-letter-escapes