Powershell - Searching AD, specifying the DC, retrieving highest usnchanged
-
Tuesday, August 07, 2012 11:27 PM
Greetings,
I need to write a script to search AD for the latest changes. I have a script that successfully searches all of AD. I want to add USNChanged to my adsi filter. In which case I need to track USNchanged each day so I can search for only what's changed.
First thing is I need to retrieve the highest USNChanged from a dc - how do I script that? - and I need to specify the same DC each time.
Also, as USNChanged is DC specific, my script needs to talk to the same DC each time. I am using [ADSISearcher] as my object but I dont seem to be able to specify which DC it uses. Do I need to use another method?
Thanks
David Z
All Replies
-
Tuesday, August 07, 2012 11:47 PM
Start here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms677627(v=vs.85).aspx¯\_(ツ)_/¯
-
Wednesday, August 08, 2012 12:53 AM
Thanks - Im trying to work out how to retrieve the HighestCommittedUsn which is a property of the domaincontroller class:
$usn = [directoryservices.activedirectory.domaincontroller]::HighestCommittedUsn
doesnt seem to work...any hints please?
Cheers
David Z
-
Wednesday, August 08, 2012 1:10 AM
Got the USN bit!
$domain = [directoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$dcany =$domain.FindDomainController()
$usn = $dcany.highestcommittedusn
-
Wednesday, August 08, 2012 3:37 AM
Worked out the rest too!
$domain = [directoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$dcany =$domain.FindDomainController()
$usn = $dcany.highestcommittedusn
$dcname = $dcany.name
#At this point you would save the dcname and usn to a file (or reg)
#then the next day you retrieve the dcname and usn
#and run the code above to get a new usn and save it etc
#then run the following to get changes only
$ADsPath = [ADSI]“LDAP://$dcname/dc=aur,dc=national,dc=com,dc=au"
$Search = New-Object DirectoryServices.DirectorySearcher($ADsPath)
$Search.filter = "(&(uSNChanged>=$usn)(ObjectClass=Computer)(OperatingSystem=Windows XP Professional))"
$Search.PageSize = 1000
"Name","Lastlogontimestamp","canonicalname" | ForEach-Object {$null = $search.PropertiesToLoad.Add($_) }
$newlist = $Search.FindAll() |Select-Object @{n='Name';e={$_.properties['name']}},@{n='canonicalnamef';e={$_.properties['canonicalname']}},@{n='lastlogontimestamp';e={[datetime]::FromFileTimeUtc([int64]$_.properties['lastlogontimestamp'][0])}}
- Marked As Answer by David Zemdegs-Australia Wednesday, August 08, 2012 3:38 AM
-
Wednesday, August 08, 2012 6:03 AM
PageSize is pointless in this situation. You are basically setting it to what it is by default and that effectively disables paging. Use a number less that 1000 to enable paging if you need to return more than 1000 objects.
$domain = [directoryServices.ActiveDirectory.Domain]::GetCurrentDomain() $dcany =$domain.FindDomainController() $usn = $dcany.highestcommittedusn $searcher=[adsisearcer]"(&(uSNChanged>=$usn)(ObjectClass=Computer)(OperatingSystem=Windows XP Professional))" $p='Name','lastlogontimestamp','canonicalname' $searcher.PropertiesToLoad.AddRange($p) $searcher.FindAll() | Select-Object @{n='Name';e={$_.properties['name']}},@{n='canonicalnamef';e={$_.properties['canonicalname']}},@{n='lastlogontimestamp';e={[datetime]::FromFileTimeUtc([int64]$_.properties['lastlogontimestamp'][0])}}Using the type accelerators can simplify the code. The searcher points to the current domain and takes a filter argument
$searcher=[adsisearcer]"(&(uSNChanged>=$usn)(ObjectClass=Computer)(OperatingSystem=Windows XP Professional))"
The properties can be loaded as an array.
$p='Name','lastlogontimestamp','canonicalname'
$searcher.PropertiesToLoad.AddRange($p)
¯\_(ツ)_/¯
- Edited by jrvMicrosoft Community Contributor Wednesday, August 08, 2012 6:04 AM
-
Wednesday, August 08, 2012 9:36 PM
Thanks for the tips. Using the type accelerator, how does one supply both the LDAP path (which includes the dc I want to connect to) and the filter argument?
Thanks
david Z
-
Wednesday, August 08, 2012 11:11 PM
Also, I found the following on MSDN regarding pagesize:
"To retrieve a set of results that is larger than 1000 items, you must set SizeLimit to its default value (zero) and set PageSize to a value that is less than or equal to 1000. For example, if a search will result in 12,000 items being returned and SizeLimit is set to 500, a total of 500 items will be returned. If, however, SizeLimit is set to zero and PageSize is set to 500, the search will return all 12,000 results in pages of 500 items, with the last page containing only 200 items. The paging occurs transparently to the application and the application does not have to perform any special processing other than setting the PageSize property to the proper value."
So it appears that setting pagesize to 1000 is indeed appropriate.
Cheers
David Z
-
Thursday, August 09, 2012 12:54 AMModerator
It doesn't matter much what value is assigned to PageSize, as long as it's between maybe 50 and 1000. The "optimal" value probably depends on many factors. Many people assume 1000 is best, but I doubt it. In my test domain, with about 3000 users, my testing showed best performance with PageSize of 200 when I retrieve all users.
Richard Mueller - MVP Directory Services
-
Thursday, August 09, 2012 6:11 AM
Also, I found the following on MSDN regarding pagesize:
"To retrieve a set of results that is larger than 1000 items, you must set SizeLimit to its default value (zero) and set PageSize to a value that is less than or equal to 1000. For example, if a search will result in 12,000 items being returned and SizeLimit is set to 500, a total of 500 items will be returned. If, however, SizeLimit is set to zero and PageSize is set to 500, the search will return all 12,000 results in pages of 500 items, with the last page containing only 200 items. The paging occurs transparently to the application and the application does not have to perform any special processing other than setting the PageSize property to the proper value."
So it appears that setting pagesize to 1000 is indeed appropriate.
Cheers
David Z
Actually no. According to the DS Team blog it must be less tha 1000. The default is 1000. Setting it to 1000 is the same as setting it to either 0 or not setting it at all. This has been discussed and argued over the years but every time the DS team has mentioned it they seem to always say "set to less than 1000". Of course I haven't read every thing they have written.
It is really too bad that they didi not design this as a flag value. "Paging=$true" then the page size would be the default of 1000 or whatever the domain is configured for.
The last time I tested this was on W2K and 1000 did not work. Only a number less that 1000 caused paging.
Some articles calim that WS2003 AD is actually set to 1500. If so then 1000 would work. I have never tested this and have seen more recent articles clain that it is stiill 1000.
¯\_(ツ)_/¯
-
Thursday, August 09, 2012 11:14 PM
Thanks for that.
My script uses a pagesize of 1000 and it works. We have over 100,000 accounts in AD.
Cheers
David Z
-
Friday, August 10, 2012 1:40 AM
Thanks for that.
My script uses a pagesize of 1000 and it works. We have over 100,000 accounts in AD.
Cheers
David Z
So you are saying that you returned more than 1000 items in that query? I don't think so. I don't hink you understand what I am posting about,
If you are returning more than 1000 records you must set the pagesize to a value greater than zero and less than 1000.
If you are only querying for a few records then pagesize is not needed.
¯\_(ツ)_/¯
-
Friday, August 10, 2012 5:08 AM
What my results show is that I get all the records (tens of thousands of them) that meet my filter and I have pagesize=1000.
Cheers
David Z
-
Friday, August 10, 2012 6:22 AM
Are you saying that you have 10s of thousands of xp computers in one domain?
No matter how I look at your code I can find no way that it can work.
I have run it six ways from Sunday and it always returns nothing.
The highest usn can be any object. It i s likely that it is only one or no objects because you have just returned the highest usn in the domain. It is completely unlikely that that wuery can return qany more than on or two computer object. Those objects are only change when AD maes a change to them.
The lastlogontimestamp is the time the computer last logged into the domain withing 14 days. It is really fairly useless.
The usn will only change if someone has edited the computer in AD.
None of this matter as there is zero liklihood that there will be any or mare than one or two that can have changed since you grabbed the domain high usn so I cannot begin to understand what you are trying to discover with this.
¯\_(ツ)_/¯
- Edited by jrvMicrosoft Community Contributor Friday, August 10, 2012 6:54 AM
-
Friday, August 10, 2012 10:55 PM
It might seem strange, but my code runs successfully - yes we do have around 40,000 XP computers in one domain.
I run it every day and it only gives me computer accounts that have changed since the last run.
I will post the code after the weekend.
-
Friday, August 10, 2012 11:07 PM
I don't think you understand yet. I don't care if you have on e,illion XP compuyers. It is only the number you return that matter. It is impossible that you are returning more than 100 computers. You are querying more than 1000 but it is only the ones you return that count. Very few admins who are not certified in AD understand that subtlety. The number only applies to results. If you wuery 40000 computers and reqturn 10 the value is unimoprtant. If your result is 1000 or more then you need to set the value correctly.
At the AT&T group I worked on for 10 years duirng teh initial deploymnet of AD2000 there wer more than 60,000 desktops. Luckily they were in multiple domains. We stil needed to set teh size to lees than 1000 to return all of the computers in a domain. Failure to set it or setting it to 1000 left the query short of results. at that time event thhe Microsoft Corporate Consultants for the Exchange 5.5 upgrade didn't get that right. It took some smart engineers in teh systems group to put us on the correct path.
It still makes me crazy that Microsoft designed it that way.
¯\_(ツ)_/¯
-
Sunday, August 12, 2012 10:27 PM
Greetings,
I do understand, its just that my results shows that this pagesize thing maybe weird.
Here is the script:
$objSearcher = [adsisearcher]""
$objsearcher.pagesize=1000
"Name","Lastlogontimestamp","canonicalname" | Foreach-Object {$null = $objSearcher.PropertiesToLoad.Add($_) }
$objSearcher.Filter = '(&(ObjectClass=Computer)(OperatingSystem=Windows XP Professional))'$newlist = $objSearcher.FindAll()
This script returns all 74,318 XP computers and I have verified that is the correct number by creating a saved query in ADUC.
It is a strange design but every time I use pagesize=1000 I get all the right results.....
Cheers
David Z
-
Sunday, August 12, 2012 10:34 PM
OK David, if that is the case then do me a favor, set it to 0 and then to 1500 and tell me what happens. You may be onto something that I cannot test right now.
¯\_(ツ)_/¯
-
Sunday, August 12, 2012 11:48 PM
When I set pagesize to zero, I get 1250 records returned.
When I set pagesize to 1500, I get all 70,000+ records returned.
I found this as an explanation as to why the search was designed this way:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa746459%28v=vs.85%29.aspx
..but even their doco doesnt match my results - I get 1250 with pagesize=0 and they say 1000???
-
Monday, August 13, 2012 7:40 AM
Note what the documentatio says:
When you use a paged search, the size limit does not override page size. Size limit can only be used when you retrieve a result set that contains fewer than 1000 entriesAND
If neither of these search preferences is set, the default is no paging. Searches of the Active Directory performed without paging are limited to returning a maximum of the first 1000 records, so you must use a paged search if there is the possibility that the result set will contain more than 1000 items.
If your admins have set a differnt default of say 2000 records then setting anything less but not zero will produce paging.
If youset zero then your result wil lbe the page size. I suggest your admins have altered teh default page size to 1250 because that is what yu get returned when you set zero. The result you get when you set 1500 is counter to all experience or documentation.
Someone has altered your AD settings. I know from testing that AD 2000 is set to 1000. I hace never specifically tested on AD 2003 or later. I will later today. My local test system does not have that many object so I cannot test this.
¯\_(ツ)_/¯
-
Monday, August 13, 2012 9:43 PM
Hi,
I checked with NTDSUTIL and the maximum pagesize has indeed been altered to 1250. However it doesnt explain why mine worked with 1500. So I ran it with pagesize=2500 and it worked!
So its either ignoring what I enter, or if its not=1000, it allows any pagesize?
Anyway, a learning experience!
Thanks
David Z
-
Monday, August 13, 2012 10:10 PM
No someone has modified your AD installation. I suspect they were experiminting with things leraned on a forum. It is possible to completely disable paging which appears to be wwhat has been done. This can cripple AD by someone rpeatedly executing large queries, It is a denail of service hack. If you are on AD 2800R2 then it will be very hard to crash AD (the server) as the server will be 64 bit with lots of memory if you are in a very large domain.
Another reason we would disble paguing is to exewcute a stress test to be sure teh serve goes to sleep in a nice way. If it takes teh domian down then something else is wrong.
I suspect it was just done by someone fooling around.
I don't remember how to disable paging it can be found.
¯\_(ツ)_/¯

