# 您想知道有關雜湊表的一切

## 什麼是陣列？

``````\$array = @(1,2,3,5,7,11)
``````

``````foreach(\$item in \$array)
{
Write-Output \$item
}

Write-Output \$array[3]
``````

``````\$array[2] = 13
``````

## 什麼是雜湊表？

``````\$ageList = @{}
``````

``````\$key = 'Kevin'
\$value = 36

``````

## 使用大括號進行存取

``````\$ageList['Kevin']
\$ageList['Alex']
``````

``````\$ageList = @{}

\$key = 'Kevin'
\$value = 36
\$ageList[\$key] = \$value

\$ageList['Alex'] = 9
``````

### 使用一些值建立雜湊表

``````\$ageList = @{
Kevin = 36
Alex  = 9
}
``````

### 做為查閱資料表

``````\$environments = @{
Prod = 'SrvProd05'
QA   = 'SrvQA02'
Dev  = 'SrvDev12'
}

\$server = \$environments[\$env]
``````

#### 多重選擇

``````\$environments[@('QA','DEV')]
\$environments[('QA','DEV')]
\$environments['QA','DEV']
``````

## 逐一查看雜湊表

``````PS> \$ageList | Measure-Object
count : 1
``````

``````PS> \$ageList.count
2
``````

``````PS> \$ageList.values | Measure-Object -Average
Count   : 2
Average : 22.5
``````

``````PS> \$ageList.keys | ForEach-Object{
\$message = '{0} is {1} years old!' -f \$_, \$ageList[\$_]
Write-Output \$message
}
Kevin is 36 years old
Alex is 9 years old
``````

``````foreach(\$key in \$ageList.keys)
{
\$message = '{0} is {1} years old' -f \$key, \$ageList[\$key]
Write-Output \$message
}
``````

### GetEnumerator()

``````\$ageList.GetEnumerator() | ForEach-Object{
\$message = '{0} is {1} years old!' -f \$_.key, \$_.value
Write-Output \$message
}
``````

``````\$environments = @{
Prod = 'SrvProd05'
QA   = 'SrvQA02'
Dev  = 'SrvDev12'
}
``````

``````\$environments.Keys | ForEach-Object {
\$environments[\$_] = 'SrvDev03'
}

An error occurred while enumerating through a collection: Collection was modified; enumeration operation may not execute.
+ CategoryInfo          : InvalidOperation: tableEnumerator:HashtableEnumerator) [], RuntimeException
``````

``````foreach(\$key in \$environments.keys) {
\$environments[\$key] = 'SrvDev03'
}

Collection was modified; enumeration operation may not execute.
+ CategoryInfo          : OperationStopped: (:) [], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException
``````

``````\$environments.Keys.Clone() | ForEach-Object {
\$environments[\$_] = 'SrvDev03'
}
``````

## 雜湊表即屬性集合

### 屬性型存取

``````\$ageList = @{}
\$ageList.Kevin = 35
\$ageList.Alex = 9
``````

``````\$person = @{
name = 'Kevin'
age  = 36
}
``````

``````\$person.city = 'Austin'
\$person.state = 'TX'
``````

### 檢查索引鍵和值

``````if( \$person.age ){...}
``````

``````if( \$person.age -ne \$null ){...}
``````

``````if( \$person.ContainsKey('age') ){...}
``````

### 移除和清除索引鍵

``````\$person.remove('age')
``````

``````\$person = @{}
``````

``````\$person.clear()
``````

## 所有有趣的事物

### 排序的雜湊表

``````\$person = [ordered]@{
name = 'Kevin'
age  = 36
}
``````

### 內嵌雜湊表

``````\$person = @{ name = 'kevin'; age = 36; }
``````

### 一般管道命令中的自訂運算式

``````\$property = @{
name = 'totalSpaceGB'
expression = { (\$_.used + \$_.free) / 1GB }
}
``````

`name` 就是讓 Cmdlet 標示該資料行。 `expression` 是執行的指令碼區塊，其中 `\$_` 是管道上物件的值。 以下是該指令碼的運作方式：

``````\$drives = Get-PSDrive | Where Used
\$drives | Select-Object -Property name, \$property

Name     totalSpaceGB
----     ------------
C    238.472652435303
``````

``````\$drives | Select-Object -property name, @{n='totalSpaceGB';e={(\$_.used + \$_.free) / 1GB}}
``````

### 自訂排序運算式

``````Get-ADUser | Sort-Object -Parameter @{ e={ Get-TotalSales \$_.Name } }
``````

#### 排序雜湊表清單

``````\$data = @(
@{name='a'}
@{name='c'}
@{name='e'}
@{name='f'}
@{name='d'}
@{name='b'}
)

\$data | Sort-Object -Property @{e={\$_.name}}
``````

## 在 Cmdlet 展開雜湊表

``````Add-DhcpServerv4Scope -Name 'TestNetwork' -StartRange'10.0.0.2' -EndRange '10.0.0.254' -SubnetMask '255.255.255.0' -Description 'Network for testlab A' -LeaseDuration (New-TimeSpan -Days 8) -Type "Both"
``````

``````\$DHCPScope = @{
Name        = 'TestNetwork'
StartRange  = '10.0.0.2'
EndRange    = '10.0.0.254'
Description = 'Network for testlab A'
LeaseDuration = (New-TimeSpan -Days 8)
Type = "Both"
}
``````

### 針對選擇性參數進行展開

``````\$CIMParams = @{
ClassName = 'Win32_Bios'
ComputerName = \$ComputerName
}

if(\$Credential)
{
\$CIMParams.Credential = \$Credential
}

Get-CIMInstance @CIMParams
``````

### 多個展開

``````\$Common = @{
LeaseDuration = (New-TimeSpan -Days 8)
Type = "Both"
}

\$DHCPScope = @{
Name        = 'TestNetwork'
StartRange  = '10.0.0.2'
EndRange    = '10.0.0.254'
Description = 'Network for testlab A'
}

``````

### 針對全新程式碼進行展開

``````\$log = @{Path = '.\logfile.log'}
``````

### 展開可執行檔

``````\$robo = @{R=1;W=1;MT=8}
robocopy source destination @robo
``````

## 新增雜湊表

``````\$person += @{Zip = '78701'}
``````

## 巢狀雜湊表

``````\$person = @{
name = 'Kevin'
age  = 36
}
\$person.location = @{}
\$person.location.city = 'Austin'
\$person.location.state = 'TX'
``````

``````\$person = @{
name = 'Kevin'
age  = 36
location = @{
city  = 'Austin'
state = 'TX'
}
}
``````

``````\$person.location.city
Austin
``````

``````\$people = @{
Kevin = @{
age  = 36
city = 'Austin'
}
Alex = @{
age  = 9
city = 'Austin'
}
}
``````

``````PS> \$people.kevin.age
36
PS> \$people.kevin['city']
Austin
PS> \$people['Alex'].age
9
PS> \$people['Alex']['City']
Austin
``````

``````foreach(\$name in \$people.keys)
{
\$person = \$people[\$name]
'{0}, age {1}, is in {2}' -f \$name, \$person.age, \$person.city
}
``````

### 查看巢狀雜湊表

``````PS> \$people
Name                           Value
----                           -----
Kevin                          {age, city}
Alex                           {age, city}
``````

``````PS> \$people | ConvertTo-Json
{
"Kevin":  {
"age":  36,
"city":  "Austin"
},
"Alex":  {
"age":  9,
"city":  "Austin"
}
}
``````

## 建立物件

``````\$person = [pscustomobject]@{
name = 'Kevin'
age  = 36
}

\$person

name  age
----  ---
Kevin  36
``````

``````\$person = @{
name = 'Kevin'
age  = 36
}

[pscustomobject]\$person

name  age
----  ---
Kevin  36
``````

## 讀取和寫入雜湊表至檔案

### 儲存至 CSV

``````\$person | ForEach-Object{ [pscustomobject]\$_ } | Export-CSV -Path \$path
``````

### 將巢狀雜湊表儲存至檔案

``````\$people | ConvertTo-JSON | Set-Content -Path \$path
\$people = Get-Content -Path \$path -Raw | ConvertFrom-JSON
``````

``````@{ a = @{ b = @{ c = @{ d = "e" }}}} | ConvertTo-Json

{
"a": {
"b": {
"c": "System.Collections.Hashtable"
}
}
}
``````

``````@{ a = @{ b = @{ c = @{ d = "e" }}}} | ConvertTo-Json -Depth 3

{
"a": {
"b": {
"c": {
"d": "e"
}
}
}
}
``````

### 將 JSON 轉換成雜湊表

``````[Reflection.Assembly]::LoadWithPartialName("System.Web.Script.Serialization")
\$JSSerializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new()
\$JSSerializer.Deserialize(\$json,'Hashtable')
``````

``````'{ "a": "b" }' | ConvertFrom-Json -AsHashtable

Name      Value
----      -----
a         b
``````

PowerShell 6.2 已將 Depth 參數新增至 `ConvertFrom-Json`。 預設 Depth 為1024。

### 直接從檔案讀取

``````\$content = Get-Content -Path \$Path -Raw -ErrorAction Stop
\$scriptBlock = [scriptblock]::Create( \$content )
\$scriptBlock.CheckRestrictedLanguage( \$allowedCommands, \$allowedVariables, \$true )
\$hashtable = ( & \$scriptBlock )
``````

## 索引鍵可以是任何物件

``````\$person = @{
'full name' = 'Kevin Marquette'
'#' = 3978
}
\$person['full name']
``````

``````\$person.'full name'

\$key = 'full name'
\$person.\$key
``````

``````\$ht = @{ @(1,2,3) = "a" }
\$ht

Name                           Value
----                           -----
{1, 2, 3}                      a
``````

``````\$key = \$ht.keys[0]
\$ht.\$(\$key)
a
\$ht[\$key]
a
``````

## 用於自動變數

### \$PSBoundParameters

\$PSBoundParameters 是只存在於函式內容內的自動變數。 其包含呼叫函數時搭配的所有參數。 這不是真正的雜湊表，但是足以讓您將其等同視之。

### \$PSDefaultParameterValues

``````\$PSDefaultParameterValues["Out-File:Encoding"] = "UTF8"
``````

``````\$PSDefaultParameterValues[ "Connect-VIServer:Server" ] = 'VCENTER01.contoso.local'
``````

``````\$PSDefaultParameterValues[ "Get-*:Verbose" ] = \$true
\$PSDefaultParameterValues[ "*:Credential" ] = Get-Credential
``````

## Regex \$Matches

``````\$message = 'My SSN is 123-45-6789.'

\$message -match 'My SSN is (.+)\.'
\$Matches[0]
\$Matches[1]
``````

### 具名比對

``````\$message = 'My Name is Kevin and my SSN is 123-45-6789.'

if(\$message -match 'My Name is (?<Name>.+) and my SSN is (?<SSN>.+)\.')
{
\$Matches.Name
\$Matches.SSN
}
``````

## Group-Object -AsHashtable

``````Import-CSV \$Path | Group-Object -AsHashtable -Property email
``````

## 複製雜湊表

### 指派參考型別

``````PS> \$orig = @{name='orig'}
PS> \$copy = \$orig
PS> \$copy.name = 'copy'
PS> 'Copy: [{0}]' -f \$copy.name
PS> 'Orig: [{0}]' -f \$orig.name

Copy: [copy]
Orig: [copy]
``````

### 淺層複製，單層

``````PS> \$orig = @{name='orig'}
PS> \$copy = \$orig.Clone()
PS> \$copy.name = 'copy'
PS> 'Copy: [{0}]' -f \$copy.name
PS> 'Orig: [{0}]' -f \$orig.name

Copy: [copy]
Orig: [orig]
``````

### 淺層複製，巢狀

``````PS> \$orig = @{
person=@{
name='orig'
}
}
PS> \$copy = \$orig.Clone()
PS> \$copy.person.name = 'copy'
PS> 'Copy: [{0}]' -f \$copy.person.name
PS> 'Orig: [{0}]' -f \$orig.person.name

Copy: [copy]
Orig: [copy]
``````

### 深層複製

``````function Get-DeepClone
{
[CmdletBinding()]
param(
\$InputObject
)
process
{
if(\$InputObject -is [hashtable]) {
\$clone = @{}
foreach(\$key in \$InputObject.keys)
{
\$clone[\$key] = Get-DeepClone \$InputObject[\$key]
}
return \$clone
} else {
return \$InputObject
}
}
}
``````

``````function Get-DeepClone
{
param(
\$InputObject
)
\$TempCliXmlString = [System.Management.Automation.PSSerializer]::Serialize(\$obj, [int32]::MaxValue)
return [System.Management.Automation.PSSerializer]::Deserialize(\$TempCliXmlString)
}
``````