2013-10-20 70 views
0

我有一個函數Get-Projects,它返回一個對象數組。我想將這些打印到控制檯,以便用戶可以選擇他們感興趣的項目。但是,我有四種情況,其中只有兩種打印所需/期望的結果。將PowerShell對象寫入控制檯時的行爲不同

方案1 - 表格輸出,無功能

當我簡單的「返回」像這樣的項目,它們打印出來如預期以表格的方式。這是所需的格式。

$projects = Get-Projects 
$projects 

# Console Output 
id  name   children              
--  ----   --------              
1  Project 1 1 {@id=2; name=Project 2} 
3  Project 3 3 {@id=4; name=Project 4} 

兩個方案 - 不輸出瓦特/寫功能的項目

我創建了一個名爲Write-Projects封裝的情況下,格式化行爲,我決定改變如何格式化的道路功能。然而,當我這樣做時,沒有任何東西印在控制檯上。

Function Write-Projects 
{ 
    Param([Object[]] $projects) 

    $projects 
} 

$projects = Get-Projects 
Write-Projects $projects 

# No Console Output 

方案3 - 字符串輸出瓦特/寫功能的項目

如果我修改寫項目中使用Write-Host $projects我得到的控制檯輸出,但不是我所期待。這似乎是我的Object數組的字符串表示形式。

Function Write-Projects 
{ 
    Param([Object[]] $projects) 

    Write-Host $projects 
} 

$projects = Get-Projects 
Write-Projects $projects 

# Console Output 
@{id=1; name=Project 1; children=System.Object[]} @{id=2; name=Project 2; children=System.Object[]} 

方案4 - 表格輸出瓦特/寫功能的項目

我發現this question解決了問題,但我不清楚這是爲什麼。本質上,我的Write-Projects方法現在看起來像這樣。

Function Write-Projects 
{ 
    Param([Object[]] $projects) 

    Write-Host ($projects | Format-Table | Out-String) 
} 

$projects = Get-Projects 
Write-Projects $projects 

# Console Output 
id  name   children              
--  ----   --------              
1  Project 1 1 {@id=2; name=Project 2} 
3  Project 3 3 {@id=4; name=Project 4} 

每種情況下發生了什麼,爲什麼我得到的輸出如上所述?

回答

2

我不知道爲什麼場景2不起作用。只是爲了測試我做了一些自定義對象,並嘗試過,它對我有效:

PS> $obj1 = New-Object PSObject @{ a = 1; b = 2 } 
PS> $obj2 = New-Object PSObject @{ a = 3; b = 4 } 
PS> $obj1,$obj2 

Name       Value 
----       ----- 
a        1 
b        2 
a        3 
b        4 

PS> function write-projects { param ([object[]] $projects) $projects } 
PS> write-projects -projects $obj1,$obj2 

Name       Value 
----       ----- 
a        1 
b        2 
a        3 
b        4 

我知道爲什麼場景3不起作用。這是因爲當你使用Write-Host的對象是使用其toString()方法轉換爲文本表示,因此這就是爲什麼你的對象不是原樣輸出:

PS> function write-projects { param ([object[]] $projects) write-host $projects } 
PS> write-projects -projects $obj1,$obj2 
System.Collections.Hashtable System.Collections.Hashtable 

# notice the output of toString() 
PS> $obj1.ToString() 
System.Collections.Hashtable 

一個更好的辦法是使用Write-Output爲(一)這會自動枚舉對象,並且(b)它是「管道友好的」,因爲對象不會直接寫入主機,而是傳遞到下一步。

PS> function write-projects { param ([object[]] $projects) write-output $projects } 
PS> write-projects -projects $obj1,$obj2 

Name       Value 
----       ----- 
a        1 
b        2 
a        3 
b        4 

而之所以方案4名的作品是因爲你直接輸出對象 - 隱枚舉它 - 那麼它的格式化和格式化輸出是什麼Write-Host接收發射到屏幕上。我想說你可以跳過場景4中的Write-Host,它應該仍然有效。

PS> function write-projects { param ([object[]] $projects) $projects | format-table } 
PS> write-projects -projects $obj1,$obj2 

Name       Value 
----       ----- 
a        1 
b        2 
a        3 
b        4 

希望有幫助!

0

這個問題有一個簡單的答案和複雜的解決方案:

不要用寫主機(除了格式化)直接

寫主機輸出到屏幕上,它阻止你永遠使用數據。您理想地希望Get-Projects以您想要的方式顯示項目,並且仍然是一個真正的對象。你可以用格式化程序來做到這一點。

當您在第一種情況下編寫主機時發生了什麼情況是PowerShell將輸入(對象列表)強制爲字符串。

在第二個示例中,您運行的是同一個bug的嵌套版本:子句被強制轉換爲字符串,以便它適用於Format-Table。

正確的方法是使用格式化程序。

有幾種方法可以做到這一點,但我建議一個幾年前我寫的模塊叫做EzOut。 EZOut允許您使用Cmdlet編寫格式化程序,並允許您動態添加它們。

爲了使這項工作,修改獲取,項目的每個輸出像這樣:

$output.pstypenames.clear() 
$output.pstypenames.add("Project") 

我最好再推薦進口EZOut和編寫自定義格式:

Write-Format -TypeName "Project" -Action { 
    $project = $_ 
    " 
    Project Name : $($project.Name) 
      ID : $($project.ID) 
      Children $(
       $(
        $project.Children | format-Table | Out-String | Foreach-Object { "   " + $_ + " 
"} 
       ) 
    " 
} | 
    Out-FormatData | 
    Add-FormatData 

這將創建一個格式化程序(應該)顯示縮進的孩子,並將其註冊。