Search code examples
c#powershellpowershell-cmdlet

In PowerShell, How to refer to a cmdlet itself rather than executing it?


I'm currently learning Powershell 101 using PowerShell 7.4, and I'm interested in inpecting the type of some expressions, for example by executing

 [Powershell] | gm

I get:

 TypeName: System.RuntimeType

or by executing

[Powershell].getType()

I get

IsPublic IsSerial Name            BaseType
-------- -------- ----            --------
False    False    RuntimeType     System.Reflection.TypeInfo

However, I can't get the type of a Cmdlet since it's executed automatically, for example :

 get-help | gm

this command give the members of the returned object, rather than the members of the Cmdlet itself.


I tried executing:

(Get-Command Get-Help).GetType()

I got:

IsPublic IsSerial Name          BaseType
-------- -------- ----          --------
True     False    CmdletInfo    System.Management.Automation.CommandInfo

So I think that the Get-Command Cmdlet does not return an object of type Cmdlet , instead, it gives a CmdletInfo object.


According to the Powershell SDK 7.4.0, the class of a Cmdlet is System.Management.Automation.Cmdlet

[System.Management.Automation.Cmdlet]
IsPublic IsSerial Name   BaseType

-------- -------- ----   --------

True     False    Cmdlet System.Management.Automation.Internal.InternalCommand

So how can I refer to a Cmdlet itself in Powershell instead of executing it to play with its features?


Solution

  • Use the .ImplementingType property of the System.Management.Automation.CmdletInfo instance returned by Get-Command:

    (Get-Command Get-Help).ImplementingType
    

    This directly returns a System.Type-derived instance that represents the .NET type that implements the Get-Help cmdlet, namely Microsoft.PowerShell.Commands.GetHelpCommand.

    Every time you call Get-Help from PowerShell code, an instance of Microsoft.PowerShell.Commands.GetHelpCommand is created behind the scenes.

    As you note, all cmdlets must derive from the System.Management.Automation.Cmdlet base class; the System.Management.Automation.PSCmdlet class (which itself derives from the former) is more typically used as the base class, as it provides better integration with the PowerShell runtime.


    While you can directly obtain an instance of a cmdlet-implementing type as follows in order to inspect its properties, note that you won't be able to call .Invoke() on instances of PSCmdlet-derived types, which the majority of the built-in cmdlets are:

    # Create an instance of the class that implements the `Get-Help` cmdlet.
    $cmdletInstance = 
      (Get-Command Get-Help).ImplementingType::new()
    
    # Ditto, using the type directly:
    $cmdletInstance = 
      [Microsoft.PowerShell.Commands.GetHelpCommand]::new()
    

    A - rare - example of where calling .Invoke() does work is the Cmdlet-derived Get-Date:

    # Same as calling `Get-Date`
    (Get-Command Get-Date).ImplementingType::new().Invoke()