Entrada de pipeline para funções - Write-progress e Alias

1

Atualmente, estou trabalhando em um script para coletar muitas informações de computadores em um domínio. Como eu quero mostrar até onde isso aconteceu (a tarefa pode ser executada por horas ou minutos), eu queria usar o progresso de gravação. Funciona bem, até que comecei a passar a lista de computadores através do pipeline e não como parâmetros "normais" ..

Considere este código:

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
}
}

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

Eu recebo duas perguntas / problemas aqui:

  1. Os dados que recebo de Get-ADComputer são DNSHostName e não ComputerName (daí o alias), mas parece que não são apanhados quando me refiro a ComputerName na parte PROCESS . Se eu alterar o parâmetro para ser DNSHostName, recebo o valor correto. Então eu acho que estou perdendo algo muito relevante aqui com o pipeline.

    • Isso é resolvido fazendo (e sim, obrigado Microsoft, isso parece muito legal ...):

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

    Obrigado ao jbsmith por esclarecer isso

  2. Não consigo obter a contagem total de objetos transmitidos pelo pipeline. Existe uma maneira de fazer isso sem o loop de todo o pipeline de objetos de entrada?

por mdavidsen 24.09.2014 / 17:12

2 respostas

2

  1. Esse é um problema conhecido com objetos retornados dos cmdlets do AD. Se você solicitar uma propriedade a eles que eles não possuem, eles criarão automaticamente como $ null. É um comportamento incomodo, não padrão, que também me confundiu ao canalizar objetos para as minhas próprias funções do PowerShell. Portanto, o PowerShell tenta vincular a propriedade ComputerName primeiro e obtém $ null, portanto, nunca tenta o alias. Basta trocar o alias e o nome do parâmetro real e as coisas funcionarão conforme o esperado. Eu faço exatamente isso para todos os meus parâmetros ComputerName apenas por esse motivo. Isso NÃO é típico, e o que você está tentando fazer funcionaria com praticamente todos os outros cmdlets.

Deixarei que outra pessoa cuide da sua segunda pergunta - não conheço uma boa maneira de fazer isso, ao mesmo tempo em que preservo a capacidade de canalizar sua função com facilidade.

    
por 24.09.2014 / 23:41
1

Isso não parece ser um bug de pipeline geral, mas sim uma peculiaridade com os Cmdlets do AD e a maneira como as Propriedades carregadas do Active Directory são preenchidas.

Se você canalizar todo o objeto Computador como Object s (convertido usando [Object []] no seu bloco de parâmetros) e inspecionar as propriedades do objeto com $_.psobject.Properties , deverá ver internamente, o objeto passado para o cmdlet Test- tem todos os Atributos do AD armazenados em uma única propriedade de matriz chamada Properties (yay para nomear confusão) e as "propriedades" que você vê quando canaliza o objeto para Get-Member são realmente dinâmicas e preenchidas este array.

Uma maneira mais elegante de garantir que a propriedade DNSHostName seja preenchida e funcione durante a execução dos objetos do computador seria:

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

ou

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

Isso deve forçar as propriedades a persistirem se você quiser, assim como seu exemplo foreach.

Com relação a Write-Progress , o problema é que, quando o piping de outro Cmdlets, você não pode saber quantos objetos esperar quando você começar a processar o primeiro bloco.

Se você quiser usar Write-Progress -PercentCompleted , primeiro precisará carregar todos os seus computadores em uma coleção e, em seguida, executar o cmdlet Test- , efetivamente derrotando seus esforços de Pipelining:

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

E então tem algo parecido com isso no bloco Begin:

$ComputerCount = $ComputerName.Count
$i = 0

Agora você deve ser capaz de fazer

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

Não faça isso com a entrada de pipeline, pois $ComputerCount seria zero e somente Chuck Norris pode dividir por zero

    
por 26.09.2014 / 09:33

Tags