Convert Linux shell commands into PowerShell cmdlets
New Harmonies
PowerShell Crescendo [1] converts commands from other shell environments into PowerShell cmdlets and modules and runs them with all the benefits and convenience of the PowerShell environment. These commands can be piped or controlled with parameters. In this article, I show you how to set up and use a Crescendo environment in Linux.
Crescendo was available as a Technical Preview at the time of writing, so all of the approaches discussed here may change in future releases. However, because a Crescendo package and the wrappers it generates work without an Internet connection once downloaded, your environment can remain stable by not applying updates or not transpiling the wrappers again.
Crescendo Work Environment
Crescendo relies on a two-step process: Before using a command-line tool, you need to transpile a wrapper with the Crescendo environment and one or more JSON control files. If this is successful, the result will be an ordinary PowerShell module that you can use in pretty much any PowerShell version. This two-pronged approach is also reflected in the system requirements: To create a package based on Crescendo, you need PowerShell version 7.0, whereas the modules will run in Windows PowerShell 5.1 or PowerShell 7.0.
I used a Windows 10 workstation for this example. Annoyingly, it came with PowerShell version 5 out of the box. Microsoft provides the latest stable version of PowerShell in a GitHub repository [2] if you need to upgrade. At the time of writing, this was the PowerShell-7.1.4-win-x64.msi
file, which let me install and start PowerShell 7.
If you want to distinguish between different PowerShell versions, you can use the $PSVersionTable
query. Note that the table created in this way returns a group of attributes with different data types. If you use the contents of the table with a script, PowerShell lets you target individual fields with $PSVersionTable.PSVersion
.
To download the Crescendo transpiler, enter the command:
Install-Module Microsoft.PowerShell.Crescendo -AllowPrerelease
You need to confirm any security prompts telling you about a non-trusted package repository.
After successful installation, your PowerShell is a few cmdlets richer. You will also find the C:\Users\<Users>\Documents\PowerShell\Modules\Microsoft.PowerShell.Crescendo\0.6.1\Samples
folder with some sample files intended for Unix-style commands.
Executing Commands
The most common use of Crescendo-generated wrappers is to wrap command-line commands in verb-noun form. As a reminder, all PowerShell commands begin with a verb that describes the task to be accomplished by the particular command followed by a noun that describes the goal of the action triggered by the verb.
In Crescendo Preview 3 (the third preview release supports combining multiple commands in a JSON file), command declarations look like Listing 1. Besides the $schema
line used to declare the XML syntax, you will see the Commands
array that lists the commands to be wrapped. Each command has Verb
and Noun
fields that specify the PowerShell verbs and nouns to activate the command. The OriginalName
contains the path to the file to be executed.
Listing 1
Commands Declaration
01 { 02 "$schema": "./Microsoft.PowerShell.Crescendo.Schema.json", 03 "Commands": [ 04 { 05 "Verb": "New", 06 "Noun": "Command1", 07 "OriginalName": "<Path><Command>" 08 }, 09 { 10 "Verb": "New", 11 "Noun": "Command2", 12 "OriginalName": "<Path><Command>" 13 } . . . 14 ] 15 }
Before I describe the procedure further, note that if you want to integrate your cmdlet into the calling conventions of PowerShell, you will need to restrict yourself to the verbs released by Microsoft if they suit your needs. A list of the verbs and the roles are provided by Microsoft [3], along with the Crescendo cmdlets and their parameters [4].
The first execution target is winver
, which opens a pop-up window with the current Windows version. To create a crescendo wrapper to execute winver
, you need a JSON file (created in the runwinver.json
file in Notepad):
{ "$schema" : "./Microsoft.PowerShell.Crescendo.Schema.json", "Verb": Run", "Noun": "TamsWinVer", "OriginalName":"/Windows/System32/winver.exe", "Parameters": [] }
Besides the Verb
and Noun
attributes, which are necessary for PowerShell, you have to specify the path to winver.exe
in the OriginalName
field. Paths in the C:\Windows
directory can be expressed as shown. Because the tool does not need parameters, you will be passing in an empty field to the parameter array.
You might have already noticed the missing quotation mark in the "Verb": Run"
line. Why this is so is soon obvious. For now, tell Crescendo to transpile:
Export-CrescendoModule -ConfigurationFile "runwinver.json" -ModuleName 'TansWinver.psm1'.
The ConfigurationFile
parameter refers to the JSON file, and ModuleName
specifies the name of the PowerShell script module (PSM1) file to be generated. Crescendo generates a native PowerShell module that you can use without the Crescendo runtime. The JSON parser notices the missing quotation mark and terminates processing with an error message (Figure 1). Now, correct the JSON file and transpile again.
Working Around an Annoying Bug
The cause of this annoying behavior is that Crescendo always generates output files explicitly, even if transpiling the JSON file fails or provides no useful information. The Export-CrescendoModule
command generates the TansWinver.psd1
and TansWinver.psm1
files with the parameterization shown above, which you have to delete before trying to generate again.
In theory, you could now transpile the corrected file, but the export-CrescendoModule
command fails again, telling you that You cannot call a method on a null-valued expression
. Recall the warning earlier about changes to Crescendo's behavior. Microsoft has tinkered with the file format in Preview 3 to allow parallel execution of multiple commands. Documents previously published on the Internet that failed to take note of these changes lost their validity as a result. A JSON file usable for Crescendo Preview 3 requires an array that currently only contains the command needed to call winver
(Listing 2).
Listing 2
Commands Array for JSON file
01 { 02 "$schema": "../src/Microsoft.PowerShell.Crescendo.Schema.json", 03 "Commands": [ 04 { 05 "Verb": "Run", 06 "Noun": "TamsWinVer", 07 "OriginalName": ""/Windows/System32/winver.exe",", 08 "Parameters": [] 09 } 10 ] 11 }
Another change relates to the path passed in to $schema
. Crescendo worked best in tests with the working directory C:\Users\<User>\Documents\PowerShell\Modules\Microsoft.PowerShell.Crescendo\0.6.1\Samples
. The next step is to check the information contained in the Crescendo.json
file:
Import-CommandConfiguration .\tamswinver.Crescendo.json
Analyzing the JSON file leads to outputting all of the commands it contains. The Import-CommandConfiguration
cmdlet makes it convenient because the command does not create metafiles and is useful for testing to rule out gross syntax and other errors. If the table contains all the commands you created in your JSON file, it will probably work. The next step is to transpile:
Export-CrescendoModule -ModuleName "tamswinver1.psm1" -ConfigurationFile ".\tamswinver. Crescendo.json"
The use of winver
is a good choice at this point because the program performs a visible action when activated. The transpilation reproducibly activated the program. You need to take this into account if you will be running a program with potentially harmful side effects. You can now load the generated file like an ordinary PowerShell module:
Import-Module -Name '.\<tamswinver1.psm1>'
PowerShell 7.1.4 throws the error message WARNING: The names of some imported commands from the module …
if an "invalid" verb is used. It tells you that the cmdlet does not appear in some listing commands; however, this is not a problem for the experiments here; winver
can now be activated with Run-TamsWinVer
.
Last but not least, you need to delete the module from the module directory of the local PowerShell by running Remove-Module
and passing in the name of the PSM1 file without the file extension.
Buy this article as PDF
(incl. VAT)