Temauke: Windows PowerShell del 4

I del 4 av denne artikkel-serien skal vi se på funksjoner og script i PowerShell.

Operatører

Før vi ser på hva funksjoner og script er skal vi se litt på operatører i PowerShell, siden de er en grunnleggende del man bør ha kjennskap til.

Vi starter med å se på oversikten over basisoperatører i PowerShell før vi tar noen eksempler med de mest brukte.

Arithmetic operators
+Addition, concatenation
Subtraction
*Multiplication, string repetition
/Division
%Modulus
Array operators
..Range operator
,Array operator
[]Array operator
Assignment operators
=Assigns a value to a variable
+=Adds a value to a variable
-=Subtracts a value from a variable
*=Multiplies a variable by a value
/=Divides a variable by a value
%=Performs a modulus on a variable
Comparison operators
-eqEqual To
-ltLess Than
-gtGreater Than
-geGreater Than or Eqaul To
-leLess Than or Equal To
-neNot Equal To
-isCompare types (2 -is int)
Logical and bitwise operators
-andAnd
-orOr
-notNot
!Not
-bandBitwise And
-borBitwise Or
-bnotBitwise Not
Redirection operators
>Create
>>Append
2>Redirect error output
2>>Redirect error output and append
2>&1Redirect error to output
Unary operators
++Increment a variable
Decrement a variable
+ –Indicate that a number is positive
– –Indicate that a number is negative
Containment operators
-contain
-notcontain
Text, pattern and string operators
-matchRegex pattern matching
-notmatchRegex pattern matching
-likeGlobbing pattern matching
-notlikeGlobbing pattern matching
-replaceReplace elements in a string
-joinJoin elements of a collection to a single string
-splitSplit strings into a collection of substrings
+Concatenate two strings
*Repeat a string some number of times
-fFormat a string

Eksempler på bruk av operatører

Enkel bruk av de aritmetiske operatørene.

Bruk av array operatører. I det siste eksempelet angir vi med tallet 3 i [] at vi vil hente det 4. elementet i det det definerte arrayet (husk at PowerShell starter på 0).

Bruk av assignment operatør. Her definerer vi et array med èn string, hvor vi ved hjelp av assignment operatøren += legger til enda en string.

Bruk av sammenlignings operatører. Disse returnerer false eller true.

Enkel bruk av logiske operatører.

Bruk av redirection operatører. Disse er relativt enkle å sette seg inn i.

Bruk av unary operators. Eksempelet viser hvordan disse kan brukes til å øke eller minske verdien på en variabel.

Bruk av containment operators. Disse returnerer false eller true, basert på om samlingen på venstre side innholder den angitte operatør-verdien.

Bruk av text, pattern og string operatører. Den mest kraftfulle av disse er –match operatøren, som lar oss bruke regular expressions. Det er utenfor scopet på denne artikkelen å gå i dybden på regular expressions, men det er sterkt anbefalt å se nærmere på dette for de som vil bli dyktige i scripting. Faktisk er det skrevet hele bøker om kun dette emnet, noe som sier litt om hvor omfattende det er.

Da har vi gått gjennom basis operatørene i PowerShell. Det er en fordel å ha erfaring med disse før man skal lage funksjoner og script, så det er anbefalt å prøve seg fram for å få litt erfaring før man går videre.

Funksjoner

PowerShell har 4 kommando-typer:

  • Functions – definert og navngitt PowerShell script-kode som ligger i minne i motsetning til et script som ligger lagret i en tekstfil. Funksjoner forkastes når PowerShell lukkes og må defineres på nytt for å kunne brukes i en ny PowerShell-sesjon. Funksjoner kan selvsagt også lagres i et script eller en såkalt PowerShell-profil for enklere gjenbruk.
  • Cmdlets – PowerShell-spesifikke kommandoer som bygger på en .NET class. Å lage cmdlets er typisk en utvikler-oppgave som krever bruk av PowerShell SDK (Software Developer Kit). Cmdlets har en verb-substantiv oppbygging (eksempelvis Get-Process), og det er definert en liste over godkjente PowerShell-verb, tilgjengelig med cmdlet`en Get-Verb og på MSDN.
  • Scripts – script-kode som ligger i en tekst-fil med fil etternavnet *.ps1
  • External commands – Native Windows kommandoer som kan kjøres av operativsystemet. Typisk kjørbare filer (exe-filer) som for eksempel ipconfig og netsh.

Vi skal nå se litt på bruk av funksjoner. Versjon 1.0 av PowerShell hadde en litt begrenset mulighet for funksjoner, mens PowerShell 2.0 som ble lansert sammen med Windows 7, introduserte en tiltrengt utvidelse. PowerShell har fra og med versjon 2.0 noe som heter “advanced functions” som tillater mer sofistikerte funksjoner.

En funksjon kan i sin enkleste form se slik ut:

NB: Eksemplene er skrevet i en PowerShell script editor for lettere lesbarhet med fargekoding

“function” er et såkalt keyword i PowerShell, og må stå først på linjen hvor funksjonen defineres. Etterfulgt av et mellomrom settes navnet på funksjonen, det er dette man kaller opp funksjonen med når den er definert. Etterfulgt av enda et mellomrom defineres funksjonens body i en såkalt statement-list. $args er en automatisk variabel som inneholder argumentene som sendes til funksjonen. I bruk ser den definerte funksjonen vi har laget slik ut:

Det neste vi skal lage er en funksjon som genererer brukernavn på en bestemt måte; 3 første tegn fra fornavn + 3 førte tegn fra etternavn + løpenummer.

På linje 1 definerer vi navnet på funksjonen.
På linje 2 definerer vi at fornavn skal bestå av tegn 0 til 3 basert på det første argumentet som sendes til funksjonen ($arg[0]).
På linje 3 definerer vi at etternavn skal bestå av tegn 0 til 3 basert på det andre argumentet som sendes til funksjonen ($arg[1]).
På linje 4 definerer vi variabelen $username som består av $firstname + $lastname + et løpenummer.
På linje 5 skriver vi resultatet av variabelen $username tilbake til kommandolinja. Vi angir at $username skal bestå av små bokstaver ved å kjøre metoden ToLower.

I bruk ser funksjonen slik ut:

Kombinert med Active Directory-modulen i PowerShell kunne man lagt inn en sjekk på om brukernavnet eksisterer, og isåfall øke verdien på løpenummeret (med unary operatøren ++) med 1 før man tar en ny sjekk på om brukernavnet eksisterer. Funksjonen ville da vært fullt brukbar i et produksjons-script for generering av brukerkontoer i Active Directory.

Script

Som nevnt innledningsvis i forrige avsnitt er et PowerShell-script kode lagret i en tekst-fil med filetternavnet *.ps1. Dette er den tradisjonelle metoden for lagring og deling av script-kode.

Før vi går videre skal vi se på sikkerheten rundt script-kjøring. I motsetning til det gamle kommandolinje verktøyet i Windows, cmd.exe, tillater ikke standard-innstillingene i PowerShell script-kjøring. Hvis du prøver å kjøre et script i PowerShell uten å endre “PowerShell execution policy” vil du få denne feilmeldingen:

PowerShell execution policy har 4 nivåer:

  • Restricted – ingen script-kjøring tillatt
  • AllSigned – krever at alle script er signert med en digital signatur
  • RemoteSigned – krever at alle script lastet ned fra internett er signert med en digital signatur. Script laget på lokal maskin tillates kjørt uten signatur.
  • Unrestricted – tillatter kjøring av alle script, både lokale og nedlastede fra internett.

Disse innstillingene kan styres ved hjelp av Group Policy i et domene-miljø.

Det er anbefalt å tillate kun signerte script (AllSigned) i et produksjonsmiljø, men for testing kan man benytte RemoteSigned. Unrestricted er det sterkt anbefalt å unngå, denne bør kun brukes i lab-miljøer hvor sikkerhets-nivået kan tillate dette.

Signering av script er utenfor scopet til denne artikkelen, men det kan være aktuelt å gå inn på i en senere artikkel om det er interesse for dette. Man kan komme i gang og finne linker til online ressurser ved å kjøre følgende fra en PowerShell-sesjon: Get-Help about_signing

En annen ting man må være klar over før man prøver å kjøre script er at PowerShell krever såkalt “dot-sourcing”. Forsøker man å kjøre et script uten dette vil man få følgende feilmelding:

Dot-sourcing vil si at man må sette inn et punktum og en backslash før scriptnavnet. Dette vil si at man vil kjøre det angitte scriptet fra gjeldende mappe:

Årsaken til at det kreves “dot-sourcing” er den samme som for standard execution policy; Sikkerhet. Microsoft`s policy er “secure by default”, og disse tiltakene i PowerShell forhindrer skadelig kode å kjøre. Et eksempel på dette er “I love you”-viruset som herjet for en del år siden, noe som ville vært unngått med sikkerhetsmekanismene i PowerShell, siden script ikke vil kjøre på en standard Windows installasjon hvor execution policy ikke er endret av brukeren/IT-avdelingen.

Et script kan i sin enkleste form se ut som eksempelet over:

Selv om script kan skrives i notepad vil jeg anbefale å bruke en scripteditor for å få tilgang til funksjoner som fargekoding, Intellisense, samt enklere muligheter for debugging (vi kommer nærmere tilbake til dette i del 7). Windows PowerShell 2.0 inneholder også et grafisk grensesnitt som heter PowerShell ISE (Integrated Scripting Environment), som er en veldig god innebygd scripteditor.

Andre gode scripteditorer som kan anbefales:

PowerGUI – Gratis produkt som i tillegg til å ha en god scripteditor er et verktøy som gir et grafisk grensesnitt over kommandolinjen i PowerShell, hvor man kan bygge egne såkalte PowerPacks. Også tilgjengelig i norsk språkdrakt for de som foretrekker det.
PowerShell Plus – Kommersielt produkt som inneholder et avansert interaktivt konsoll med blant annet Intellisense. Scripteditoren har støtte for enkel signering av script, og produktet har også et interaktivt learning center som er veldig nyttig.
Sapien`s PrimalScript – Også et bra kommersielt produkt med mange avanserte funksjoner.
PowerShell Analyzer – I likhet med PowerGUI et gratis produkt.

Alle har egne preferanser, så uten å komme med en direkte anbefaling vil jeg anbefale å prøve ut litt forskjellige script editorer for å finne en som passer deg.

Flyt-kontroll i script

Som i andre script-språk har PowerShell støtte for ulike såkalte statements for flyt-kontroll. Dette er innebygde mekanismer (keywords) som gjør det mulig å for eksempel utføre en handling på alle objekter i en samling av data. Den kanskje største fordelen i PowerShell kontra andre språk er bruk av pipeline hvor andre språk kun tillater enkle uttrykk (expressions).

Vi skal nå ta en gjennomgang av de ulike statement med eksempler som viser hvordan de kan brukes i praksis.

Conditional statements

If-statementet lar scriptet avgjøre om en handling skal utføres basert på evalueringen av angitte expression. Eksempel:

Selv om dette statementet lar seg skrive på èn linje er det vanlig å skrive det over flere linjer for bedre lesbarhet:

I dette tilfellet hvor $a er satt til verdien 10 vil statementet returnere “Verdien er større enn 5”.

Loop statements

En while-loop vil utføre angitte statement så lenge den angitte expression evalueres til $true. Eksempel:

Resultatet av denne while loop`en ser slik ut:

En do-while-loop er nesten det samme som en while-loop. Forskjellen er at angitte statement kjøres en gang før angitte expression evalueres. Forrige eksempel vil i en do-while-loop se slik ut:

En for-loop er en loop som lar scriptet gå gjennom en samling av objekter. Eksempel:

Det første elementet, $a=1, er den initielle verdien. Det andre elementet, $a –lt 6, er evalueringen det testes mot. Det tredje elementet, $a++, er en expression hvor verdien økes/minskes. Statementet utføres før det andre elementet evalueres til $true.

En foreach-loop er det mest brukte loop-statementet, og brukes for å utføre en handling på alle objekter i en samling av data. Eksempelet vi bruker her er et praktisk eksempel fra Active Directory hvor vi vil legge til alle brukere i domenet i en bestemt gruppe:

Vi definerer først samlingen av data (objekter) vi vi jobbe mot i variabelen $AllUsers.

Deretter definerer vi at foreach-loopen skal kjøres mot $user (dynamisk variabel som representerer hvert objekt i datasamlingen vi jobber mot) in $allusers.

For hvert objekt ($user i dette tilfellet) kjører vi Add-ADGroupMember for å legge til brukerne i angitt Active Directory gruppe.

Switch statement

Switch-statementet er det mest kraftfulle statementet i PowerShell. Basis funksjonaliteten er som i andre språk; Man kan velge en handling basert på en bestemt verdi (expression). I tillegg kan det behandle hele datasamlinger (collections) i motsetning til kun enkeltobjekter. Det støtter avansert pattern matching med –like og –match operatørene. I tillegg kan man kjøre hele filer gjennom switch-statementet, da typisk logg-filer etc. Store filer bør man være forsiktig med med tanke på ytelse og ressursbruk. Et enkelt eksempel:

Dette switch-statementet velger hva som skal returneres basert på verdien av variabelen $a.

Flow-control cmdlets

Selv om PowerShell i seg selv har støtte for flyt-kontroll gjennom de ulike statementene vi har sett på, eksisterer det også to cmdlets for dette.

ForEach-Object fungerer på mange måter som foreach statementet, men noen forskjeller er det. Ved bruk av ForEach-Object må man ikke assigne en dedikert variabel for hvert objekt i datasamlingen, man kan bruke den innebygde $_, som vil si “gjeldende objekt i pipeline”. En annen viktig forskjell er at foreach vil generere hele listen over objekter som skal behandles før noe utføres på disse objektene, mens ForEach-Object behandler ett og ett objekt. Når man jobber med store datamengder kan dette ha stor påvirkning på ytelsen. ForEach-Object har også støtte for flere såkalte script blocks; Begin (prosesseres før noen objekter prosesseres) , Process (prosesseres for hvert objekt) og End (prosesseres etter alle objekter er prosessert). Selv om det er flere nyanser mellom foreach og ForEach-Object har vi gått gjennom de viktigste. La oss se på et eksempel:

Her gjør vi det samme som i et tidligere eksempel, vi henter alle brukere i Active Directory, og for hvert objekt kjører vi en kommando som legger de til som medlem av en gruppe. I motsetning til foreach-varianten har vi ikke definert noen variabel for hvert objekt, men benytter i stedet $_.

Where-Object kan ses på som en enkel switch cmdlet. For hvert objekt i pipeline kjører den en scripblock, og dersom scriptblock`en evalueres til $true sendes objektet videre i pipeline. Et par eksempler:

Det første eksempelet henter alle brukere i Active Directory og disse pipes videre til Where-Object. Scriptblock`en i Where-Object sier at vi vil sende alle bruker-objekter som har Department-attributtet satt til “Salg”.

Det andre eksempelet henter alle servicer på maskinen og piper disse videre til Where-Object. Scriptblock`en sier at vi vil sende alle objekter som har Displayname er lik “Print Spooler”.

Break/Continue statements

I motsetning til andre språk har ikke PowerShell noe “goto:” statement, siden dette fort kan gjøre lange script veldig komplekse og vanskelig å sette seg inn i. I stedet har vi statementene break og continue, i tillegg til labeled loops. Med break og continue kan man påvirke hvordan en loop skal virke under gitte kriterier.

Eksempel på bruk av continue statement:

Denne foreach-løkken vil skrive alle tall mellom 1 og 10, unntatt 8, tilbake til konsollet. If-løkken indikerer at hvis det gjeldende tallet i løkken er 8, fortsetter loopen til neste objekt, og 8 skrives dermed ikke tilbake til konsollet. Hadde man i stedet brukt et break statement ville løkken avsluttet og verken 8, 9 eller 10 ville blitt returnert.

Eksempel på bruk av break statement:

Denne for-loopen kjører i utgangspunktet til tallet 50 er nådd, men ved hjelp av break-statementet i if-løkken som slår inn når tallet 10 er nådd vil scriptet bryte ut av loopen.

Eksempel på bruk av et labeled break statement:

Hvis $a har en verdi vil en ny while-løkke sjekke om $b har en verdi. Om $b har en verdi vil løkken kjøre for evig om man ikke har med et break statement. Når man i den indre løkken breaker til en label (den ytre løkka) vil scriptet gå ut av den indre loopen. Hadde man i den indre løkka kun skrevet break ville den kun breaket tilbake til while ($b) løkka, og den hadde kjørt for evig.

Hvis $b ikke har en verdi vil den ytre løkka kan avsluttes med kun break (uten label), siden den ikke er en del av en overordnet løkke.

Hvis $a ikke har en verdi vil ikke den ytre while-løkka kjøres, og dermed heller ikke den indre.

Oppsummering

I denne delen av artikkel-serien om Windows PowerShell har vi tatt en gjennomgang av de mest brukte operatørene, og sett på litt praktiske eksempler rundt bruken av disse.

Videre så vi på hvordan funksjoner og script er bygd opp, før vi avsluttet med en gjennomgang av flyt-kontroll i script og bruk av ulike statements.

Forhåpentligvis har denne gjennomgangen bidratt til å hjelpe deg på veien til å komme i gang med egne funksjoner og script. Nøl ikke med å komme med forslag til ting vi skal gå mer i dybden på i senere artikler, eller å spørre i forumet om det er noe du lurer på.

Kommentarer