PowerShell - неоднородная коллекция объектов export-csv - неправильные столбцы

У меня есть скрипт, который принимает список серверов, просматривает их реестр и ищет значения реестра, используя подстановочные знаки. Для каждого имени хоста он создает объект, но его свойства различаются. Эти объекты добавляются в коллекцию, а затем я экспортирую эту коллекцию в csv. Мне бы очень хотелось, чтобы там были все возможные заголовки столбцов, но мне кажется, что я всегда получаю только заголовки из первого объекта коллекции. Что может быть лучше, если я заранее не знаю всех возможных свойств объекта?

$res=@()
$hosts = Get-Content hosts.txt
foreach ($hostname in $hosts){
 $server = New-Object -TypeName psobject
 $server | Add-Member -MemberType NoteProperty -Name hostname -Value $hostname
 $server | Add-Member -MemberType NoteProperty -Name online -Value ""
 $server | Add-Member -MemberType NoteProperty -Name IP -Value ""
 $server | Add-Member -MemberType NoteProperty -Name OS -value ""
 $rtn=test-connection $hostname -Count 2 -BufferSize 16 -erroraction silentlycontinue
 if(!$rtn){
   $server.online=$false
   write-host "$hostname offline" -ForegroundColor red;
 }else{
   $server.online=$true
   $server.IP=(($rtn.properties|? name -eq "ProtocolAddress").value|select -first 1)

   $wmi=get-wmiobject -computer $hostname win32_operatingsystem -ErrorAction SilentlyContinue
   $server.OS=$wmi.caption

   $s=Invoke-Command -cn $hostname -ScriptBlock {
       Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*|where {$_.displayname -like "*McAfee*"}|select displayname,displayversion    
   }
   $s|foreach{
       $server | Add-Member -MemberType NoteProperty -Name $_.displayname -Value $_.DisplayVersion
   }
 }
 $res+=$server
}
$res
$res|export-csv "versions.csv" -NoTypeInformation
notepad "versions.csv"

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

пример вывода здесь:

hostname     : server1
online       : True
IP           : secretip
OS           : Microsoft Windows Server 2008 R2 Standard 
McAfee Agent : 5.0.5.658

hostname                                            : server2
online                                              : True
IP                                                  : secretip
OS                                                  : Microsoft Windows Server 2016 Standard
McAfee Agent                                        : 5.0.5.658
McAfee Endpoint Security Threat Prevention          : 10.5.1
McAfee_EndpointSecurityForServer_10.5.1_0_x64_P0_EN : 10.5.1

hostname     : server3
online       : True
IP           : secretip
OS           : Microsoft Windows Server 2008 R2 Standard 
McAfee Agent : 5.0.5.658

hostname     : server4
online       : True
IP           : secretip
OS           : Microsoft Windows Server 2008 R2 Standard 
McAfee Agent : 5.0.5.658

hostname : server5
online   : False
IP       : 
OS       : 

hostname                                            : server6
online                                              : True
IP                                                  : secretip
OS                                                  : Microsoft Windows Server 2012 R2 Standard
McAfee Agent                                        : 5.0.5.658
McAfee Endpoint Security Threat Prevention          : 10.5.1
McAfee_EndpointSecurityForServer_10.5.1_0_x64_P0_EN : 10.5.1

hostname                                   : server7
online                                     : True
IP                                         : secretip
OS                                         : Microsoft Windows Server 2016 Standard
McAfee Agent                               : 5.0.5.658
McAfee Endpoint Security Threat Prevention : 10.5.1
McAfee Endpoint Security Platform          : 10.5.1

результирующий CSV из вышеупомянутого имеет только столбцы из первого объекта в коллекции, но я хочу, чтобы все возможные варианты этих строк McAfee что-то

2 ответа

Я предлагаю:

  • сохранить данные каждого сервера в отдельный файл CSV, а затем
  • сначала собрать данные столбца и применить его к каждому CSV с помощью Select-Object, который
  • создает пустые столбцы в файлах без этого столбца и упорядочивает все столбцы одинаково

Так что вместо

$res+=$server

вставить

$server | Export-Csv "X:\path\$($server.Hostname).csv" -NoTypeInformation

и пусть этот скрипт выполняет объединение:

## Q:\Test\2019\01\18\sf_949737.ps1

$Columns = @('hostname','online','IP','OS')
$Files = (Get-ChildItem server*.csv)

## gather all columns/header
ForEach($File in $Files){
    ((Import-Csv $File)[0].psobject.Properties).Name | ForEach-Object{
        if($Columns -notcontains $_){$Columns += $_}
    }
}
"All columns`r`n-----------"
$Columns
"="*75
@() | Select-Object $Columns | Export-Csv Versions.csv -NoTypeInformation

ForEach($File in $Files){
    Import-Csv $File | Select-Object $Columns | Export-Csv Versions.csv -Append -NoTypeInformation
}

Import-Csv Versions.csv

Пример вывода на основе ваших данных выше:

> Q:\Test\2019\01\18\sf_949737.ps1
All columns
-----------
hostname
online
IP
OS
McAfee Agent
McAfee_EndpointSecurityForServer_10.5.1_0_x64_P0_EN
McAfee Endpoint Security Threat Prevention
McAfee Endpoint Security Platform
===========================================================================


hostname                                            : server1
online                                              : True
IP                                                  : secretip
OS                                                  : Microsoft Windows Server 2008 R2 Standard
McAfee Agent                                        : 5.0.5.658
McAfee_EndpointSecurityForServer_10.5.1_0_x64_P0_EN :
McAfee Endpoint Security Threat Prevention          :
McAfee Endpoint Security Platform                   :

hostname                                            : server2
online                                              : True
IP                                                  : secretip
OS                                                  : Microsoft Windows Server 2016 Standard
McAfee Agent                                        : 5.0.5.658
McAfee_EndpointSecurityForServer_10.5.1_0_x64_P0_EN : 10.5.1
McAfee Endpoint Security Threat Prevention          : 10.5.1
McAfee Endpoint Security Platform                   :

...

Спасибо за ваше решение, это полезно. Между тем я нашел более короткий, не используя другие файлы CSV:

$initObj= New-Object -TypeName psobject
$res|foreach{
    foreach($object_properties in $_.PsObject.Properties){
        if(!(Get-Member -inputobject $initobj -name $object_properties.Name -Membertype Properties)){
            write-host "adding property "$object_properties.Name
            $initObj | Add-Member -MemberType NoteProperty -Name $object_properties.Name -Value ""
        }
    }
}
$resfinal=@()
$resfinal+=$initobj
$res|foreach{
    $resfinal+=$_
}

Это создает новый объект $initObj, затем просматривает все объекты в ранее созданном массиве $ res и проверяет, находятся ли их имена свойств в $ initobj. Если нет, они добавляются. Затем я создаю новый массив $ resfinal, добавляю $ initobj в качестве первого элемента, а затем добавляю все остальные элементы из $ res. Единственным недостатком является то, что первая строка с $ initobj - это пустые строки.

Другие вопросы по тегам