Я пытаюсь создать сценарий для запуска как запланированной задачи, который будет запускаться на нескольких серверах и извлекать некоторую информацию.
Для начала я заполняю список серверов, запрашивая в 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