Назад | Перейти на главную страницу

Сценарии Powershell "один ко многим"

Я пытаюсь создать сценарий для запуска как запланированной задачи, который будет запускаться на нескольких серверах и извлекать некоторую информацию.

Для начала я заполняю список серверов, запрашивая в AD все серверы, соответствующие определенному набору критериев, используя Get-ADComputer.

Проблема в том, что список возвращается как объект, который я не могу передать в список New-PSSession. Я попытался преобразовать его в строку, разделенную запятыми, выполнив следующие действия:

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

но это все равно не работает.

Альтернативой является итерация по списку и запуск различных команд для каждого сервера по очереди, но я предпочитаю избегать этого и запускать их с использованием удаленного взаимодействия «один ко многим».

ОБНОВИТЬ: Чтобы прояснить, что я хочу в итоге сделать, я использую -ComputerName $serverlist, поэтому я хочу, чтобы $ serverlist был строкой, а не объектом.

ОБНОВЛЕНИЕ 2: Спасибо за все предложения. Между ними и моим первоначальным методом я начинаю задаваться вопросом, не -ComputerName может принимать строковую переменную? У меня были разные степени успеха, когда список компьютеров преобразовывался в строку, разделенную запятыми, но как бы я это ни делал, я всегда получаю неверный сетевой адрес.

Чтобы объяснить это еще немного, если вы выполнили Get-ADComputer тогда вы, возможно, получите обратно массив объектов или один объект.

Я предполагаю, что вы вызываете что-то вроде следующего:

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

Это получило бы все компьютеры с DC на их имя.

Поскольку у вас потенциально есть массив (более одного) или объекты, которые вы обрабатываете с помощью ForEach-Object командлет (также известный как % или foreach) - хороший подход. Это в основном выполнение блока сценария для каждой записи в конвейере. Однако, как вы уже знаете, из запроса возвращается объект, а не строка. Так что вам просто нужно выбрать недвижимость для использования.

Например, если вы используете:

$serverList[0] | Get-Member

Вы получите все свойства компьютерного объекта. gm также является псевдонимом для Get-Member. Например.

PS> $ serverList [0] | гм

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

Быстро посмотрев, вы увидите, что есть свойство DNSHostName.

Итак, чтобы выполнить свою команду, вы можете использовать что-то вроде:

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

Однако отмечу, что New-PSSession командлет ничего не делает, кроме создания сеанса удаленного взаимодействия с компьютером (для поддержки этого необходимо включить удаленное взаимодействие PowerShell). Вам нужно будет использовать Invoke-Command командлет для выполнения чего-либо из сценария.

Пример 1:

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

Пример 2:

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

Второй пример оптимизирует New-PSSession потому что это действительно не нужно, если вы собираетесь только позвонить Invoke-Command без дополнительных опций.

Также обратите внимание, что нет реальной необходимости сохранять результат Get-ADComputer в переменной вы бы сделали это, только если Get-ADComputer на выполнение потребовалось много времени, и вам пришлось использовать его более одного раза.

В $_ переменная конвейера, которая становится любым объектом, находящимся в конвейере в данный момент.

Обновлено

Специально для использования Invoke-Command для выполнения идентичной команды на нескольких компьютерах вы можете использовать -ComputerName параметр для предоставления массива строк. (В этом можно убедиться, посмотрев справку, т.е.-ComputerName <String[]>. Это может быть не для всех команд).

Как уже упоминалось, вывод из Get-ADComputer это объект. Итак, строковый массив, совместимый с -ComputerName параметр будет построен.

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

В основном это создает новый массив и добавляет к нему имя хоста DNS каждого компьютера, но в итоге вы получаете string[]. Тогда вы сможете использовать:

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

Однако также обратите внимание, что, хотя может показаться, что вы выполняете только одну команду под капотом, это почти всегда номер командлета PowerShell. Например, командный конвейер имеет тихий | Out-Host прилагается к ним.

Вы также можете заключить любую из команд в функцию для выполнения одной команды.

Надеюсь, что ответит на ваш вопрос.

У меня нет доступа к командлетам AD, поэтому я могу предложить только то, что делал раньше, когда мне нужен объект в виде строки.

Я написал на MSSQLTips.com совет по резервному копированию баз данных с помощью SQLPS. Поэтому я в основном запросил в SQLPS имена базы данных, а затем передал это в BACKUP команда, которая должна была видеть имя как строку, а не тип объекта. Вы можете это увидеть Вот если вы хотите.

Если вы возьмете свой $serverlist и передайте это Get-Memberпосмотрите, есть ли ToString() метод. Я думаю, что этот метод подходит для большинства типов системных объектов. Если вы видите это, вы можете попробовать свою команду следующим образом:


$serverlist | foreach {$_.ToString()} | foreach {New-PSSession -computer $_}

Каждый результат в PowerShell - это объект .Net.

Когда у вас есть результат в PowerShell, такой как ваш (объект), и вам нужна строка для поиска или использования в другой команде, вы можете передать результат (объект) в командлет Out-String. В качестве альтернативы вы можете использовать Out-File.

Если вы хотите что-то изменить в Output, вы можете объединить его с другими командлетами, такими как Format- *, Format-Table, Format-List, и т.д.

Итак, когда вы получаете объект и вам нужна строка, используйте что-то вроде этого:

Command-Let | Out-String

или

Command-Let | Format-Custom (parameters) | Out-String