na koniec samo ciało skryptu. logika.
pierwotny skrypt składa się w 2o% z komentarzy [dokumentacja] oraz 8o% z ciała skryptu zmieszanego z deklaracjami [management]. takie statystyki oznaczają jedno – to jest źle napisany skrypt. obecna wersja to [ok.] 27% komentarzy [dokumentacja], 18% deklaracje [magazyn danych], 4o% w funkcjach [siła robocza] oraz 15% ciała [management]. to oznacza, że:
- jest jasna izolacja bloków kodu co zwiększa przejrzystość i wydziela zakresy odpowiedzialności
- skrypt jest lepiej opisany,
- duża część kodu może być wielokrotnie wykorzystana
- a samo ciało zajmuje się wyłącznie zarządzaniem – niezbędna logika sterująca funkcjami [siłą roboczą] które z kolei korzystają ze zmiennych [magazyn].
dodam jeszcze, że całkiem przypadkiem, oba skrypty mają [u mnie] identyczną ilość linii.
deklaracje już były, pozostaje zatem do przedstawienia sama logika [silnik]:
$incativeFlag="(&(!userAccountControl:1.2.840.113556.1.4.803:=2)(userAccountControl:1.2.840.113556.1.4.803:=65536))" $loggedBeforeFlag="(&(objectCategory=[OBJCATEGORY])(objectClass=user)(|(lastLogonTimeStamp<=[INTERVAL])(!lastLogonTimeStamp=*)))" Switch -regex($scope) { 'nonExpiring|all' { doTheSearch -type "user" -filter $incativeFlag -fileName $FILE_NON_EXPIRING } 'Users|all' { $LDAPFilter=$loggedBeforeFlag.Replace("[OBJCATEGORY]","person").Replace("[INTERVAL]",$lastLogonIntervalLimit) doTheSearch -type "user" -filter $LDAPFilter -fileName $FILE_INACTIVE_USERS } 'Computers|all' { $LDAPFilter=$loggedBeforeFlag.Replace("[OBJCATEGORY]","computer").Replace("[INTERVAL]",$lastLogonIntervalLimit) doTheSearch -type "computer" -filter $LDAPFilter -fileName $FILE_INACTIVE_COMPUTERS } }
i to wszystko.
ogólna idea jest bardzo prosta – zależnie od wybranego zakresu [$scope] wykonywane jest wyszukiwanie przy pomocy funkcji 'doTheSearch’, opisanej w poprzedniej części. funkcji przekazywane są wszystkie niezbędne zmienne – informacja o rodzaju obiektu, definicja filtru oraz nazwa pliq wyjściowego, która jest zależna od typu wyszukiwania. jedyne, co jest nietypowe, to wykorzystanie prostych wyrażeń regularnych.
dzięki temu, że switch pozwala na wykorzystanie regex, można zastąpić wiele linijek ifów i elsifów bardzo kompaktowym zapisem – jak na załączonym obrazq. oznacza to, że podczas decyzji wykonywany jest $scope -match <regex> – czyli jeśli wpada parametr 'Users’ to:
'Users’ -match 'nonExpiring OR all’ -> false
'Users’ -match 'Users OR all’ -> true, wykonaj kod
jeśli $scope jest równy 'all’ – wpadnie we wszystkie zdefiniowane przypadki. wygodne.
obiecałem wyjaśnić bardziej złożone wyrażenie regularne, z poprzedniej części:
[regex] $ouRX = ‘(‘ + (($OUsTOSKIP |foreach {[regex]::escape($_)}) –join “|”) + ‘)’ if($customObj.distinguishedname -match $ouRX) {$customObj.skip=$true}
WTF? otóż te dwie linijki zastępują brzydkie, wielokrotne porównania, przyspieszając wyszukiwanie wartości w macierzy:
foreach($ou in $OUsToSKIP) { if($customObj.distinguishedname -match $ou) {$customObj.skip=$true; break} }
'match’ jest ostatnio moim ulubionym operatorem. zastępuje -like '*coś*’ ale co ważniejsze – wyszuqje w macierzach. prosty przykład użycia przedstawiałem a propos wyszukiwania podstawowego adresu email. jest prosty, zastępuje bezsensowne pętle i … jest super szybki – nawet o rząd wielkości szybszy niż zastosowanie pętli. oczywiście nie ma to znaczenia jeśli w tablicy są 3 elementy – jak w tym przykładzie, ale jeśli ilość idzie w tysiące, zaczyna to odgrywać poważną rolę. a tutaj – po prostu jest geekowe =^.^’=
[regex]::escape($string) warto zapamiętać – jest to automat 'escapeujący’ wszystkie znaki specjalne – kropki, przecinki, znaki z poza zakresu, slashe itd. dzięki temu cokolwiek by było w nazwie – zostanie automatycznie zmienione na string z pojedynczą interpretacją. w efekcie powstanie zwykły regex [widać wyescapeowane spacje]:
[regex]$ouRX=(Servers|_UnusedObjects|Service\ Accounts|Shared\ Mailboxes)
w efekcie wykonywane jest proste porównanie – „jeśli w distinguishedName znajdziesz którąkolwiek z wartości w $ouRX to…” i pozamiatane. warto zwrócić uwagę, że taka odwrócona logika jest bardziej ludzka, bo przedstawioną pętlę można przeczytać jako: „dla każdego elementu z $ouToSkip sprawdź, czy nie występuje gdzieś w distinguishedName. jeśli tak to…”, co nie jest po naszemu.
każda opowieść ma swój finał. ta kończy się w ten sposób:
#FINISH write-host -ForegroundColor Magenta "done." if(!$toScreen) { Write-Host "files written:`n$usedFiles"}
download: find-UnusedADObjects
eN.