Skip to content

[bugfix] Pass PowerShell inline commands via -EncodedCommand so quotes survive on Windows (#3907) - #4491

Open
IT-Althusser wants to merge 1 commit into
apache:masterfrom
IT-Althusser:fix/powershell-command-quoting
Open

IT-Althusser wants to merge 1 commit into
apache:masterfrom
IT-Althusser:fix/powershell-command-quoting

Conversation

@IT-Althusser

@IT-Althusser IT-Althusser commented Oct 24, 2026 •

Copy link
Copy Markdown

What's changed

PowerShell inline commands are now passed to powershell.exe via -EncodedCommand (Base64 of UTF-16LE) instead of -Command, and the CLIXML stderr that -EncodedCommand produces is normalized back to plain error text.

Why

On Windows, ProcessBuilder wraps an argument in double quotes but does not escape embedded quotes, so a script such as Write-Output "x y" reaches the child as "Write-Output "x y"". powershell.exe -Command re-tokenizes that raw command line, so quoting-heavy monitoring commands (nested quotes, pipes, backtick escapes — e.g. the one in #3907) arrive mangled, fail to parse, and the collector only reports Script response data is null. Reproduced on Windows 11 against the exact command shape from the issue:

# before (via -Command): stdout empty, stderr: 无法将"info"项识别为 cmdlet...
# after  (via -EncodedCommand): command runs and returns its output

Base64-encoded scripts contain no characters the command-line parser can alter, so the script reaches PowerShell verbatim. The payload is UTF-16LE, which also removes the input-encoding ambiguity for non-ASCII scripts. -EncodedCommand is supported by Windows PowerShell 5.1, the executable this code path invokes.

-EncodedCommand also makes PowerShell serialize progress/information/error records to a redirected stderr as a CLIXML document. Left as-is, every collection would log roughly 0.4 KB of XML, failure messages would show XML instead of the PowerShell error, and the empty-output oneRow path would stop working because stderr is never empty. ScriptCollectImpl now keeps only the <S S="Error"> entries, so logs and failure messages stay readable and the empty-output behavior is preserved.

How checked

  • Two new cross-platform unit tests for the CLIXML normalizer (run on the Linux CI).
  • Three regression tests gated by @EnabledOnOs(OS.WINDOWS): a quoting-heavy Write-Output, a pipe + backtick-escape command mirroring [BUG] 使用windows命令监控采集问题 #3907, and a failing command whose message must not contain XML. They are skipped on the Linux CI because powershell.exe does not exist there.
  • Locally on Windows 11 (Windows PowerShell 5.1, JDK 25):
    • mvn -pl hertzbeat-collector/hertzbeat-collector-basic -am test -Dtest='ScriptCollectImplTest#preCheck+supportProtocol+normalizePowerShellStderrKeepsErrorsAndDropsProgress+normalizePowerShellStderrLeavesPlainTextUntouched+collectPowershellWithQuotes+collectPowershellPipelineWithBacktickEscape+failingPowerShellCommandReportsReadableError' -Dsurefire.failIfNoSpecifiedTests=false → 7 tests, 0 failures.
    • Running the whole class gives 8 tests / 1 failure: the pre-existing collect() bash case fails on this machine because bash resolves to the WSL stub without a distro. That case is green on the upstream Linux CI and is unrelated to this diff.
  • bash / cmd / -File paths are untouched.

Note: Base64/UTF-16LE expands the script roughly 2.7x, so inline scripts must stay well below the Windows 32,767-character command-line limit (about 12k characters); longer scripts can still be deployed through scriptPath / -File.

Closes #3907

Checklist

  • I have read the Contributing Guide
  • I have written the necessary doc or comment.
  • I have added the necessary unit tests and all cases have passed.

Add or update API

  • I have added the necessary e2e tests and all cases have passed. (not applicable — no API change)

… on Windows (apache#3907)

-EncodedCommand passes the script as Base64/UTF-16LE, so the Windows command-line parser cannot strip quotes, pipes or backtick escapes. PowerShell serializes progress/information/error records as CLIXML on a redirected stderr; normalize them so failure messages stay readable.
@IT-Althusser
IT-Althusser force-pushed the fix/powershell-command-quoting branch from 0fe98ef to 6ace2c2 Compare October 24, 2026 03:47

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 使用windows命令监控采集问题

1 participant