我被要求修复一个同事今天写的PowerShell脚本的输出,当我试图从foreach
循环中输出时,我注意到了一些奇怪的行为。当我在没有将可迭代对象$gpos
输送到foreach
的情况下运行循环时:
# This is the foreach loop in question
foreach ( $gpo in $gpos ) {
[xml]$XML = Get-GPOReport -$gpo.DisplayName -ReportType Xml
$admins = $XML.DocumentElement.Computer.ExtensionData.Extention.RestrictedGroups.Member
# Not this one
$admins | foreach {
[PSCustomObject]@{
"GroupPolicy" = $gpo.DisplayName;
"Permisisons" = $_.name.'#text';
}
}
} | Export-CSV -Path \path\to\file.csv -NoTypeInformation
我得到一个错误“一个空管道元素是不允许的”。
但是,如果我将$gpos
对象输送到foreach
循环中,如下所示:
$gpos | foreach {
$gpo = $_
# ...the rest of the code above
} | Export-CSV -Path \path\to\file.csv -NoTypeInformation
我能使用最后一根管子而不出问题。当语句以foreach
循环开始,而不是迭代对象中的管道时,管道为什么不能工作?我自己很少使用第一种格式,所以我编写的代码没有遇到这个问题。我想不出这两种格式不应该工作的功能原因,因为如果管道输入为null,那么在本例中会抛出一个适当的异常。
发布于 2017-08-24 20:42:35
当语句以
foreach
循环开始,而不是迭代对象中的管道时,管道为什么不能工作?
因为一种语法是foreach
语句,另一种语法是ForEach-Object
命令的别名。这就像是Get-ChildItem
和if {} else {}
之间的区别。
PowerShell的作者愚蠢地认为过度使用这个词是个好主意。从那以后,它就让语言的使用者感到困惑。
比较:
Get-Help about_Foreach -ShowWindow
Get-Help ForEach-Object -ShowWindow
前者甚至描述了PowerShell如何决定哪个是:
当Foreach出现在命令管道中时,Windows PowerShell使用foreach别名,它调用ForEach-Object命令。在命令管道中使用foreach别名时,不像使用Foreach语句那样包含($ in $)语法。这是因为管道中的优先命令提供了此信息。
底线是foreach
不会将输出发送到管道中。你可以做得很好:
$x = foreach ($i in 1..10) { $i }
但这将失败:
foreach ($i in 1..10) { $i } | Where-Object { $_ -eq 2 }
正如MathiasR.Jesen在注释中所指出的,您可以将foreach
语句包装在一个子表达式中,以使它与管道一起工作:
$(foreach ($i in 1..10) { $i }) | Where-Object { $_ -eq 2 }
ForEach-Object
命令总是使用(并且需要)管道。
发布于 2017-08-24 20:35:06
一个是语言关键字foreach
,另一个实际上是cmdlet ForEach-Object
的别名。
语言关键字不能成为管道的一部分,这就是为什么您会得到这个异常。这也是为什么它们在不同的上下文中有不同的含义,如果foreach
已经是管道的一部分,引擎就不会将它解析为关键字。
https://stackoverflow.com/questions/45870275
复制相似问题