我在Powershell中键入以下内容,列出我所有azure Web应用程序的名称:
Get-AzureRmWebApp | % { $_.Name }
它输出:
coolum-exercise-web-app
practice-web-app
AzureSandbox
但后来我想在名称上过滤此输出。我打字这个:
Get-AzureRmWebApp | ? { $_.Name -like "coolum-exercise-web-app" } | % { $_.Name }
我希望只看到一个输出。相反,我明白了
coolum-exercise-web-app
practice-web-app
AzureSandbox
为什么没有应用名称过滤器?
如果我直接在-Name
上使用Get-AzureRmWebApp
参数,它可以工作:
Get-AzureRmWebApp -Name "coolum-exercise-web-app" | % { %_.Name }
输出:
coolum-exercise-web-app
但是为什么where-object
无法按预期应用过滤器?
Get-AzureRmWebApp
in brackets, the filter works as you would expect it to.
(Get-AzureRmWebApp) | ? { $_.Name -like "coolum-exercise-web-app" } | % { $_.Name }
输出:
coolum-exercise-web-app
谁能解释这种行为?为什么将命令括在括号中会使过滤工作?
请尝试:(注意括号)
(Get-AzureRmWebApp) | ? { $_.Name -like 'cool*' }
看起来整个where子句被视为Get-AzureRmWebApp的默认命名参数。这就是为什么你必须用括号从where子句中分离CmdLet的原因。
实际上Get-AzureRmWebApp返回一个列表,而像Get-AzureRmVM这样的其他CmdLet返回一个对象。
Get-AzureRmWebApp | gm
Get-AzureRmVM | gm
这是一个已知的错误:#1544 Get-AzureRmWebApp - unable to pipe into select-object
Get-AzureRmWebApp
的结果是一个列表。您希望列表中的每个项目都是通过逐项管道发送的。相反,整个列表作为单个对象通过管道发送一次。
展示:
Get-AzureRmWebApp | % { $_.GetType().FullName }
显示器
System.Collections.Generic.List`1[[Microsoft.Azure.Management.WebSites.Models.Site, Microsoft.Azure.Management.Websites, Version=1.0.0.2, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]
而
(Get-AzureRmWebApp) | % { $_.GetType().FullName }
显示器
Microsoft.Azure.Management.WebSites.Models.Site
Microsoft.Azure.Management.WebSites.Models.Site
Microsoft.Azure.Management.WebSites.Models.Site
发生错误是因为底层的C#代码调用WriteObject(sendToPipeline = list),它应该调用WriteObject(sendToPipeline = list, enumerateCollection = true)
我希望Azure团队解决这个问题,因为对于倒霉的自动化脚本编写者来说会有意想不到的后果。
例如,我原来的电话:
Get-AzureRmWebApp | ? { $_.Name -like "coolum-exercise-web-app" } | % { $_.Name }
被解释为“如果任何值具有Name
之类的coolum-exercise-web-app
,则显示所有值。”
编辑(2019年3月)
我用Azure Az Powershell Modules测试了这个,我可以看到这个问题已得到解决。