Powershell Remoting ja TrustedHosts

Powershelliga teises masinas toimetamine on süsteemiülema jaoks väga mugav.  Ent ilma erilise vaevata töötab see vaid domeeni keskkonnas.  Niipea, kui masin(ad) ei kuulu domeeni või kuuluvad domeenidesse, mis teineteist ei usalda, ei ole see enam nii lihtne.

Põhjus peitub selles, et kaugühenduse loomisel kontrollitakse nii kasutajat (et see tohib üldse kaugsessiooni luua) kui ka masinat (ühenduse looja kontrollib, et sihtmasin on ikka õige).  Ja kui masinad saavad autentimiseks oma domeenikontosid kasutada, ongi asi korras.

Kui aga domeenikontod ei sobi, siis saab asja siiski tööle.  Selleks tuleb ühendust loovas masinas kuidagi korraldada sihtmasina usaldusväärsus.  Üks võimalus oleks kasutada serte, aga see muudaks asja enamasti veelgi keerulisemaks.  Natuke lihtsam oleks sihtmasina lisamine usaldusväärsete masinate nimekirja.  Sinna nimekirja lisamine tähendab sisuliselt seda, et sihtmasina identiteeti enam ei kontrollita.

Nimetatud tegevust saab teostada ainult süsteemiülema õigustes kasutaja.  Ning teha saab seda näiteks järgnevalt:

#Requires -RunAsAdministrator
#Requires -Version 2

$NewList = "uusmasin, 192.168.2.3"

# salvestame praeguse listi
$OldHosts = (Get-Item WSMan:\localhost\Client\TrustedHosts).Value

# salvestame listi
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $NewList -Concatenate

Viimases reas lisatud käsurea parameeter korraldab selle, et uus väärtus lisatakse olemasolevale, mitte ei kirjutata üle. Tänud Kaidole, kes sellele parameetrile peale sattus 🙂

Nüüd tasuks sihtmasinas üle vaadata, kas ja kes kaugsessioonide kaudu üldse sisse saavad.  Vaikimisi saavad kaugsessioone kasutada vaid süsteemiülemad.  Alates Windows 8/Server 2012 keskkonnast on ligipääs lubatud veel lokaalse grupi Remote Management Users liikmetele.  Varasemate OS-versioonide puhul sellist gruppi pole ning seetõttu tuleks ligipääsuõigusi täiendada.  Lihtsaim viis oleks vastava dialoogiakna avamine:

#Requires -RunAsAdministrator
#Requires -Version 2
Set-PSSessionConfiguration Microsoft.PowerShell –ShowSecurityDescriptorUI

#Requires -Version 3
Set-PSSessionConfiguration microsoft.powershell.workflow –ShowSecurityDescriptorUI

Kui sihtmasin on Windows Server 2012 või kui sihtvõrgus on selline OS kättesaadav, siis saab kaugsessiooni häälestust mõnevõrra lihtsustada.  Nimelt on Server 2012-s olemas komponent Windows PowerShell Web Access (PSWA).  Ja see on sisuliselt veebisait, mis vahendab Powershelli käsurida veebilehitsejasse.  Jääb muidugi veel probleem, et Server 2012 (PSWA) masinast tuleb edasi sihtmasinasse saada ikkagi WinRM sessiooni kaudu ning kogu ülaltoodud jutt võib olla oluline.

Powershell ja admin õigused

Vahel on vaja, et skriptis saaks käivitada mingi osa teise kasutaja (adminni) õigustes.  Windows 2000/XP/Srv2k3 sees on võimalik kasutada käsku RunAs.exe, ja Powershell 1.0 aegu oli see ka pea-aegu kõik, mida kasutada sai.  Ainsaks alternatiiviks oli sarnane kood:

$credential = Get-Credential domain\user
[System.Diagnostics.Process]::Start("cmd.exe",
                                    "/c dir",
                                    "user",
                                    $credential.Password,
                                    "domain")

Vindows Vista väljatuleku järel muutus aktuaalseks User Account Control.  See tegi osad tegevused keerulisemaks ning tuli hakata kasutama kolmanda partei utiliite, nagu näiteks tutvustas Technet Magazine.  Nimetatud utiliidid kasutavad tegelikult Vista standardset rakenduste käivitamise liidest, mida saab kasutada ka otse skriptis, nii et ülaltoodud näite saaks ümber kirjutada kujule:

$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.Verb = "runas"
$psi.FileName = "cmd.exe"
$psi.Arguments = "/c dir"
[System.Diagnostics.Process]::Start($psi)

Powershell 2.0 teeb asja palju lihtsamaks.  Ainus asi, mida peab kasutama, on järgmine koodilõik:

#requires –Version 2.0
Start-Process -Verb runas -FilePath cmd.exe -ArgumentList "/c dir"

Mõlemad ülaltoodud skriptid kasutavad võimalust käivitada protsess režiimis Run As Administrator.  Pole vaja hiirega paremklõpsata või käivitada käsurida otsingulahtrist klahvikombinatsiooniga Ctrl-Shift-Enter.  Ent kui me tahaks rakendust käivitada mitte adminni, vaid kellegi teise õigustes?  Pole midagi lihtsamat:

#requires –Version 2.0
Start-Process -Credential domainuser -FilePath cmd.exe -ArgumentList "/c dir"

Ent mis saab siis, kui me tahaksime teise kasutaja (adminni) õigustes käivitada ainult osa skriptist?  Powershell 1.0 ajal tuli selleks see osa koodist panna eraldi skripti ning kahe ülemise koodinäite võimalusi käivitamaks powershell.exe koos käsurea parameetritega skripti käivitamiseks.  Powershell 2.0 lisab uusi võimalusi.  Järgnevate näidete eelduseks on see, et arvutis, kus koodinäide jooksma peaks, on Powershelli kaugkasutus sisse lülitatud.

Juhul, kui on vaja käivitada üksikuid käske/skripte:

#requires –Version 2.0
$session = New-PSSession -ComputerName . -Credential domainuser
Invoke-Command -Session $session -ScriptBlock {whoami.exe}

Juhul, kui on vaja pikemat interaktiivset sessiooni:

#requires –Version 2.0
$session = New-PSSession -ComputerName . -Credential domainuser
Enter-PSSession -Session $session

Mõlemad ülaltoodud näited võivad kasutada sessioonimuutujat korduvalt, kuni sessioon eksisteerib ja püsti on.

Lisaks ülaltoodule omavad paljud Powershelli käsud argumenti –Credential , mille abil saab nende käskude käivitamiseks kasutada teist identiteeti.  Selliste käskude loendi saab järgmise käsureaga:

Get-Help * -Parameter credential

#Requires -Version 3.0
Get-Command -ParameterName credential

Nüüd võib muidugi tekkida kiusatus salvestada identiteet ja seda edaspidi failist lugeda:

Get-Credential | Export-Clixml .\admin.xml

$user = Import-Clixml .\admin.xml
Start-Process -Credential $user -FilePath cmd.exe -ArgumentList "/c dir"

Siinjuures tuleb arvestada, et kuna salvestatud faili läheb nii kasutajanimi, kui parooli räsi, siis saab sama faili abil igaüks salvestatud identiteeti kasutada. Natuke parem variant oleks see, kui me salvestaksime ainult parooli:

#requires –Version 2.0
Read-Host -AsSecureString "Ütle üks parool" |
  ConvertFrom-SecureString |
  out-file .\parool.txt

$pass = Get-Content .\parool.txt | ConvertTo-SecureString
$user = New-Object -TypeName System.Management.Automation.PSCredential `
                   -ArgumentList "domain\kasutaja", $pass
Start-Process -Credential $user -FilePath cmd.exe -ArgumentList "/k dir"

Ka sellel lähenemisel on probleem, et igaüks, kes saab kätte korraga skripti ja paroolifaili, saab salvestatud parooli samas masinas kasutada.  Ainult skriptile või paroolifailile ligipääsu korral tuleb teist osapoolt mõistatama hakata. Ja kui püüda salvestatud parooli kasutada teises masinas, siis see ei tööta.

Saaks veel ka nii, et me kodeerime parooli räsi ära. See garanteerib, et salvestatud parooli saab erinevates masinates kasutada. Ent siis jääb küsimus, et kus/kuidas hoida koodi, millega parooli räsi kätte saab:

#Requires –Version 2.0

$parool = Read-Host -AsSecureString "Ütle üks parool"
$kood = Read-Host -AsSecureString "Ütle kood, millega parool kodeerida"
ConvertFrom-SecureString $parool -SecureKey $kood |
    Out-File .\turvaline.txt

$pass = Get-Content .\turvaline.txt |
    ConvertTo-SecureString -SecureKey $kood
$user = New-Object -TypeName System.Management.Automation.PSCredential `
                   -ArgumentList "domain\kasutaja", $pass
Start-Process -Credential $user -FilePath cmd.exe -ArgumentList "/k whoami"