Double layered application with PowerShell in the middle

, 6 minutes to read

There are sev­eral rea­sons why use Pow­er­Shell. The most sig­nif­i­cant ad­van­tage is abil­ity to use script in­stead of user in­ter­face. Pow­er­Shell is for ad­min­is­tra­tor al­most the same en­vi­ron­ment as a con­sole ap­pli­ca­tion for de­vel­oper. When the core of your ap­pli­ca­tion is highly in­de­pen­dent so it is ex­treme easy build a con­sole ap­pli­ca­tion based on it con­sider us­ing Pow­er­Shell layer.

Why should I use a Pow­er­Shell in­ter­face in my ap­pli­ca­tion in­stead of di­rect ref­erenc­ing li­brary? When de­vel­oper wants to ex­plore a li­brary the first step is usu­ally con­sole ap­pli­ca­tion. It is de­vel­oper’s sand­box with quick graph­i­cal out­put be­cause ev­ery ob­ject has a ToString method. No ev­ery­one knows how to write a con­sole ap­pli­ca­tion. Ad­min­is­tra­tors like Pow­er­Shell where write-com­pile-run loop is much faster. De­vel­op­ers like code where a break­point can be set on ev­ery com­mand. So again – why Pow­er­Shell in­ter­face? The an­swer is not sur­pris­ing – be­cause it is very use­ful for a spe­cific kind of ap­pli­ca­tions.

When the code con­fig­ures some­thing there is clear that im­ple­ment­ing Pow­er­Shell sup­port is a great in­vest­ment. In my case I used a Pow­er­Shell in­ter­face for a crypt­anal­y­sis li­brary. There are many al­gorithms, but I didn’t want to hard­code steps how to decrypt an en­crypted mes­sage. I wanted give abil­ity to user use al­gorithms and de­cide based on heuris­tics and own judg­ment which ones put to­gether. It is sim­i­lar ap­proach like work­flow de­fined in XAML. What Pow­er­Shell can do best is a fast user in­ter­ac­tion and, of course, In­tel­liSense is not lost be­cause Pow­er­Shell has au­to­com­plete ca­pa­bil­ity.

Ar­chi­tec­ture is sim­ple. Li­brary im­ple­ments Pow­er­Shell interface. User in­ter­face runs a Pow­er­Shell host, gen­er­at­ing com­mands to it and re­ceiv­ing ob­jects from it to fill View­Models with. Im­ple­men­ta­tion of this pat­tern is not triv­ial for many rea­sons. First of all, there are ba­si­cally two ver­sions of .NET – 2.0 and 4.0 (1.0 is ob­so­lete, 3.0 and 3.5 are ex­ten­sions of 2.0). Pow­er­Shell has 2 ver­sions, third is cur­rently in a beta stage. Another com­pli­ca­tion is dual en­vi­ron­ment – 32 bit and 64 bit. I spent many hours solv­ing is­sues caus­ing these as­pects. When I was fi­nally done I felt duty to write an ar­ti­cle about it.

Let’s talk about li­brary point of view first. Li­brary has to ref­er­ence Sys­tem.Man­age­ment.Au­toma­tion li­brary which is part of Pow­er­Shell SDK. There are two im­por­tant classes – PSCmdlet and Cus­tomPSS­napIn. PSCmdlet is a com­mand which Pow­er­Shell can ex­e­cute and op­tion­ally re­turn an ob­ject or col­lec­tion. Cus­tomPSS­napIn is a set of Pow­er­Shell com­mands with ven­dor in­for­ma­tion in one pack. Your classes must derivate from them. Cmdlet classes must be dec­o­rated by Cmdlet at­tribute and the SnapIn class muse be dec­o­rated by RunIn­staller at­tribute. It is re­quired for re­flec­tion be­cause that’s how Pow­er­Shell finds cmdlets in your li­brary. Li­brary is com­piled to MSIL, so when you keep Any CPU con­fig­u­ra­tion, it works both in 32 bit and 64 bit en­vi­ron­ment. You should choose .NET Frame­work 3.5 against Pow­er­Shell 2 and .NET Frame­work 4 against Pow­er­Shell 3. SnapIn as­sem­bly com­piled as .NET 3.5 should works fine in Pow­er­Shell 3, but not vice versa.

The li­brary con­tain­ing cmdlets must be reg­is­tered. There is an In­stal­lU­til.exe do­ing this job for you. The prob­lem is this util­ity is plat­form de­pen­dent. Avoid­ing guess­ing which frame­work ver­sion run or when­ever use 32 bit or 64 bit vari­ant re­quires knowledge that this util­ity is just a wrap­per of As­sem­blyIn­staller class. This means that dur­ing ap­pli­ca­tion launch the li­brary can be eas­ily reg­is­tered so host­ing Pow­er­Shell knows about its ex­is­tence. Dur­ing ap­pli­ca­tion exit the li­brary is un­reg­is­tered so its lo­ca­tion can be changed in fu­ture without caus­ing any er­rors. This reg­is­tra­tion ap­proach doesn’t fit all sce­nar­ios at all. Li­brary reg­is­tra­tion should be made by in­staller rather that ap­pli­ca­tion it­self, but who likes in­stallers? Users who use Pow­er­Shell have of­ten User Ac­count Pro­tec­tion turned off be­cause they know re­ally well what they are do­ing.

User in­ter­face point of view is more dif­fi­cult. First of all it is worth to know that even 64 bit ap­pli­ca­tion runs 32 bit Pow­er­Shell in­s­tance. Ap­pli­ca­tion .NET Frame­work ver­sion is not im­por­tant. What is im­por­tant is abil­ity to ref­er­ence Sys­tem.Man­age­ment.Au­toma­tion li­brary. This li­brary is lo­cated in v1.0 di­rec­tory but it doesn’t mean that Pow­er­Shell 1 is used. Lat­est avai­l­able ver­sion is al­ways used.

When user in­ter­face launches a Pow­er­Shell host it must load the SnapIn first us­ing Ad­dPSS­napIn class in Run­s­pace­Con­fig­u­ra­tion. Then ap­pli­ca­tion can call Pow­er­Shell.Cre­ate method and use Pow­er­Shell com­mands de­fined in the li­brary. Ad­van­tage of Pow­er­Shell 3 is that is built on the top of Dy­namic Lan­guage Run­time. This means you can type PSOb­ject as dy­namic and shorten your code.

Hope this helps build­ing friendly con­fig­ured en­vi­ron­ments. When you know how to do that you will find it’s re­ally easy. Just fol­low the nam­ing con­ven­tions.