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}

场景二 - 没有输出 w/写项目功能

我创建了一个名为Write-Projects封装格式化行为的函数,以防我决定更改格式化方式。然而,当我这样做时,控制台不会打印任何内容。

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

    $projects
}

$projects = Get-Projects
Write-Projects $projects

# No Console Output

场景 3 - 带有写入项目功能的字符串输出

如果我修改 Write-Projects 以使用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 - 带有写入项目功能的表格输出

我发现了解决问题的这个问题,但我不确定为什么。基本上我的 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-Outputas (a) this 自动枚举对象,并且 (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接收到的要发送到屏幕的内容。我想说你可以跳过Write-Host场景 4,它应该仍然有效。

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 将输入(对象列表)强制转换为字符串。

在第二个示例中,您遇到了相同错误的嵌套版本:Children 被强制转换为字符串,因此它适用于 Format-Table。

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

有几种方法可以做到这一点,但我推荐我几年前写的一个模块,叫做EzOut。EZOut 允许您使用 Cmdlet 编写格式化程序,并允许您动态添加它们。

要完成这项工作,请修改 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 回答