na początek zaprezentuję… początek. całkiem logicznie q:
find-UnusedADObjects.ps1
<#
.NOTES
################################################################################
# script to search unused AD objects v2.o #
# purpose: maintenance #
# nexorek@gmail.com #
# o8.o5.2o15 #
# - whole code rewritten #
# #
################################################################################
.PARAMETER scope
defines the query. possible are queries for:
inactive computers ("Computers"),
inactive users ("Users"),
users with nonExpiring password ("nonExpiring")
and do all the queries ("all")
.PARAMETER unusedTime
defines the period of maximum inactivity based on lastLogon attribute
.PARAMETER toScreen
data are saved to files by defaults. use toScreen to output to screen
#>
#Requires –Version 3
[cmdletBinding()]
param(
[validateSet("Computers","Users","nonExpiring","All")][string]$scope="All",
[validateRange(1,1096)][int]$unusedTime=96,
[string[]]$OUsTOSKIP=(gc .\find-UnusedADObjects.OUsToSkip),
[switch]$toScreen,
[switch]$splitFiles
#additional option to split/extract files with 'skipped' objects in seperate files
#for easier reviewing. better reporting.
)
#maxium number of days the user/computer may be inactive
$MAXUSERIDLE=$unusedTime
$MAXCOMPUTERIDLE=$unusedTime
#output file for further processing
$fdate=get-date -Format ("yyyyMMddhhmm")
$FILE_NON_EXPIRING=".\fado-nonexpiring-$fdate.csv"
$FILE_INACTIVE_USERS=".\fado-inactiveUsers-all-$fdate.csv"
$FILE_INACTIVE_COMPUTERS=".\fado-inactiveComputers-$fdate.csv"
$usedFiles=""
#list of OU names, that should be skipped during object scan.
[regex] $ouRX = ‘(‘ + (($OUsTOSKIP |foreach {[regex]::escape($_)}) –join “|”) + ‘)’
#prepare LDAP filters for queries
$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=*)))"
$searchProperties="sAMAccountName,displayname,distinguishedname,lastLogonTimeStamp,passwordlastset,objectclass"
# Convert the local time to UTC format because all dates are expressed in UTC (GMT) format in Active Directory
$currentDateUtc = (get-date).ToUniversalTime()
$lastLogonIntervalLimit = $currentDateUtc.AddDays(-$MAXUSERIDLE).ToFileTime()
po pierwsze nazwa skryptu z przyjętą w PS notacją. korzyść – bardziej intuicyjne wykorzystanie.
po drugie bardziej rozbudowane komentarze. odpowiednio zrobione są bardzo wygodne – korzystając z polecenia get-help wyświetli się pełny opis. każda wersja PS wprowadza coraz więcej obsługiwanych słów kluczowych, a żeby dowiedzieć się o całości należy poszukać ’comment based help’. niektórzy mogą powiedzieć – 'eeee, jestem zbyt leniwy na takie szlaczki’. zatem zwróćcie uwagę na to, jak opisany jest parametr 'scope’ a jak 'splitFiles’:
- ’scope’ jest wyniesiony na początek , do 'comment based help’
- ’splitFiles’ jest opisany 'na lenia’ jako komentarze tuż pod opcją
obie wersje są obsługiwane przez get-help, więc jak się okazuje – nawet nie trzeba rysować szlaczków. wystarczy minimum wysiłq aby na szybko opisać po co jest dany parametr – z korzyścią dla twórcy jak i dla end-usera.
jest jeszcze jedna metoda tworzenia komentarzy, ale wydaje mi się, że to jeden z pomysłów, który się nie przyjął i został porzucony. jego zastosowanie jest, delikatnie mówiąc, niszowe:
param( [parameter(mandatory=$true,HelpMessage="tutaj można wpisać jakiś komentarz")][string]$variable )
wiadomość można zobaczyć na dwa sposoby – badając kod źródłowy skryptu, lub:
jeśli wartość zdefiniowana jest jako obligatoryjna ORAZ nie wprowadzimy jej ORAZ po wyświetleniu komunikatu wpiszemy ’!?’ [SIC!]:
C:\...ive\_ScriptZ :))o- .\test-helpmessage.ps1
cmdlet test-helpmessage.ps1 at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
variable: !?
tutaj moĹĽna wpisaÄ┼ jakiĹ> komentarz
variable:
wygląda na to, że ktoś miał pomysł… tylko inni go nie podzielili (;
„#Required -version 3” zapewnia kompatybilność. nie bawiłem się w ładowanie modułów bo zakładam, że zostaną załadowane automatycznie [od ver. PS3.o] oraz wykorzystane jest kilka technik zapisu, które nie jestem pewien czy zadziałają w PS2.o. to zabezpieczy przed przypadkowym odpaleniem na starej wersji.
następnie parametry. nie tylko są, ale są zdefiniowane w bardziej rozbudowany sposób – część z nich ma określone ograniczenia poprzez validateSet i validateRange. to kolejna rzecz, która nie służy wyłącznie dla zaspokojenia puryzmu i widzi-mi-się. jedną z najwygodniejszych cech PS jest dokończanie TABem. jeśli zdefiniowany jest validateSet, to szybko można całe polecenie wpisać: „find-u<TAB dokończy nazwę skryptu> –s<TAB dokończy nazwę parametru> <TAB będzie przerzucał pomiędzy zdefiniowanymi wartościami>”. takie niuanse są prawdziwą SiłąPowłoki (;
inną ciekawostką jest zdefiniowane zmiennej, której standardowa deklaracja jest kawałkiem kodu:
[string[]]$OUsTOSKIP=(gc .\find-UnusedADObjects.OUsToSkip)
zacznę od tego, że jestem przeciwnikiem takiego pisania – braqje tu obsługi błędów. ale w całym skrypcie darowałem sobie obsługę błędów – zupełnie nieedukacyjnie… ale to na inny wpis, kiedyś. drugi błąd popełniony w tej linijce to wykorzystanie aliasu 'gc’. aliasy mogą być globalnie przedefiniowane więc dla pewności w skryptach powinno się ładnie używać pełnych, prawidłowych nazw commandletów. trzecią 'głupią’ rzeczą, której w praktyce nie robię i jest tutaj bardziej do celów edukacyjnych, jest wyniesienie zmiennych do oddzielnego pliq.
find-UnusedADObjects.OUsToSkip
Servers
_UnusedObjects
Service Accounts
w starej wersji pliq było wewnątrz: $OUsToSkip=”Servers”,”_UnusedObjects”,”Service Accounts” . kiedy należy wynieść wartości do zewnętrznego pliq? kiedy skrypt będzie zaszyfrowany lub podpisany certyfikatem. czyli nie będzie można w nim dokonać żadnej modyfikacji. należy wtedy jednak dobrze opisać w helpie jak taki plik ma się nazywać, co ma zawierać itd. sporo problemu. a ponieważ zazwyczaj celowo oddaję źródła, zależy mi na 'kompaktowości’ rozwiązania – potęga skryptów to często fakt, że jest to *pojedynczy*, mały plik. niemniej warto wiedzieć, że tak również można zrobić, i to w całkiem prosty sposób.
oczywiście oprócz pliq można po prostu podać tablicę stringów jako parametr… ale niezbyt to wygodne w codziennym użyciu.
kolejne drobiazgi w deklaracjach to np. fakt, że pliki będą się odkładać a nie nadpisywać, ponieważ zawierają datę w nazwie.
dalej widać regex który omówię w późniejszych częściach, deklaracje filtrów wyszukiwania, $searchProperties – które, jak się finalnie okaże, wyniesione w tym miejscu pozwoli w bardzo łatwy i szybki sposób poszerzyć funkcjonalność, jeśli klient nagle zażyczy sobie w raporcie dodatkowych danych.
i to na tyle w tej części. niby tylko 'komentarze i deklaracja zmiennych’ a okazuje się, że już w tej fazie, jest wiele istotnych detali na które należy zwrócić uwagę aby skrypt był wygodny w użyciu i przejrzysty.
eN.
Hyper-v replication – Critical
Hyper-v Replica – problemy
Hv Replica jest dobrą ideą – jednak wykonanie szwanqje. wiele operacji, jakie jest wykonywane w ramach HvR jest zabójcze dla niego samego. do tego zachowanie jest bardzo nieprzejrzyste – do powodu błędów trzeba mocno dociekać, opisy są zwodnicze, braqje narzędzi do bezpośredniego debugowania. mówiąc w skrócie – mechanizm zaprojektowany jest jako samograj, a niestety jest na tyle niestabilny, że ciągle trzeba przy nim grzebać i jest to ciężka systemówka.
replikacja przerzuca pliki wektorów zmian [.hrl]. kiedy zostanie przerzucony plik, następuje… łączenie [merge] plików vhd. o ile w przypadq małej zmiany i małego pliq wszystko sobie działa dobrze, o tyle przewalenie kilq GB pliq do zmerdżowania z np. 1TB dyskiem, jest operacją zabijającą mechanizm – nie ma możliwości skończyć się ani w 5min [standardowy czas przerzucania zmian HvR] ani w 15min [max. jaki można ustawić] a zdarza się, że i godzina byłoby za mało, jeśli dyski są na prawdę duże. operacja jest wykonywana po stronie odbiorcy i jest to operacja bloqjąca – w czasie, kiedy jest wykonywana, z maszyną nie da się nic zrobić, a nadawca dostaje informację, że replikacji nie można wykonać.
dodatkowym problemem jest fakt, iż operacja łączenia dysków nie jest w żaden sposób pokazywana przez interfejs. błędy wyglądają następująco:
serwer wysyłający
log Hyper-V-VMMS/Admin, Event ID: 32552,
log Hyper-V-VMMS/Admin, Event ID: 32315,
serwer odbierający
log Hyper-V-VMMS/Admin, Event ID: 15268 [nie występuje zawsze]
log Hyper-V-VMMS/Storage, Event ID: 27000,
ponadto jest możliwość szybkiej weryfikacji przy pomocy PowerShell, weryfiqjąc status maszyny na serwerze odbierającym:
statusy wyraźnie pokazują – 'InService’ oraz 'ModifyingUpVirtualMachine’ – być może taki status jest również w innych scenariuszach, ale regularnie powtarzający się – może oznaczać tylko jedno. dyski się łączą.
dalsze konsekwencje
to za chwilę prowadzi to zmiany statusu repliki na 'critical’ i ustawienia wymuszenia resynchronizacji w następnym cyklu [standardowo chyba raz dziennie o 18.oo – godzinę można sobie ustawić]. jeśli ręcznie wymusi się powtórną próbę replikacji po zakończeniu operacji 'merge’, to wszystko powinno być ok i maszyna powinna się zacząć replikować. jeśli jednak zostawi się na automat, to do cyklu resync może minąć zbyt wiele czasu, a to będzie oznaczało faktyczny resync.
i tu dochodzimy do kolejnej maskrycznej operacji – resynchronizacja. jest to kolejna operacja bloqjąca, podczas trwania której sypią się backupy [lockowany jest VSS], a biorąc pod uwagą ile trwa czasu dla dużych dysqw, potrafi spowodować lawinowe błędy.
jak uniknąć części błędów
różnymi automatami – trzeba monitorować replikację i oskryptować całe rozwiązanie. można to zrobić w bardziej wyrafinowany sposób, można po prostu co jakiś czas wymuszać resync dla wszystkich maszyn.
jest też ciekawostka, która nigdzie nie jest opisana – w każdym razie nie trafiłem – podeślijcie linka, jeśli się mylę. póki co – wisienka na torcie, exclusive dla w-filesowiczów (;
kiedy poobserwuje się replikację, można zauważyć, że w pewnym momencie taski 'zawisają’. jeśli z powodów opisanych powyżej wykonuje się kilka resynchronizacji, nagle okazuje się, że pozostałe maszyny co i rusz, również wchodzą w stan 'critical’. ograniczeniem jest opcja definiująca ilość równoczesnych 'storage migration’, ustawiana we właściwościach Hyper-V. standardowo są to dwie operacje. nawet jeśli maszyny rozłożone są na kilq węzłach klastra, może okazać się, że jakieś dwie długie synchronizacje lub resynchronizacje, będą blokować pozostałe maszyny. dla tego warto ten parametr zwiększyć. to znacząco obniża ilość problemów!
ponoć w Windows 1o Server, mechanizm replikacji ma być wymieniony – ale również nie mogę znaleźć artykułu potwierdzającego ten fakt /:
będę wdzięczny za linki (:
eN.