Mám tu historický (ovšem ale stále platný) článek na vyhledávání v Active Directory. A v něm se hledá podle data a času. Například účty, které se už dlouho nepřihlásili, nebo kdo si už dlouho nezměnil heslo. Podobně jsem se už o časech zmiňoval i v článku o atributu lastLogonTimestamp.
Jak jsem si všiml, ten archivní článek se odkazuje na nějaký můj starší skript ve VBScriptu, který se mi už nechce hledat. Raději to uděláme v PowerShellu.
Data a časy v Active Directory
V Active Directory jsou data a časy velmi často uloženy ve formě int64 - tedy 64bitového celého čísla. Číslo zachycuje počet ticků - 100ns intervalů od 1.1.1601. Pokud byste se přihlásili 11.11.2012 v 8:55, viděli byste tam jen hodnotu 129962370145625000. To není úplně příjemné na výpočty :-)
Atributy, kterých se to týká, jsou například pwdLastSet, lastLogon, lastLogonTimestamp, lockoutTime, badPasswordTime apod.
Jak převedu počet ticků na datum a čas?
Můžete použít i příkazovou řádku CMD. V tomhle případě na to máte vybavení ve formě příkazu W32TM a jeho parametru NTTE:
w32tm /ntte 129962370145625000
Ale jak převedeme datum a čas na tohle hnusné číslo?
Trošku se nejprve podívejme na PowerShell. Aktuální datum a čas získáte pomocí Get-Date:
Konkrétní datum získáte pomocí statické metody Parse a ANSI/ISO formátu data (umí to i regionální formáty, ale záviselo by to na zvoleném aktuálním nastavení):
[DateTime]::Parse('1979-09-29')
Data a časy se dají odečítat. Takže tu je konkrétní použití na aktuální datum a čas:
(Get-Date) - [DateTime]::Parse('1601/01/01')
((((Get-Date) - [DateTime]::Parse('1601/01/01')).Ticks
Nebo chcete třeba ticky k datu 1.11.2012?
([DateTime]::Parse('2012/11/01') - [DateTime]::Parse('1601/01/01')).Ticks
Další parádní věc je, že PowerShell (nebo lépe řečeno .NET Framework) umí počítač relativní data. Jak třeba zjistíte datum a čas přes 35 dny?
A už tedy jednoduše - výpočet ticků před dvěma měsíci:
((Get-Date).AddMonths(-2) - [DateTime]::Parse('1601/01/01')).Ticks
Vyhledání všech účtů, které si už 3 měsíce nezměnili heslo?
Troška PowerShellu v kombinaci s DSQUERY udělá zázraky:
$oldDate = ((Get-Date).AddMonths(-2) - [DateTime]::Parse('1601/01/01')).Ticks
DSQUERY '*' 'DC=gopas,DC=virtual' '-filter' ('(&(objectCateogry=person)(pwdLastSet<={0}))' -f $oldDate)