Publikoval Michal Kočí dňa 29.6.2006 o 01:41 v kategórii PowerShell
CmdLet alebo CommandLet sa dá chápať ako príkaz v PowerShell-i (ďalej len PS). V samotnej podstate sa však jedná o triedu naprogramovanú v niektorom z .Net jazykov. Preto je vcelku jednoduché si v prípade potreby a/alebo chuti nejaký CmdLet naprogramovať.
Keďže sa jedná o triedu napísanú v niektorom .Net jazyku, je vhodné mať Visual Studio, prípadne jeho odľahčenú verziu z rady Express, napríklad Microsoft Visual C# 2005 Express Edition, ktorá sa dá bezplatne stiahnuť aj bezplatne používať dokonca aj na komerčné účely. Je potrebné triedu prísať pre .Net Framework (ďalej len FW) 2.0. Projekt ktorý bude obsahovať CmdLet musí referencovať assembly System.Management.Automation.Dll, ktorá sa nainštaluje spolu s PS, pretože CmdLet je trieda dediaca z triedy CmdLet alebo PsCmdLet nachádzajúcej sa práve v spomenutej assembly.
Tak ak to zhrniem, mali by ste mať na počítači nainštalované:
Power Shell je momentálne ešte len vo verzii Release Candidat 1, z čoho vyplýva niekoľko dôležitých faktov:
I keď je možné kód písať v textovom editore (napríklad Poznámkový blok) a prekompilovať cez príkazovú riadku kompilátorom, ktorý je súčasťou .Net FW, jednoduchšie je mať naištalované aj vývojové prostredie, napríklad Visual C# 2005 Express:
Či už použijete vývojové prostredie, alebo budete assembly s CmdLet-om kompilovať z príkazovej riadky, nezabudnite referencovať assembly System.Management.Automation.Dll, ktorú nájdete v adresári kde sa Vám nainštaloval Power Shell (pri čtandardnej inštalácii je to adresár c:\Program Files\Windows PowerShell\v1.0).
CmdLet je teda trieda zdedená z triedy Cmdlet alebo PsCmdlet. Navyše, trieda musí byť označená atribútom CmdletAttribute, kde špecifikuje sloveso a podstatné meno, ktoré sa bude používať pri volaní CmdLet-u z PS. Ak s PS pracujete, iste ste si všimli, že názov každého CmdLet-u sa skladá zo slovesa (anglicky verb), pomlčky a podstatného mena (anglicky noun), pričom podstatné meno sa uvádza v jednotnom čísle (napríklad Get-Process, Set-Date, ...). Pri tvorbe CmdLet-u je vhodné tento štandard dodržiavať a rovnako vhodné je použitie štandardného slovesa. Štandardné slovesá sa dajú získať ako statické polia niekoľkých statických tried, napríklad sloveso Get ako člen Get triedy VerbsCommon alebo sloveso Start ako člen Start triedy VerbsLifeCycle.
[Cmdlet(VerbsCommon.Get, "MsSqlDatabase")] public class GetMsSqlDatabaseCommand: Cmdlet { }
V príklade je vhodné si všimnúť:
Trieda dediaca z triedy Cmdlet (prípadne z triedy PsCmdlet, ktorá tiež dedí z Cmdlet) vykonáva samotné spracovanie v jednej z prepísaných metód BeginProcessing, ProcessRecord a/alebo EndProcessing. V ktorej, o tom je potrebné sa rozhodnúť na základe toho, čo má CmdLet vykonávať, aké parametre bude príjímať a či parametre bude prijímať z príkazovej riadky alebo z pipeline. Je vhodné poznať spôsob, ako a kedy sú tieto metódy zavolané PS-om:
Ak sa na to pozrieme z druhej strany a opäť zjednodušene, tak platí, že:
[Cmdlet(VerbsCommon.Get, "MsSqlDatabase")] public class GetMsSqlDatabaseCommand: Cmdlet { protected override void BeginProcessing() { } protected override void ProcessRecord() { } protected override void EndProcessing() { } }
Ako prvý príklad CmdLetu vytvoríme jednoduchý CmdLet Get-MsSqlDatabase, ktorý sa pripojí na Microsoft SQL server a zistí všetky jeho databázy. Pripojenie sa pre jednoduchosť bude konať v kontexte prihláseného užívateľa, teda bude použité integrované Windows overenie.
Aby bolo možné sa pripojiť k MS SQL Serveru, je potrebné špecifikovať ku ktorému serveru sa má CmdLet pripojiť. Názov serveru bude CmdLet prijímať z príkazového riadku. Aby CmdLet mohol prijímať parametre z príkazoveho riadku (ale vlastne aj z pipeline), je potrebné aby mal verejnú vlastnosť (public property), ktorá bude navyše označená atribútom ParameterAttribute. Týmto sa špecifikuje najmä:
Pridáme teda do triedy vlastnosť ServerName, bude to prvý parameter príkazového riadka, nebude možné ho plniť cez pipeline a bude to povinný parameter:
[Parameter(Mandatory=true, Position=0, ValueFromPipeline=false)] public string ServerName { get { return serverName; } set { serverName = value; } }
Čo je dobré vedieť:
Ak chceme, môžeme parametru priradiť aj alternatívny názov - alias. Slúži na to atribút AliasAttribute. Mohli by sme parametru ServerName priradiť aliasy Srv a
[Parameter(Mandatory=true, Position=0, ValueFromPipeline=false)] [Alias("Srv", "DbServer")] public string ServerName { get { return serverName; } set { serverName = value; } }
V tomto momente máme triedu, ktorá ešte nevykonáva žiadnu činnosť, ale už vie prijať parameter. V tomto momente by bolo možné CmdLet volať ľubovolným z nasledujúcich spôsobov (ak by bol zaregistrovaný v PS). Vychádzame z predpokladu, že nás zaujímajú databázy na serveri dbsrv1:
Výsledok všetkých vyššie uvedených volaní by bol rovnaký.
Keďže tento CmdLet prijíma iba jeden parameter a tento prijíma z príkazoveho riadku a nie z pipeline, spracovanie vykonáme v metóde EndProcessing. Skúsime sa pripojiť na požadovaný databázový server a zistíme názvy databáz z tabuľky sysdatabases z databázy master. Na zápis názvov databáz je použitá metóda WriteObject, ktorá ako prvý parameter prijáma samotný objekt, ktorý má byť výstupom a druhý parameter určuje, či výstupný objekt je členom kolekcie. V našom prípade je, pretože výstupom nášho CmdLet-u je kolekcia názvov databáz databázového servera.
protected override void EndProcessing() { string cs = string.Format( "Data Source={0};" + "Initial Catalog=master;" + "Integrated Security=SSPI;", serverName); string sc = "select dbid, name, crdate, filename " + "from master..sysdatabases order by name"; SqlConnection c = new SqlConnection(cs); SqlCommand cmd = new SqlCommand(sc, c); try { c.Open(); SqlDataReader dr = cmd.ExecuteReader(); if(dr.HasRows) { while(dr.Read()) { WriteObject((string) dr["name"], true); } } dr.Dispose(); } finally { cmd.Dispose(); c.Close(); c.Dispose(); } }
Keď máme triedu hotovú, isto by sme si radi CmdLet vyskúšali. Na to aby sme mohli CmdLet použiť v PS je potrebné vytvoriť SnapIn. SnapIn je akýsi zásuvný modul obsahujúci CmdLet-y a Provider-y. Ak chcete zaregistrovať iba ich istú podmnožinu, je potrebné SnapIn zdediť z triedy CustomPSSnapIn. V našom prípade budeme chcieť zaregistrovať všetky CmdLety obsiahnuté v assembly, preto SnapIn zdedíme z triedy PSSnapIn. V tomto momente máme síce len jeden CmdLet, ale na demonštráciu tvorby CmdLet-ov budeme programovať ešte jeden.
Popis uvedených tried nájdete tu:
Tým, že trieda zdedená z PSSnapIn zaregistruje všetky CmdLet-y stačí, ak v nej prepíšeme tri vlastnosti:
Kód potom vyzerá nasledovne:
[RunInstaller(true)] public class MsSqlPsSnapIn : PSSnapIn { public MsSqlPsSnapIn() : base() { } public override string Name { get { return "MsSqlPsSnapIn"; } } public override string Vendor { get { return "Mifko"; } } public override string Description { get {return "This is a snapin that includes the *-MsSql* cmdlets"; } } }
Všimnite si, že trieda MsSqlPsSnapIn je označená atribútom RunInstaller. Tento zabezpečí inštalovateľnost assembly nástrojom Installer Tool (InstallUtil.Exe). Aby šiel projekt skompilovať, je ešte potrebné pridať referenciu na assembly System.Configuration.Install.Dll, v ktorej sa nachádza trieda Installer, z ktorej PsSnapIn dedí.
Náš projekt sa teda skladá z dvoch hlavných súborov
Uvedené súbory si môžete stiahnuť ako projekt pre Visual Studio, respektí Visual C#. V súbore ponechávam aj prekompilovanú assembly pre tých, ktorým sa nechce projekt kompilovať, prípadne nemajú možnosť kompilácie: MsSqlSnapIn.v1.0.zip (8KB).
Po prekompilovaní projektu treba výslednú assembly nainštalovať spomenutým nástrojom nasledovne:
"c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe" MsSqlPsSnapIn.dll
V prípade že by ste chceli assembly odinštalovať, poslúži Vám nasledovný príkaz:
"c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe" /u MsSqlPsSnapIn.dll
Tak, keď je assembly nainštalovaná, je potrebné ju v PS pridať. Ak sa chcete presvedčiť, či je assembly v systéme nainštalovaná a je možné ju v PS pridať, použite príkaz:
Get-PSSnapin -Registered
Jeho výstupom by malo byť niečo podobné tomuto:
Name : MsSqlPsSnapIn PS Version : 1.0 Description : This is a snapin that includes the *-MsSql* cmdlets
To svedčí o tom, že assembly je nainštalovaná a že je možné SnapIn pridať do PS konzoly a následne využívať jeho CmdLet-y. Pridanie SnapIn-u do konzoly sa vykonáva príkazom Add-PSSnapin:
Add-PSSnapin MsSqlPsSnapIn
Hotovo. Akonáhle je SnapIn pridaný, je možné použiváť CmdLet Get-MsSqlDatabase. V krátkosti teda zhrniem hlavné body, ktoré treba vykonať, aby ste naprogramovali CmdLet a mohli ho používať v PS:
Toľko ukážka tvorby jednoduchého CmdLetu. Nabudúce sa pozrieme na trochu pokročilejšie možnosti programovania CmdLet-ov, konkrétne na:
Ak nechceš premeškať príspevky ako je tento, sleduj ma na Twitteri, alebo ak máš RSS čítačku, môžeš sledovať môj RSS kanál.