PowerShell FAQ - 函數傳回集合物件注意事項
1 |
最近依舊是寫 PowerShell 多過 C# (雖然在 PowerShell 裡卯起來用 .NET 元件),開始進入見山不是山的階段,程式寫得更多之後,踩到一些奇怪特性,會覺得自己並不懂 PowerShell,哈!
下面這個範例是一個讓我吶喊「花惹發」的行為。我在函式裡建立 System.Data.DataTable 回傳給呼叫端,為了對照在內部先分別檢查 .Rows.Count 及 .Columns.Count,預期數值應為 2 跟 3。呼叫端接收存入參數,再檢查一次 .Rows.Count 及 .Columns.Count,大家覺得數字會是多少?
function CreateDemoDataTable() {
$dt = New-Object System.Data.DataTable
$dt.Columns.Add("Id", [int]) | Out-Null
$dt.Columns.Add("Name", [string]) | Out-Null
$dt.Columns.Add("RegDate", [datetime]) | Out-Null
$dt.Rows.Add(1, "Jeffrey", (Get-Date)) | Out-Null
$dt.Rows.Add(2, "Jack", (Get-Date)) | Out-Null
Write-Host "Internal Check:" -ForegroundColor Yellow
Write-Host " Rows.Count = $($dt.Rows.Count)"
Write-Host " Columns.Count = $($dt.Columns.Count)"
return $dt
}
$dt = CreateDemoDataTable
Write-Host "External Check:" -ForegroundColor Yellow
Write-Host " Rows.Count = $($dt.Rows.Count)"
Write-Host " Columns.Count = $($dt.Columns.Count)"
Write-Host "`$dt.WTF.Count = $($dt.WTF.Count)" -ForegroundColor DarkRed
Write-Host "`$dt.GetType = $($dt.GetType())"
答案揭曉, .Rows.Count 及 .Columns.Count 都是 2,搞什麼鬼,乾脆怒查一個 $dt.WTF.Count,這總會出現錯誤吧?登楞! 沒出錯,也傳回 2。最後檢查 $dt.GetType(),發現它不是 DataTable,而是 System.Object[]。
爬了文大概才知道是怎麼一回事。
依據官方文件:
When you return a collection from your script block or function, PowerShell automatically unrolls the members and passes them one at a time through the pipeline. This is due to PowerShell's one-at-a-time processing.
在程式區塊或函式傳回集合物件時,PowerShell 會自動展開集合,以便一次一個元素送進 Pipeline
要避免集合被展開,有兩種寫法:
return (, $collectionObject)
或直接return ,$collectionObject
return Write-Output -NoEnumerate $colletionObject
或直接Write-Output $collectionObject
在 return $dt 前加上逗號,就能順利傳回 DataTable,.Columns.Count 及 .Rows.Count 也正常了。
但 $dt.WTF.Count = 2 是怎麼回事?
我做了一個實驗,發現在 $dt 後方接上不存在的屬性名稱,會得到 object[],在不知名屬性名稱後方加上 .Count 會得到 Rows 筆數,但不知名屬性 -eq $null 卻又相等! 這...
猜想是背後某個轉型原則始然,但爬了好一陣子文章也沒找到解答。這個謎團,就留待等高手先進路過再幫忙指點迷津了。
[2024-09-17 中秋節更新]此行為與應 Member Access Enumeration 有關,參考
Introduce to the unrolling behavior when returning collection type in PowerShell.
Comments
# by 艾力萊茵
一般只用Powershell來做安裝script 和 在citrix 上做configuration 長智識了,黑大謝謝你的分享 另外,在下在自家的部落格 link了你的Blog 希望黑大不會介意