0

I have written 2 cmdlets, for converting between GUIDs and Oracle's Guid equivalent, the strings it displays for RAW columns used to store GUIDs. The first, Convert-GuidToRaw, accepts a GUID string param and outputs a raw string:

var raw = GuidConverter.Core.GuidConverter.ToRaw(Input);
WriteObject(raw);

Where raw has type string. When I run this cmdlet, I get a plain and simple string output:

PS D:\SANRAL\NRA2> New-Guid | Convert-GuidToRaw                                                                  
DD8386EE09231A43B7731880CCAD6B87
PS D:\SANRAL\NRA2>

My other cmdlet, Convert-RawToGuid, accepts a RAW string param representing a GUID and outputs a raw GUID:

var guid = GuidConverter.Core.GuidConverter.FromRaw(Input);
WriteObject(guid);

Where guid has type Guid. When I run this cmdlet, I get output formatted like a table:

PS D:\SANRAL\NRA2> Convert-RawToGuid DD8386EE09231A43B7731880CCAD6B87

Guid
----
ee8683dd-2309-431a-b773-1880ccad6b87


PS D:\SANRAL\NRA2>

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?

It may be worth noting that the Convert-GuidToRaw cmdlet, with its plain, un-formatted, string output, doesn't seem to properly write to the pipeline. Both cmdlets take one parameter, from the pipeline. I would expect this cmdlet pipeline below to output a GUID, when instead the last cmdlet in the pipeline is till looking for input:

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:

Why is Convert-RawToGuid not getting a "pipelined" string from Convert-GuidToRaw? Swapping the order of the pipeline as below, causes the expected behaviour:

PS C:\WINDOWS\system32> Convert-RawToGuid F3BD9411DE8E4F4BBCACECFCED6D305D | Convert-GuidToRaw
F3BD9411DE8E4F4BBCACECFCED6D305D
PS C:\WINDOWS\system32>

The Convert-RawToGuid cmdlet looks like this:

[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);
    }
}

The Convert-GuidToRaw cmdlet looks like this:

[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);
    }
}
5
  • Could you post the code for Convert-GuidToRaw as well? I should have thought to ask for that at the same time as Convert-RawToGuid! :-S Commented Feb 17, 2020 at 20:04
  • @mclayton Have done so. Commented Feb 18, 2020 at 6:43
  • I've tried to repro the issue here with a new Visual Studio solution (C# Class Library, .Net Framework 4.7.2), adding the NuGet package Microsoft.PowerShell.5.1.ReferenceAssemblies and then just pasting your code into two new class files (except for the serialisation format - using Input.ToString() and new Guid(this.Input) to convert values). Then, in PowerShell Import-Module ".\MyCmdlet.dll"; New-Guid | Convert-GuidToRaw | Convert-RawToGuid and it just works :-S. Could you see if your project is any different to my repro, and maybe try my steps yourself? Commented Feb 18, 2020 at 9:30
  • @mclayton For which Cmdlet did you use Input.ToString() and new Guid(this.Input)? Nowhere can the input string be converted straight to a Guid - it must be parsed. Commented Feb 19, 2020 at 4:18
  • I've added a Part 2 to my answer that explains the above comment in more detail than 600 characters can :-). Commented Feb 19, 2020 at 21:04

1 Answer 1

1

Part 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?

When a command in an interactive session returns an unassigned value, PowerShell passes it to a default 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 is one of those types.

For example:

PS> [Guid]::NewGuid()

Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420

The default formatters for various types are configured in *.Format.ps1xml files in PowerShell 5.1, and are baked into the source code from PowerShell 6 onwards as per About Format.ps1xml

In PowerShell 5.1, the default formatter configuration for System.Guid can be found in $PSHOME\DotNetTypes.format.ps1xml and looks like this:

<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>

so you get a table with a single column that contains the Guid property.

You get exactly the same result if you do this:

PS> [Guid]::NewGuid() | Format-Table -Property "Guid"

Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420

and if you want to capture the result of the default formatting command into a string variable (e.g. to write to a log file) you can do this:

PS> $text = [Guid]::NewGuid() | Out-String
PS> $text

Guid
----
ee737b6f-7f68-4015-8841-1278b37a6420

Part 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:

I'm not able to reproduce your issue, but the following works for me (with the caveat that I couldn't find a library with the the class GuidConverter.Core.GuidConverter so I'm assuming it's a private implementation and I'm using the default string fomat instead - e.g. : "024673b5-9c65-447a-be87-dae5f11f5142"). You could try this locally and see if you get the same result or the issue you reported, and go from there...

  • Create a new C# Class Library solution using .Net Framework 4.7.2 in Visual Studio
  • Add a reference to the Microsoft.PowerShell.5.1.ReferenceAssemblies NuGet package
  • Add the code below into a new class file and build the project:
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);
        }
    }

}

If I build this code I can reference it from PowerShell and the following code works:

PS> Import-Module ".\MyCmdlet.dll"
PS> New-Guid | Convert-GuidToRaw | Convert-RawToGuid

Guid
----
15591624-44c9-4c55-acd7-22b7a2d0bee0
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for all the info on formatting. I have added my implementation of Convert-RawToGuid to the question. It is C# and not PowerShell script.
It's interesting that you use a .NET invocation to get a new GUID, where I have a New-Guid cmdlet available, that seems build in.
@ProfK - re [Guid]::NewGuid - I come from a C# background - I tend to drop down to the .Net classes by default :-).
I'm also from a long C# background, but I always forget how easy it is to use the .Net classes in PS. Thanks for a reminder.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.