使用 PowerShell Write-Output 创建后损坏的 Cmd 脚本

Broken Cmd scripts after creation with PowerShell Write-Output

我们有一个域范围的自动化工具,可以以管理员身份在服务器上启动作业(Stonebranch UAC - 请注意:这与 Windows“用户访问控制”无关,Stronebranch UAC 是一个企业自动化工具)。本机,它会查找 Cmd 批处理脚本,因此我们使用它们。

但是,我更喜欢使用 PowerShell 来处理所有事情,因此我使用 PowerShell 批量创建了数十个 .bat 脚本。没有任何效果,每当尝试 运行 .bat 脚本时,自动化工具就会崩溃。所以我削减了脚本,使它们只包含一行 echo 123 但仍然,一切都被打破了。我们认为这是该工具的问题,但后来尝试 运行 服务器上的 .bat 脚本,但它们也被破坏了,只是在命令行上生成了一些 unicode 而未能 运行。

所以我们突然意识到,有关 PowerShell 如何泵送 Write-Output 命令来创建批处理脚本的一些事情正在破坏它们(这是在 Windows 2012 R2 上,PowerShell 是 5.1)。我重复这个,例如,如果我在 PowerShell 控制台上键入以下内容:

Write-Output "echo 123" > test.bat

如果我现在打开 cmd.exe 然后尝试 运行 test.bat,我只会在屏幕上看到 2 个看起来像 unicode 的字符,除此之外什么都没有。

有人可以向我解释 a) 为什么会发生这种行为,以及 b) 我如何才能继续使用 PowerShell 生成这些批处理脚本 而不会 它们被破坏?即我是否必须更改 BOM 或 UTF-8 设置或其他任何设置才能使其正常工作,请问我该怎么做?

Windows PowerShell>中,就像底层的Out-File cmdlet一样,总是[1] 创建“Unicode”(UTF-16LE) 文件,cmd.exe 无法读取(即使 /U开关)。

PowerShell [Core] v6+ 中,一直使用 无 BOM 的 UTF-8 编码,包括 > .

因此:

  • 如果您使用 PowerShell [Core] v6+ 并且批处理文件的内容仅包含 ASCII 范围字符(7 位范围),你可以使用 >.

  • 否则,使用 Set-Content-Encoding Oem

'@echo 123' | Set-Content -Encoding Oem test.bat

如果您的批处理文件源代码仅包含 ASCII 范围字符(7 位范围),您也可以逃脱(在两个 PowerShell 版本中):

'@echo 123' | Set-Content test.bat

注:

  • 正如 -Encoding 参数所暗示的那样,使用系统的活动 OEM 代码页,这是批处理文件所期望的。

  • OEM代码页是ASCII编码的超集,所以用-Encoding Oem保存的文件只由 的 ASCII 范围字符隐式也是一个 ASCII 文件。这同样适用于仅由 ASCII 范围字符组成的 BOM-less UTF-8 和 ANSI (Default) 编码文件。

  • -Encoding Oem - 与-Encoding Ascii相反,甚至使用Set-Content默认编码[2] - 因此只有当批处理文件的源代码中有非 ASCII 范围的字符时才有意义,例如 é。然而,考虑到 OEM 代码页是固定宽度的单字节编码,此类字符总共限制为一组 256 个字符,这意味着许多 Unicode 字符本质上是不可用的,例如 .


[1] 在 Windows PowerShell v5.1(及更高版本)中,可以通过 $PSDefaultParameterValues 首选项变量更改 > 的编码- 参见 - 但是,您将无法 select BOM-less UTF-8 编码,这将是创建批处理文件所必需的(仅由 ASCII 范围字符组成)。

[2] Set-Content 的默认编码是 Windows PowerShell[=88 中的活动 ANSI 代码页 (Default) =](另一个 ASCII 超集),以及(对于所有 cmdlet)PowerShell [Core] v6+ 中的无 BOM UTF-8;有关 Windows PowerShell 中极其不一致的字符编码的概述,请参阅 .

默认情况下创建无 bom utf8 文件的方法是:

    new-item -Path outfile.bat -itemtype file -value "echo this"