Scripts Powershell um-para-muitos

3

Estou tentando criar um script para ser executado como uma tarefa agendada, que será executada em vários servidores e recuperará algumas informações.

Para começar, preencho a lista de servidores consultando o AD para todos os servidores que correspondem a um determinado conjunto de critérios, usando Get-ADComputer.

O problema é que a lista é retornada como um objeto, que eu não posso passar para a lista New-PSSession. Eu tentei convertê-lo em uma string separada por vírgula fazendo o seguinte:

foreach ($server in $serverlist) {$newlist += $server.Name + ","}

mas isso ainda não funciona.

a alternativa é fazer uma iteração na lista e executar os vários comandos em cada servidor, um de cada vez, mas minha preferência seria evitá-los e executá-los usando comunicação remota um-para-muitos.

UPDATE: Para esclarecer o que eu quero fazer é usar -ComputerName $serverlist , então eu quero que $ serverlist seja uma string ao invés de um objeto.

UPDATE 2: Obrigado por todas as sugestões. Entre eles e meu método original, estou começando a me perguntar se -ComputerName pode aceitar uma variável de string? Eu tenho vários graus de sucesso, obtendo a lista de computadores convertidos em uma string separada por vírgula, mas não importa como eu o faço, eu sempre recebo um endereço de rede inválido.

    
por Matt 11.10.2011 / 01:13

3 respostas

4

Para explicar um pouco mais, se você executou Get-ADComputer , você terá possivelmente uma matriz de objetos ou um único objeto de volta.

Suponho que você esteja chamando algo como o seguinte:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';

Isso levaria todos os computadores com DC em seus nomes.

Como você tem potencialmente uma matriz (mais de uma) ou objetos que você usa usando o cmdlet ForEach-Object (também conhecido como % ou foreach ) é uma boa abordagem. Que é basicamente executar um bloco de script para cada registro no pipeline. No entanto, como você experimentou, você está recebendo um objeto de volta da consulta e não uma string. Então você só tem que escolher uma propriedade para usar.

Por exemplo, se você usar:

$serverList[0] | Get-Member

Você obterá todas as propriedades de um objeto de computador. gm também é um alias para Get-Member . Por exemplo,

PS > $ serverList [0] | gm

TypeName: Microsoft.ActiveDirectory.Management.ADComputer

Name              MemberType            Definition
----              ----------            ----------
Contains          Method                bool Contains(string propertyName)
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode       Method                int GetHashCode()
GetType           Method                type GetType()
ToString          Method                string ToString()
Item              ParameterizedProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string p...
DistinguishedName Property              System.String DistinguishedName {get;set;}
DNSHostName       Property              System.String DNSHostName {get;set;}
Enabled           Property              System.Boolean Enabled {get;set;}
Name              Property              System.String Name {get;}
ObjectClass       Property              System.String ObjectClass {get;set;}
ObjectGUID        Property              System.Nullable'1[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, ...
SamAccountName    Property              System.String SamAccountName {get;set;}
SID               Property              System.Security.Principal.SecurityIdentifier SID {get;set;}
UserPrincipalName Property              System.String UserPrincipalName {get;set;}

Olhando rapidamente, você pode ver que existe uma propriedade DNSHostName.

Então, para executar seu comando, você pode usar algo como:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';
$serverList | ForEach-Object { New-PSSession -ComputerName $_.DNSHostName; }

No entanto, observarei que o cmdlet New-PSSession não faz muito, exceto criar uma sessão de remoting em um computador (o PowerShell Remoting deve estar habilitado para oferecer suporte a isso). Você precisaria usar o cmdlet Invoke-Command para executar algo de um script.

Exemplo 1:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';
$serverList | ForEach-Object { New-PSSession -ComputerName $_.DNSHostName; } | ForEach-Object { Invoke-Command -Session $_ -ScriptBlock { #Execute commands here }; };

Exemplo 2:

Get-ADComputer -LDAPFilter '(cn=*DC*)' | % { Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock { #Execute commands here }; };

O segundo exemplo otimiza o New-PSSession , porque não é realmente necessário se você só vai chamar o Invoke-Command sem opções avançadas.

Observe também que não há necessidade real de armazenar o resultado de Get-ADComputer em uma variável, você só faria isso se Get-ADComputer demorasse muito tempo para ser executado e você tivesse que usá-lo mais de uma vez.

O $_ é uma variável de pipeline que se torna qualquer objeto atualmente no pipeline.

Atualizado

Especificamente para usar Invoke-Command para executar um comando idêntico em vários computadores, você pode usar o parâmetro -ComputerName para fornecer uma matriz de seqüências de caracteres. (Isso pode ser visto consultando a ajuda, por exemplo, -ComputerName <String[]> . Esse não seria o caso de todos os comandos).

Como mencionado, a saída de Get-ADComputer é um objeto. Portanto, um array de strings compatível com o parâmetro -ComputerName seria construído por.

$serverList = @();
Get-ADComputer -LDAPFilter '(cn=*DC*)' | % { $serverList += $_.DNSHostName; }

Basicamente, isso cria uma nova matriz e adiciona o nome do host DNS de cada computador, mas você acaba com string[] . Você poderia então usar:

Invoke-Command -ComputerName $serverList -ScriptBlock { #Execute commands here };

No entanto, observe também que, embora possa parecer que você está executando apenas um único comando sob o capô, quase sempre há um número de cmdlet do PowerShell. Por exemplo, o pipeline de comando tem um | Out-Host silencioso anexado a eles.

Você também pode agrupar qualquer um dos comandos em uma função para executar um único comando.

Espero que você responda a uma pergunta.

    
por 02.10.2012 / 23:44
0

Todo resultado no PowerShell é um objeto .Net.

Quando você tem um resultado em powershell como o seu (um objeto) e precisa de uma string para uma pesquisa ou para usar em outro comando, pode canalizar o resultado (o objeto) para o cmdlet Out-String . Como alternativa, você pode usar Out-File .

Se você quiser alterar algo no resultado, poderá combiná-lo com outros cmdlets, como os Format- *, Format-Table , Format-List , etc.

Então, quando você pega um objeto e precisa de uma string, use algo assim:

Command-Let | Out-String

ou

Command-Let | Format-Custom (parameters) | Out-String
    
por 11.10.2011 / 08:52
0

Eu não tenho acesso a cmdlets do AD, por isso só posso oferecer algo que fiz antes quando precisar do objeto como uma string.

Eu escrevi uma dica em MSSQLTips.com para fazer backup de bancos de dados usando o SQLPS. Então, eu basicamente consultei SQLPS para os nomes do banco de dados e passei para o comando BACKUP , que precisava ver o nome como uma string e não o tipo de objeto que era. Você pode ver aqui se você quiser.

Se você pegar seu $serverlist e passá-lo para Get-Member , veja se há um método ToString() . Eu acho que esse método aparece para a maioria dos tipos de objeto do sistema. Se você vir, então você pode tentar o seu comando desta maneira:


$serverlist | foreach {$_.ToString()} | foreach {New-PSSession -computer $_}
    
por 12.10.2011 / 23:12