web-dev-qa-db-fra.com

PowerShell: Comment initialiser un tableau d'objets personnalisés

Tout d'abord, comme cela m'amène à ma question, je commencerai par noter que j'ai beaucoup travaillé avec XML dans PowerShell et que je peux facilement lire les données de fichiers XML rapidement dans des tableaux d'objets personnalisés. Par exemple, si j'avais le fichier XML suivant:

<stuff>
 <item name="Joe" age="32">
  <info>something about him</info>
 </item>
 <item name="Sue" age="29">
  <info>something about her</info>
 </item>
 <item name="Cat" age="12">
  <info>something else</info>
 </item>
</stuff>

Et si je le lis simplement, comme ceci:

[xml]$myxml = Get-Content .\my.xml

Ensuite, je peux accéder à un tableau de mes éléments comme ceci:

[array]$myitems = $myxml.stuff.Item
$myitems

name   age  info
----   ---  ----
Joe    32   something about him
Sue    29   something about her
Cat    12   something else

Alors maintenant ma question:

Comment puis-je créer une structure similaire d'un tableau d'objets personnalisés, et les initialiser dans mon script, sans lecture d'un fichier?

Je peux faire beaucoup de boucles et/ou beaucoup de création/initialisation d'objets individuels, puis ajouter des éléments à un tableau ...

Mais il semble qu'il devrait exister un moyen d'effectuer cette création/initialisation d'une manière plus simple. Notez que la clé ici est que mes objets personnalisés ont plus de deux éléments (sinon, j'aurais utilisé un hachage).

J'ai même envisagé de créer une grosse chaîne de XML et d'utiliser Select-XML, mais je ne pouvais tout simplement pas comprendre la syntaxe correctement (même si c'était le bon chemin à suivre).

42
SteveDJ

Je ferais quelque chose dans ce sens:

$myitems =
@([pscustomobject]@{name="Joe";age=32;info="something about him"},
[pscustomobject]@{name="Sue";age=29;info="something about her"},
[pscustomobject]@{name="Cat";age=12;info="something else"})

Notez que cela ne fonctionne que dans PowerShell 3, mais comme vous n'avez pas mentionné la version dans votre question, je suppose que cela n'a pas d'importance pour vous.

Mettre à jour

Il a été mentionné dans les commentaires que si vous procédez comme suit:

$younger = $myitems | Where-Object { $_.age -lt 20 } 
Write-Host "people younger than 20: $($younger.Length)" 

Vous n'obtiendrez pas 1 comme vous pouvez vous attendre. Cela se produit lorsqu'un seul pscustomobject est renvoyé. Cela n’est plus un problème pour la plupart des autres objets de PowerShell, car ils ont des propriétés de substitution pour Length et Count. Malheureusement, pscustomobject ne le fait pas. Ceci est corrigé dans Powershell 6.1.0. Vous pouvez contourner ce problème en utilisant l'opérateur @():

$younger = @($myitems | Where-Object { $_.age -lt 20 })

Pour plus d'informations voir ici et ici .

57
Andrew Savinykh

Voici un moyen concis d'initialiser un tableau d'objets personnalisés dans PowerShell.

> $body = @( @{ Prop1="1"; Prop2="2"; Prop3="3" }, @{ Prop1="1"; Prop2="2"; Prop3="3" } )
> $body

Name                           Value
----                           -----
Prop2                          2
Prop1                          1
Prop3                          3
Prop2                          2
Prop1                          1
Prop3                          3  
25
Shaun Luttin

Peut-être que tu veux dire comme ça? J'aime faire un objet et utiliser Format-Table:

PS C:\Users\Joel> $array = @()
PS C:\Users\Joel> $object = New-Object -TypeName PSObject
PS C:\Users\Joel> $object | Add-Member -Name 'Name' -MemberType Noteproperty -Value 'Joe'
PS C:\Users\Joel> $object | Add-Member -Name 'Age' -MemberType Noteproperty -Value 32
PS C:\Users\Joel> $object | Add-Member -Name 'Info' -MemberType Noteproperty -Value 'something about him'
PS C:\Users\Joel> $array += $object
PS C:\Users\Joel> $array | Format-Table

Name                                                                        Age Info
----                                                                        --- ----
Joe                                                                          32  something about him

Cela mettra tous les objets que vous avez dans le tableau en colonnes en fonction de leurs propriétés.

Astuce: Utiliser -auto permet de mieux dimensionner la table

PS C:\Users\Joel> $array | Format-Table -Auto

Name Age Info
---- --- ----
Joe   32 something about him

Vous pouvez également spécifier les propriétés que vous souhaitez dans la table. Il suffit de séparer chaque nom de propriété par une virgule:

PS C:\Users\Joel> $array | Format-Table Name, Age -Auto

Name Age
---- ---
Joe   32
21
Joel Smith

Le moyen le plus simple d'initialiser un tableau

Créer un tableau

$array = @()

Créez votre en-tête

$line = "" | select name,age,phone

Remplissez la ligne

$line.name = "Leandro"
$line.age = "39"
$line.phone = "555-555555"

Ajouter une ligne à $ array

$array += $line

Résultat

$array

name                                                     age                                                      phone
----                                                     ---                                                      -----
Leandro                                                  39                                                       555-555555
7
Leandro Cascão

Voici une version plus concise de la réponse acceptée qui évite de répéter les identifiants NoteProperty et le [pscustomobject]- cast:

$myItems =  ("Joe",32,"something about him"), ("Sue",29,"something about her")
            | ForEach-Object {[pscustomobject]@{name = $_[0]; age = $_[1]; info = $_[2]}}

Résultat:

> $myItems

name           age         info
----           ---         ----
Joe            32          something about him
Sue            29          something about her
7
davidhigh

Utilisez un "Here-String" et convertissez au format XML.

[xml]$myxml = @"
<stuff>
 <item name="Joe" age="32">
  <info>something about him</info>
 </item>
 <item name="Sue" age="29">
  <info>something about her</info>
 </item>
 <item name="Cat" age="12">
  <info>something else</info>
 </item>
</stuff>
"@

[array]$myitems = $myxml.stuff.Item

$myitems
1
AMissico

Je devais créer un tableau d'un type prédéfini et j'ai réussi à faire ce qui suit:

[System.Data.DataColumn[]]$myitems = ([System.Data.DataColumn]("col1"), 
                [System.Data.DataColumn]("col2"),  [System.Data.DataColumn]("col3"))
0
Ravi Anand

Compte tenu des données ci-dessus, voici comment je procéderais:

# initialize the array
[PsObject[]]$people = @()

# populate the array with each object
$people += [PsObject]@{ Name = "Joe"; Age = 32; Info = "something about him" }
$people += [PsObject]@{ Name = "Sue"; Age = 29; Info = "something about her" }
$people += [PsObject]@{ Name = "Cat"; Age = 12; Info = "something else" }

Le code ci-dessous fonctionnera même si vous ne disposez que d'un élément après un Where-Object:

# display all people
Write-Host "People:"
foreach($person in $people) {
    Write-Host "  - Name: '$($person.Name)', Age: $($person.Age), Info: '$($person.Info)'"
}

# display with just 1 person (length will be empty if using 'PSCustomObject', so you have to wrap any results in a '@()' as described by Andrew Savinykh in his updated answer)
$youngerPeople = $people | Where-Object { $_.Age -lt 20 }
Write-Host "People younger than 20: $($youngerPeople.Length)"
foreach($youngerPerson in $youngerPeople) {
    Write-Host "  - Name: '$($youngerPerson.Name)'"
}

Résultat:

People:
  - Name: 'Joe', Age: 32, Info: 'something about him'
  - Name: 'Sue', Age: 29, Info: 'something about her'
  - Name: 'Cat', Age: 12, Info: 'something else'
People younger than 20: 1
  - Name: 'Cat'
0
Kody