2016-03-12 3 views
1

Давайте создавать книгиРабота с (членами) гетерогенных массивов

$a = New-Object –TypeName PSObject 
$a | Add-Member –MemberType NoteProperty –Name Title –Value "Journey to the West" 
$a | Add-Member –MemberType NoteProperty –Name Price –Value 12 

$b = New-Object –TypeName PSObject 
$b | Add-Member –MemberType NoteProperty –Name Title –Value "Faust" 
$b | Add-Member –MemberType NoteProperty –Name Author –Value "Goethe" 

$array1 = $a,$b 
$array2 = $b,$a 

Теперь давайте показывать эти два массива

PS D:\Developpement\Powershell> $array1 

Title    Price 
-----    ----- 
Journey to the West 12 
Faust      

PS D:\Developpement\Powershell> $array2 

Title    Author 
-----    ------ 
Faust    Goethe 
Journey to the West 

Так, насколько я понимаю, это в основном означает, что то, что Powershell считают свойства массива - это свойства его первого элемента (на самом деле это даже не так, потому что если первый элемент равен $null, то следующий будет рассмотрен). Теперь, также подразумевает, что:

  • если вы звоните Get-Member на массиве, вы получите только член первого элемента
  • если вы звоните Convert-ToCvs на массиве, вы будете экспортировать только значение свойств для свойств определяются первый элемент
  • и т.д.

Я с трудом понимаю, что позади рациональные и это поведение сделало раздражающе болезненным для меня работать с разнородными массивами в PowerShell.

Я хотел бы импортировать данные из разных внешних источников, обрабатывать их, а затем экспортировать их в файл cvs. Элементы аналогичны, но большинство из них непредсказуемо пропускают некоторые свойства. Есть ли очевидный способ справиться с этим в Powershell без перепрограммирования колеса?

+0

'$ array | sel ect ($ array |% {$ _. PSObject.Properties} | select -exp name -u) | ConvertTo-Csv' – PetSerAl

+0

'Get-Member' показывает набор элементов для первого объекта каждого отдельного типа в массиве. '$ A.pstypenames.Insert (0, "BookForSale"); $ A1 | gm' –

ответ

2

Так оно и должно быть, потому что PowerShell использует конвейеры. Когда вы запускаете ex. $array1 | Export-CSV ...., PowerShell начинает записывать в CSV-файл, как только приходит первый объект. В этот момент он должен знать, как будет выглядеть заголовок, поскольку это первая строка в csv-файле. Поэтому PowerShell должен предположить, что класс/свойства первого объекта представляют все остальные объекты в конвейере. То же самое относится к Format-Table и аналогичным командам, которым необходимо задать стиль/представление перед выводом любых объектов.

Обычным обходным путем является указание заголовка вручную с использованием Select-Object. Он добавит все отсутствующие свойства ко всем объектам со значением $null. Таким образом, все объекты, отправленные на ex. Export-CSV будут иметь все те же свойства, которые определены.

Чтобы получить заголовок, вам необходимо получить все уникальные имена свойств из всех объектов в вашем массиве. Ex.

$array1 | 
ForEach-Object { $_.PSObject.Properties} | 
Select-Object -ExpandProperty Name -Unique 

Title 
Price 
Author 

Затем вы можете указать, что в качестве заголовка, используя Select-Object -Properties Title,Price,Author перед отправкой объекты Export-CSV Ex:

$a = New-Object –TypeName PSObject 
$a | Add-Member –MemberType NoteProperty –Name Title –Value "Journey to the West" 
$a | Add-Member –MemberType NoteProperty –Name Price –Value 12 

$b = New-Object –TypeName PSObject 
$b | Add-Member –MemberType NoteProperty –Name Title –Value "Faust" 
$b | Add-Member –MemberType NoteProperty –Name Author –Value "Goethe" 

$array = $a,$b 

$AllProperties = $array | 
ForEach-Object { $_.PSObject.Properties} | 
Select-Object -ExpandProperty Name -Unique 

$array | Select-Object -Property $AllProperties | Export-CSV -Path "mycsv.out" -NoTypeInformation 

Это создаст этот CSV-файл:

"Title","Price","Author" 
"Journey to the West","12", 
"Faust",,"Goethe" 

Если у вас есть mulltiple массивы вы можете их комбинировать следующим образом: $array = $array1 + $array2