Group Policy ja User Account Control (UAC)

Hiljuti juhtus selline probleem: miskipärast ei võetud kasutajale Group Policy logon skriptiga külge võrguketast.  Täpselt sama juhtus ka siis, kui skripti asemel sai proovitud Group Policy Preferences funktsionaalsust.  Lähemal uurimisel selgus, et võrguketas võetakse külge küll, aga Windows Explorer ei tea sellest midagi.  Edasine uurimine viis KB artiklini, mis tõi asjasse valgust.

Nimelt tuleb välja, et võrguketaste külgevõtmine käib kasutaja mandaadi järgi.  Ja alates Windows Vistast on admin-õigustega kasutajatel (sisselülitatud UAC korral) alati kaks mandaati: üks administraatori õigustega ja teine ilma nendeta.  Ehk siis nagu ülalmainitud artikkel väidab, et kui võtta võrguketas külge admin-õigustes, siis tavaõigustes seda võrguketast näha ei ole.  Ja vastupidi.

Probleem aga on hoopis selles, et sama efekt tekib ka siis, kui võrguketas külge võtta Group Policy abiga.  See viitab sellele, et Group Policy rakendamine toimub arvutis enne, kui admin-õigustega kasutajale luuakse ilma admin-õigusteta mandaat ning käivitatakse töölaud.  Kes teab, mis seal veel võib tegemata jääda või vale mandaadi küljes olla…

Et asi veel keerulisem oleks, tuli välja, et kui Group Policy rakendamisel kasutati loopback processing režiimi, siis tulid võrgukettad kasutajale külge.  Seega rakendatakse loopback processing režiimis juba käivitatud töölaua seest (ehk siis mitte-admin õigustes).

Ülalmainitud artikkel väidab, et probleem esineb Windows Vista sees.  Tegelikult ilmneb see ka Server 2008 ja 2008 R2 (seega ka Windows 7) sees.  Ning väidetavasti on sama mure veel ka Windows 8 sees.  Nii et kui võrguketaste külgevõtmisega on probleeme, siis tasub otsida abi ülaltoodud artikli soovitustest.

Advertisements

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"