about_Hash_Tables
簡短描述
描述如何在PowerShell中建立、使用和排序哈希表。
詳細描述
哈希表也稱為字典或關聯數位,是儲存一或多個索引鍵/值組的精簡數據結構。 例如,哈希表可能包含一系列IP位址和計算機名稱,其中IP位址是索引鍵,而計算機名稱是值,反之亦然。
在 PowerShell 中,每個哈希表都是 [System.Collections.Hashtable]
物件。 您可以在 PowerShell 中使用 物件的屬性和方法 Hashtable 。
從 PowerShell 3.0 開始,您可以使用 [ordered]
類型加速器在 PowerShell 中建立 [System.Collections.Specialized.OrderedDictionary]
物件。
已排序的字典與哈希表不同,因為索引鍵一律會以您列出它們的順序顯示。 哈希表中索引鍵的順序不具決定性。
哈希表中的索引鍵和值也是 .NET 物件。 它們通常是字串或整數,但是可以有任何物件類型。 您也可以建立巢狀哈希表,其中索引鍵的值是另一個哈希表。
哈希表經常使用,因為它們有效率地尋找和擷取數據。 您可以使用哈希表來儲存清單,並在PowerShell中建立匯出屬性。 而且,ConvertFrom-StringData
Cmdlet 會將結構化字串數據轉換成哈希表。
語法
哈希表的語法如下所示:
@{ <name> = <value>; [<name> = <value> ] ...}
已排序字典的語法如下所示:
[ordered]@{ <name> = <value>; [<name> = <value> ] ...}
類型 [ordered]
加速器是在PowerShell 3.0中引進的。
若要建立哈希表,請遵循下列指導方針:
- 使用 at 符號來開始哈希表 (
@
)。 - 以大括弧括住哈希表(
{}
)。 - 輸入哈希表內容的一或多個索引鍵/值組。
- 使用等號 (
=
) 將每個索引鍵與其值分開。 - 使用分號 (
;
) 或換行符隔索引鍵/值組。 - 包含空格的索引鍵必須以引號括住。 值必須是有效的 PowerShell 表達式。 字串必須以引號顯示,即使字串不包含空格也一樣。
- 若要管理哈希表,請將它儲存在變數中。
- 將已排序的哈希表指派給變數時,請將
[ordered]
類型放在@
符號之前。 如果您將它放在變數名稱之前,命令會失敗。
您可以使用使用哈希表的相同方式來使用已排序的字典。 任一類型都可以當做接受哈希表或字典 (iDictionary) 類型對象的參數值。
建立哈希表和已排序的字典
請考慮下列哈希表和已排序的字典範例:
$hash = @{
1 = 'one'
2 = 'two'
'three' = 3
}
$hash
Name Value
---- -----
three 3
2 two
1 one
如您所見,哈希表中的索引鍵/值組不會依定義的順序呈現。
建立已排序字典最簡單的方式是使用 [ordered]
屬性。 將屬性放在符號正前 @
。
$dictionary = [ordered]@{
1 = 'one'
2 = 'two'
'three' = 3
}
$dictionary
Name Value
---- -----
1 one
2 two
three 3
不同於哈希表,已排序的字典會維護索引鍵/值的順序。
轉換哈希表和已排序的字典
您無法使用 [ordered]
類型加速器來轉換或轉換哈希表。
如果您在變數名稱之前放置已排序的屬性,命令會失敗,並出現下列錯誤訊息。
[ordered]$orderedhash = @{}
ParserError:
Line |
1 | [ordered]$orderedhash = @{}
| ~~~~~~~~~~~~~~
| The ordered attribute can be specified only on a hash literal node.
若要更正表示式,請移動 [已排序] 屬性。
$orderedhash = [ordered]@{}
您可以將已排序的字典轉換成哈希表,但無法保證成員的順序。
[hashtable]$newhash = [ordered]@{
Number = 1
Shape = "Square"
Color = "Blue"
}
$newhash
Name Value
---- -----
Color Blue
Shape Square
Number 1
Hashtable 和字典屬性
哈希表和已排序的字典會共享數個屬性。
$hash
請考慮先前範例中定義的和 $dictionary
變數。
$hash | Get-Member -MemberType Properties, ParameterizedProperty
TypeName: System.Collections.Hashtable
Name MemberType Definition
---- ---------- ----------
Item ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
$dictionary | Get-Member -MemberType Properties, ParameterizedProperty
TypeName: System.Collections.Specialized.OrderedDictionary
Name MemberType Definition
---- ---------- ----------
Item ParameterizedProperty System.Object Item(int index) {get;set;},
System.Object Item(System.Object key) {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
最常使用的屬性是 Count、索引鍵、值和 Item。
Count 屬性,指出 物件中的索引鍵/值組數目。
Keys 屬性是哈希表或字典中索引鍵名稱的集合。
PS> $hash.Keys three 2 1 PS> $dictionary.Keys 1 2 three
Values 屬性是哈希表或字典中值的集合。
PS> $hash.Values 3 two one PS> $dictionary.Values one two 3
Item 屬性是參數化屬性,會傳回您指定的專案值。 哈希表會使用索引鍵做為參數化屬性的參數,而字典預設會使用索引。 此差異會影響您存取每個類型值的方式。
存取值
有兩種常見方式可以存取哈希表或字典中的值:成員表示法或陣列索引表示法。
成員表示法 - 您可以使用索引鍵名稱做為物件的成員屬性來存取值。 例如:
PS> $hash.1 one PS> $dictionary.2 two
陣列索引表示法 - 您可以使用索引表示 法來存取值。 PowerShell 會將該表示法轉換成物件的 Item 參數化屬性呼叫。
當您搭配哈希表使用索引表示法時,括弧內的值為索引鍵名稱。 如果索引鍵是字串值,請以引號括住索引鍵名稱。 例如:
PS> $hash['three'] 3 PS> $hash[2] two
在此範例中,索引鍵值
2
不是值集合中的索引。 這是索引鍵/值組中的索引鍵值。 您可以藉由將索引編製至值集合來證明這一點。PS> ([array]$hash.Values)[2] one
當您搭配字典使用索引表示法時,括弧內的值會根據其類型來解譯。 如果值是整數,則會將其視為值集合中的索引。 如果值不是整數,則會將其視為索引鍵名稱。 例如:
PS> $dictionary[1] two PS> ([array]$dictionary.Values)[1] two PS> $dictionary[[object]1] one PS> $dictionary['three'] 3
在此範例中,陣列值
[1]
是使用參數化屬性多載的值集合中的Item(int index)
索引。 陣列值[[object]1]
不是索引,而是使用 多載的Item(System.Object key)
索引鍵值。注意
當索引鍵值是整數時,這種行為可能會造成混淆。 可能的話,您應該避免在字典中使用整數索引鍵值。
處理屬性名稱衝突
如果索引鍵名稱與 keys
,而且您想要傳回 HashTable 索引鍵的集合,請使用下列語法:
$hashtable.psbase.Keys
此需求適用於實作 介面的其他類型 System.Collections.IDictionary ,例如 OrderedDictionary。
逐一查看索引鍵和值
您可以迭代哈希表中的鍵,以不同方式處理值。 本節中的每個範例都有相同的輸出。 他們會逐一查看 $hash
這裡定義的變數:
$hash = [ordered]@{Number = 1; Shape = "Square"; Color = "Blue"}
注意
在這些範例中, $hash
會定義為已排序的字典,以確保輸出一律以相同順序。 這些範例適用於標準哈希表,但無法預測輸出的順序。
每個範例都會傳回每個索引鍵及其值的訊息:
The value of 'Number' is: 1
The value of 'Shape' is: Square
The value of 'Color' is: Blue
此範例會使用 區塊逐一 foreach
查看金鑰。
foreach ($Key in $hash.Keys) {
"The value of '$Key' is: $($hash[$Key])"
}
此範例會使用 ForEach-Object
來逐一查看索引鍵。
$hash.Keys | ForEach-Object {
"The value of '$_' is: $($hash[$_])"
}
這個範例會 GetEnumerator()
使用 方法,透過管線將每個機碼/值組傳送至 ForEach-Object
。
$hash.GetEnumerator() | ForEach-Object {
"The value of '$($_.Key)' is: $($_.Value)"
}
此範例會使用 GetEnumerator()
和 ForEach()
方法來逐一查看每個機碼/值組。
$hash.GetEnumerator().ForEach({"The value of '$($_.Key)' is: $($_.Value)"})
新增和移除索引鍵和值
一般而言,當您建立哈希表時,您會在定義中包含索引鍵/值組。 不過,您可以隨時從哈希表中新增和移除鍵值對。 下列範例會建立空的哈希表。
$hash = @{}
您可以使用陣列表示法來新增索引鍵/值組。 例如,下列範例會將索引鍵 Time
和值 Now
新增至哈希表。
$hash["Time"] = "Now"
您也可以使用 System.Collections.Hashtable 物件的 Add()
方法,將索引鍵和值新增至哈希表。 方法 Add()
具有下列語法:
Add(Key, Value)
例如,若要將 Time
索引鍵,並且值為 Now
,新增至哈希表,請使用下列語句格式。
$hash.Add("Time", "Now")
此外,您可以使用加法運算符 (+
) 將哈希表新增至現有的哈希表,將索引鍵和值新增至哈希表。 例如,下列語句會將索引鍵 Time
及值 Now
新增至 $hash
變數中的哈希表。
$hash = $hash + @{Time="Now"}
您也可以新增儲存在變數中的值。
$t = "Today"
$now = (Get-Date)
$hash.Add($t, $now)
您無法使用減法運算符從哈希表移除索引鍵/值組,但您可以使用哈希表物件的 Remove()
方法。 方法 Remove
具有下列語法:
$object.Remove(<key>)
下列範例會 Time
從 $hash
中移除機碼/值組。
$hash.Remove("Time")
HashTable 中的物件類型
哈希表中的索引鍵和值可以具有任何 .NET 物件類型,而單一哈希表可以具有多個類型的索引鍵和值。
下列語句會建立進程名稱字串和進程物件值的哈希表,並將它儲存在 $p
變數中。
$p = @{
"PowerShell" = (Get-Process PowerShell)
"Notepad" = (Get-Process notepad)
}
您可以在 $p
中顯示哈希表,並使用索引鍵名稱屬性來顯示值。
PS> $p
Name Value
---- -----
PowerShell System.Diagnostics.Process (PowerShell)
Notepad System.Diagnostics.Process (notepad)
PS> $p.PowerShell
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
441 24 54196 54012 571 5.10 1788 PowerShell
PS> $p.Keys | ForEach-Object {$p.$_.Handles}
441
251
哈希表中的索引鍵可以是任何 .NET 類型。 下列語句會將索引鍵/值組新增至 $p
變數中的哈希表。 索引鍵是 代表 WinRM 服務的 Service 物件,而值是服務的目前狀態。
$p = $p + @{
(Get-Service WinRM) = ((Get-Service WinRM).Status)
}
您可以使用哈希表中其他配對所使用的相同方法來顯示和存取新的索引鍵/值組。
PS> $p
Name Value
---- -----
PowerShell System.Diagnostics.Process (PowerShell)
Notepad System.Diagnostics.Process (notepad)
System.ServiceProcess.Servi... Running
PS> $p.Keys
PowerShell
Notepad
Status Name DisplayName
------ ---- -----------
Running winrm Windows Remote Management (WS-Manag...
PS> $p.Keys | ForEach-Object {$_.Name}
WinRM
哈希表中的鍵和值也可以是 Hashtable 物件。 下列語句會將索引鍵/值組新增至 $p
變數中的哈希表,其中索引鍵為字串 Hash2,而值是具有三個索引鍵/值組的哈希表。
$p = $p + @{
"Hash2"= @{a=1; b=2; c=3}
}
您可以使用相同的方法來顯示和存取新值。
PS> $p
Name Value
---- -----
PowerShell System.Diagnostics.Process (pwsh)
Hash2 {[a, 1], [b, 2], [c, 3]}
Notepad System.Diagnostics.Process (Notepad)
WinRM Running
PS> $p.Hash2
Name Value
---- -----
a 1
b 2
c 3
PS> $p.Hash2.b
2
排序索引鍵和值
哈希表中的項目本質上是未排序的。 每次顯示索引鍵/值組時,可能會以不同的順序顯示。
雖然您無法排序哈希表,但您可以使用哈希表的 GetEnumerator()
方法來列舉索引鍵和值,然後使用 Sort-Object
Cmdlet 來排序要顯示的列舉值。
例如,下列命令會列舉變數中哈希表中 $p
的索引鍵和值,然後依字母順序排序索引鍵。
PS> $p.GetEnumerator() | Sort-Object -Property key
Name Value
---- -----
Hash2 {[a, 1], [b, 2], [c, 3]}
Notepad System.Diagnostics.Process (Notepad)
PowerShell System.Diagnostics.Process (pwsh)
WinRM Running
下列命令使用相同的程式,以遞減順序排序哈希值。
PS> $p.GetEnumerator() | Sort-Object -Property Value -Descending
Name Value
---- -----
PowerShell System.Diagnostics.Process (pwsh)
Notepad System.Diagnostics.Process (Notepad)
Hash2 {[a, 1], [b, 2], [c, 3]}
WinRM Running
從哈希表建立物件
從 PowerShell 3.0 開始,您可以從屬性和屬性值的哈希表建立物件。
語法如下所示:
[<class-name>]@{
<property-name>=<property-value>
<property-name>=<property-value>
}
這個方法只適用於具有沒有參數之建構函式的類別。 物件屬性必須是公用和可設定的。
如需詳細資訊,請參閱 about_Object_Creation。
ConvertFrom-StringData
ConvertFrom-StringData
Cmdlet 會將字串或 here-string 的鍵值對轉換成哈希表。 您可以在腳本的 [數據] 區段中安全地使用 ConvertFrom-StringData
Cmdlet,而且可以搭配 Import-LocalizedData
Cmdlet 在目前使用者的使用者介面 (UI) 文化特性中顯示使用者訊息。
當哈希表中的值包含引號時,這裡字串特別有用。 如需 here-strings 的詳細資訊,請參閱 about_Quoting_Rules。
下列範例示範如何在上一個範例中建立使用者訊息的 here-string,以及如何使用 ConvertFrom-StringData
將它們從字串轉換成哈希表。
下列命令會建立機碼/值組的 here-string,然後將它儲存在 變數中 $string
。
$string = @"
Msg1 = Type "Windows".
Msg2 = She said, "Hello, World."
Msg3 = Enter an alias (or "nickname").
"@
此命令會使用 ConvertFrom-StringData
Cmdlet,將 here-string 轉換成哈希表。
ConvertFrom-StringData $string
Name Value
---- -----
Msg3 Enter an alias (or "nickname").
Msg2 She said, "Hello, World."
Msg1 Type "Windows".
如需 here-strings 的詳細資訊,請參閱 about_Quoting_Rules。