‘What is what we wanted to achieve, again?’, said the driver, taking a step back from his/here keyboard.
‘Write our beloved .NET code to perform some tasks that can be invoked from the command line.’, answered the bewildered navigator, dilated pupils in awe for the departure of the driver from The Keyboard.
‘Oh, and that hassle of parsing arguments?’, the driver asked, taking a slow approach towards the lonely desk.
‘That? I prefer not to write it, thank you very much.’, suspired a relieved navigator.
‘Do you know who deals with command line arguments pretty nicely?’, questioned a mused driver.
‘A command-line shell!’, came out from the peers in unison.
‘Do you know any of those shells that is happy speaking to .NET code?’, the driver frowned. Silence seized the war-room for the first time in sprints. Everyone looked down or handled planning poker cards nervously, trying to look too busy to even answer the deep cry for help.
‘Any?’, one could feel despair in the pitch of the navigator’s voice.
‘How about one that is actually built on the .NET Framework!?’. The phrase sounded like a thunder while the door slammed open, pushed by the furious hand of The Team Lead, making his way back from a tiresome and unproductive status meeting, the last remanent of corporative practices that refuses to go away.
How about Powershell?
What if we did not have to write any argument parsing code because someone does a very good job already? What if we only had to write plain-old classes with methods and forget about dispatching because someone is able to instantiate our classes and call our methods?
Both desirables can be achieved using features of Powershell:
CmdletBinding()
to parse arguments and bind them to variables- The ability of Powershell to instantiate .NET objects though
New-Object
(previous use of[System.Reflection.Assembly]::LoadFile()
).
Our commands become single scripts with very little infrastructure to support calling methods on .NET classes that know nothing about Powershell or any other command line juju.
Let’s go through the important bits:
- LoadAssembly(): makes the types that implement our commands available to the script by (not suprisingly) loading the assembly into the script assuming the convention that the assembly resides in the same location as the script.
- Param section: Defines the arguments that our script can receive and binds them to a type (otherwise they all would be strings). It defines whether they are mandatory and decorates them with information.
- BuildOptions(): Packs the arguments of the script into the argument object that gets passed to the method which does the job.
- DoSomething(): Is the most important bit. It instantiates the class that does the job with the packed arguments already parsed.
Of all those moving parts, the only “infrastructure” (AKA boring stuff that has nothing to do with our problem at hand) is LoadAssembly()
.
The Challenges
Mandatory Arguments
Decorate the parameter with [Parameter(Mandatory=$True)]
at it becomes mandatory. If not provided, Powershell will prompt for it when executing the command:
Non-Textual Arguments
Just by decorating the parameter with the type that we want to convert to, Powershell will do the job for us. It the conversion is not successful, we would be getting a very informative, albeit dramatic, exception message:
Multi-Arguments
Just by defining the argument are string[]
and passing the values as comma-separated values, we are able to bind to collections:
It may be a little difficult to see, but the “here, there” fragment of the output contains an extra space that was not present in the input. That indicates, that
Showing Help
Powershell offers a lot of possibilities to display information: descriptions, examples,… The simplest we can do is display a short purpose of the command in the Synopsis section and explain each argument. Then use the standard Powershell Get-Help
command and voilá:
Is that it?
Actually not, the coolest feature of this way of working comes as help from the shell itself: auto-completion. After typing the name of the script that we want to invoke, hitting TAB will display a list of available arguments or complete if it is possible:
An here we can see Powershell’s feature of prompting missing mandatory arguments it all its glory:
Conclusion
We are only scratching the surface of what Powershell can offer, but it is a scratch I am going to keep. I told you, dear reader, my last console program has already been written. No matter how sweet console frameworks get, I won’t review any more.
From now on, all my eyes can discern is class libraries and thin Powershell wrappers. Oh, what is that over there? Could it be happiness?…
Last Console Series
- The Beginning
- Mono.Options
- NConsoler
- ManyConsole
- Powershell (this)