70

首先,由于这引出了我的问题,我将首先指出我在 PowerShell 中使用了相当多的 XML,以及如何将 XML 文件中的数据快速读取到自定义对象数组中。例如,如果我有以下 XML 文件:

<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>

如果我简单地阅读它,就像这样:

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

然后我可以像这样访问我的项目数组:

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

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

所以,现在我的问题:

如何创建自定义对象数组的类似结构,并在我的脚本中初始化它们,而不读取文件?

我可以做很多循环和/或大量创建/初始化单个对象,然后一次添加到一个数组中......

但似乎应该有一种方法可以以更简单的方式执行此创建/初始化。请注意,这里的关键是我的自定义对象有两个以上的元素(否则,我会使用哈希)。

我什至看过创建一大串 XML 并使用 Select-XML,但我就是无法正确使用语法(如果那是正确的前进道路的话)。

4

9 回答 9

104

我会按照这些思路做一些事情:

$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"})

请注意,这仅适用于PowerShell 3,但由于您没有在问题中提及版本,因此我假设这对您无关紧要。

更新

评论中已经提到,如果您执行以下操作:

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

你不会得到1你所期望的。当单曲pscustomobject返回时会发生这种情况。现在这对于 PowerShell 中的大多数其他对象来说不是问题,因为它们具有Length和的代理属性Count。不幸pscustomobject的是没有。这已在 PowerShell 6.1.0 中修复。您可以使用 operator 解决此问题@()

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

有关更多背景信息,请参见此处此处

更新 2

在 PowerShell 5 中,可以使用来实现类似的功能。例如,您可以像这样定义一个类:

class Person {
    [string]$name
    [int]$age
    [string]$info; `
`
    Person(
    [string]$name,
    [int]$age,
    [string]$info
    ){
        $this.name = $name
        $this.age = $age
        $this.info = $info
    }
}

此处的反引号是为了让您可以将其复制并粘贴到命令行,脚本中不需要它们。一旦定义了类,您就可以按照通常的方式创建一个数组:

$myitems =@([Person]::new("Joe",32,"something about him"),
[Person]::new("Sue",29,"something about her"),
[Person]::new("Cat",12,"something else"))

请注意,这种方式没有上一次更新中提到的缺点,即使在 PowerShell 5 中也是如此。

更新 3

您还可以使用哈希表初始化类对象,类似于第一个示例。为此,您需要确保定义了默认构造函数。如果您不提供任何构造函数,则会为您创建一个,但如果您提供非默认构造函数,则默认构造函数将不存在,您需要显式定义它。这是一个带有自动创建的默认构造函数的示例:

class Person {
    [string]$name
    [int]$age
    [string]$info;
}

有了它,您可以:

$person = @([Person]@{name='Kevin';age=36;info="something about him"}
[Person]@{name='Sue';age=29;info="something about her"}
[Person]@{name='Cat';age=12;info="something else"})

这有点冗长,但也更明确。感谢@js2010 指出这一点。

于 2013-06-27T23:17:52.000 回答
38

这是在 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  
于 2014-10-16T22:26:59.460 回答
28

也许你的意思是这样的?我喜欢制作一个对象并使用 Format-Table:

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

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

这将根据它们的属性将数组中的所有对象放在列中。

提示:-auto更好地使用表格大小

> $array | Format-Table -Auto

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

您还可以在表中指定所需的属性。只需用逗号分隔每个属性名称:

> $array | Format-Table Name, Age -Auto

Name Age
---- ---
Joe   32
于 2013-06-27T22:16:11.767 回答
21

初始化数组的最简单方法

创建数组

$array = @()

创建您的标题

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

填充线

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

将行添加到 $array

$array += $line

结果

$array

name                                                     age                                                      phone
----                                                     ---                                                      -----
Leandro                                                  39                                                       555-555555
于 2017-05-10T14:02:53.037 回答
9

这是已接受答案的更简洁版本,可避免重复 NoteProperty 标识符和[pscustomobject]-cast:

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

结果:

> $myItems

name           age         info
----           ---         ----
Joe            32          something about him
Sue            29          something about her
于 2016-07-27T14:51:43.720 回答
2

使用“Here-String”并转换为 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
于 2017-03-02T03:18:59.533 回答
2

鉴于上面的数据,我会这样做:

# 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" }

即使您在 a 之后只有一项,以下代码也将起作用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)'"
}

结果:

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'
于 2019-02-19T00:37:45.517 回答
1

类的一点变化。用哈希表初始化它。

class Point { $x; $y }

$a = [Point[]] (@{ x=1; y=2 },@{ x=3; y=4 })

$a

x y        
- -          
1 2
3 4

$a.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Point[]                                  System.Array

$a[0].gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    Point                                    System.Object
于 2019-07-18T02:07:33.663 回答
0

我必须创建一个预定义类型的数组,并且我成功地执行了以下操作:

[System.Data.DataColumn[]]$myitems = ([System.Data.DataColumn]("col1"), 
                [System.Data.DataColumn]("col2"),  [System.Data.DataColumn]("col3"))
于 2018-06-06T17:49:19.557 回答