Photo by Larisa Birta on Unsplash

Photo by Larisa Birta on Unsplash

Convert Linux shell commands into PowerShell cmdlets

New Harmonies

Article from ADMIN 68/2022
By
Convert Linux shell commands into PowerShell cmdlets and modules and run them in a PowerShell environment.

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.

Figure 1: The second call to the Export-CrescendoModule command fails with an error message, telling you that the file already exists.

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

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

comments powered by Disqus