为什么一个 CmdLet 的文本输出是格式化的,而另一个 CmdLet 的文本输出不是?
Why is text output from one CmdLet formatted and text output from another is not?
我写了 2 个 cmdlet,用于在 GUID 和 Oracle 的等效 Guid 之间转换,它为用于存储 GUID 的 RAW 列显示的字符串。第一个,Convert-GuidToRaw
,接受一个 GUID 字符串参数并输出一个原始字符串:
var raw = GuidConverter.Core.GuidConverter.ToRaw(Input);
WriteObject(raw);
其中 raw
的类型为 string
。当我 运行 这个 cmdlet 时,我得到一个简单明了的字符串输出:
PS D:\SANRAL\NRA2> New-Guid | Convert-GuidToRaw
DD8386EE09231A43B7731880CCAD6B87
PS D:\SANRAL\NRA2>
我的其他 cmdlet Convert-RawToGuid
接受表示 GUID 的 RAW 字符串参数并输出原始 GUID:
var guid = GuidConverter.Core.GuidConverter.FromRaw(Input);
WriteObject(guid);
其中 guid
的类型为 Guid
。当我 运行 这个 cmdlet 时,我得到的输出格式类似于 table:
PS D:\SANRAL\NRA2> Convert-RawToGuid DD8386EE09231A43B7731880CCAD6B87
Guid
----
ee8683dd-2309-431a-b773-1880ccad6b87
PS D:\SANRAL\NRA2>
在这两种情况下,我都输出单个对象,而不是列表,并且在这两种情况下,对象都可以很容易地用简单的字符串表示。当我 return 一个 Guid
类型时,为什么我得到表格输出?
可能值得注意的是,Convert-GuidToRaw
cmdlet 及其普通、未格式化的字符串输出似乎无法正确写入管道。两个 cmdlet 都从管道中获取一个参数。我希望下面的这个 cmdlet 管道输出一个 GUID,而管道中的最后一个 cmdlet 直到寻找输入:
PS C:\WINDOWS\system32> New-Guid | Convert-GuidToRaw | Convert-RawToGuid
cmdlet Convert-RawToGuid at command pipeline position 3
Supply values for the following parameters:
Input:
为什么 Convert-RawToGuid
没有从 Convert-GuidToRaw
得到 "pipelined" 字符串?如下交换管道的顺序,会导致预期的行为:
PS C:\WINDOWS\system32> Convert-RawToGuid F3BD9411DE8E4F4BBCACECFCED6D305D | Convert-GuidToRaw
F3BD9411DE8E4F4BBCACECFCED6D305D
PS C:\WINDOWS\system32>
Convert-RawToGuid
cmdlet 如下所示:
[Cmdlet(VerbsData.Convert, "RawToGuid")]
public class ConvertRawToGuidCommand : System.Management.Automation.Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public string Input { get; set; }
protected override void ProcessRecord()
{
if (string.IsNullOrEmpty(Input) || Input.Length != 32)
{
throw new ArgumentException("Input must be a 32 character hex string");
}
var guid = GuidConverter.Core.GuidConverter.FromRaw(Input);
WriteObject(guid);
}
}
Convert-GuidToRaw
cmdlet 如下所示:
[Cmdlet(VerbsData.Convert, "GuidToRaw")]
public class ConvertGuidToRawCommand : System.Management.Automation.Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public Guid Input { get; set; }
protected override void ProcessRecord()
{
var raw = GuidConverter.Core.GuidConverter.ToRaw(Input);
WriteObject(raw);
}
}
第 1 部分
In both cases I output a single object, not a list, and in both cases the object is easily represented by a simple string. Why do I get tabular output when I return a Guid type?
当交互式会话中的命令 returns 未分配值时,PowerShell 将其传递给默认值 Format Command to generate the text before it's written to the console. PowerShell is pre-configured with a bunch of Format Commands for some specific types, and System.Guid 是其中一种类型。
例如:
PS> [Guid]::NewGuid()
Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420
各种类型的默认格式化程序在 PowerShell 5.1 的 *.Format.ps1xml 文件中配置,并从 PowerShell 6 开始按照 About Format.ps1xml
嵌入到源代码中
在 PowerShell 5.1 中,System.Guid 的默认格式化程序配置可以在 $PSHOME\DotNetTypes.format.ps1xml
中找到,如下所示:
<View>
<Name>System.Guid</Name>
<ViewSelectedBy>
<TypeName>System.Guid</TypeName>
</ViewSelectedBy>
<TableControl>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Guid</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
所以你得到一个 table,其中只有一个列包含 Guid
属性.
如果你这样做,你会得到完全相同的结果:
PS> [Guid]::NewGuid() | Format-Table -Property "Guid"
Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420
如果您想将 default 格式化命令的结果捕获到字符串变量中(例如写入日志文件),您可以这样做:
PS> $text = [Guid]::NewGuid() | Out-String
PS> $text
Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420
第 2 部分
Why is Convert-RawToGuid not getting a "pipelined" string from Convert-GuidToRaw? Swapping the order of the pipeline as below, causes the expected behaviour:
我无法重现您的问题,但以下对我有用(需要注意的是我找不到带有 class GuidConverter.Core.GuidConverter
的库,所以我假设它是一个私有实现,我使用默认的字符串格式代替 - 例如:“024673b5-9c65-447a-be87-dae5f11f5142”)。您可以在本地尝试此操作,看看您是否得到相同的结果或您报告的问题,然后从那里开始...
- 在 Visual Studio
中使用 .Net Framework 4.7.2 创建新的 C# Class 库解决方案
- 添加对 Microsoft.PowerShell.5.1.ReferenceAssemblies NuGet 包的引用
- 将下面的代码添加到新的 class 文件中并构建项目:
using System;
using System.Management.Automation;
namespace MyCmdlet
{
[Cmdlet(VerbsData.Convert, "RawToGuid")]
public class ConvertRawToGuidCommand : Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public string Input { get; set; }
protected override void ProcessRecord()
{
if (string.IsNullOrEmpty(this.Input) || this.Input.Length != 36)
{
throw new ArgumentException("Input must be a 36 character hex string");
}
var guid = new Guid(this.Input);
WriteObject(guid);
}
}
[Cmdlet(VerbsData.Convert, "GuidToRaw")]
public class ConvertGuidToRawCommand : Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public Guid Input { get; set; }
protected override void ProcessRecord()
{
var raw = this.Input.ToString();
WriteObject(raw);
}
}
}
如果我构建此代码,我可以从 PowerShell 引用它,并且以下代码有效:
PS> Import-Module ".\MyCmdlet.dll"
PS> New-Guid | Convert-GuidToRaw | Convert-RawToGuid
Guid
----
15591624-44c9-4c55-acd7-22b7a2d0bee0
我写了 2 个 cmdlet,用于在 GUID 和 Oracle 的等效 Guid 之间转换,它为用于存储 GUID 的 RAW 列显示的字符串。第一个,Convert-GuidToRaw
,接受一个 GUID 字符串参数并输出一个原始字符串:
var raw = GuidConverter.Core.GuidConverter.ToRaw(Input);
WriteObject(raw);
其中 raw
的类型为 string
。当我 运行 这个 cmdlet 时,我得到一个简单明了的字符串输出:
PS D:\SANRAL\NRA2> New-Guid | Convert-GuidToRaw
DD8386EE09231A43B7731880CCAD6B87
PS D:\SANRAL\NRA2>
我的其他 cmdlet Convert-RawToGuid
接受表示 GUID 的 RAW 字符串参数并输出原始 GUID:
var guid = GuidConverter.Core.GuidConverter.FromRaw(Input);
WriteObject(guid);
其中 guid
的类型为 Guid
。当我 运行 这个 cmdlet 时,我得到的输出格式类似于 table:
PS D:\SANRAL\NRA2> Convert-RawToGuid DD8386EE09231A43B7731880CCAD6B87
Guid
----
ee8683dd-2309-431a-b773-1880ccad6b87
PS D:\SANRAL\NRA2>
在这两种情况下,我都输出单个对象,而不是列表,并且在这两种情况下,对象都可以很容易地用简单的字符串表示。当我 return 一个 Guid
类型时,为什么我得到表格输出?
可能值得注意的是,Convert-GuidToRaw
cmdlet 及其普通、未格式化的字符串输出似乎无法正确写入管道。两个 cmdlet 都从管道中获取一个参数。我希望下面的这个 cmdlet 管道输出一个 GUID,而管道中的最后一个 cmdlet 直到寻找输入:
PS C:\WINDOWS\system32> New-Guid | Convert-GuidToRaw | Convert-RawToGuid
cmdlet Convert-RawToGuid at command pipeline position 3
Supply values for the following parameters:
Input:
为什么 Convert-RawToGuid
没有从 Convert-GuidToRaw
得到 "pipelined" 字符串?如下交换管道的顺序,会导致预期的行为:
PS C:\WINDOWS\system32> Convert-RawToGuid F3BD9411DE8E4F4BBCACECFCED6D305D | Convert-GuidToRaw
F3BD9411DE8E4F4BBCACECFCED6D305D
PS C:\WINDOWS\system32>
Convert-RawToGuid
cmdlet 如下所示:
[Cmdlet(VerbsData.Convert, "RawToGuid")]
public class ConvertRawToGuidCommand : System.Management.Automation.Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public string Input { get; set; }
protected override void ProcessRecord()
{
if (string.IsNullOrEmpty(Input) || Input.Length != 32)
{
throw new ArgumentException("Input must be a 32 character hex string");
}
var guid = GuidConverter.Core.GuidConverter.FromRaw(Input);
WriteObject(guid);
}
}
Convert-GuidToRaw
cmdlet 如下所示:
[Cmdlet(VerbsData.Convert, "GuidToRaw")]
public class ConvertGuidToRawCommand : System.Management.Automation.Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public Guid Input { get; set; }
protected override void ProcessRecord()
{
var raw = GuidConverter.Core.GuidConverter.ToRaw(Input);
WriteObject(raw);
}
}
第 1 部分
In both cases I output a single object, not a list, and in both cases the object is easily represented by a simple string. Why do I get tabular output when I return a Guid type?
当交互式会话中的命令 returns 未分配值时,PowerShell 将其传递给默认值 Format Command to generate the text before it's written to the console. PowerShell is pre-configured with a bunch of Format Commands for some specific types, and System.Guid 是其中一种类型。
例如:
PS> [Guid]::NewGuid()
Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420
各种类型的默认格式化程序在 PowerShell 5.1 的 *.Format.ps1xml 文件中配置,并从 PowerShell 6 开始按照 About Format.ps1xml
嵌入到源代码中在 PowerShell 5.1 中,System.Guid 的默认格式化程序配置可以在 $PSHOME\DotNetTypes.format.ps1xml
中找到,如下所示:
<View>
<Name>System.Guid</Name>
<ViewSelectedBy>
<TypeName>System.Guid</TypeName>
</ViewSelectedBy>
<TableControl>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Guid</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
所以你得到一个 table,其中只有一个列包含 Guid
属性.
如果你这样做,你会得到完全相同的结果:
PS> [Guid]::NewGuid() | Format-Table -Property "Guid"
Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420
如果您想将 default 格式化命令的结果捕获到字符串变量中(例如写入日志文件),您可以这样做:
PS> $text = [Guid]::NewGuid() | Out-String
PS> $text
Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420
第 2 部分
Why is Convert-RawToGuid not getting a "pipelined" string from Convert-GuidToRaw? Swapping the order of the pipeline as below, causes the expected behaviour:
我无法重现您的问题,但以下对我有用(需要注意的是我找不到带有 class GuidConverter.Core.GuidConverter
的库,所以我假设它是一个私有实现,我使用默认的字符串格式代替 - 例如:“024673b5-9c65-447a-be87-dae5f11f5142”)。您可以在本地尝试此操作,看看您是否得到相同的结果或您报告的问题,然后从那里开始...
- 在 Visual Studio 中使用 .Net Framework 4.7.2 创建新的 C# Class 库解决方案
- 添加对 Microsoft.PowerShell.5.1.ReferenceAssemblies NuGet 包的引用
- 将下面的代码添加到新的 class 文件中并构建项目:
using System;
using System.Management.Automation;
namespace MyCmdlet
{
[Cmdlet(VerbsData.Convert, "RawToGuid")]
public class ConvertRawToGuidCommand : Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public string Input { get; set; }
protected override void ProcessRecord()
{
if (string.IsNullOrEmpty(this.Input) || this.Input.Length != 36)
{
throw new ArgumentException("Input must be a 36 character hex string");
}
var guid = new Guid(this.Input);
WriteObject(guid);
}
}
[Cmdlet(VerbsData.Convert, "GuidToRaw")]
public class ConvertGuidToRawCommand : Cmdlet
{
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)]
public Guid Input { get; set; }
protected override void ProcessRecord()
{
var raw = this.Input.ToString();
WriteObject(raw);
}
}
}
如果我构建此代码,我可以从 PowerShell 引用它,并且以下代码有效:
PS> Import-Module ".\MyCmdlet.dll"
PS> New-Guid | Convert-GuidToRaw | Convert-RawToGuid
Guid
----
15591624-44c9-4c55-acd7-22b7a2d0bee0