从 Windows PowerShell 3.0 开始,零个或一个 对象的集合具有数组的某些属性。
创建和初始化数组
若要创建和初始化数组,请将多个值分配给变量。 数组中存储的值用逗号分隔,并通过赋值运算符 (
=
) 与变量名称分隔。
例如,若要创建一个名为 的
$A
数组,其中包含 7 个数值 (整数) 值 22、5、10、8、12、9 和 80,请键入:
$A = 22,5,10,8,12,9,80
逗号还可用于通过将逗号放在单个项之前来初始化单个项数组。
例如,若要创建名为 的 $B
单个项数组,其中包含单个值 7,请键入:
$B = ,7
还可以使用 range 运算符 () ..
创建和初始化数组。
以下示例创建一个包含值 5 到 8 的数组。
$C = 5..8
因此, $C
包含四个值:5、6、7 和 8。
如果未指定数据类型,PowerShell 会 (System.Object[]) 创建每个数组作为对象数组。 若要确定数组的数据类型,请使用 GetType()
方法。 例如:
$A.GetType()
若要创建强类型数组,即只能包含特定类型的值的数组,请将变量强制转换为数组类型,例如 string[]、 long[]或 int32[]。 若要强制转换数组,请在变量名称前面加上用括号括起来的数组类型。 例如:
[int32[]]$ia = 1500, 2230, 3350, 4000
因此, $ia
数组只能包含整数。
可以创建强制转换为 .NET 中任何受支持的类型的数组。 例如,检索以表示进程的对象 Get-Process
属于 System.Diagnostics.Process 类型。 若要创建进程对象的强类型数组,请输入以下命令:
[Diagnostics.Process[]]$zz = Get-Process
数组子表达式运算符
数组子表达式运算符从数组中的语句创建数组。 无论运算符内部的 语句生成什么,运算符都会将其置于数组中。 即使有零个或一个对象。
数组运算符的语法如下所示:
@( ... )
可以使用 array 运算符创建包含零个或一个对象的数组。 例如:
$a = @("Hello World")
$a.Count
$b = @()
$b.Count
获取对象时,数组运算符在脚本中很有用,但不知道预期数量。 例如:
$p = @(Get-Process Notepad)
有关数组子表达式运算符的详细信息,请参阅 about_Operators。
访问和使用数组元素
可以使用数组的变量名称来引用数组。 若要显示数组中的所有元素,请调用数组名称。 例如, $a
是数字 0 到 9 的数组:
可以使用索引引用数组中的元素。 将索引号括在方括号中。 索引值从 开始 0
。 例如,若要显示数组中的 $a
第一个元素,请键入:
$a[0]
若要显示数组中的第三个 $a
元素,请键入:
$a[2]
可以使用索引的 range 运算符检索数组的一部分。 例如,若要检索数组的第二到第五个元素,请键入:
$a[1..4]
从数组末尾计数负数。 例如, -1
引用数组的最后一个元素。 若要按索引升序显示数组的最后三个元素,请键入:
$a = 0 .. 9
$a[-3..-1]
如果按降序键入负索引,则输出会更改。
$a = 0 .. 9
$a[-1..-3]
但是,使用此表示法时要小心。 表示法从结束边界到数组的开头周期。
$a = 0 .. 9
$a[2..-2]
此外,一个常见的错误是假定 $a[0..-2]
引用数组的所有元素,最后一个元素除外。 它引用数组中的第一个、最后一个和倒数第二的元素。
可以使用加号运算符 (+
) 将范围与数组中的元素列表组合在一起。 例如,若要在索引位置 0、2 和 4 到 6 处显示元素,请键入:
$a = 0 .. 9
$a[0,2+4..6]
此外,若要列出多个区域和单个元素,可以使用加号运算符。 例如,列出零到二、四到六的元素,以及第八个位置类型的元素:
$a = 0..9
$a[+0..2+4..6+8]
对数组元素进行迭代
还可以使用循环构造(如 foreach
、 for
和 while
循环)来引用数组中的元素。 例如,若要使用 foreach
循环显示数组中的 $a
元素,请键入:
$a = 0..9
foreach ($element in $a) {
$element
循环 foreach
循环访问数组,并返回数组中的每个值,直到到达数组的末尾。
在 for
检查数组中的元素时递增计数器时,循环非常有用。 例如,若要使用 for
循环返回数组中的所有其他值,请键入:
$a = 0..9
for ($i = 0; $i -le ($a.length - 1); $i += 2) {
$a[$i]
可以使用 while
循环来显示数组中的元素,直到定义的条件不再为 true。 例如,若要在数组索引小于 4 时显示数组中的 $a
元素,请键入:
$a = 0..9
while($i -lt 4) {
$a[$i]
数组的属性
Count 或 Length 或 LongLength
若要确定数组中有多少项,请使用 Length 属性或其 Count 别名。 如果数组包含超过 2,147,483,647 个元素,则 Longlength 非常有用。
$a = 0..9
$a.Count
$a.Length
返回数组中的维数。 PowerShell 中的大多数数组只有一个维度。 即使你认为要生成多维数组,如以下示例所示:
$a = @(
@(0,1),
@("b", "c"),
@(Get-Process)
"`$a rank: $($a.Rank)"
"`$a length: $($a.Length)"
"`$a[2] length: $($a[2].Length)"
"Process `$a[2][1]: $($a[2][1].ProcessName)"
在此示例中,你将创建一个包含其他数组的单维数组。 这也称为 交错数组。 属性 Rank 证明这是单维的。 若要访问交错数组中的项,索引必须位于单独的方括号中, ([]
) 。
$a rank: 1
$a length: 3
$a[2] length: 348
Process $a[2][1]: AcroRd32
多维数组按 行主顺序存储。 以下示例演示如何创建真正的多维数组。
[string[,]]$rank2 = [string[,]]::New(3,2)
$rank2.rank
$rank2.Length
$rank2[0,0] = 'a'
$rank2[0,1] = 'b'
$rank2[1,0] = 'c'
$rank2[1,1] = 'd'
$rank2[2,0] = 'e'
$rank2[2,1] = 'f'
$rank2[1,1]
若要访问多维数组中的项,请使用逗号 (,
) 在一组括号 () []
中分隔索引。
多维数组上的某些操作(例如复制和串联)需要平展该数组。 平展将数组转换为无约束类型的一维数组。 生成的数组按行优先顺序显示所有元素。 请考虑以下示例:
$a = "red",$true
$b = (New-Object 'int[,]' 2,2)
$b[0,0] = 10
$b[0,1] = 20
$b[1,0] = 30
$b[1,1] = 40
$c = $a + $b
$a.GetType().Name
$b.GetType().Name
$c.GetType().Name
输出显示 , $c
是一个一维数组,其中包含从 $a
和 $b
按行主顺序排列的项。
Object[]
Int32[,]
Object[]
数组的方法
Clear
将所有元素值设置为数组的元素类型的 默认值 。 方法 Clear()
不会重置数组的大小。
在下面的示例 $a
中是 对象的数组。
$a = 1, 2, 3
$a.Clear()
$a | % { $null -eq $_ }
在此示例中, $intA
被显式类型化为包含整数。
[int[]] $intA = 1, 2, 3
$intA.Clear()
$intA
ForEach()
允许循环访问数组中的所有元素,并为数组的每个元素执行给定的操作。
方法 ForEach()
具有多个执行不同操作的重载。
ForEach(scriptblock expression)
ForEach(scriptblock expression, object[] arguments)
ForEach(type convertToType)
ForEach(string propertyName)
ForEach(string propertyName, object[] newValue)
ForEach(string methodName)
ForEach(string methodName, object[] arguments)
ForEach (scriptblock 表达式)
ForEach (scriptblock 表达式,object[] 参数)
此方法已添加到 PowerShell v4 中。
语法需要使用脚本块。 如果 scriptblock 是唯一参数,则括号是可选的。 此外,方法与左括号或大括号之间不得有空格。
以下示例演示如何使用 ForEach()
方法。 在这种情况下,目的是生成数组中元素的平方值。
$a = @(0 .. 3)
$a.ForEach({ $_ * $_})
就像 的 ForEach-Object
ArgumentList 参数一样, arguments
参数允许将参数数组传递到配置为接受参数的脚本块。
有关 ArgumentList 行为的详细信息,请参阅 about_Splatting。
ForEach (type convertToType)
方法 ForEach()
可用于将元素强制转换为其他类型;以下示例演示如何将字符串日期列表转换为 [DateTime]
类型。
("1/1/2017", "2/1/2017", "3/1/2017").ForEach([datetime])
Sunday, January 1, 2017 12:00:00 AM
Wednesday, February 1, 2017 12:00:00 AM
Wednesday, March 1, 2017 12:00:00 AM
ForEach (字符串属性名称)
ForEach (string propertyName, object[] newValue)
方法 ForEach()
还可用于检索或设置集合中每个项的属性值。
# Set all LastAccessTime properties of files to the current date.
(dir 'C:\Temp').ForEach('LastAccessTime', (Get-Date))
# View the newly set LastAccessTime of all items, and find Unique entries.
(dir 'C:\Temp').ForEach('LastAccessTime') | Get-Unique
Wednesday, June 20, 2018 9:21:57 AM
ForEach (string methodName)
ForEach (string methodName, object[] 参数)
LastForEach()
方法可用于对集合中的每个项执行方法。
("one", "two", "three").ForEach("ToUpper")
THREE
与 的 ForEach-Object
ArgumentList 参数一样,arguments
参数允许将值数组传递到配置为接受它们的脚本块。
从 Windows PowerShell 3.0 开始,还可以使用“标量对象和集合的方法”来检索集合中每个项的属性和执行方法。 可在此处about_Methods阅读有关此 内容的详细信息。
Where()
允许筛选或选择数组的元素。 该脚本的计算结果必须不同于:零 (0) 、空字符串或 $false
$null
要在 之后 Where()
显示的元素。 有关布尔计算的详细信息,请参阅 about_Booleans。
方法有一个定义 Where()
。
Where(scriptblock expression[, WhereOperatorSelectionMode mode
[, int numberToReturn]])
语法需要使用脚本块。 如果 scriptblock 是唯一参数,则括号是可选的。 此外,方法与左括号或大括号之间不得有空格。
Expression
是筛选所需的脚本块,mode
可选参数允许其他选择功能,可选numberToReturn
参数允许限制从筛选器返回的项数。
的值 mode
必须是 WhereOperatorSelectionMode 枚举值:
Default
0
() - 返回所有项目
First
1
() - 返回第一项
Last
2
() - 返回最后一项
SkipUntil
3
() - 跳过项,直到条件为 true,返回所有剩余项 (包括条件为 true 的第一项)
Until
4
() - 返回所有项,直到条件为 true
Split
5
() - 返回包含两个元素的数组
- 第一个元素包含匹配项
- 第二个元素包含其余项
以下示例演示如何从数组中选择所有奇数。
(0..9).Where{ $_ % 2 }
此示例演示如何选择不为空的字符串。
('hi', '', 'there').Where({$_.Length})
there
Default
模式 Default
使用 Expression
scriptblock 筛选项。
如果提供了 , numberToReturn
则指定要返回的最大项数。
# Get the zip files in the current users profile, sorted by LastAccessTime
$Zips = dir $env:userprofile -Recurse '*.zip' | Sort-Object LastAccessTime
# Get the least accessed file over 100MB
$Zips.Where({$_.Length -gt 100MB}, 'Default', 1)
Default
模式和First
模式都返回第一个 (numberToReturn
) 项,并且可以互换使用。
$h = (Get-Date).AddHours(-1)
$logs = dir 'C:\' -Recurse '*.log' | Sort-Object CreationTime
# Find the last 5 log files created in the past hour
$logs.Where({$_.CreationTime -gt $h}, 'Last', 5)
SkipUntil
该 SkipUntil
模式跳过集合中的所有对象,直到对象通过脚本块表达式筛选器。 然后,它返回 所有 剩余的收集项,而无需对其进行测试。 仅测试一个通过项。
这意味着返回的集合同时包含尚未测试的传递项和非传递项。
可以通过将值传递给 numberToReturn
参数来限制返回的项数。
$computers = "Server01", "Server02", "Server03", "localhost", "Server04"
# Find the first available online server.
$computers.Where({ Test-Connection $_ }, 'SkipUntil', 1)
localhost
Until
模式 Until
反转 SkipUntil
模式。 它返回集合 中的所有项, 直到项通过脚本块表达式。 一旦项 通过 scriptblock 表达式,该方法 Where()
将停止处理项。
这意味着从 方法接收第一组 非传递 项 Where()
。 一个项目通过后,其余项将不进行测试或返回。
可以通过将值传递给 numberToReturn
参数来限制返回的项数。
# Retrieve the first set of numbers less than or equal to 10.
(1..50).Where({$_ -gt 10}, 'Until')
# This would perform the same operation.
(1..50).Where({$_ -le 10})
和 SkipUntil
都在Until
不测试一批项的前提下运行。
Until
返回第一个 PASS之前的项。 SkipUntil
返回第一个传递之后的所有项,包括第一个传递项。
Split
该 Split
模式将集合项拆分或分组为两个单独的集合。 传递 scriptblock 表达式的和不传递脚本块表达式的。
如果指定了 ,则第一个 numberToReturn
集合包含 传递 的项,而不是超过指定的值。
其余对象(即使是 传递 表达式筛选器的对象)将在第二个集合中返回。
$running, $stopped = (Get-Service).Where({$_.Status -eq 'Running'}, 'Split')
$running
Status Name DisplayName
------ ---- -----------
Running Appinfo Application Information
Running AudioEndpointBu... Windows Audio Endpoint Builder
Running Audiosrv Windows Audio
$stopped
Status Name DisplayName
------ ---- -----------
Stopped AJRouter AllJoyn Router Service
Stopped ALG Application Layer Gateway Service
Stopped AppIDSvc Application Identity
ForEach()
和 Where()
方法是内部成员。 有关内部成员的详细信息,请参阅 about_Instrinsic_Members。
获取数组的成员
若要获取数组的属性和方法(如 Length 属性和 SetValue 方法),请使用 cmdlet 的 Get-Member
InputObject 参数。
通过管道将数组传递给 Get-Member
时,PowerShell 一次发送一个项,并 Get-Member
返回数组中每个项的类型, (忽略重复项) 。
使用 InputObject 参数时, Get-Member
返回数组的成员。
例如,以下命令获取数组变量的成员 $a
。
Get-Member -InputObject $a
还可以通过在传递给 Get-Member
cmdlet 的值之前键入逗号 (,
) 来获取数组的成员。 逗号使数组成为数组中的第二项。 PowerShell 一次传递一个数组,并 Get-Member
返回数组的成员。 就像接下来的两个示例一样。
,$a | Get-Member
,(1,2,3) | Get-Member
可以更改数组中的元素,将元素添加到数组,并将两个数组中的值合并到第三个数组中。
若要更改数组中特定元素的值,请指定要更改的元素的数组名称和索引,然后使用赋值运算符 (=
) 为元素指定新值。 例如,若要将数组中 $a
第二项的值 (索引位置 1) 更改为 10,请键入:
$a[1] = 10
还可以使用数组的 SetValue 方法更改值。 以下示例将数组 (索引位置 1) 的第二个 $a
值更改为 500:
$a.SetValue(500,1)
可以使用 +=
运算符将元素添加到数组。 以下示例演示如何向数组添加元素 $a
。
$a = @(0..4)
$a += 5
使用 +=
运算符时,PowerShell 实际上会创建一个具有原始数组值和附加值的新数组。 如果重复多次操作或数组大小太大,这可能会导致性能问题。
从数组中删除元素并不容易,但可以创建仅包含现有数组的选定元素的新数组。 例如,若要使用数组中的所有$a
元素(索引位置 2 处的值除外)创建$t
数组,请键入:
$t = $a[0,1 + 3..($a.length - 1)]
若要将两个数组合并为单个数组,请使用加号运算符 (+
) 。 以下示例创建两个数组,将它们组合在一起,然后显示生成的组合数组。
$x = 1,3
$y = 5,9
$z = $x + $y
因此, $z
数组包含 1、3、5 和 9。
若要删除数组,请将 值 $null
赋给数组。 以下命令删除 变量中的 $a
数组。
$a = $null
也可以使用 Remove-Item
cmdlet,但赋值 $null
速度更快,尤其是对于大型数组。
零或 1 的数组
从 Windows PowerShell 3.0 开始,零个或一个 对象的集合具有 Count 和 Length 属性。 此外,还可以索引到一个对象的数组中。 此功能可帮助你避免在需要集合的命令获得少于两个项时发生的脚本错误。
以下示例演示此功能。
$a = $null
$a.Count
$a.Length
$a = 4
$a.Count
$a.Length
$a[0]
$a[-1]
对 System 的索引支持。Tuple 对象
PowerShell 6.1 添加了对对象的索引访问 Tuple 的支持,类似于数组。 例如:
PS> $tuple = [Tuple]::Create(1, 'test')
PS> $tuple[0]
PS> $tuple[1]
PS> $tuple[0..1]
PS> $tuple[-1]
与数组和其他集合对象不同, Tuple 通过管道传递对象或由支持对象数组的参数传递对象时,对象被视为单个对象。
有关详细信息,请参阅 System.Tuple
为实现的 .NET 类型编制索引 IDictionary<TKey, TValue>
PowerShell 不会为实现泛型 IDictionary<TKey, TValue>
接口的类型调用类型的真实索引器。 相反,当给定密钥时,PowerShell 会使用 TryGetValue()
测试密钥是否存在,当密钥不存在时,它将返回 $null
。
相反,如果使用 调用类型的 true 索引器 Item(<key>)
,当键不存在时, 方法将引发异常。
以下示例演示了差异。
PS> [Collections.Generic.Dictionary[string, int]]::new()['nosuchkey']
# No output ($null)
PS> [Collections.Generic.Dictionary[string, int]]::new().Item('nosuchkey')
GetValueInvocationException: Exception getting "Item": "The given key 'nosuchkey'
was not present in the dictionary."
成员访问枚举
从 PowerShell 3.0 开始,使用成员访问运算符访问列表集合中不存在的成员时,PowerShell 会自动枚举集合中的项,并尝试访问每个项上的指定成员。 有关详细信息,请参阅 about_Member-Access_Enumeration。
以下示例创建两个新文件并将生成的 对象存储在数组变量 $files
中。 由于数组对象没有 LastWriteTime 成员,因此将针对数组中的每个项返回 WriteTime 的值Last。
$files = (New-Item -Type File -Force '/temp/t1.txt'),
(New-Item -Force -Type File '/temp/t2.txt')
$files.LastWriteTime
Friday, June 25, 2021 1:21:17 PM
Friday, June 25, 2021 1:21:17 PM
成员访问枚举使你能够从集合中的项 获取 值,但不能 设置 集合中项的值。 例如:
$files.LastWriteTime = (Get-Date).AddDays(-1)
InvalidOperation: The property 'LastWriteTime' cannot be found on this object.
Verify that the property exists and can be set.
若要设置值,必须使用 方法。
$files.set_LastWriteTime((Get-Date).AddDays(-1))
$files.LastWriteTime
Thursday, June 24, 2021 1:23:30 PM
Thursday, June 24, 2021 1:23:30 PM
方法是 set_LastWriteTime()
FileInfo 对象的隐藏成员。 以下示例演示如何查找具有 隐藏set
方法的成员。
$files | Get-Member | Where-Object Definition -like '*set;*'
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
由于方法针对集合中的每个项执行,因此在使用成员枚举调用方法时应小心。
about_For
about_ForEach
about_Hash_Tables
about_Member-Access_Enumeration
about_Operators
about_Assignment_Operators
about_While