Как добавить вывод из командлета в массив? - PullRequest
1 голос
/ 05 февраля 2020

Я пытаюсь определить, установлены ли указанные c Windows исправления на наших Windows серверах. Я довольно новичок в написании сценариев PowerShell, и вот что у меня есть:

$servers = Get-ADComputer -Filter {(OperatingSystem -like "Windows Server 2019*") -and (enabled -ne $false)} -Property *
$result = @()
ForEach ($item in $servers) {
    $testhotfix = Get-HotFix -Id KB4534310,KB4534314,KB4534283,KB4534288,KB4534297,KB4534309,KB4534271,KB4534273 -ComputerName $item.Name | `
    select $item.Name,$item.CanonicalName,$item.OperatingSystem
    $result += $testhotfix
}
$result | Export-Csv -Path C:\Users\user1\Desktop\Servers.csv -NoTypeInformation

Созданный CSV-файл содержит одну строку с информацией, которую я ищу, а затем несколько строк запятых, вот так:

Вывод скрипта

"SERVER1", "somedomain.com/Servers/Non-Prod/New_Server_Staging/SERVER1","Windows Сервер 2019 Стандартный 1012 *

У нас есть несколько серверов, на которых установлено хотя бы одно исправление. Как добавить каждый сервер в массив $ result ?

Спасибо

Ответы [ 2 ]

0 голосов
/ 05 февраля 2020

Я бы использовал PSCustomObject.

    $array = foreach($item in $obj)
    {
        [PSCustomObject]@{
            Name = $item.Name
            CanonicalName = $item.CanonicalName
            OS = $item.OperatingSystem
        }
    }
0 голосов
/ 05 февраля 2020

Вообще говоря:

select $item.Name,$item.CanonicalName,$item.OperatingSystem

должно быть:

select Name, CanonicalName, OperatingSystem

То есть вам нужно передать свойство names (например, Name), а не свойство текущего входного объекта значения (например, $item.Name) to select (командлет Select-Object).

Эффект net заключается в том, что Select-Object создает пользовательские объекты, свойства которых (по ошибке) названы для свойства значения и сами по себе не имеют значения , учитывая, что входные объекты не имеют таких свойств. Это объясняет вывод, который вы видели.

Однако большая проблема в том, что даже это не сработает, учитывая, что имена свойств относятся к объекту $item, а не к объектам, выводимым Get-HotFix, то есть те, с которыми select работает.

Как выясняется, вам действительно нужно использовать Get-HotFix вызов как условное , чтобы записать строку CSV для компьютера под рукой, только если установлено хотя бы одно из указанных исправлений :

$hotfixIds = 'KB4534310', 'KB4534314', 'KB4534283', 'KB4534288', 'KB4534297', 'KB4534309', 'KB4534271', 'KB4534273'

if (0 -ne (Get-HotFix -ErrorAction SilentlyContinue -Id $hotfixIds -ComputerName $item.Name).Count)  {
  $result += $item | select Name, CanonicalName, OperatingSystem
}

Примечание:

  • Обратите внимание, что теперь $item (компьютер под рукой) передается по каналу select, чтобы обеспечить извлечение его свойств (в виде пользовательских объект с этими свойствами).

  • Вы можете вообще пропустить 0 -eq и полагаться на неявное преобразование PowerShell в булево, где любое ненулевое число равно $true (см. нижний раздел этого ответа для краткого изложения всех правил.

    • Если вместо этого вы хотите проверить все указанных установленных исправлений, заменив 0 -ne на $hotfixIds.Count -eq.
  • -ErrorAction SilentlyContinue, чтобы заставить ошибки замолчать с компьютеров, на которых нет указанных исправлений; затем вы можете проверить коллекцию automati c $Error или использовать -ErrorVariable err для сбора всех указанных в команде ошибок c в переменной $err.

Кроме того, ваш Общая команда может быть значительно упрощена - см. нижний раздел.


Решение для другого сценария, которое также может представлять интерес:

Если вы требуемые до объединяют свойства из выходных объектов Get-HotFix со свойствами из $item объектов (представляющих компьютер под рукой):

Следующая команда:

  • выбирает все свойства из Get-HotFix объектов вывода (-Property *)
  • добавляет интересующие свойства из текущего $item, используя вычисленные свойства
# Additional 'KB...' values omitted for brevity.
Get-HotFix -Id KB4534310, KB4534314 -ComputerName $item.Name | 
  Select-Object -Exclude Name -Property *,
                  @{ n = 'Name'; e = { $item.Name } },
                  @{ n = 'CanonicalName'; e = { $item.CanonicalName } },
                  @{ n = 'OperatingSystem'; e = { $item.OperatingSystem } }

Обратите внимание, что -Exclude Name исключает свойство Name из входных объектов (Get-HotFix выходные объекты, имеющие такое свойство , но это пусто ), так что Name может быть добавлено как свойство co имя компьютера.


Что касается того, что вы пытались:

Помимо упомянутой выше проблемы с именем свойства Select-Object, ваша главная проблема заключалась в том, что вы ожидали, что сегмент конвейера условный , который не работает как конвейеры:

Get-HotFix ... | select ...

Выше просто отправляет Get-HotFix '* выходные данные объекты с по select (Select-Object), которые затем безоговорочно обрабатывают их (и, как уже говорилось, ищут свойства с данными именами в этих объектах ).

Теперь, если Get-HotFix произвел no output, тогда условная логика c применяется неявно: команда select тогда просто не будет вызываться.

И наоборот, если Get-HotFix выдает несколько выходных данных, select будет вызываться для каждого .

То есть, если мы наивно пытались исправить вашу команду из:

Get-HotFix ... | select ...

до:

Get-HotFix ... | ForEach-Object { $item | select ... }

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


Модернизированная версия Ваша (исправленная) команда:

Ваша команда может быть упрощена для использования только одного конвейера, без необходимости aux. переменные:

Get-ADComputer -Filter '(OperatingSystem -like "Windows Server 2019*") -and (enabled -ne $false)' -Property * |
  ForEach-Object {
    if (0 -ne (Get-HotFix -ErrorAction SilentlyContinue -ComputerName $item.Name -Id KB4534310,KB4534314,KB4534283,KB4534288,KB4534297,KB4534309,KB4534271,KB4534273).Count) {
      $item | select Name, CanonicalName, OperatingSystem
    }
  } | Export-Csv -Path C:\Users\user1\Desktop\Servers.csv -NoTypeInformation

Примечание:

  • Если вы заканчиваете строку с |, вы делаете не нужен трейлинг ` для сигнализации о продолжении линии.

    • PowerShell [Core] v7.0 + теперь также позволяет помещать | в начале следующей строки .
  • Строка в одинарных кавычках ('...') используется вместо блока скрипта ({ ... }) для передачи аргумента -Filter, потому что tt лучше всего избегать использования блоков сценариев ({ ... }) в качестве -Filter аргументов .

  • Выходные экземпляры пользовательских объектов, созданные с помощью $item | select Name, CanonicalName, OperatingSystem, отправляются непосредственно в конвейер .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...