Powershell:關於hashtable你想知道的一切


譯者語:本篇為一篇譯文,詳細介紹了在powershell中如何使用hashtable這種數據類型.本文為本人2018年最后一篇博文(哈哈,一年內寫沒寫幾篇),也是本人的第一次譯文,有不足之處還請指教.祝大家元旦快樂!

我在工作中經常用到它,現在想停下來討論一下它(hashtable).昨天夜里小組會議后我教了一些同事如何使用hashtable,我很快意識到初識hashtable時我也曾經有與他們相同的困惑.Hashtable在powershell里着實非常重要因此我們需要對它有充會的理解.

hashtable是元素的集合

首先,我想讓你們把hastable看作傳統意義上定義的集合.這將會使你對后面它在高級應用中是如何工作的有一些基本的了解.通常很多困惑都源自於對此沒有認知.

什么是數組

在討論什么是hashtable之前,我想要先提一下數組.就本討論而言,數組是一系列元素或者對象的集合(或列表)

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

一旦數組中有了對象,你就可以使用foreach來迭代它們或者索引來訪問某元素

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

Write-Output $array[3]

同樣,你可以使用索引來更新值

$array[2] = 13

這里我僅僅介紹了數組的一些皮毛,但是把我們下面將要討論的hashtable引到了正確的話題上.

什么是hashtable

我們首先從一般的,被許多編程語言都采用的技術性描述開始,然后再轉到powershell里對它的定義

hashtable是一個類似於數組的數據結構,除了你使用鍵來存儲一個值(或者對象),它是一個基本的鍵/值對存儲.首先,我們來創建一個空的hashtable

$ageList = @{}

注意這里用的是花括號,而上面定義數組用的是小括號.
然后我們使得鍵來添加一些值:

$key = 'Kevin'
$value = 36
$ageList.add( $key, $value )

$ageList.add( 'Alex', 9 )

以上人名是鍵,而值是我們想存儲的東西.

使用中括號訪問元素

一旦你把值添加到hashtable,你可以使用添加時使用的鍵把值取出來(不像上面數組使得的是數字索引)

$ageList['Kevin']
$ageList['Alex']

當我想要獲取Kevin的年齡時,我使用他的名字來獲取,我們也可以使用這種方法來添加或者更新hashtable里的值.這和上面使用add方法效果是一樣的

$ageList = @{}

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

$ageList['Alex'] = 9

還有一種另外的語法來添加元素,我們后面會講到,如果你是從其它語言轉到powershell你會看到以上使用和你在其它語言的使用方法類似.

創建包含值的hashtable

截至目前我們創建的hashtable初始狀態是一個空集合,我們在創建hashtable時也可以預先添加一些鍵值:

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

作為一個查找表(原文為lookup table)

下面是一個例子:

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

$server = $environments[$env]

在這個例子中,你可以指定一個環境變量的值,然后就可以獲取到正確的服務器(示例中的hashtable值是服務器名),當然你也可以使用switch($env){...}這種方法,不過hashtable一種很好的替換

譯者注,這個示例僅僅是偽代碼,並不能運行通過,作者實際想要表述的是你可以把服務器的鍵存到環境變量量,然后就可以通過鍵索引取出來.比如說你定義了一個名為ServerEnv的環境變量,並賦值為Prod,則可以通過
$server = $environments[$env:ServerEnv]來獲取到hashtable對應的服務器名

獲取多項

一般情況下,你認為hashtable是一個鍵值對集合,你提供一個鍵,獲取一個值,實際上powershell允許提供一系列的鍵來獲取多個值.

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

在這個例子中我們使用上上面的查找表並且提供了三種不同風格的數組來獲取匹配的項.這是powershell隱藏的未被多數人發掘的寶貝.

譯者注,以上三種確為powerhsell數組的三種定義方式,是等價的,一般情況下數組定義使用@()這種形式,對於泛型數組類型或者幾個離散元素通常使用第三種形式,例如$num=1..5或者$num=1,2,3,5,5,效果是一樣的

遍歷hashtable

由於hashtable是一系列的鍵值對,因此你不能像遍歷數組或者普通列表一樣來遍歷它.
首先需要注意的是如果你使用管道來操作hashtable,則hashtable被視為一個整體對象

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

即便它的count屬性告訴了你它其實包含了多少個元素

PS:\> $ageList.count
2

譯者注 以上就是說hashtable被視為一個整體對象,因此你使用Measure-Object來獲取它的元素個數的時候,你將得不到正確結果.很多初識powershell的童鞋不知道如何獲取集合元素的個數,其實一般是通過在管道下一級使用 Measure-Object來實現的
measure-object 展示信息中count屬性即為集合元素的個數.如果你想要通過程序化的方式來拿到這個count屬性也很簡單,就是把以上操再加一級Select Count管道
measuremeasure-object命令的另名.命令的別名和命令本身是等效的.

如果你需要的僅僅是值,則可以通過.values屬性來獲取值,這個問題就解決了.(實際上values獲取的是一個數組,數組使用measure-object是可以正確獲取到元素個數的)

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

譯者注 Meausre-object是獲取元素個數信息的好幫手,如果沒有任何參數只有count屬性,這里指定的Average,實際上還可以指定Max,Min,Sum等參數來獲取集合元素的統計信息

通常情況下遍歷hashtable的鍵集合,然后通過鍵來獲取值是很有用的.

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(){...}循環,效果是一樣的

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

譯者注 由於這是一篇全面講解hashtable的文章,因此很多地方超出了基本范圍,很多沒有powershell基礎的童鞋可能看一些語法感覺很費勁,上面ForEach-Object管理可能看起來不如下面foreach循環更為直觀,更符合編程語言語法

我們遍歷hashtable里的每一個key,然后使用key來索引元素的值,這是我們遍歷hashtable的慣用方法.

使用GetEnumerator()方法

我們也可以使用GetEnumerator()來遍歷hashtable

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

迭代器迭代出一個個的鍵值對,它是專為這種場景使用設計的.謝謝Mark Kraus提醒我這種方法

譯者注: 使用迭代器可能在一些語言中很常用,但是在powershell里並不是很常用,一般使用foreach循環就好了

遍歷異常

一個非常重要的細節是在遍歷hashtable的時候,你不能修改它.我們仍然使用上面的$environments來舉例

$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
+ FullyQualifiedErrorId : BadEnumeration

以下看起來沒問題,實際上同樣運行時會出錯

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

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

這里有個小伎倆我們在遍歷前先把keys復制一份

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

hashtable作為屬性集合

截至目前我們往hashtable里添加的都是同一種類型元素.在powershell里hashtable一個常用的用法主是用它來存儲一系列的屬性集合,把屬性名作為鍵,把屬性值作為值.

基於屬性的訪問

基於屬性的訪問改變了hashtable的動態屬性和使用poweshell的使用方式.下面示例使用上面的例子使用鍵來作為屬性

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

和前面的示例一樣,如果key不在集合里則會被添加進去.

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

我們也可以使用下面方法來訪問$person的屬性

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

突然之間hashtable看起來像個對象,實際上它仍然是一個集合,對以上所有示例仍然是有效的.我們僅僅是從不同的視角來看待.

檢測鍵和值

通常情況下,你可能使用如下方法來檢測值

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

它非常簡單但是卻是產生很多bug的源頭因為以上忽略了一個重要的邏輯.我們使用它來檢測一個key是否存在,但是如果正好值是$false或者0,以上檢測將返回意外地返回false

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

以上解決了前面的問題但是仍然解決不了值正好是$null的情況.大多數情況下你不需要區分這些這么嚴格但是確立有方法解決這一問題:

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

hashtable里還有一個ContainsValue在你不知道key的時候判斷一個value是否存在,而不用遍歷整個集合.

刪除和清空鍵

你可以使用Remove方法來刪除一個鍵

$person.remove('age')

把鍵的值設置為$null僅僅留下一個空key(值為$null,並不能把鍵刪除掉)

一個常用的把集合清空的方法是把它的值設置為一個空集合

$person = @{}

也可以使用clear()方法

$person.clear()

在這些示例中,使用方法使得代碼整潔,不言自明.

關於有序hashtable

默認情況下,hashtable是無序的.在傳統的上下文中,你使用鍵來獲取值順序往往無關緊要.但是你使用它來存儲屬性的時候,你可能希望屬性存儲的順序和你定義它們時候的順序是一致的.幸好,可以使用ordered關鍵字來定義.

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

這時候你再遍歷它,它將保持順序

行內hashtable

你可以把hashtable定義在一行,不同的鍵值之間用分號;隔開

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

如果你是在管道中創建hashtable這將非常有用

在常見的管道命令里使用自定義表達式

有少數命令支持使用hashtable來創建自定義或者計算屬性,最為常見的是Select-ObjectFormat-Table,hashtable有一種特殊的形式展開形式如下:

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

名字是命令用來標識列的,expression 是一個代碼塊可以被執行,$_是從管道傳過來的值,以下腳本使用了上面定義:

PS:\> $drives = Get-PSDrive | Where Used 
PS:\> $drives | Select-Object -Properties name, $property

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

我把它放在了一個變量量,實際上可以使用內聯的方式定義,你也可以使用n作為name的縮寫,使用'e'作為expression的縮寫

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

自定義排序表達式

如果集合中有你想要按照它來排序的字段,排序是非常容易的,你可以把數據添加到對象里或者使用Sort-Object來創建一個自定義排序表達式

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

在這個示例中,我取出了用戶集合並使用自定義命令獲取額外信息用來排序.

排序hashtable列表

如果你有一個hashtable的列表(list)想來排序,你會發現Sort-Object 並不會把鍵作為屬性.我們可以使用自定義排序表達式來解決這個問題

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

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

在命令中把hashtable打散

這是我最為喜歡的一個功能,早些時候很多人並不知道.除了把所有的屬性都在一行內提供,你可以首先把它們打包成一個hashtable.然后你可以通過特殊方式把hashtable傳入函數作為參數.以下是使用普通方法來創建DHCP

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"

在不使用打散方法前,所有的參數都在一行甚至會超出屏幕視覺范圍或者折行,下面我們比較一下使用hashtable打散的方法傳入參數

$DHCPScope = @{
    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"
}
Add-DhcpServerv4Scope @DHCPScope

使用@符而不是$來調用hashtable的打散功能.

我們停下來欣賞這下這段代碼可讀性是多么的高!同樣的命令,同樣的值.下面的代碼比上面可讀性和可維護性都提高很多.

當命令參數變得很長的 時候,我就地考慮使用hashtable打散.

參數打散在可選參數中使用

在日常工作中,一個最為常見的情況是用打散來處理可選參數,比如說我有一個封閉好的名字叫作Get-CIMInstance的方法,方法調用時有一個可選參數叫作$Credential

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

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

Get-CIMInstance @CIMParams

從最基本的參數開始,然后我添加了$Credential參數如果它存在的話,因為這里使用了參數打散,在代碼里僅需要調用Get-CIMInstance一次,這種模式非常簡潔並且可以很容易地處理很多常見的可選參數

多項打散

你可以把多個hashtable打散到一個cmdlet命令里,我們來看下其初的一個示例

$Common = @{        
    SubnetMask  = '255.255.255.0'
    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'        
}

Add-DhcpServerv4Scope @DHCPScope @Common

如果有一些共同的參數需要傳入到許多不同的命令,我經常使用這種方法

為了代碼的整潔使用打散

如果為了代碼整潔,即便只打散一個參數也是不為過的

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

Add-Content "logging this command" @log

hashtable相加

hashtable支持額外的操作簽把兩個hashtable相加

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

嵌套hashtable

我們可以把hashtable作為另一個hashtable的值

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

這個hashtable初始包含兩個鍵,然后添加了一個鍵為location值為一個空hatable的條目.我們也可以以內聯的方式聲明:

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

這和上面創建的hashtable是等效的,我們也可以使用同樣的方法來訪問它的屬性:

PS:> $person.location.city
Austin

有許多方法可以獲取到對象的結構,下面是另一種視角來看待這個問題:

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

這里混合使用了hashtable是對象集合和屬性集合的概念.不管你使用什么方法,獲取嵌套對象仍然是很簡單的.

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
}

hashtable可以嵌套帶來了更多編程靈活性選擇

查看嵌套hashtable

當你開始使用hashtable的時候,你需要一個簡單的方式從控制台查看它們.如果我們在控制台查看上面的hashtable,它像下面一樣層次非常深:

ps:\> $people
Name                           Value
----                           -----
Kevin                          {age, city}
Alex                           {age, city}

這里可以使用ConvertTo-JSON因為它非常簡潔並且我經常使用它來做其它事情

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

即便你不知道json,你仍然可以看明白它.powershell有一個Format-Custom命令來查看結構化的數據但是我仍然更傾向使用json查看

創建對象

有些時候你需要創建一個對象來完成僅僅使用hashtable來保存一些屬性無法完成的工作.最為常見的是你想把鍵作為列名.使用pscustomobject可以使這項工作變得非常簡單

$person = [pscustomobject]@{
    name = 'Kevin'
    age  = 36
year=2014
}

 PS:\> $person
   
name  age
----  ---
Kevin  36

譯者注,很多童鞋如果僅僅是看文章而沒動手的話可能一下子看不明白加了pscustomobject之后和之前有什么區別,其它自動動手看一下主知道.hashtable展示的是鍵作為一列,值作為一列.一共兩列,而對象有多少個屬性就會有多少列.

即便在初始的時候你沒有創建pscustomobject,你仍然可以在需要使用的時候轉換成它

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

 PS:\> [pscustomobject]$person
   
name  age
----  ---
Kevin  36

保存為csv

嘗試着把上面提到的hashtable轉為csv是一件非常掙扎的事.把hashtable轉為pscustomobject可以正確地保存csv.如果你在創建的時候就使用了pscustomobject則可以保存創建的順序.但是你也可以使用內聯的方式轉化為pscustomobject

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

把嵌套對象保存到文件

如果我想要把嵌套hashtable保存到文件並且可以還原回來,我會使用json命令來做

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

這里有兩個重要的點.首先寫入文件時json文件是多行的,因此我需要使用Raw選項把它讀到到單行.第二點是導入的對象不再是一個hashtable,而是一個pscustomobject,並非可能會產生非預期的結果

如果在導入的時候你想要它是一個hashtable,這時候你需要使用Export-CliXmlImport-CliXml命令

鍵僅僅是字符串

鍵僅僅是字符串,我們可以給任何對象加上引號把它變成鍵

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

你甚至可以做一些你認為為可能的奇怪的事:

$person.'full name'

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

雖然你可以這樣做,但並不意味着你應該這樣做.最后一行很容易產生bug和誤解.

從技術上講,鍵並不僅僅是字符串(可以是字符串外其它對象).但是如果你僅僅使用字符串你可以把它當作字符串.

PSBoundParameters

PSBoundParameters是一個僅僅存在於函數上下文的自動對象.它包含了函數需要調用的所有參數,准確地講它並不是一個hashtable但是你可以把它當作hashtable.

它包括的移除鍵和打散到其它函數.想進一步了解它,請查看微軟官方文檔以了解更多細節.

PSBoundParameters 問題

一件很重要的事是它僅僅包含了傳入的參數.如果你不家其它默認參數但是沒有被調用者傳入進來,PSBoundParameters 不會包含這些值,這一點經常被忽略.

PSDefaultParameterValues

這個自動變量讓你可以在不改變命令情況下給它指定默認值:

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

這添加了一個把Out-File-Encoding參數值默認設置為UTF8 hashtable.這僅僅是對特定session有效的因此你需要把它添加到$profile

當需要經常鍵入一些命令的時候我經常預先賦一些值

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

它還接收通配符,因此你可以批量設置

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

正則匹配

當你使用-match操作符,一個叫作$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
}

以上示例中,`(?<Name>.*)`是子表達式的名稱.值被存儲在`$Matches.Name`屬性里

## Group-Object -AsHashtable

關於`Group-Object`一個鮮為人知的特性是:它可以把一些數據集轉化為hashtable

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

這會把每一行都添加到hashtable,使用指定的鍵來訪問它.

## 拷貝hashtable

很重要的一點是hashtable是對象的集合.每一個變量都是對一個對象的引用,這就意味着想要拷貝一個hashtable會有更多的工作要做

### 賦值引用類型

當你有一個hashtable並且你把它賦值給一個變量,它們都批向同一個hashtable

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]


這個示例表名它們是同一個對象因為任意的一個改變都會影響到另一個.把hashtable傳入其它的函數也是如此,如果這個函數改變了hashtable的值,原始的hashtable也被改變

### 一級淺拷貝

如果我們的hashtable像上面示中那樣非常簡單,我們可以使用`.Clone()`做個淺拷貝

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]


這樣我們改變其中一個對象就不會改變另一個.

### 嵌套淺拷貝

我之所以叫它淺拷貝因為它僅僅拷貝了基層屬性.如果其中 一個屬性是引用對象(比如說是一個hashtable),這時候嵌套對象之間仍然有互相引用關系.

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]


你會 看到即便我克隆了hashtable,對person對象的引用並沒有克隆,我們需要一個正真的深拷貝來使它們之間不再有關聯

### 深拷貝

在寫此篇文章的時候,我還沒有找到一個更聰明的方法來對hashtable做深拷貝.下面是一個快速方法來實現深拷貝

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


這並不能處理數組或其它的引用類型,但是它是一個好的開端

## 結語

我快速的講述了一些基礎知識.每當你看這篇文章的時候我希望你能從別處學到一些新的知識以便可以理好的理解.因為我涵蓋了所有的范圍,很多特征並不能馬上對你有用.

原文鏈接:https://kevinmarquette.github.io/2016-11-06-powershell-hashtable-everything-you-wanted-to-know-about/#adding-hashtables


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM