The Microsoft.PowerShell.Crescendo module is mostly brand new. It’s still early on in its development. It’s currently at version 0.4.1. This isn’t my first discussion on this topic, so please read Part I on this topic. That’ll give you an idea of my first experience working with the module. In that post, we created a PowerShell module that contained a single command that wrapped the mstsc.exe Remote Desktop Connection executable. Although there are several, I only wrote it with a single parameter: a stand-in for /v. This parameter expects the name of the computer or IP address, such as mstsc /v Server01
.
In that example I copied, pasted, and edited an existing *.Crescendo.json file. Today, we’ll wrap the same command (even though I alluded to using something else), however, we’ll do it using other cmdlets from the module. These will include New-CrescendoCommand
, New-ParameterInfo
, New-UsageInfo
, and New-ExampleInfo
. I had no idea what these were for as the help is limited, but I think I figured it out for now. If you know more, then of course you’re welcome to comment and participate.
In the first example, we invoked New-CrescendoCommand
. The available parameters at the time of this writing are -Verb
and -Noun
. Knowing those parameters, it’s straightforward what this was about. This is the naming for our new PowerShell command. As you can see, I supplied Connect
and RemoteComputer
, respectively. These are the same values that we supplied in Part I of this series. As you can likely tell, the command creates an object (a [TypeName] Command object to be exact). We send that object to ConvertTo-Json
, as we’ll need everything in JSON before creating our mstsc.Crescendo.json file. As you can also tell, the object — both the PowerShell object and JSON object — has several other properties. As best as I could determine, there was no way to include these when invoking the New-CrescendoCommand
. Do notice that the OriginalName property is blank and that there wasn’t a way to include that when invoking the command. We’ll be back to discuss this later.
[PS7.1.0] $Command = New-CrescendoCommand -Verb Connect -Noun RemoteComputer [PS7.1.0] $Command Verb : Connect Noun : RemoteComputer OriginalName : OriginalCommandElements : Aliases : DefaultParameterSetName : SupportsShouldProcess : False SupportsTransactions : False NoInvocation : False Description : Usage : Parameters : {} Examples : {} OriginalText : HelpLinks : OutputHandlers : [PS7.1.0] $Command = $Command | ConvertTo-Json [PS7.1.0] $Command { "Verb": "Connect", "Noun": "RemoteComputer", "OriginalName": null, "OriginalCommandElements": null, "Aliases": null, "DefaultParameterSetName": null, "SupportsShouldProcess": false, "SupportsTransactions": false, "NoInvocation": false, "Description": null, "Usage": null, "Parameters": [], "Examples": [], "OriginalText": null, "HelpLinks": null, "OutputHandlers": null }
In this code example, we essentially do the same thing. We create a PowerShell object and then convert it to JSON. This is the addition of a new parameter.
[PS7.1.0] $Parameter = New-ParameterInfo -Name ComputerName -OriginalName /v [PS7.1.0] $Parameter ParameterType : object Position : 2147483647 Name : ComputerName OriginalName : /v OriginalText : Description : DefaultValue : DefaultMissingValue : AdditionalParameterAttributes : Mandatory : False ParameterSetName : Aliases : OriginalPosition : 0 ValueFromPipeline : False ValueFromPipelineByPropertyName : False ValueFromRemainingArguments : False NoGap : False [PS7.1.0] $Parameter = $Parameter | ConvertTo-Json [PS7.1.0] $Parameter { "ParameterType": "object", "Position": 2147483647, "Name": "ComputerName", "OriginalName": "/v", "OriginalText": null, "Description": null, "DefaultValue": null, "DefaultMissingValue": null, "AdditionalParameterAttributes": null, "Mandatory": false, "ParameterSetName": null, "Aliases": null, "OriginalPosition": 0, "ValueFromPipeline": false, "ValueFromPipelineByPropertyName": false, "ValueFromRemainingArguments": false, "NoGap": false }
And in this code example, we essentially do the same thing, too. This PowerShell object converted to JSON has to do with Usage. I’m still working that one over in my mind, but we’ll take a closer look.
[PS7.1.0] $Usage = New-UsageInfo -usage 'Runs Remote Desktop Connection' [PS7.1.0] $Usage Synopsis SupportsFlags HasOptions -------- ------------- ---------- Runs Remote Desktop Connection False False [PS7.1.0] $Usage = $Usage | ConvertTo-Json [PS7.1.0] $Usage { "Synopsis": "Runs Remote Desktop Connection", "SupportsFlags": false, "HasOptions": false, "OriginalText": null }
Finally, we create a comment-based help example and ensure it’s in the JSON format.
[PS7.1.0] $Example = New-ExampleInfo -command Connect-RemoteComputer -originalCommand 'C:\Windows\System32\mstsc.exe' -description 'Wraps Remote Desktop Connection' [PS7.1.0] $Example Command OriginalCommand Description ------- --------------- ----------- Connect-RemoteComputer C:\Windows\System32\mstsc.exe Wraps Remote Desktop Connection [PS7.1.0] $Example = $Example | ConvertTo-Json [PS7.1.0] $Example { "Command": "Connect-RemoteComputer", "OriginalCommand": "C:\\Windows\\System32\\mstsc.exe", "Description": "Wraps Remote Desktop Connection" }
Next, we have to manually put these pieces of JSON together into our single, mstsc.Crescendo.json file. Let’s do that next. We’ll begin with the Parameter JSON we created and add to it the Command JSON. In the Command JSON section, we had an entry that said "Parameters": [],
In between the square brackets, we have to add the Parameter JSON. This has been done below.
{ "Verb": "Connect", "Noun": "RemoteComputer", "OriginalName": null, "OriginalCommandElements": null, "Aliases": null, "DefaultParameterSetName": null, "SupportsShouldProcess": false, "SupportsTransactions": false, "NoInvocation": false, "Description": null, "Usage": null, "Parameters": [ { "ParameterType": "object", "Position": 2147483647, "Name": "ComputerName", "OriginalName": "/v", "OriginalText": null, "Description": null, "DefaultValue": null, "DefaultMissingValue": null, "AdditionalParameterAttributes": null, "Mandatory": false, "ParameterSetName": null, "Aliases": null, "OriginalPosition": 0, "ValueFromPipeline": false, "ValueFromPipelineByPropertyName": false, "ValueFromRemainingArguments": false, "NoGap": false } ], "Examples": [], "OriginalText": null, "HelpLinks": null, "OutputHandlers": null }
Next, we’ll add our Usage JSON to its place in our mstsc.Crescendo.json file
{ "Verb": "Connect", "Noun": "RemoteComputer", "OriginalName": null, "OriginalCommandElements": null, "Aliases": null, "DefaultParameterSetName": null, "SupportsShouldProcess": false, "SupportsTransactions": false, "NoInvocation": false, "Description": null, "Usage": { "Synopsis": "Runs Remote Desktop Connection", "SupportsFlags": false, "HasOptions": false, "OriginalText": null }, "Parameters": [ { "ParameterType": "object", "Position": 2147483647, "Name": "ComputerName", "OriginalName": "/v", "OriginalText": null, "Description": null, "DefaultValue": null, "DefaultMissingValue": null, "AdditionalParameterAttributes": null, "Mandatory": false, "ParameterSetName": null, "Aliases": null, "OriginalPosition": 0, "ValueFromPipeline": false, "ValueFromPipelineByPropertyName": false, "ValueFromRemainingArguments": false, "NoGap": false } ], "Examples": [], "OriginalText": null, "HelpLinks": null, "OutputHandlers": null }
And finally, we’ll add our Example JSON.
{ "Verb": "Connect", "Noun": "RemoteComputer", "OriginalName": null, "OriginalCommandElements": null, "Aliases": null, "DefaultParameterSetName": null, "SupportsShouldProcess": false, "SupportsTransactions": false, "NoInvocation": false, "Description": null, "Usage": { "Synopsis": "Runs Remote Desktop Connection", "SupportsFlags": false, "HasOptions": false, "OriginalText": null }, "Parameters": [ { "ParameterType": "object", "Position": 2147483647, "Name": "ComputerName", "OriginalName": "/v", "OriginalText": null, "Description": null, "DefaultValue": null, "DefaultMissingValue": null, "AdditionalParameterAttributes": null, "Mandatory": false, "ParameterSetName": null, "Aliases": null, "OriginalPosition": 0, "ValueFromPipeline": false, "ValueFromPipelineByPropertyName": false, "ValueFromRemainingArguments": false, "NoGap": false } ], "Examples": [ { "Command": "Connect-RemoteComputer", "OriginalCommand": "C:\\Windows\\System32\\mstsc.exe", "Description": "Wraps Remote Desktop Connection" } ], "OriginalText": null, "HelpLinks": null, "OutputHandlers": null }
I don’t think it’s there yet, but one day there will likely be a command that does all this for us. Maybe there already is and somehow I’ve overlooked it. With this JSON created and saved as mstsc.Crescendo.json, we can attempt to use it with Export-CrescendoModule
as we did in Part I.
[PS7.1.0] Export-CrescendoModule -ConfigurationFile 'C:\Users\tommymaynard\Documents\PowerShell\Modules\Microsoft.PowerShell.Crescendo\0.4.1\Samples\mstsc.Crescendo.json' -ModuleName 'RemoteComputer.psm1'
If you try this, you’ll notice it fails.
This is because the New-CrescendoCommand
didn’t include an OriginalName parameter and therefore our JSON didn’t include a much-needed value. Without it, the command doesn’t point to an existing command on the computer, which becomes the reason behind the above error message. Even though it throws an error, it still creates the file (although it’s missing much of the good stuff). You’ll have to remove the file or you’ll get another error about the file already existing.
Our JSON ends up with this: “OriginalName”: null, instead of this: “OriginalName”:”/Windows/System32/mstsc.exe”,. As you can see below, I’ve added this in, so the code here is complete.
{ "Verb": "Connect", "Noun": "RemoteComputer", "OriginalName": "/Windows/System32/mstsc.exe", "OriginalCommandElements": null, "Aliases": null, "DefaultParameterSetName": null, "SupportsShouldProcess": false, "SupportsTransactions": false, "NoInvocation": false, "Description": null, "Usage": { "Synopsis": "Runs Remote Desktop Connection", "SupportsFlags": false, "HasOptions": false, "OriginalText": null }, "Parameters": [ { "ParameterType": "object", "Position": 2147483647, "Name": "ComputerName", "OriginalName": "/v", "OriginalText": null, "Description": null, "DefaultValue": null, "DefaultMissingValue": null, "AdditionalParameterAttributes": null, "Mandatory": false, "ParameterSetName": null, "Aliases": null, "OriginalPosition": 0, "ValueFromPipeline": false, "ValueFromPipelineByPropertyName": false, "ValueFromRemainingArguments": false, "NoGap": false } ], "Examples": [ { "Command": "Connect-RemoteComputer", "OriginalCommand": "C:\\Windows\\System32\\mstsc.exe", "Description": "Wraps Remote Desktop Connection" } ], "OriginalText": null, "HelpLinks": null, "OutputHandlers": null }
Have fun and keep watching for newer versions. I suspect I will.