我在TFS构建中运行的powershell脚本存在以下问题。这两个问题都与TFS无关,可以使用简单的PowerShell命令行窗口重现。
1)与TFS完全无关。在管道方面,似乎Powershell不喜欢德国变形金刚。
1a)这行代码工作正常,所有变音符号都正确显示
.\TF.exe hist "$/Test" /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /version:C1~T
1b)这条线与变音符号混淆
.\TF.exe hist "$/Test" /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /version:C1~T | Out-String
最初我尝试过Out-File并且仅将编码更改为每个排版中的变音符号编码错误(UTF8,unicode,UTF32,...)
我真的不知道如何从标准输出中提取字符串并使变音符合适。
2)当使用Out-File或Out-String时,输出中的每一行在80个字符后被截断,似乎是默认的屏幕缓冲区设置。如何在powershell脚本中更改它,以及为什么在重定向输出时它甚至会产生影响。
答案 0 :(得分:0)
问题2不是Powershell问题。 tfs documentation表示关注默认/format
参数(即/format:brief
)
某些数据可能会被截断。
/format:detailed
没有该警告,但会返回更多信息,您可以在执行Out-String
或Out-File
之前使用Powershell处理这些信息。
答案 1 :(得分:0)
tl;dr
以下应该解决您的两个问题,这些问题源于 tf.exe
使用 ANSI 字符编码而不是预期的 OEM 编码,以及默认情况下截断输出.:
$correctlyCapturedOutput =
& {
$prev = [Console]::OutputEncoding
[Console]::OutputEncoding = [System.Text.Encoding]::Default
# Note the addition of /format:detailed
.\tf.exe hist '$/Test' /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /format:detailed /version:C1~T
[Console]::OutputEncoding = $prev
}
如果您使用的是跨平台、按需安装PowerShell (Core) 7+:
[System.Text.Encoding]::Default
在 Windows PowerShell 中报告活动 ANSI 代码页的编码,在 PowerShell (Core) 中报告(无 BOM)UTF-8(反映 .NET Core 的 / .NET 5+ 的行为)。因此,必须明确确定活动的 ANSI 代码页,最可靠的方法是通过注册表完成。$correctlyCapturedOutput =
& {
$prev = [Console]::OutputEncoding
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding(
[int] ((Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Nls\CodePage ACP).ACP)
)
# Note the addition of /format:detailed
.\tf.exe hist '$/Test' /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /format:detailed /version:C1~T
[Console]::OutputEncoding = $prev
}
This Gist 包含 helper 函数 Invoke-WithEncoding
,它可以在两个 PowerShell 版本中将上述简化如下:
$correctlyCapturedOutput =
Invoke-WithEncoding -Encoding Ansi {
.\tf.exe hist '$/Test' /recursive /collection:https://TestTFS/tfs/TestCollection /noprompt /format:detailed /version:C1~T
}
你可以直接用下面的命令下载并定义函数(虽然我个人可以向你保证这样做是安全的,但最好先检查源代码):
# Downloads and defines function Invoke-WithEncoding in the current session.
irm https://gist.github.com/mklement0/ef57aea441ea8bd43387a7d7edfc6c19/raw/Invoke-WithEncoding.ps1 | iex
继续阅读以进行详细讨论。
重新变音(字符编码)问题:
虽然外部程序的输出可以打印到控制台,但是当涉及到在变量中捕获输出或重定向它时< /em> - 例如在您的情况下通过管道将其发送到 Out-String
- PowerShell 使用存储在中的字符编码将输出解码为 .NET 字符串 [Console]::OutputEncoding
。
如果 [Console]::OutputEncoding
与外部程序使用的实际编码不匹配,PowerShell 将误解输出。
解决方案是(临时)将[Console]::OutputEncoding
设置为外部程序使用的实际编码。
虽然 official tf.exe
documentation 不讨论字符编码,但此 comment on GitHub 表明 tf.exe
使用系统的活动 ANSI 代码页,例如美国英语或西欧的 Windows-1252系统。
应该注意,ANSI 代码页的使用是控制台应用程序的非标准行为 ,因为控制台应用程序应该使用系统的活动 OEM 代码页。顺便说一句:python
在默认情况下也表现出这种非标准行为,尽管其行为是可配置的。
顶部的解决方案展示了如何将 [Console]::OutputEncoding
临时切换到活动的 ANSI 代码页的编码,以确保 PowerShell 正确解码 tf.exe
的输出。
使用 Out-String
/ Out-File
重新截断输出行(因此还有 >
和 >>
):
正如 Mustafa Zengin's helpful answer 指出的那样,在您的特定情况下 - 由于使用了 tf.exe
- 截断发生在源 ,即 tf.exe
本身按照其默认格式输出截断数据(当还指定 /format:brief
时隐含 /noprompt
)。
一般来说,Out-String
和 Out-File
/ >
/ >>
会根据情况截断或换行基于控制台窗口宽度的输出行(在没有控制台的情况下默认为 120
个字符):
换行的截断仅适用于源自 PowerShell 丰富的输出格式系统生成的非原始、非字符串对象表示的输出行:
字符串本身([string]
输入)以及.NET 原始类型的字符串表示(加上一些更多的单值类型)< /em> 不会被截断/换行。
由于 PowerShell 只将 外部程序 的输出解释为 text([string]
实例),因此截断/换行会 em>不会发生。
Out-String
- 除非您需要连接输出行的流(数组)以形成一个 , 多行字符串用于进一步的内存处理。Out-String
总是在结果字符串中添加一个尾随换行,这可能是我们不希望看到的;使用 (...) -join [Environment]::NewLine
来避免这种情况; Out-String
的问题行为在 GitHub issue #14444 中讨论。