Az én példám egy helpdesk csapat számára kialakított speciális távoli hozzáférési felület a tartományvezérlőhöz, amin keresztül a helpdesk szakemberek az Active Directory csak lekérdező parancsaihoz férnek hozzá, ezen kívül csak a munkájukhoz szükséges Set-ADAccountPassword és Set-ADUser parancsokhoz. Nem ez jelenti a tényleges biztonsági beállítást, hiszen az AD-ben jogok delegálásával kell azt beállítani, de a PowerShell lehetőségek szűkítése hatékonyabbá teszi a munkavégzést, hiszen még véletlenül sem tévedhetnek a munkatársak olyan cmdletek közelébe, amelyek futtatása során úgyis jogosultsági hibajelzéseket kapnának.
Elsőként létrehozom a tartományvezérlőn azt a szkriptet, amelyik majd kialakítja a lekorlátozott környezetet. Ehhez Windows Server 2008 R2 tartományvezérlő vagy Management Gateway kell, hiszen ott áll rendelkezésre az ActiveDirectory modul:
Import-Module activedirectory
$commands = (Get-Command -Module activedirectory |
where-object {$_.verb -eq "get"} | %{$_.name}
)
$commands += "Set-ADUser"
$commands += "Set-ADAccountPassword"
"Get-Command", "Get-FormatData", "Select-Object",
"Get-Help", "Measure-Object"
| ForEach-Object {$commands += $_ }
$ExecutionContext.SessionState.Applications.Clear()
$ExecutionContext.SessionState.Scripts.Clear()
Get-Command | ?{$Commands -notcontains $_.name} |
ForEach-Object {$_.Visibility="Private"}
$ExecutionContext.SessionState.LanguageMode="RestrictedLanguage"
Első lépésként importálom tehát az ActiveDirectory modult, hiszen a helpdeskeseknek biztosítani akarom a címtárral kapcsolatos cmdletek egy részét. Ezután pont a számukra szükséges parancskészletet alakítom ki azzal, hogy kiválogatom a számukra elérhető cmdleteket a $commands változóba. Ezek a cmdletek az AD modul összes Get igéjű cmdletje, plusz az ő tevékenységükhöz szükséges két Set cmdlet, a Set-ADUser és a Set-ADAccountPassword. Valamint van néhány kötelezően engedélyezendő cmdlet, ezeket látjuk a következő sorban. Ezekkel túl sok kárt nem lehet okozni, így ennek semmilyen biztonsági kockázata sincsen, viszont enélkül nem működik a távoli futtatási környezet.
Ezután az $ExecutionContext automatikus változó SessionState tulajdonságának jellemzőit állítom be. Egyrészt letiltom az elérhető alkalmazásokat. Ilyen alkalmazás pl. a WinRM szolgáltatás használata, azaz letiltom, hogy az ide, a tartományvezérlőhöz kapcsolódó személy még távolabbi gépre kezdeményezhessen távoli kapcsolatot. Hasonló módon a szkripteket is letiltom, azaz például a helyi profilok szkriptjeit.
Ezután az összes elérhető cmdletet, amelyek nincsenek rajta az engedélyezett cmdletek listáján, láthatatlanná teszem azáltal, hogy a Visibility tulajdonságukat Private-ra állítom.
A legvégén az egész környezetet ebben a formában lezárom, hogy nehogy ezeket a beállításokat vissza tudja csinálni a leleményes helpdeskes. Ezt a LanguageMode tulajdonság beállításával tettem meg.
Ezután szintén a tartományvezérlőn létrehozok egy új távoli kapcsolódási környezetet, egy un. PSSessionConfiguration objektumot. Előtte, ha szükséges, engedélyezzük a távoli futtatás lehetőségét:
Enable-PSRemoting # ha még nem volt engedélyezve
register-pssessionConfiguration -name HelpDesk -startupScript ` C:\lurdy\startup.ps1 –ShowSecurityDescriptorUI
Ez létrehoz egy HelpDesk nevű „játszóteret” távoli futtatás céljára, ahol tehát eleve be lesz importálva az ActiveDirectory modul, viszont egy csomó cmdlet nem lesz elérhető. Mindezt a korábban látott startup.ps1 szkript alakítja ki. Ezt a játszóteret még a jogosultság megfelelő beállításával is védjük, hogy ne csatlakozhasson ide bárki, mindjárt látjuk, hogy hogyan.
Ezt futtatva ilyen kimenetet kapunk:
[62] PS C:\> register-pssessionConfiguration -name HelpDesk -startupScript ` C:\lurdy\startup.ps1 –ShowSecurityDescriptorUI
Confirm
Are you sure you want to perform this action?
Performing operation "Register-PSSessionConfiguration" on Target "Name:
HelpDesk. This will allow administrators to remotely run Windows PowerShell
commands on this computer".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):y
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin
Name Type Keys
---- ---- ----
HelpDesk Container {Name=HelpDesk}
Confirm
Are you sure you want to perform this action?
Performing operation ""Restart-Service"" on Target "Name: WinRM".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):y
Confirm
Are you sure you want to perform this action?
Performing operation "Restart-Service" on Target "Windows Remote Management
(WS-Management) (winrm)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):y
Néhány megerősítést kért tőlünk, és megjelent (lásd alább) a –ShowSecurityDescriptorUI kapcsoló hatására a következő grafikus dialógusablak:
137 . ábra Grafikus - karakteres együttműködés
Ezen a felületen megadtam a Helpdesk Hugó részére (a demó rendszeremen ő szimbolizálja a helpdesk csoportot) a szükséges Execute (Invoke) jogot. Itt ezt sokkal egyszerűbb beállítani, mint a karakteres konzolon, de ott is meg lehetett volna tenni.
Nézzük, hogy a távoli gépen hogyan lehet ehhez a környezethez csatlakozni:
PS C:\> $s = New-PSSession -ComputerName dc -ConfigurationName helpdesk
Ez nem túl bonyolult, de vajon hogyan tudja lekérdezni Hugó a felhasználókat az AD-ből?
PS C:\> Invoke-Command -Session $s -ScriptBlock {get-aduser -filter 'name -like
"főn*"'}
PSComputerName : dc
RunspaceId : 81cb2f79-afa9-4e9a-8552-f8d296380932
PSShowComputerName : True
DistinguishedName : CN=Főnök Ferenc,OU=Managed Users,DC=r2,DC=dom
Enabled : True
GivenName : Ferenc
Name : Főnök Ferenc
ObjectClass : user
ObjectGUID : a067ce05-b902-4f26-812e-4bbb62280ea8
SamAccountName : ff
SID : S-1-5-21-3398938913-3940250523-927435294-1123
Surname : Főnök
UserPrincipalName : ff@r2.dom
Itt már némi szomorúságot vélek felfedezni lelki szemeim előtt Hugó arcán. Elég macerás ez neki, főleg, hogy a „restricted” üzemmódú környezetben nem használhat scriptblock adattípust, így a –Filter-hez idézőjellel kell megadnia a feltételt. Szerencsére a PowerShell nagyon humánus, nem kárhoztatja a szegény helpdeskeseket állandó Invoke-Command parancsok használatára, mert be lehet importálni a távoli környezet lehetőségeit a lokális környezetbe az Import-PSSession cmdlet segítségével:
PS C:\> Import-PSSession -Session $s
ModuleType Name ExportedCommands
---------- ---- ----------------
Script tmp_e8a8b3de-e7fe-472a... {Get-ADUser, Get-ADServiceAccount, Get...
Ez a parancs „áthozza” a távoli környezet cmdleteit, valójában ugyanolyan nevű függvényeket hoz létre, mint a távoli cmdletek, és ebbe a függvénybe ágyazza be azt az Invoke-Command kifejezést, ami valójában a távoli parancsot végrehajtja. Nézzünk ezeket a függvényeket:
PS C:\> Get-Command -CommandType function | ?{$_.name -match "-AD"}
CommandType Name Definition
----------- ---- ----------
Function Get-ADAccountAuthorizationGroup ...
Function Get-ADAccountResultantPasswo... ...
Function Get-ADComputer ...
Function Get-ADComputerServiceAccount ...
Function Get-ADDefaultDomainPasswordP... ...
Function Get-ADDomain ...
Function Get-ADDomainController ...
Function Get-ADDomainControllerPasswo... ...
Function Get-ADDomainControllerPasswo... ...
Function Get-ADFineGrainedPasswordPolicy ...
Function Get-ADFineGrainedPasswordPol... ...
Function Get-ADForest ...
Function Get-ADGroup ...
Function Get-ADGroupMember ...
Function Get-ADObject ...
Function Get-ADOptionalFeature ...
Function Get-ADOrganizationalUnit ...
Function Get-ADPrincipalGroupMembership ...
Function Get-ADRootDSE ...
Function Get-ADServiceAccount ...
Function Get-ADUser ...
Function Get-ADUserResultantPasswordP... ...
Function Set-ADAccountPassword ...
Function Set-ADUser ...
Láthatjuk, hogy az elérhető AD cmdletek tényleg csak a Get igéjűeket tartalmazzák, plusz a Set-ADAccountPassword és a Set-ADUser. Pillantsunk bele egy függvénydefinícióba is (kicsit megvágtam a paraméterdefiníciós rész):
PS C:\> ${function:get-aduser}
param(
[Alias('db')]
[Switch]
${Debug},
[Alias('wv')]
${WarningVariable},
[Alias('Property')]
${Properties},
${SearchBase},
${ResultPageSize},
${Credential},
…
begin {
try {
$positionalArguments = & $script:NewObject collections.arraylist
foreach ($parameterName in $PSBoundParameters.BoundPositionally)
{
$null = $positionalArguments.Add( $PSBoundParameters[$paramete
rName] )
$null = $PSBoundParameters.Remove($parameterName)
}
$positionalArguments.AddRange($args)
$clientSideParameters = Get-PSImplicitRemotingClientSideParameters
$PSBoundParameters $True
$scriptCmd = { & $script:InvokeCommand `
@clientSideParameters `
-HideComputerName `
-Session (Get-PSImplicitRemotingSession -CommandNa
me 'Get-ADUser') `
-Arg ('Get-ADUser', $PSBoundParameters, $positiona
lArguments) `
-Script { param($name, $boundParams, $unboundParam
s) & $name @boundParams @unboundParams } `
}
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation
.CommandOrigin)
$steppablePipeline.Begin($myInvocation.ExpectingInput, $ExecutionC
ontext)
…
}
Ez tulajdonképpen szerkezetileg egy olyan függvény, mint amit a 2.5.7 Meglevő cmdletek kiegészítése, átalakítása fejezetben láttunk. Az elején ugyanolyan paramétereket definiál a függvény, mint ami az eredeti cmdletnek van, majd a paraméterátadáshoz szétválogatja a pozícionális paramétereket és a nevesítetteket. Nem mondom, hogy minden világos pontosan számomra, hogy mi is történik, a lényeg, hogy meg lesz hívva távoli módon az eredeti cmdlet.
Ráadásul így a TAB kiegészítés is működik, ezzel még kényelmesebb lesz a helpdeskes munkája. Nézzük, hogyan tudja a korábbi parancsot futtatni:
PS C:\> Get-ADUser -Filter {name -like "főn*"}
RunspaceId : 81cb2f79-afa9-4e9a-8552-f8d296380932
DistinguishedName : CN=Főnök Ferenc,OU=Managed Users,DC=r2,DC=dom
Enabled : True
GivenName : Ferenc
Name : Főnök Ferenc
ObjectClass : user
ObjectGUID : a067ce05-b902-4f26-812e-4bbb62280ea8
SamAccountName : ff
SID : S-1-5-21-3398938913-3940250523-927435294-1123
Surname : Főnök
UserPrincipalName : ff@r2.dom
Láthatjuk, hogy minden ugyanúgy működik, mintha ott ülne az illető a tartományvezérlőre bejelentkezve! Mindezt úgy, hogy nem kellett telepíteni semmit sem a helpdeskes munkaállomására.