我有一个函数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}
场景二 - 没有带有写作项目功能的输出
我创建了一个名为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 - 带有写入项目功能的表格输出
我发现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}
每个场景中发生了什么以及为什么我按照描述获得输出?
答案 0 :(得分: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
希望有所帮助!
答案 1 :(得分:0)
这个问题有一个简单的答案和一个复杂的解决方案:
不要使用Write-Host(格式化程序除外)
Write-Host直接输出到屏幕,这可以防止您使用数据。理想情况下,您希望Get-Projects以您希望的方式显示项目,并且仍然是一个真实的对象。您可以使用格式化程序执行此操作。
当您在第一个场景中写入主机时,PowerShell正在将输入(对象列表)强制转换为字符串。
在第二个示例中,您遇到了同一个bug的嵌套版本:正在强制将子项转换为字符串,因此它适用于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
这将创建一个格式化程序,(应该)显示缩进的子项,并将其注册。