1

Get-Projectsオブジェクトの配列を返す関数があります。ユーザーが興味のあるプロジェクトを選択できるように、これらをコンソールに出力したいと考えています。

シナリオ 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}

シナリオ 2 - Write-Projects 関数による出力なし

Write-Projectsフォーマットの方法を後で変更することにした場合に備えて、フォーマットの動作をカプセル化するという名前の関数を作成しました。それでも、これを行うと、コンソールには何も出力されません。

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

    $projects
}

$projects = Get-Projects
Write-Projects $projects

# No Console Output

シナリオ 3 - Write-Projects 関数を使用した文字列出力

Write-Projects を使用するように変更するWrite-Host $projectsと、コンソール出力は得られますが、期待したものではありません。私のオブジェクト配列の文字列表現のようです。

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 - Write-Projects 関数を使用した表形式の出力

問題を解決するこの質問を発見しましたが、その理由はわかりません。基本的に、私の 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}

これらの各シナリオで何が起こっているのか、説明されている出力が得られるのはなぜですか?

4

2 に答える 2

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、(a) オブジェクトを自動的に列挙し、(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

それが役立つことを願っています!

于 2013-10-20T11:34:43.087 に答える
0

この質問には、単純な答えと複雑な解決策があります。

Write-Host を使用しないでください (フォーマッターを除く)

Write-Host は画面に直接出力するため、データを使用できなくなります。理想的には、Get-Projects でプロジェクトを希望どおりに表示し、実際のオブジェクトのままにする必要があります。これはフォーマッタで行うことができます。

最初のシナリオで Write-Host を実行すると、PowerShell が入力 (オブジェクトのリスト) を強制的に文字列に変換します。

2 番目の例では、同じバグのネストされたバージョンに遭遇しています: Children is being coerced into a string, so that it works for Format-Table.

これを行う正しい方法は、フォーマッタを使用することです。

これを作成するにはいくつかの方法がありますが、数年前に書いたEzOutというモジュールをお勧めします。EZOut では、コマンドレットを使用してフォーマッタを記述し、それらを動的に追加できます。

これを機能させるには、Get-Projects の各出力を次のように変更します。

$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

これにより、インデントされた子を表示する (すべき) フォーマッタが作成され、それが登録されます。

于 2013-10-20T10:14:52.030 に答える