Powershell spikri kirjutamine

Powershelli spikri kasutamisest sai mõnda aega tagasi kirjutatud. Nüüd vaataks, kuidas selle spikri sisu loomise ja muutmisega on.

Powershelli spikri süsteem kasutab info hoidmiseks XML-vormingut, mis on isegi dokumenteeritud. Ent sellega ümberkäimine on suhteliselt ebamugav ning see peab olema samas masinas, kus spikrit lugeda tahetakse. Seetõttu on spikri sisu dünaamiline muutmine/uuendamine natuke keeruline.

Teiseks on skriptidele spikri kirjutamisel võimalik kasutada XML-vormingu asemel hoopis skripti sisse käivat kommentaaripõhist spikrit. Muidugi saab kommentaaripõhisest spikrist alati viidata ka välisele (XML-põhisele) spikrile.

Kolmandaks on moodulite spikris niinimetatud about-teemad, mida hoitakse tavaliste tekstifailide kujul.

Powershell 3.0 lisas spikrisüsteemile veel Online-spikri ja spikri värskendamise toe. Aga see teeb elu veelgi ebamugavamaks, kuna nüüd tuleb hallata nelja erinevat vormingut:

  1. tekstifailid
  2. XML-vormingus spikker
  3. veebisait online-spikriga
  4. veebisait, kust saab muudetud spikri sisu alla laadida (ja sellega koos alla laetava spikri fail).

Õnneks paistab tunneli otsast valgust. Powershelli moodul platyPS pakub võimalust tuua kõik ülalmainitud spikri vormingud kokku ühe ja sama allika peale ning muuta spikri sisu samast allikast kättesaadavaks kõigis ülaltoodud vormingutes.

platyPS pakub võimalust hoida spikri sisu Markdown-vormingus, mis on inimloetav ja lihtsasti muudetav mistahes tekstiredaktoriga. Paljud veebisaidid oskavad Markdown-vormingut automaatselt näidata HTMLi kujul. Seega on Online-spikker sellega valmis.

Järgmine samm on XML-vorming. platyPS sisaldab käsku
New-ExternalHelp, millega saab Markdown-spikri teemad teisendada XML-vormingusse. Ja ühtlasi pakkida ka uuendatava spikri failiks, mida saab veebisaiti üles laadida.

Kui Sa leiad, et Markdown on koodist eraldi ning jääb seetõttu tähelepanuta, siis oskab platyPS teisendada kommentaaripõhise spikri Markdown-vormingusse. Nii et siis tuleb lihtsalt aeg-ajalt värskendada oma Markdown spikri teemasid ja need seejärel kättesaadavaks teha. Kommentaarid ise on alati koodiga koos ja seega kohe kättesaadavad koodi arendajale.

Powershell 6 plaanib kogu spikrisüsteemi viia XML-vormingult üle Markdown vormingusse. Juba praegu on Powershell 6.1-s lisatud käsk ConvertFrom-Markdown, mis loeb Markdown-vormingut ja muudab selle Powershelli käsurealt kasutatavaks.

Suuremates projektides tekib vajadus hoida dokumentatsioon (ja spikker) koodist lahus, kuna dokumenteerimisega võivad tegeleda teised inimesed. Ka sellisel juhul on Markdown-vorming hea. Ilus näide selle kohta on Microsofti dokumentatsiooni sait docs.microsoft.com. Kogu selle sisu on tegelikult Github’is üleval ja kaastööks kättesaadav.

Advertisements

Powershell Direct

Windows 10 ja Server 2016 võimaldavad luua PowerShelli sessiooni Hyper-V host masina pealt otse virtuaalmasinasse.  See funktsionaalsus kannab nime PowerShell Direct ja on isegi dokumenteeritud.

Dokumentatsioonist on välja kukkunud see pisiasi, et virtuaalmasina häälestuse versioon peab olema 8.0 või värskem.  Ilma selleta ei õnnestu virtuaalmasinaga ühendust saada.  Selle asemel tuleb veateade:

An Error has occured which Windows PowerShell cannot handle. A remote session might have ended.

Põnev on see, et nii saab ühendust isegi Windows 10 virtuaalmasinaga, milles on Powershell Remoting ikka veel välja lülitatud.

 

Powershelli tulevikust

Eelmine kord rääkisime sellest, kuidas tuvastada keskkonda, milles skript jookseb.  Sealt jäi välja üks pisiasi: kuidas tuvastada Nano Server või Server Core keskkonda.

Server Core keskkonnaga on lihtne, seal on meil tavaline Powerhsell keskkond ja OS funktsioonidega kaasatulevad haldusmoodulid.  Vajadusel saab seda kontrollida:

$regPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels\'

#Requires -Version 5.0
Get-ItemPropertyValue -Path $regPath -Name ServerCore

#Requires -Version 2.0
$RegKey = Get-ItemProperty -Path $regPath -EA SilentlyContinue
if ($RegKey."Server-Gui-Shell") {
  "Server with Desktop Experience"
} elseif ($RegKey.ServerCore) {
  "Server Core"
} elseif ($RegKey.NanoServer) {
  "Nano Server"
} else {
  "Not a Server OS"
}

Nano Server keskkonnaga on natuke raskem.  Nimelt on seal ruumi kokkuhoiuks OS funktsionaalsust vähendatud, sealhulgas .Net Framework on seal .Net Core, mitte täielik .Net Framework.  Ja kuna Powershell sõltub .Net keskkonnast, siis on ka Powershelli funktsionaalsus vähendatud.  Lisaks on puudu terve hunnik haldusmooduleid, mis tavaliselt olemas on.  Vähendatud funktsionaalsusega keskkond on tuntud kui Powershell Core edition:

$PSVersionTable.PSEdition

if ($PSVersionTable.PSEdition -like 'Core') {
  Write-Verbose 'Powershell Core'
} else {
  Write-Verbose 'Windows Powershell'
}

Skriptile võib lisada kontrolli, et vältida skripti käivitumist vales keskkonnas:

#Requires -Version 5.1
#Requires -PSEdition Core

Samuti on võimalik mooduli lisamisel/kasutamisel kontrollida, et see toetab keskkonda, kus teda kavatsetakse kasutada:

Find-Module -Tag PSEdition_Core

Get-Module -ListAvailable |
  Where-Object CompatiblePSEditions -Contains "Core"

Get-Module -ListAvailable | Where-Object {$_.CompatiblePSEditions}

Esialgu on moodulid ilma vajaliku infota manifestis, ent Windows 10 v1809 on OS-iga kaasatulevad moodulid juba ilusti märgistatud.  Powershell Gallery moodulid on juba sildistatud või siis ei ole mooduli autor pidanud seda vajalikuks.

Arvestades, et Powershell 6 on juba olemas, tasub tähele panna:

  • Windows Powershell 5.1 on viimane omast klassist ja seda edasi ei arendata.
    • Kõik Windows Powershelliga seotud probleemid/ettepanekud tuleb raporteerida UserVoice saidis.  Vigade parandusi väidetavasti veel tehakse.
  • Powershell v6 on täielikult Powershell Core.  Seda ei panda Windowsiga kaasa, kuna seda arendatakse korraga mitmele platvormile: Windows, Linux, macOS.
  • Powershell Core paigaldatakse Windows Powershelli kõrvale ja see tuleb käivitada kui pwsh.exe
  • kogu tulevane arendus toimub Powershell Core peal.
    • kõik Powershell Core-ga seotud probeemid/ettepanekud tuleb esitada Github saidis.
  • Powershell Core ei sisalda enam järgmiseid asju:
    • Powershell ISE liides.  Arendustiim pakub alternatiivina kasutada Visual Studio Code redaktorit, mille Powershelli plugin on suht tasemel.
    • Töövoogude (workflow) mootor.
  • Desired State Configuration saab samuti ümber kirjutatud .Net Core baasil.
  • Powershell 2.0 režiimist on kavas lahti saada.

Powershell Core kasutamisel on vaja tuvastada ka OS, mille peal joostakse.  Kuna CimCmdlets moodul pole veel Powershell Core osa, kui OS ei ole Windows, siis tuleb OS tuvastada teist moodi:

$PSVersionTable.PSEdition

#Requires -PSEdition Core
$PSVersionTable.OS

if ($PSVersionTable.PSEdition -like "core" ) {
  "Powershell core, OS: {0}" -f $PSVersionTable.OS
} else {
  "Windows Powershell"
}

#Requires -Version 6
$IsWindows
$IsMacOs
$IsLinux

Praegu veel ei ole, aga tulevikus peaks moodulite manifesti ilmuma ka toetatud OS-i näitamine.

Kokkuvõtteks võib öelda, et juba praegu tasub vähehaaval oma skripte/mooduleid üle vaadata ning lisada vajalikud kontrollid, et vales keskkonnas mitte tundmatuid veateateid saada.

Mis keskkonnas mu skript jookseb

Iga Windowsi süsteemiülem peab oskama PowerShelli kasutada.  Kui ta seda ei oska, siis ei saa ta ennast Windowsi süsteemiülemaks nimetada.  Ja vähehaaval nad seda ka õpivad (kui nad juba ei oska).

Kõik on väga tore, kuni me teame, millises masinas me oma asju jooksutame.  Aga kui me oleme jõudnud juba sinnamaale, et koodi jooksutatakse automaatselt, siis läheb elu keerulisemaks.  Nimelt tuleb siis hakata tuvastama, et mis keskkonnas kood parasjagu jookseb.  Sest kui seda mitte teha, siis võib kood mitte töötada.

Üks esimesi asju mida tuvastada on see, et kas meil on ka süsteemiülema õigused.  Seda on lihtsaim teha, kui luua omale abistav funktsioon:

function Test-IsAdmin {
  $AdminRole = [Security.Principal.WindowsBuiltinRole]::Administrator
  $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
  $CurrentUser = [Security.Principal.WindowsPrincipal] $CurrentIdentity
  $CurrentUser.IsInRole($AdminRole)
}

Ja siis saab seda kasutada.  Alates Powershelli versioonist 4.0 on ka teine viis (täpsem info Powershelli spikris):

if (-not (Test-IsAdmin)) {
  throw "Süsteemiülema õigused vajalikud, katkestan"
}

#Requires -RunAsAdministrator

Kui süsteemiülema õigused on puudu, siis saab neid vajadusel omandada.  Sellest sai kirjutatud varem.

Tasub tähele panna ka seda, et #Requires kontrollid töötavad ainult salvestatud skripti sees ning neid kontrollitakse juba skripti laadimisel.  See tähendab, et kui nõue pole täidetud, ei käivitata skripti üldse ning seetõttu ei saa ka skripti sees midagi selle suhtes ette võtta.

Kui Sa jooksutad oma skripte erinevate Powershelli versioonide peal, siis on vaja ka seda kontrollida.  Selleks oli kaks meetodit:

if ($PSVersionTable.PSVersion -lt "5.0") {
  throw "see on vale PowerShelli versioon"
}

#Requires -Version 5.0

Neist esimese puhul ei pea tingimata skripti tööd katkestama.

Windows 8-st alates hakkasid Powershelli moodulid kaasa tulema ka opsüsteemiga.  Samuti on vaja moodulite olemasolu kontrollida juhul, kui kasutada mõnd lisatud funktsionaalsust.  Ka seda saab kahte moodi teha:

if (-not (get-module Hyper-V -ListAvailable)) {
  Write-Error "Vajalik funktsioon puudu, katkestan" -EA Stop
}

#Requires -Modules Hyper-V

Vajadusel saab kontrollida ka mooduli versiooni:

$ModuleId = @{ModuleName='Hyper-V';ModuleVersion="2.0.0.0"}
if (-not (Get-Module -FullyQualifiedName $ModuleId -ListAvailable)) {
  throw "Vajalik moodul puudu, katkestan"
}

#Requires -Modules @{ModuleName="Hyper-V";ModuleVersion="2.0.0.0"}

Kui moodulite halduseks on oma koodihoidla, siis saab muidugi lihtsamalt:

#Requires -RunAsAdministrator
#Requires -Modules PowerShellGet
Find-Module UserProfile -MinimumVersion 1.0 -Repository PSGallery |
  Install-Module -Force -Scope AllUsers

Get-InstalledModule | Update-Module

Aga vahel ei piisa ka mooduli olemasolu/versiooni kontrollist.  Näiteks on Windows 8.1-ga kaasas olevas moodulis (NetTCPIP) olemas käsk Test-NetConnection, mida Windows 8-ga kaasas olevas moodulis pole.  Aga mooduli versiooninumber on mõlemal sama.  Siis tuleb kontrollida konkreetse käsu olemasolu:

if (Get-Command Test-NetConnection -ErrorAction SilentlyContinue) {
  #olemas, võib tegutseda
} else {
  Write-Error "käsk puudu"
}

Get-Command telnet

Vahel oleks vaja hoopis teada, kas mõni opsüsteemi funktsioon on antud masinas olemas või puudu.  Windows Serveri haldusliidesed on funktsionaalsustest eraldi paigaldatavad ning võivad paikneda hoopis teises masinas.  Serveriga on asi lihtne.  Kui skripti jooksutavas masinas on ServerManager moodul (seda saab ka klient-OSile paigaldada, kui tõmmata omale RSAT)

if (-not (Get-WindowsFeature -Name RSAT-DNS-Server).Installed) {
  Install-WindowsFeature -Name RSAT-DNS-Server
}
#olemas, võib tegutseda

Klient-OSi puhul on see natuke keerulisem:

#Requires -Modules Dism
#Requires -RunAsAdministrator

# Win10/Srv16/Srv19
Get-WindowsCapability -Online -Name OpenSSH.Client*

$Feature = Get-WindowsOptionalFeature -Online -FeatureName telnet*
if ($Feature.State -eq [Microsoft.Dism.Commands.FeatureState]::Disabled) {
  Enable-WindowsOptionalFeature -Online -FeatureName TelnetClient
}

Nüüd jääb veel vaid üle kontrollida, et kas meil on käes server-OS või midagi muud:

#Requires -Modules CimCmdlets
switch ((Get-CimInstance Win32_OperatingSystem).ProductType) {
  1 { "Workstation"}
  2 { "DC" }
  3 { "Server" }
}

Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion" |
  Select-Object -Property EditionId, InstallationType

#Requires -Modules Dism
#Requires -RunAsAdministrator
if ((Get-WindowsEdition -Online).Edition -like 'Server*') {
  "on server"
} else {
  "klient, vist"
}

Olen seni teadlikult vältinud OS versiooni kontrolli.  nagu ülaltpoolt näha, pole seda enamasti vaja.  Ent arvestades Windows 10 (ja nüüd kohe varsti ka Server 2016) väljalaske tsükliga, võib seda vaja minna:

if ([environment]::OSVersion.Version -ge "6.3") {
  "Windows 8.1 või värskem"
}

Õnnetuseks otsustas Microsoft antud viisile panna peale kontrolli: kui rakendus ise ei deklareeri, et ta tunneb uuemaid OS versioone, siis valetatakse talle versiooniks alati “6.2.9200” ehk siis Windows 8/Server 2012.  Lisaks on Windows 10 versiooninumbri algus kõigil väljalasetel sama, muutub ainult BuildNumber.  Seda aga saab kontrollida:

#Requires -Modules CimCmdlets
switch ((Get-CimInstance Win32_OperatingSystem).BuildNumber) {
  10240 {"Win10 RTM"}
  10586 {"Win10 1511"}
  14393 {"Win10/Svr16 1607"}
  15063 {"Win10 1703"}
  16299 {"Win10/Svr16 1709"}
  17134 {"Win10/Svr16 1803"}
  17763 {"Win10/Srv19/Svr16 1809"}
  default {"Insider/future build"}
}

Tegelikult saaks siin registrist info mugavamini kätte:

#Requires -Version 5.0
$RegPath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion"
Get-ItemPropertyValue -Path $RegPath -Name ReleaseId

Get-CimInstance kasutamine võimaldab teha kontrolli ka eemalt.  Samamoodi saab ka versiooninumbri kätte.  Tuleb lihtsalt arvestada, et CIM tagastab versiooninumbri kui stringi ja see tuleb ise versiooninumbriks teisendada, kui seda vaja peaks olema:

#Requires -Modules CimCmdlets
(Get-CimInstance Win32_OperatingSystem).Version -as [version]

PowerShell Linuxile

Ja ongi saanud tõeks see, mida juba mõnda aega oodatud on.  Powershell on kättesaadav Linuxi ja Mac OS X platvormile.  Koos sellega on Powershelli lähtekood tehtud avalikuks ning on saadaval GitHubis Powershelli projekti saidis.

Vastav info on väljas ka Powershelli kodulehel .

Muuhulgas tasub mainida, et koos Windows 10 aastapäeva väljalaskega tuli välja ka Windows Management Framework (WMF) 5.1 .  Varasematele platvormidele on praegu saadaval vaid eelvaate versioon.  Ning Windows 7 ja Server 2008-le paigaldamisel eeldatakse, et WMF 4.0 on masinas juba olemas…

Nagu ka varasemate versioonidega, ei tasu seda installida Exchange või Sharepoint serverisse.

Powershell 5.0 lõpuks valmis

Sel nädalal sai valmis Windows Management Framework (WMF) 5.0, mis muuhulgas sisaldab Powershell 5.0 versiooni.  Toetatud on Windows Serveri (2008 R2 kuni 2012 R2), ning pärast klientide sooviavaldust on toetatud ka Windows klient-OS (7 ja 8.1).

See versioon asendab Powershell 5.0 Production Preview versiooni (seda pole vaja enne maha võtta).  Seetõttu on paigaldamise eeltingimused enam-vähem samad.  Server 2008 R2 puhul tuleb enne masinasse paigaldada WMF 4.0 .  Lisaks tuleb arvestada, et Powershell WorkFlow ja DSC vajavad mõlemad sisselülitatud WinRM-i.

Kui funktsionaalsuse osas tekib mõtteid, mida tahaks arendajatega jagada, siis UserVoice saidis on eraldi Powershelli foorum, mis asendab endist Microsoft Connect saiti.

Exchange 2013 uuenduste paigaldus

Sai hiljuti just läbi tehtud Exchange 2013 serverile uuenduste paigaldus.  Ja pärast seda olen veendunud, et ainuke õige viis Exchangele uuenduste pealepanekuks on olemasoleva serveri kõrvale uue paigaldamine ning rollide ületõstmine.  Sest nii hoiab kõvasti närve ja tõenäoliselt ka aega kokku.  Ning lisaks muudele eelistele saab uuendamist teha rahulikult keset päeva.

Exchange on juba pikka aega olnud selline keskkond, kus parandused lastakse välja ühe komplektina.  Ning Exchange 2013 puhul on seesama komplekt sobiv ka uue serveri paigalduseks.  Aga kui Sa järele proovid, siis tuleb välja, et testitud on ainult tühja masinasse Exchange paigaldust.

Mis siis valesti on?  Paigaldusprotsess on jagatud mitmeks sammuks.  Iga samm paigaldab/uuendab ühe komponendi.  Uuendamise puhul võetakse sammu alguses ports teenuseid (sealhulgas Exchange teenused), pannakse need seisma ja keelatakse nende käivitamine.  Kuskil paigalduse käigus aga läheb neid teenuseid järsku vaja ning teenused käivitatakse uuesti.  Windowsi teenustega on tavaliselt kõik hästi, ent Exchange enda teenuste puhul on paigaldusprotsess unustanud, et teenused keelati ära.  Ja tulemuseks on veateade ning poolik paigaldus.

Mis halvasti, see uuesti.  Aga tulemuseks on sama probleem, kuna paigalduse sammu alguses keelatakse teenused ning töö käigus püütakse neid uuesti käivitada.  Ja seda hoolimata sellest, et antud sammu on juba korduvalt jooksutatud…

See probleem pole Exchange 2013 Cumulative Update 10 juures unikaalne, vaid eksisteerib juba mitu aastat.  Ning kuskilt otsast pole näha, et midagi muutuks.

Kui ülaltoodud jutt pole Sind veel piisavalt ära hirmutanud ja Sa siiski proovid, siis varu kannatust ning ära mine arvutist kaugele, sest paigaldusprotsessi tuleb pidevalt järele aidata.

Enne alustamist tasuks salvestada hetke teenuste häälestus.  Seda saab teha näiteks Powershelliga:

Get-CimInstance -ClassName Win32_Service |
  Select-Object Name, StartMode , State |
  Export-Csv -Path .\teenused.csv -UseCulture -Encoding Default

Kui jooksva sammu progress on jõudnud ~3% peale, siis tuleks (tavalises) Powershellis käivitada järgmised käsud:

Get-Service -Name msexchange*, fsm |
  Set-Service -StartupType Manual

Ja sedasi iga kord, kui paigaldus uue sammu peale läheb.  Seetõttu ei tohigi masinast kaugele minna, sest teenused tuleb uuesti käivituvaks teha, muidu jääb paigaldus pooleli. Ja tuleb jälle kõik sammud läbi käia…

Kui nüüd paigaldus on lõppenud, siis on kogu selle sebimise käigus läinud kaduma teenuste varasem staatus.  Seetõttu tuleb see ise taastada:

$teenused = Import-Csv .\teenused.csv -UseCulture

$teenused | Where-Object StartMode -Like "Auto" |
  ForEach-Object {
    Set-Service -Name $_.name -StartupType $_.StartMode
  }

$teenused | Where-Object State -Like "Running" |
  Start-Service

Tegelikult salvestab Exchange paigaldus samuti teenuste häälestuse.  Ent miskipärast häälestuse taastamisega paigalduse lõpus enam hakkama ei saadud.