Végezetül nézzünk egy összetettebb feladatot a Windows Server 2008 tartományi környezetben felmerülő problémára. Egy új lehetőség itt az un. „Fine grained password policy”, azaz a tartományi szintnél alacsonyabb szinten beállítható jelszó házirendek létrehozásának lehetősége. Ezzel csak egy probléma van: nem szervezeti egységekre, hanem biztonsági csoportokra tudjuk ezeket kiosztani. Ha konzisztensek szeretnénk maradni a házirendek tekintetében, akkor érdemes „árnyékcsoportokat” létrehozni, azaz olyan csoportokat, amelyek egy adott szervezeti egység összes felhasználóját tartalmazzák. Erre készítettem ezt a függvényt, amely automatikusan létrehozza „shadow” névelőtaggal és az OU nevével mint utótaggal a csoportot az adott OU-ban, ha még nincs ilyen. Belerakja az összes olyan felhasználót ebbe a csoportba, akik még nem tagjai. Paraméterként egy OU distinguished name adatát kell megadni. Ha egy felhasználót kitörlünk az adott OU-ból, akkor azt az AD automatikusan kiszedi a shadowgroup-ból, viszont ha csak átmozgatjuk a felhasználót egy másik tárolóba, akkor annak a csoport tagjaiból való eltávolításáról nekünk kell gondoskodni. Ezt hajtja végre a szkript vége.
Rendszeresen futtatva szinkronban tarthatjuk az árnyékcsoportok tagságát az OU felhasználói objektumaival.
function update-shadowgroup ([string] $ou = "OU=Demó 2,DC=iqjb,DC=w08")
{
$adou = [ADSI] "LDAP://$ou"
$query = new-object system.directoryservices.directorysearcher
$query.SearchScope = "OneLevel"
$query.SearchRoot = $adou
$query.filter = "(&(objectCategory=group)(name=shadow-$($adou.name)))"
$sg = $query.FindOne()
if(-not $sg)
{
$ADS_GROUP_TYPE_GLOBAL_GROUP = 0x00000002
$ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 0x00000004
$ADS_GROUP_TYPE_LOCAL_GROUP = 0x00000004
$ADS_GROUP_TYPE_UNIVERSAL_GROUP
=
0x00000008
$ADS_GROUP_TYPE_SECURITY_ENABLED
=
0x80000000
$groupType = $ADS_GROUP_TYPE_SECURITY_ENABLED -bor $ADS_GROUP_TYPE_GLOBAL_GROUP
$sg = $adou.Create("Group",
"CN=shadow-$($adou.name)")
Write-Host
"Creating group: shadow-$($adou.name)..."
$sg.Put("groupType",
$groupType)
$sg.SetInfo()
}
else
{
$sg = [ADSI] $sg.Path
}
$query.SearchScope = "OneLevel"
$query.SearchRoot = $adou
$query.filter = "(objectCategory=user)"
$users = $query.FindAll()
foreach($user in $users)
{
if($user.properties.memberof
-notcontains $sg.distinguishedname)
{
$sg.member += $user.properties.distinguishedname
write-host
"Inserting $($user.properties.name)..."
}
}
$sg.setinfo()
$members = $sg.member
foreach($member in $members)
{
if(-not $member.Contains(",OU=$($adou.name),"))
{
write-host
"Removing $member..."
$sg.Remove("LDAP://$member")
$sg.setinfo()
}
}
}