stream水线inputfunction – 写入进度和别名

我目前正在编写一个脚本来从域中的计算机收集大量信息。 正如我想显示它已经走了多远(任务可能会运行几个小时或几分钟),我想使用写入进度。 工作正常,直到我开始通过pipe道传递计算机列表,而不是“正常”的参数..

考虑这个代码:

Function Test-SomethingOnAllComputers { [CmdletBinding()] param ( [parameter( valuefrompipeline=$true, ValueFromPipelineByPropertyName=$true)] [Alias("DNSHostName") [string[]]$ComputerName ) BEGIN { ## Do some init. stuff Write-progress -PercentComplete 0 -Status "Init..." $i = 1 } PROCESS { # Do something with each computername passed in. Write-Progress -PercentComplete ($Input.Count/$i*100) -Status "Doing stuff to $ComputerName" } END { Write-Progress -PercentComplete 100 -status "Done with all objects in the pipeline. Finalizing..." # Clean up and complete the job.. Write-Progress -PercentComplete 100 - Status "Finished.." -Completed } } 

用法: Get-ADComputer -Filter {Name -like "Prod*"} | Test-SomethingOnAllComputers Get-ADComputer -Filter {Name -like "Prod*"} | Test-SomethingOnAllComputers

我在这里得到两个问题/问题:

  1. 我从Get-ADComputer得到的数据是DNSHostName,而不是ComputerName(因此是别名),但是当我在PROCESS部分中引用ComputerName时,它看起来并不像它。 如果我将参数更改为DNSHostName,我会得到正确的值。 所以我猜想我只是在这里与pipe道失去了一些非常相关的东西。

    • 这是通过做(和是的,谢谢微软,这看起来很不错…)解决:

    Get-ADComputer -Filter { Name -like "Prod*"} | % {[string[]]$_.DNSHostName}| Test-SomethingOnAllComputers

    感谢jbsmith清理这个

  2. 我无法获得传递给pipe道的对象的总数。 有没有办法做到这一点,没有循环,但整个input对象pipe道?

  1. 这是从AD cmdlet返回的对象的已知问题。 如果你向他们请求一个他们没有的财产,他们将自动创build它为$ null。 这是令人讨厌的,非标准的行为,当我第一次pipe道对象到我自己的PowerShellfunction时,也困惑我。 因此,PowerShell首先尝试绑定ComputerName属性,并获取$ null,所以它永远不会尝试别名。 只要交换别名和实际的参数名称,事情就会按照您的预期工作。 我为我所有的ComputerName参数做这个确切的事情正是因为这个原因。 这不是典型的,你正在尝试做什么将基本上与其他任何cmdlet一起工作。

我会让其他人来处理你的第二个问题 – 我不知道有一个好的方法来做这件事,同时保留了很容易pipe理你的function的能力。

这似乎不是一个普遍的pipe道错误,而是一个AD Cmdlet的怪癖和从Active Directory加载的属性的填充方式。

如果你将整个计算机对象作为Object (在你的参数块中使用[Object []]进行转换),并用$_.psobject.Properties检查对象的属性,你应该在内部看到Object传递给Test-cmdlet将所有AD属性存储在一个名为Properties (名称混淆的Yay)的单个数组属性中,而将对象传递给Get-Member时看到的“属性”实际上是dynamic的,并从此数组中填充。

确保DNSHostName属性填充并在pipe道计算机对象时工作的更好方法是:

 Get-ADComputer -Filter * | Select-Object -Property DNSHostName | Test-SomethingOnAllComputers 

要么

 Get-ADComputer -Filter * | Select-Object -Property * | Test-SomethingOnAllComputers 

如果你愿意的话,这应该强制这些属性持久化,就像你的foreach例子一样。


关于Write-Progress ,问题是,当从另一个Cmdlet进行pipe道连接时,无法知道在开始处理第一个块时需要多less个对象。

如果要使用Write-Progress -PercentCompleted ,则需要先将所有计算机加载到集合中,然后运行Test- cmdlet,从而有效地Write-Progress -PercentCompleted了stream水线工作:

 $Computers = Get-ADComputer -Filter * |Select-Object -ExpandProperty DNSHostName Test-SomethingOnAllComputers -ComputerName $Computers 

然后在Begin块里有这样的东西:

 $ComputerCount = $ComputerName.Count $i = 0 

现在你应该可以做到

 $i++ Write-Progress -Activity "Doing Stuff" -Status "Doing stuff to $ComputerName" -PercentComplete $($i/$ComputerCount * 100) 

不要用stream水线input做这件事,因为$ComputerCount是零,只有Chuck Norris能被零除