joeware - never stop exploring... :)

Information about joeware mixed with wild and crazy opinions...

7/31/2013

Using PowerShell Get-ADGroup Question…

by @ 10:59 pm. Filed under tech

So I am trying to duplicate the output of a very simple AdFind command to locate a universal group and enumerate the members in a simple quoted DN format. I want identical output to the console or perhaps I could live without the quotes.

The AdFind command looks like:

adfind -gcb -f "displayname=some group displayname" member –qlist

 

I spent more time than I should trying to figure out how to duplicate it. Nothing intuitive seemed to work.

Apparently Get-ADGroup requires you to specify the actual GC name and port in order to perform a GC search… Several other ADWS cmdlets seem to require the same. WTF?? Seriously? Anyone remember serverless bind on the team that wrote those cmdlets? How hard is it to add a simple -gc switch or if you absolutely must -GlobalCatalog or even -PleaseUseAD***GlobalCatalog?

The best I have gotten to to this point is:

$gc=(Get-ADDomainController -discover -service globalcatalog).hostname[0] + ":3268" ; $dn=(Get-ADGroup -server $gc -searchbase "" -f ‘displayname -eq "some group displayname"’).distinguishedname ; (Get-ADGroupMember $dn).distinguishedname

Even for PowerShell that seems a bit verbose. What am I doing wrong?

    joe

Rating 4.00 out of 5

10/15/2010

Free PowerShell PDF Book from Don Jones

by @ 12:44 pm. Filed under tech

http://nexus.realtimepublishers.com/accwp.php?ref=dj4

The book does require registration, but there’s no corporate sponsor – so there’s no associated spamming

Rating 3.00 out of 5

6/28/2008

PowerShell

by @ 12:56 pm. Filed under quotes

“PowerShell is the COBOL of the scripting world. In that I mean as you type out what you need to do your fingers actually get tired. Powerful no doubt, but it will require most PowerShell scripters to buy a gripmaster to build up finger strength for those marathon scripting sessions or more likely, there will be a good market for autocomplete IDEs for writing PoS code.” 

Rating 3.00 out of 5

6/18/2008

PowerShell + S.DS.Protocols Versus AdFind Redux… Sorta

by @ 10:24 pm. Filed under tech

So you will recall my previous post on AdFind and PowerShell using S.DS.Protocols…

If you read activedir.org you will know that I realized some odd things occurred… I didn’t want to post back here until I had some more understanding of what is going on but now almost 2 weeks later I still haven’t a clue what is going on. I wanted to respond though. Admittedly the weather has been pretty nice here lately so I haven’t been playing computer geek as much as I did on the 9th when we had tornadoes whistling around the area (don’t worry, closest that got to me was about 3 miles away, so plenty of safety margin).

Basically the problem is that I have one PowerShell window that is performing like complete crap for the test script, and other Windows I open even though I seem to configure them similarly perform fine normally. I have been able to cause them to slow down a little by running the same commands over and over and watching it suck up silly amounts of memory but haven’t gotten it to slow down to the point the first window slows down. This really bothers me, I hate inconsistency. It throws all sorts of doubt on testing and what you have in front of you.

Interestingly running AdFind out of the two PowerShell windows results in identical performance, it is entirely within the realm of the PoS Scripts and .NET. But what? ~Eric suggested using some CLR profiler application but it apparently can’t profile something that is already running, you have to launch it with the profiler and unfortunately, my screwed up PoS window is already running.

Looking at the two Windows now, the PoS window that is “acting up” in which I just reran the test script to make sure it is still screwing up and that is all it has done in a couple of days is sitting there sucking up 140MB of RAM. The other PoS window is is using a “paltry”[1] 14MB[2].

When running in these “other” windows, the performance of PowerShell with the script is within 25% of AdFind. This is much closer to what I was expecting when I first tested it. The processor utilization of the “good” window is considerably less than what I saw with the “bad” window. Better actually than I expected out of PoS which is good. Network utilization is also much closer to AdFind which is what I expected; its the same data coming over the wire.

Again, I have no clue why that one PoS window is being troublesome, sorry. No answers here for you on that.

So anyway, oddness aside, I wanted to comment on each of the points from before.

1. Testing Methodology

I didn’t like Brandon’s testing methodology, I still don’t like what he initially did. He changed it and is now posting numbers with the new methodology. Very nice. :)

2. Testing Environment

Nothing new here.

3. Considerable performance hit on the machine running the tools…

This is related to the “bad” PoS window. Again, no clue what is happening here. The “good” PoS window has much better performance characteristics.

4. Network utilization

As mentioned above, this is now in line with AdFind as originally anticipated, again this was screwed before due to the bad window.

5. Umm there is a problem in the PoS Script…

This was all me, shortly afterward I realized while chatting with Dean about it that I used objectclass=* for AdFind and PoS was only doing an objectclass=user. I told Dean, I assume he passed that info on to Brandon.

6. The PoS doesn’t seem to fast in relation to AdFind…

Again, this is related to the bad window. The results are much closer now; within 25% in my limited tests.

 

While I have been off doing whatever, Brandon has continued forward in his tests, I highly recommend checking his blog out and reading about them. You can find it here – http://bsonposh.com/. He actually has some stuff way cooler than the perf testing that he has posted about now which is the STATS control stuff. He has sample code on how to return that info which I highly applaud. I know he spent a good portion of the weekend working through it as I got a bunch of emails from him on the details etc of it. I helped with what I felt I could[4] and then he found some docs up on MSFT in the protocols descriptions that were recently posted for legal reasons that actually describe all the stuff I had to reverse back in 2004 – http://msdn.microsoft.com/en-us/library/cc200562.aspx. I didn’t look closely at the code, but note that there were some changes in the STATS handling around the 2003 SP1 time frame as I had several people hit me with bug reports and I had to change how I was handling some of the info. I think the issue was around the calltime stuff but it was back in 2005 and I honestly don’t recall the details at the moment.

Oh Brandon mentions on his blog how PoS started surpassing AdFind for most tests when he started doing CSV data and that I would explain why. I explained to Brandon (and Dean) prior to them even getting into the tests that I expected it to occur. I don’t care too much to get into it but the gist is that the CSV handling was a hack into the tool to try and get it in there (along with -soao and -oao switches) because so many people were asking for it and I previously wasn’t planning on doing it until I built the 2.0 version of the AdFind internal logic framework[5]. Anyway when I say hack, I mean total hack, I am passing whole AdFind formatted output strings for the entire object around internally like for example

dn:DC=test,DC=loc
>objectClass: top
>objectClass: joeware-ServerClass
>objectClass: domain
>objectClass: domainDNS
>description: Test.Loc
>distinguishedName: DC=test,DC=loc
>instanceType: 5
>whenCreated: 20060512031950.0Z
>whenChanged: 20080529025642.0Z
>subRefs: CN=Configuration,DC=test,DC=loc
>subRefs: DC=ForestDnsZones,DC=test,DC=loc
>subRefs: DC=DomainDnsZones,DC=test,DC=loc
>uSNCreated: 7254

<SNIP>

and then reparsing them and reformatting into CSV format, etc. It seriously is a mess. The issue is lots of string passing between functions etc which means lots of string class instantiation going on which is dramatically slowing the AdFind down. When I was testing it back then I was seeing differences in speed between 20-60%, it was literally enough of a delta to see the difference in the output to the console. That almost prevented me from releasing the -csv/-soao/-oao switches at all. Then just bit the bullet because of my plans to rewrite the whole thing anyway. The ideas behind the new engine for AdFind will be to not do any of the formatting of the output until the very end and then it will go through a custom class that will figure out where that output is going – pipe, redirection, file, etc and output the info appropriately which should handle some of the various unicode issues people encounter at the command prompt[6].

In summary, the PoS stuff is running pretty well, when you don’t have a bad PoS Window. How you would detect that I don’t know, just have an idea on how fast your script should run I guess. For doing ad hoc DS stuff, would totally say this is fine, for constant running apps that use the directory, still won’t recommend .NET let alone PoS. PoS (and .NET) still has a lot of overhead (I had a window running some tests the other day that was eating 1.5GB and would have taken more but there was no more to take so it started throwing System.OutOfMemoryException errors…) and has been a wee bit unstable for me[7].

Possibly more later.

Oh one last thing, I tried to tweak one of Brandon’s scripts and obviously did it wrong, but it is fun to see how PoS handles it… I am currently at 1.25GB RAM being sucked up and 50%+ utilization on the PoS shell trying to run it…

$SearcherExpression = @’
$searcher = new-object System.DirectoryServices.DirectorySearcher([ADSI]“”,”(objectclass=user)”,@(“distinguishedName”))
$searcher.pagesize = 1000
$searcher.findall()
‘@
Write-Host “Test 1″
Write-Host (“-”*40)
$myresults1 = “” | select @{n=”DirectorySearcher 1″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher 2″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher 3″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher 4″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher 5″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}}, 
                          @{n=”ADFind 1″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind 2″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind 3″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind 4″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind 5″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”DSP Using 1.1 1″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 2″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 3″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 4″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 5″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
$myresults1 | fl
Write-Host “Test 2″
Write-Host (“-”*40)
$myresults2 = “” | select @{n=”ADFind #1″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #2″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #3″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #4″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #5″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”DSP Using 1.1 #1″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #2″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #3″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #4″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #5″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DirectorySearcher #1″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #2″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #3″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #4″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #5″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}}, 

$myresults2 | fl
Write-Host “Test 3″
Write-Host (“-”*40)
$myresults3 = “” | select @{n=”DSP Using 1.1 #1″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #2″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #3″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #4″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DSP Using 1.1 #5″;e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
                          @{n=”DirectorySearcher #1″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #2″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #3″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #4″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
                          @{n=”DirectorySearcher #5″;e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}}, 
                          @{n=”ADFind #1″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #2″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #3″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #4″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},
                          @{n=”ADFind #5″;e={(Measure-Command { .\adfind -b “dc=test,dc=loc” -c -f “(objectclass=user)” }).TotalSeconds}},

$myresults3 | fl
$myresults1,$myresults2,$myresults3

 

    joe

 

 

[1] Said in a sarcastic tone…. ;)

[2] For comparison, the five command prompt windows I have had open since the mid-May and that I do practically everything I do on the computer including hundreds if not thousands[3] of AdFind/AdMod commands are using 5MB combined. The PowerShell window I just opened to see how much memory it used on launch has 27MB.

[3] I run test commands against my various test AD domains all throughout the day for work.

[4]  I wasn’t about to talk about what I reverse engineered because I didn’t want to get in trouble for that…

[5] Good thing I didn’t wait, I still haven’t finished that one. ;)

[6] Not positive but last I heard, console .NET apps have the same issues. You can test it by putting in an object in your directory with some characters with umlauts or other fun characters and then write a console app to display them at the console them redirect them then pipe them and then write them to a file and then make sure it is displayed properly each way. Unicode is a bit of a pain.

[7] In trying to do various things to make it slow down like the first window I caused PoS to crash several times which I can’t recall ever doing to a command prompt window. I can understand if a script blows or an app blows, but I don’t think it should take out the shell window in the process.

Rating 3.00 out of 5

6/9/2008

PowerShell + S.DS.Protocols Versus AdFind….

by @ 3:10 am. Filed under tech

So Brandon stepped up and did something I didn’t think anyone would step up and do… Start profiling and comparing the performance of PowerShell and .NET DS Protocols against a native App using the wldap32 LDAP library[1]. Brandon’s first blog entry on the topic is here – http://bsonposh.com/archives/325

While I am going to question Brandon’s testing a little here, especially his results, I commend him for taking the time and energy to step up and actually do this[3].

I guess I should state my underlying thoughts on this whole topic since some people know, some people don’t know, and a whole lot of people *think they know* what I think about it… I would be happy to see PoS+.NET compete with or even beat out a native app+wldap32, I don’t expect it, but I would be happy to see it[6]. I definitely don’t expect to see the numbers Brandon is showing on his blog which is why I am taking the time to look at this with the detail that I am going to provide.

Anyway… Historically, there is almost always a tradeoff in terms of speed and ease of use. For instance, C++ is easier to use than Assembler but if you have a great C++ programmer and a great ASM programmer, the ASM programmer will write more code but it should almost certainly be faster, smaller compiled footprint, and more efficient overall. However some things are so painful to do or take so long or require so much code that we have moved from using ASM to using C and then C++ and other higher level compiled languages[7]. This is one of the big reasons why you use .NET. It isn’t about performance of the running code, it is about how fast you can get to having running code. It is, IMO, sort of a RAD tool, not something you want to put into heavy use, but something to prototype out what you want to do or if you just need to do something quick.

 

So after running through the tests, my results are so radically different from Brandon’s I wonder what is going on. If someone sees a mistake in the testing I followed, please let me know. I expected the results to not be as good as what Brandon came up with but I didn’t expect them to be as bad as they were.

 

1. Testing Methodology.

I don’t really like how Brandon ran his tests from a couple of angles.

The first thing I don’t like is that he uses PoS to measure the speed of PoS and AdFind. I have no clue what overhead is in there which is why I don’t like it. Brandon is obviously comfortable with it however. Whether that is blind faith or he has done comprehensive tests to prove out that it is trustworthy, I don’t know… I do know that I can’t and won’t assume the latter. His trust in it does not transition to me. I am quite untrusting.

The second thing I don’t like is how the commands are all mixed up together. When I am measuring speed on commands, especially something for AD,  I tend to run the same command over and over again so that caching is taken out of the picture as well as anything else. What I am looking for out of the numbers is consistency in times to run the specific command. If you don’t see consistency, it tends to mean something else is playing into the tests. I would prefer to see 5, 10, or 100 runs of the same command in a row and then ditto for the next command and the next, etc. I don’t see consistency in Brandon’s reported numbers. Way too much skew.

 

Solutions

My solutions for these issues are

A. Instead of using a PoS script to launch AdFind and the Counting PoS script, I changed the prompt in PoS to include the current time with the following command

function prompt {Write-Host $(get-date).Tostring(“yyyy-MM-dd HH:mm:ss”)}

That gives me a prompt that looks like

2008-06-08 17:16:25
PS>

Then I just paste in my commands I want to run with a blank line at the beginning and end of the command sequence. This is something I do in the normal command prompt as well (though my prompt in that case is instead prompt=[$D $T] $M$+ $_$P$G). That makes it so the shell stamps the time to the console right there on the spot like so…

Command Sequence

  • [ENTER]
  • [ENTER]
  • dir
  • [ENTER]
  • [ENTER]

Which generates output like

2008-06-08 18:13:12
PS>
2008-06-08 18:13:23
PS>
2008-06-08 18:13:23
PS>dir

    Directory: Microsoft.PowerShell.Core\FileSystem::G:\PSTest

Mode                LastWriteTime     Length Name
—-                ————-     —— —-
-a—         6/24/2007  10:06 PM    2013184 AdFind.exe
-a—          6/8/2008  10:37 AM       1559 PSSpeed.ps1
-a—          6/8/2008  10:33 AM       2338 Test-DSProtocalsSP.ps1

2008-06-08 18:13:23
PS>
2008-06-08 18:13:23
PS>

I think anyone who looks at it should be comfortable with this method. If not, please let me know what you aren’t comfortable about.

 

 

B. So my solution for the second issue is probably pretty obvious after seeing the solution to the first… Have a notepad document with some commands all ready to cut and paste into the PoS window in one fell swoop. That looks something like

  • [ENTER]
  • [ENTER]
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • [ENTER]
  • [ENTER]
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • [ENTER]
  • [ENTER]

 

and a “10 count run”

  • [ENTER]
  • [ENTER]
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • adfind -default -f objectclass=* -c
  • [ENTER]
  • [ENTER]
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • .\Test-DSProtocalsSP.ps1
  • [ENTER]
  • [ENTER]

 

2. Testing environment

I think testing against a 700k user environment is a bit extreme as there aren’t but a handful of AD Implementations out there that come anywhere near that but maybe it is good in that it will help stabilize any time variance issues resulting from spin up time for the app/script. I.E. If you have a second of overhead for starting an app, the more objects you have to pull, the smaller the percentage that overhead will be of the total execution time. I kind of think this tends to help PoS more than a native app because a native app has very little spin up overhead relative to PoS script or .NET but I will go with it. If anything, launching AdFind from within PoS likely has more overhead for launch than launching a PoS script from PoS. If someone wants to test on different sized environments, knock yourself out. I am already spending too much time on this.

I used AdMod to create 700k test users on my test domain with the following command:

admod -sc adau:70000;MyPassword1!;cn=PoSTest,ou=PoSTest,dc=test,dc=loc

I am running all of my tests against a virtual DC loaded with Windows Server 2003 SP2; it is one of 3 virtuals currently running on an Intel Quad Core Server box I build specifically for running virtuals using VMWARE Server. The RAM allocated (256MB) is not even close enough to cache the entire DIT (~2.75GB) even if I enabled /3GB (which I didn’t, no point…). The actual code is running on a real physical machine that has x86 XP SP2 on it and is a AMD Athlon 64 X2 4200+ Dual Core proc. Underlying network is 100Mbs with most network traffic quiesced for the testing period.

I am using the publicly available version of AdFind – V01.37.00 compiled on June 24, 2007.

PS>filever adfind.exe
–a– W32i   APP ENU     1.37.0.1604 shp  2,013,184 06-24-2007 adfind.exe

I am using the PoS Script that Brandon posted on his blog…Here it is again for completeness. Brandon, note a good modification to the script would be to output what DC it is connecting to to do the work so you know if it is consistently connecting to the same place and that AdFind and the script are connecting to the same place. I validated that it appeared to be using the same DC as AdFind by doing some network tracing. That shouldn’t be needed and honestly there should be a way to specify the domain/DC to use to make sure the same source is used consistently.

Test-DSProtocalsSP.ps1

[System.Reflection.assembly]::LoadWithPartialName(“system.directoryservices.protocols”) | Out-Null
$domain = ([ADSI]“”).distinguishedName -replace  “,”,”.” -replace “dc=”,””
$DomainDN = “DC=” + $Domain -replace “\.”,”,DC=”
[int]$pageCount = 0
[int]$pageSize = 1000
[int]$count = 0
$connection = New-Object System.DirectoryServices.Protocols.LdapConnection($domain) 
$subtree = [System.DirectoryServices.Protocols.SearchScope]“Subtree”
$filter = “(objectclass=user)”
$searchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest($DomainDN,$filter,$subtree,@(“1.1″)) 
$pagedRequest = New-Object System.DirectoryServices.Protocols.PageResultRequestControl($pageSize)
$searchRequest.Controls.add($pagedRequest) | out-null
$searchOptions = new-object System.DirectoryServices.Protocols.SearchOptionsControl([System.DirectoryServices.Protocols.SearchOption]::DomainScope)
$searchRequest.Controls.Add($searchOptions) | out-null
while ($true)
{
    ## increment the pageCount by 1
    $pageCount++
    ## cast the directory response into a
    ## SearchResponse object
    $searchResponse = $connection.SendRequest($searchRequest)
    ## verify support for this advanced search operation
    if (($searchResponse.Controls.Length -lt 1) -or
        !($searchResponse.Controls[0] -is [System.DirectoryServices.Protocols.PageResultResponseControl]))
    {
        Write-Host “The server cannot page the result set”
        return;
    }
    ## cast the diretory control into
    ## a PageResultResponseControl object.
    $pageResponse = $searchResponse.Controls[0]
    ## display the retrieved page number and the number of
    ## directory entries in the retrieved page                   
    #”Page:{0} Contains {1} response entries” -f $pageCount,$searchResponse.entries.count
    $count += $searchResponse.entries.count
    ## display the entries within this page
    ## foreach($entry in $searchResponse.entries){$entry.DistinguishedName}
    ## if this is true, there
    ## are no more pages to request
    if ($pageResponse.Cookie.Length -eq 0){write-Host $count;break}
    ## set the cookie of the pageRequest equal to the cookie
    ## of the pageResponse to request the next page of data
    ## in the send request
    $pagedRequest.Cookie = $pageResponse.Cookie
}

 

3. Considerable performance hit on the machine running the tools…. Based on .FAT[11] isn’t it???

This one is actually pretty humourous, doesn’t take much to see what is happening… It shows quite quickly and easily one of my issues with using something other than native code; especially .NET/PoS. This is what you get as you abstract and bloat… This is a part of the reason why it is slow overall, it beats the machine up.

 

Figure 1 shows my machine at “idle”. When I watched it I saw CPU usage bumps between 0% and 5% with spikes up to about 15%.

image

                                                     [Figure 1]

 

Figure 2 shows AdFind running the command “adfind -default -f objectclass=* -c” which counts the objects in the domain NC. When I watched it I saw CPU usage bumps between about 4% and 11% with spikes up to about 18%.

image

                                                     [Figure 2]

 

 

Figure 3 shows Brandon’s PoS script counting the objects in the domain NC. When I watched it I saw CPU usage bumps between 20% and 45% with spikes up to around 50%.

image

                                                     [Figure 3]

 

If you don’t like pretty pictures and prefer hard text data instead, here is output from typeperf… 35 one second samples from each state…

 

This is when idling

“(PDH-CSV 4.0)”,”\\SFMXP32\processor(_total)\% processor time”

“06/08/2008 17:00:04.789″,”0.000000″
“06/08/2008 17:00:05.789″,”0.000000″
“06/08/2008 17:00:06.789″,”0.000000″
“06/08/2008 17:00:07.789″,”0.000000″
“06/08/2008 17:00:08.789″,”0.774265″
“06/08/2008 17:00:09.789″,”0.000000″
“06/08/2008 17:00:10.789″,”0.000000″
“06/08/2008 17:00:11.789″,”0.000000″
“06/08/2008 17:00:12.789″,”0.000000″
“06/08/2008 17:00:13.789″,”0.000000″
“06/08/2008 17:00:14.789″,”0.774265″
“06/08/2008 17:00:15.789″,”0.774265″
“06/08/2008 17:00:16.789″,”0.000000″
“06/08/2008 17:00:17.789″,”0.774265″
“06/08/2008 17:00:18.789″,”0.000000″
“06/08/2008 17:00:19.788″,”0.000000″
“06/08/2008 17:00:20.788″,”2.336875″
“06/08/2008 17:00:21.788″,”0.774265″
“06/08/2008 17:00:22.788″,”2.336875″
“06/08/2008 17:00:23.788″,”0.000000″
“06/08/2008 17:00:24.788″,”0.000000″
“06/08/2008 17:00:25.788″,”0.000000″
“06/08/2008 17:00:26.788″,”0.000000″
“06/08/2008 17:00:27.788″,”0.000000″
“06/08/2008 17:00:28.788″,”0.000000″
“06/08/2008 17:00:29.788″,”0.774265″
“06/08/2008 17:00:30.788″,”0.000000″
“06/08/2008 17:00:31.788″,”1.555570″
“06/08/2008 17:00:32.788″,”0.000000″
“06/08/2008 17:00:33.787″,”0.774265″
“06/08/2008 17:00:34.787″,”0.000000″
“06/08/2008 17:00:35.787″,”0.000000″
“06/08/2008 17:00:36.787″,”0.000000″
“06/08/2008 17:00:37.787″,”0.000000″
“06/08/2008 17:00:38.787″,”0.000000″
“06/08/2008 17:00:39.787″,”0.000000″
“06/08/2008 17:00:40.787″,”0.000000″
“06/08/2008 17:00:41.787″,”0.000000″
“06/08/2008 17:00:42.787″,”0.000000″
“06/08/2008 17:00:43.787″,”0.000000″
“06/08/2008 17:00:44.787″,”0.774265″

 

This is when AdFind was running

“(PDH-CSV 4.0)”,”\\SFMXP32\processor(_total)\% processor time”

“06/08/2008 17:01:06.785″,”1.555570″
“06/08/2008 17:01:07.785″,”6.243400″
“06/08/2008 17:01:08.785″,”3.899485″
“06/08/2008 17:01:09.785″,”8.587315″
“06/08/2008 17:01:10.785″,”10.931230″
“06/08/2008 17:01:11.800″,”7.685809″
“06/08/2008 17:01:12.800″,”10.931230″
“06/08/2008 17:01:13.800″,”14.056450″
“06/08/2008 17:01:14.800″,”9.368620″
“06/08/2008 17:01:15.800″,”15.619060″
“06/08/2008 17:01:16.800″,”5.462095″
“06/08/2008 17:01:17.800″,”9.368620″
“06/08/2008 17:01:18.800″,”13.275145″
“06/08/2008 17:01:19.800″,”9.368620″
“06/08/2008 17:01:20.800″,”11.712535″
“06/08/2008 17:01:21.800″,”5.462095″
“06/08/2008 17:01:22.800″,”10.149925″
“06/08/2008 17:01:23.800″,”6.243400″
“06/08/2008 17:01:24.799″,”6.243400″
“06/08/2008 17:01:25.799″,”9.368620″
“06/08/2008 17:01:26.799″,”8.587315″
“06/08/2008 17:01:27.799″,”9.368620″
“06/08/2008 17:01:28.799″,”10.149925″
“06/08/2008 17:01:29.799″,”11.712535″
“06/08/2008 17:01:30.799″,”14.837755″
“06/08/2008 17:01:31.799″,”5.462095″
“06/08/2008 17:01:32.799″,”9.368620″
“06/08/2008 17:01:33.799″,”6.243400″
“06/08/2008 17:01:34.799″,”2.336875″
“06/08/2008 17:01:35.799″,”0.774265″
“06/08/2008 17:01:36.799″,”3.118180″
“06/08/2008 17:01:37.799″,”1.555570″
“06/08/2008 17:01:38.799″,”2.336875″
“06/08/2008 17:01:39.798″,”4.680790″
“06/08/2008 17:01:40.798″,”5.462095″
“06/08/2008 17:01:41.798″,”9.368620″
“06/08/2008 17:01:42.798″,”3.118180″

 

This is when the PoS Script was running

“(PDH-CSV 4.0)”,”\\SFMXP32\processor(_total)\% processor time”

“06/08/2008 17:09:17.344″,”36.918636″
“06/08/2008 17:09:18.407″,”41.786947″
“06/08/2008 17:09:19.422″,”43.072915″
“06/08/2008 17:09:20.469″,”44.772231″
“06/08/2008 17:09:21.516″,”35.816377″
“06/08/2008 17:09:22.563″,”33.083524″
“06/08/2008 17:09:23.594″,”36.918636″
“06/08/2008 17:09:24.594″,”29.682550″
“06/08/2008 17:09:25.594″,”33.589075″
“06/08/2008 17:09:26.609″,”29.540494″
“06/08/2008 17:09:27.656″,”29.540494″
“06/08/2008 17:09:28.734″,”41.300215″
“06/08/2008 17:09:29.734″,”36.359156″
“06/08/2008 17:09:30.797″,”34.086269″
“06/08/2008 17:09:31.812″,”31.533642″
“06/08/2008 17:09:32.812″,”28.901245″
“06/08/2008 17:09:33.828″,”33.072211″
“06/08/2008 17:09:34.859″,”33.328640″
“06/08/2008 17:09:35.859″,”34.610781″
“06/08/2008 17:09:36.905″,”34.086269″
“06/08/2008 17:09:37.952″,”35.816377″
“06/08/2008 17:09:38.952″,”35.151685″
“06/08/2008 17:09:40.015″,”32.348178″
“06/08/2008 17:09:41.046″,”39.547983″
“06/08/2008 17:09:42.093″,”38.230946″
“06/08/2008 17:09:43.139″,”40.904931″
“06/08/2008 17:09:44.186″,”38.230946″
“06/08/2008 17:09:45.217″,”39.839515″
“06/08/2008 17:09:46.233″,”36.918636″
“06/08/2008 17:09:47.233″,”46.089955″
“06/08/2008 17:09:48.280″,”41.786947″
“06/08/2008 17:09:49.280″,”27.338635″
“06/08/2008 17:09:50.280″,”38.276905″
“06/08/2008 17:09:51.279″,”39.839515″
“06/08/2008 17:09:52.279″,”32.807770″
“06/08/2008 17:09:53.295″,”31.533642″
“06/08/2008 17:09:54.295″,”41.402125″
“06/08/2008 17:09:55.342″,”49.250159″
“06/08/2008 17:09:56.342″,”34.610781″
“06/08/2008 17:09:57.388″,”39.389672″
“06/08/2008 17:09:58.388″,”32.807770″
“06/08/2008 17:09:59.420″,”41.662560″
“06/08/2008 17:10:00.435″,”42.533268″
“06/08/2008 17:10:01.497″,”39.389672″
“06/08/2008 17:10:02.513″,”31.533642″
“06/08/2008 17:10:03.513″,”32.571011″
“06/08/2008 17:10:04.575″,”40.904931″
“06/08/2008 17:10:05.575″,”32.807770″
“06/08/2008 17:10:06.575″,”32.026465″
“06/08/2008 17:10:07.575″,”9.368620″
“06/08/2008 17:10:08.575″,”27.338635″
“06/08/2008 17:10:09.591″,”37.687921″
“06/08/2008 17:10:10.637″,”41.786947″
“06/08/2008 17:10:11.653″,”39.995776″
“06/08/2008 17:10:12.684″,”46.965963″
“06/08/2008 17:10:13.731″,”58.820630″
“06/08/2008 17:10:14.762″,”39.995776″
“06/08/2008 17:10:15.778″,”39.547983″
“06/08/2008 17:10:16.840″,”40.147302″
“06/08/2008 17:10:17.871″,”37.495600″

Plugged into Excel, these are the stats for those 35 data points

Idle

  • Min: 0
  • Max: 2.336875
  • Avg: 0.332834
  • Median: 0
  • Skew: 2.156378
  • Variance: 0.401792

AdFind

  • Min: 0.774265
  • Max: 15.61906
  • Avg: 7.75793
  • Median: 8.587315
  • Skew: 0.05928
  • Variance: 15.36671

PoS

  • Min: 27.33864
  • Max: 46.08996
  • Avg: 36.14655
  • Median: 35.81638
  • Skew: 0.157006
  • Variance: 21.74553

 

4. Network Utilization

After running a couple of tests and going out and working in the yard for a bit I thought… hmmm With the results I saw, I bet the network utilization numbers are off too between AdFind and the script… Sure enough.

 

Figure 4 is idle use

image

                                                     [Figure 4]

 

Figure 5 is AdFind use

image

                                                     [Figure 5]

 

Figure 6 is the PoS Script.

image

                                                     [Figure 6]

 

Note the percentage range on the graphs… The AdFind graph has a range of 0-25% and the PoS graph has a range of 0-5%…

 

Again with some typeperf stats… 35 data points for each state again….

 

This is when idling…

“(PDH-CSV 4.0)”,”\\SFMXP32\network interface(Realtek RTL8168_8111 PCI-E Gigabit Ethernet NIC – Packet Scheduler Miniport)\Bytes Total/sec”

06/08/2008 20:21:15.101,”0.000000″
06/08/2008 20:21:16.101,”0.000000″
06/08/2008 20:21:17.101,”0.000000″
06/08/2008 20:21:18.101,”0.000000″
06/08/2008 20:21:19.101,”0.000000″
06/08/2008 20:21:20.116,”0.000000″
06/08/2008 20:21:21.116,”0.000000″
06/08/2008 20:21:22.116,”0.000000″
06/08/2008 20:21:23.116,”0.000000″
06/08/2008 20:21:24.116,”0.000000″
06/08/2008 20:21:25.116,”0.000000″
06/08/2008 20:21:26.132,”0.000000″
06/08/2008 20:21:27.132,”0.000000″
06/08/2008 20:21:28.132,”0.000000″
06/08/2008 20:21:29.132,”0.000000″
06/08/2008 20:21:30.132,”0.000000″
06/08/2008 20:21:31.132,”0.000000″
06/08/2008 20:21:32.132,”0.000000″
06/08/2008 20:21:33.132,”0.000000″
06/08/2008 20:21:34.147,”0.000000″
06/08/2008 20:21:35.147,”0.000000″
06/08/2008 20:21:36.147,”0.000000″
06/08/2008 20:21:37.147,”0.000000″
06/08/2008 20:21:38.147,”409.193170″
06/08/2008 20:21:39.147,”0.000000″
06/08/2008 20:21:40.147,”0.000000″
06/08/2008 20:21:41.147,”0.000000″
06/08/2008 20:21:42.163,”0.000000″
06/08/2008 20:21:43.163,”0.000000″
06/08/2008 20:21:44.163,”0.000000″
06/08/2008 20:21:45.163,”0.000000″
06/08/2008 20:21:46.163,”0.000000″
06/08/2008 20:21:47.163,”0.000000″
06/08/2008 20:21:48.163,”0.000000″
06/08/2008 20:21:49.163,”0.000000″

 

AdFind query…

“(PDH-CSV 4.0)”,”\\SFMXP32\network interface(Realtek RTL8168_8111 PCI-E Gigabit Ethernet NIC – Packet Scheduler Miniport)\Bytes Total/sec”

06/08/2008 20:22:48.303,”432.148631″
06/08/2008 20:22:49.303,”7812.669507″
06/08/2008 20:22:50.319,”215500.866875″
06/08/2008 20:22:51.319,”675597.824476″
06/08/2008 20:22:52.319,”210349.356274″
06/08/2008 20:22:53.319,”1266930.446812″
06/08/2008 20:22:54.319,”1416464.689079″
06/08/2008 20:22:55.319,”1558286.015944″
06/08/2008 20:22:56.319,”425118.163681″
06/08/2008 20:22:57.334,”1344444.782983″
06/08/2008 20:22:58.334,”1137181.434605″
06/08/2008 20:22:59.334,”1597069.087841″
06/08/2008 20:23:00.334,”1312058.658551″
06/08/2008 20:23:01.334,”1530619.724371″
06/08/2008 20:23:02.334,”1676687.003461″
06/08/2008 20:23:03.334,”1603403.974700″
06/08/2008 20:23:04.334,”1676201.171529″
06/08/2008 20:23:05.350,”1755335.554489″
06/08/2008 20:23:06.350,”1815894.653956″
06/08/2008 20:23:07.350,”1748979.095744″
06/08/2008 20:23:08.350,”1457658.560362″
06/08/2008 20:23:09.350,”1749027.180590″
06/08/2008 20:23:10.350,”1748969.577365″
06/08/2008 20:23:11.350,”1602738.860017″
06/08/2008 20:23:12.350,”1880224.306196″
06/08/2008 20:23:13.366,”1543784.545800″
06/08/2008 20:23:14.366,”1528733.402130″
06/08/2008 20:23:15.366,”1748985.669767″
06/08/2008 20:23:16.365,”1675179.234176″
06/08/2008 20:23:17.365,”1750306.711728″
06/08/2008 20:23:18.365,”1374845.844406″
06/08/2008 20:23:19.365,”1975074.793721″
06/08/2008 20:23:20.381,”1457283.676124″
06/08/2008 20:23:21.381,”1603445.281594″
06/08/2008 20:23:22.381,”1674138.066714″

 

And PoS script

“(PDH-CSV 4.0)”,”\\SFMXP32\network interface(Realtek RTL8168_8111 PCI-E Gigabit Ethernet NIC – Packet Scheduler Miniport)\Bytes Total/sec”

06/08/2008 20:24:23.537,”95271.394985″
06/08/2008 20:24:24.537,”152096.806819″
06/08/2008 20:24:25.537,”304867.276069″
06/08/2008 20:24:26.537,”229631.839613″
06/08/2008 20:24:27.537,”76356.320892″
06/08/2008 20:24:28.553,”282718.881348″
06/08/2008 20:24:29.553,”212996.840599″
06/08/2008 20:24:30.553,”428616.679015″
06/08/2008 20:24:31.553,”288234.300414″
06/08/2008 20:24:32.553,”288276.315703″
06/08/2008 20:24:33.553,”287835.901916″
06/08/2008 20:24:34.568,”144267.514096″
06/08/2008 20:24:35.568,”288038.282918″
06/08/2008 20:24:36.568,”287903.691420″
06/08/2008 20:24:37.568,”215894.243299″
06/08/2008 20:24:38.568,”288022.088767″
06/08/2008 20:24:39.584,”287852.416168″
06/08/2008 20:24:40.584,”287907.460559″
06/08/2008 20:24:41.584,”287867.971897″
06/08/2008 20:24:42.584,”216662.763604″
06/08/2008 20:24:43.584,”359322.953951″
06/08/2008 20:24:44.584,”216204.281269″
06/08/2008 20:24:45.599,”287921.254846″
06/08/2008 20:24:46.599,”216670.797928″
06/08/2008 20:24:47.599,”431409.468785″
06/08/2008 20:24:48.599,”216048.609884″
06/08/2008 20:24:49.599,”360909.160668″
06/08/2008 20:24:50.599,”359313.537159″
06/08/2008 20:24:51.599,”216058.961104″
06/08/2008 20:24:52.615,”287855.543216″
06/08/2008 20:24:53.615,”362659.902837″
06/08/2008 20:24:54.615,”292073.121217″
06/08/2008 20:24:55.615,”292124.653467″
06/08/2008 20:24:56.615,”219204.028101″
06/08/2008 20:24:57.615,”219607.804823″

 

Plugged into Excel, these are the stats for those 35 data points

Idle

  • Min: 0
  • Max: 409.19317
  • Avg: 11.691233
  • Median: 0
  • Skew: 5.9160798
  • Variance: 4783.9729

AdFind

  • Min: 432.15
  • Max: 1,975,074.79  (1.88 MB/s)
  • Avg: 1,364,136.09 (1.30 MB/s)
  • Median: 1,558,286.02 (1.49 MB/s)
  • Skew: -1.55
  • Variance: 301,963,579,984.33

PoS

  • Min: 76,356.32
  • Max: 431,409.47 (.41 MB/s)
  • Avg: 265,391.52 (.25 MB/s)
  • Median: 287,855.54 (.27 MB/s)
  • Skew: -0.21
  • Variance: 6,301,469,856.37

 

Average of 1.3 MB per second versus .25  MB per second… AdFind is pulling the data 5 times faster… This absolutely does not support what Brandon saw in his tests which makes me question what is different or is the PoS timing script he is using that bad? Both tools have to pull the same amount of data to get object counts, there are no shortcuts… If AdFind pulls the data 5 times faster, it has the potential to be at least 5 times faster at execution.

 

5. Umm there is a problem in the PoS Script… It doesn’t seen to know how to count correctly.

Here is what AdFind says the count is… 711387

Here is what the script says the count is… 711145

Looking at the script I am pretty sure I know what is wrong but will let Brandon sort it out.  Good learning exercise… ;)

 

6. The PoS doesn’t seem so fast in relation to AdFind…  (at least to me)

So here are the results of the actual tests…

First the two count run…

 

2008-06-08 20:52:45
PS>
2008-06-08 20:52:46
PS>
2008-06-08 20:52:46
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 20:53:19
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 20:54:01
PS>
2008-06-08 20:54:01
PS>
2008-06-08 20:54:01
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 20:57:22
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:00:48
PS>
2008-06-08 21:00:48
PS>
2008-06-08 21:00:48
PS>

Here are the numbers

AdFind

  1. 20:52:46 – 20:53:19  = 33 seconds
  2. 20:53:19 – 20:54:01 = 42 seconds

 

PoS

  1. 20:54:01 – 20:57:22 = 201 seconds (3 minutes 21 seconds)
  2. 20:57:22 – 21:00:48 = 206 seconds (3 minutes 26 seconds)

 

This is showing AdFind is roughly 4.5-6.25 times faster than the PoS script which is what the network traffic implied.

 

So let’s look at the 10 count test and see if we have consistency…

 

2008-06-08 21:01:27
PS>
2008-06-08 21:02:08
PS>
2008-06-08 21:02:08
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:02:49
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:03:36
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:04:22
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:05:06
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:05:52
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:06:38
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:07:25
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:08:13
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:09:02
PS>adfind -default -f objectclass=* -c

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) June 2007

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

711387 Objects returned
2008-06-08 21:09:47
PS>
2008-06-08 21:09:47
PS>
2008-06-08 21:09:47
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:13:17
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:16:47
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:20:14
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:23:49
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:27:18
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:30:45
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:34:14
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:37:50
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:41:22
PS>.\Test-DSProtocalsSP.ps1
711145
2008-06-08 21:45:22
PS>
2008-06-08 21:45:22
PS>
2008-06-08 21:45:22
PS>

 

Here are the numbers

 

AdFind

  1. 21:02:08 – 21:02:49 = 41 seconds
  2. 21:02:49 – 21:03:36 = 47 seconds
  3. 21:03:36 – 21:04:22 = 46 seconds
  4. 21:04:22 – 21:05:06 = 44 seconds
  5. 21:05:06 – 21:05:52 = 46 seconds
  6. 21:05:52 – 21:06:38 = 46 seconds
  7. 21:06:38 – 21:07:25 = 47 seconds
  8. 21:07:25 – 21:08:13 = 48 seconds
  9. 21:08:13 – 21:09:02 = 49 seconds
  10. 21:09:02 – 21:09:47 = 45 seconds

 

PoS

  1. 21:09:47 – 21:13:17 = 210 seconds (3 minutes 30 seconds)
  2. 21:13:17 – 21:16:47 = 210 seconds (3 minutes 30 seconds)
  3. 21:16:47 – 21:20:14 = 207 seconds (3 minutes 27 seconds)
  4. 21:20:14 – 21:23:49 = 215 seconds (3 minutes 35 seconds)
  5. 21:23:49 – 21:27:18 = 209 seconds (3 minutes 29 seconds)
  6. 21:27:18 – 21:30:45 = 207 seconds (3 minutes 27 seconds)
  7. 21:30:45 – 21:34:14 = 209 seconds (3 minutes 29 seconds)
  8. 21:34:14 – 21:37:50 = 216 seconds (3 minutes 36 seconds)
  9. 21:37:50 – 21:41:22 = 212 seconds (3 minutes 32 seconds)
  10. 21:41:22 – 21:45:22 = 240 seconds (4 minutes 0 seconds)

 

After seeing those numbers I thought wow and then tried it all again but flipped it around and had PoS run first and then AdFind. In summary the PoS stuff started at 22:51:49 and finished at 23:30:22, that is 37 minutes and 33 seconds or 2253 seconds or an average of 225.3 seconds for 10 runs (compared to 21:09:47 to 21:45:22 which is 35 minutes and 35 seconds or 2135 seconds or an average of 213.5 seconds for 10 runs). The AdFind stuff started at 23:30:22 and finished at 23:37:59, that is 7 minutes 37 seconds or 457 seconds or an average of 45.7 seconds for 10 runs (compared to 21:02:08 to 21:09:47 which is 7 minutes 39 seconds or 459 seconds or an average of 45.9 seconds for 10 runs). So we are seeing that AdFind is between 4.22 and 5.85 times faster than PoS.

 

I consider those numbers to be very consistent as well as very telling. I can’t for the life of me explain why Brandon and my numbers are so dramatically different other than maybe trying to use a PoS script to measure the perf of AdFind and the other PoS Script may not be the optimal test framework and is maybe introducing some other errors? Alternately maybe he has some special tuning for .NET stuff? That shouldn’t be needed, but I know I don’t have any special tunings, my machine has whatever the .NET stuff loads as is and PowerShell loaded on top. I guess possibly he changed the script and didn’t post the latest version to his blog… I don’t know. I just know where he was seeing seconds of difference, I see no way of that occurring.

 

Thoughts?

 

    joe

 

 

[1] I think it sort of went like this… He maybe got tired of hearing about PowerShell being fat and slow (ditto .NET) so set out to prove that it could be as performant or maybe close to as performant as native code. I am just guessing based on my knowledge of Brandon and what he has written on this testing. I know Brandon sometimes likes to fight for the sake of fighting[2]… not a problem, I am fine with that. I debated with him in person for several days at the last MVP summit.

[2] Yes you really do Brandon.

[3] FWIW, I think most folks are just going to up and assume .NET and PoS are going to be slower and accept it for what it is; people don’t use those technologies because they want raw run performance, they want ease of getting to what they want to get to[4].

[4] I am, despite what some may think, ok with that. In fact, I often tell people who are starting out now in DS programming to look at the .NET stuff instead of the native stuff[5] because quite honestly with the exception of true professional programmers I think the raw LDAP and native code stuff might be a bit much for many of the computer people of today… However, this doesn’t mean I am looking at using it. I am already spun up on the native and raw LDAP stuff.

[5] Using the .NET Framework will be easier to spin up and go for most of the folks in the field today who aren’t already seasoned programmers (with real language backgrounds… this IMO excludes VB from discussion); especially admins.  However, I don’t want them writing any serious app that is doing a ton of work that I will be dependent on using heavily. Using it to get some basic stuff going or stuff that I never have to use I have no problem with.

[6] That is because it means the “next generation” programming mechanisms aren’t going to make us all upgrade our hardware yet again… How does it go… Something like…  Intel Giveth us Speed, Microsoft takes it away… In all honesty, I don’t expect to see .NET being truly performant to any well written native code standards until it is embedded in the core and absolutely HAS to be performant. Note the key use of “well written”. Just because someone writes in native code, doesn’t mean they write well and for those people that don’t write well, they likely will do better writing in .NET. So anyway, I want to see .NET and PoS work well and efficiently because it will likely be heavily used and I would rather people not be running a bunch of slow crap out there as I may end up dealing with it one way or another.

[7] We are slowly moving out from the intricacies of the hardware abstracting more and more. It is a curve where on the far left we have the binary machine language which is all 0′s and 1′s and as you move towards the right you get to more and more complexity and robustness and hopefully ease of use. But also as you move to the right while you gain the ease of use abstraction, you pay more and more penalty in performance for that abstraction. First step after machine language… Assembler, then Macro Assembler, and then say C and then C++ and FORTRAN and COBOL, etc etc etc… We have moved further and further right in the curve[8] as we “evolve” in our use of computers and as the right becomes more acceptable either by becoming more performant from learning and making things more efficient or we just are more accepting of the trade offs because computers get faster and what ran slow yesterday runs faster today or we just can’t be bothered to worry about the speed period.

[8] The .NET framework is on the far right side of this curve right now and may or may not be what we go to next as the de facto for things that native C++, IMO, is now. I don’t think it has been proven conclusively one way or the other yet. Java has been claiming it is the de facto now for at least 10 years. I still haven’t written a line of Java though back in the late 90′s all my “cool” friends said I would, it was just a matter of time…. “You just wait joe… No one will be writing anything in C++ in 10 years… it will all be Java[9] and CORBA[10]…”

[9] The .NET stuff, at least to me, is Microsoft’s “Java”. Might as well called it MSava (sic) in my mind. :) Anyway now all my .NET friends say the same things to me my Java friends said. Granted, they are more likely to be correct, but not guaranteed to be…

[10] Interestingly, at least to me, is that now right around 10 years later most people in the computer world know of and have heard of Java but say “What the frack is CORBA???”

[11] I can’t take the credit for .FAT, but I like it just the same. :)

Rating 4.00 out of 5

3/28/2008

PowerShell

by @ 6:54 pm. Filed under tech

I don’t use it, don’t really intend to use it unless absolutely forced kicking and screaming to. Will not write a provider for AdFind nor AdMod nor any of my tools for it.

 

     love joe

Rating 3.00 out of 5

4/26/2006

Monad becomes PowerShell?

by @ 8:09 am. Filed under tech

http://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx

Yep its true… Can’t say that the name PowerShell makes me quiver or anything. I recall how the first time I heard the Monad name I was like, hey pretty cool name, a science (chemistry) term. The name PowerShell makes me think of a MAC. 

Oh well, it appears it will be released to web Q4 2006.

  joe

Rating 3.00 out of 5

9/8/2012

Barf…

by @ 2:30 pm. Filed under tech

 

image

 

I have determined that the new strategy to get people to move to powershell is to make the GUI experience so damn slow and bad you couldn’t possibly get any work done if you try to go that route.

Rating 4.33 out of 5

12/28/2011

Default Tombstone Lifetime yet again… Alternate working title: TechNet why do you hate tombstoneLifetime and correct information?

by @ 10:15 am. Filed under tech

Many moons ago I wrote a post about how a TechNet article on the default tombstone lifetime was wrong. That TechNet article eventually ended up getting corrected at some point though it doesn’t seem to be properly linked anymore to the GUID URL that I had for it – so much for theory of never losing TechNet articles again because they were "unique" GUID links… Regardless, it has been brought to my attention that once again a TechNet article has screwed this simple topic up when updating it for PowerShell[1].

http://technet.microsoft.com/en-us/library/dd392260(WS.10).aspx

Both here

By default, tombstoneLifetime is set to null. When tombstoneLifetime is set to null, the tombstone lifetime defaults to 180 days (hard-coded in the system)

and

In Windows Server 2003 with Service Pack 1 (SP1), Windows Server 2003 with Service Pack 2 (SP2), Windows Server 2008, or Windows Server 2008 R2 operating systems, when tombstoneLifetime is set to null its value defaults to 180 days.

So for now and all eternity, please link to, copy and paste, recite, or whatever you do around this topic from this blog post.

The tombstoneLifetime attribute is very simple. Don’t worry about the operating system as it exists now, don’t worry about the operating system as it existed when the Active Directory was initially built, it is all moot. The one and only way to know what the tombstoneLifetime value for a forest is is to look at it.

  1. If the value of tombstoneLifetime is NULL or <NOT SET> the value *IS* 60 days.
  2. If the value of tombstoneLifetime is > 0. The value *IS* the integer specified measured in days.

You can easily ascertain the value by using the following command: [2]

adfind -config -f objectclass=ntdsservice tombstonelifetime

Which will look like

C:\>adfind -config -f objectclass=ntdsservice tombstonelifetime

AdFind V01.45.00cpp Joe Richards (joe@joeware.net) March 2011

Using server: K8R2Dom-DC1.k8r2dom.loc:389
Directory: Windows Server 2008 R2
Base DN: CN=Configuration,DC=k8r2dom,DC=loc

dn:CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=k8r2dom,DC=loc
>tombstoneLifetime: 180

1 Objects returned

Or if you really want to make this simple, use the following:

adfind -config -f objectclass=ntdsservice tombstonelifetime -oao 60

which will display the integer value no matter what through some AdFind "magic". That magic being that the -oao switch when specified with a value will populate that value in any empty attributes. So if the value isn’t populated in AD, it will still look like it is when the output is displayed.

For example, same command with one non-existent attribute to help illustrate the point:

C:\>adfind -config -f objectclass=ntdsservice tombstonelifetime hardcodedWindowsADTombstoneLifetimeValue -oao 60

AdFind V01.45.00cpp Joe Richards (joe@joeware.net) March 2011

Using server: K8R2Dom-DC1.k8r2dom.loc:389
Directory: Windows Server 2008 R2
Base DN: CN=Configuration,DC=k8r2dom,DC=loc

dn:CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=k8r2dom,DC=loc
>tombstoneLifetime: 180
>hardcodedWindowsADTombstoneLifetimeValue: 60

1 Objects returned

You can do the same with CSV

adfind -config -f objectclass=ntdsservice tombstonelifetime -nodn -csv 60

which could look something like:

C:\>adfind -config -f objectclass=ntdsservice tombstonelifetime hardcodedWindowsADTombstoneLifetimeValue -csv 60 -nodn
"tombstonelifetime","hardcodedWindowsADTombstoneLifetimeValue"
"180","60"

Simple?

In 2017 when this gets screwed up again in TechNet when they are describing how to figure it out with whatever new fancy tool they have now switched to the above information will STILL be correct and that AdFind command will still work just fine.

 

     joe

 

[1] Further proof that PowerShell isn’t doing anything new, it is simply redoing what was done before with more verbose commands… ;)

[2] Or… even shorter  "adfind -b -pr -f objectclass=ntdsservice tombstonelifetime". That can be an exercise for the class to figure out what is happening there. 

Rating 4.00 out of 5

11/20/2011

Target Cleanup of sIDHistory Revisited

by @ 10:53 pm. Filed under tech

I recently had a conversation with an Active Directory engineer who was working on some token bloat issues. As AD has pushed past the decade mark I seem to be seeing/hearing more and more of this bloat problem as many companies continue consolidating groups into and creating new groups in AD without cleanup or normalization.

To be more clear, say a company took whole hog the groups they had before, likely in a couple, but possibly up to hundreds of NT4 domains and collapsed it all into a single forest or they took all of the machine local groups on member servers and sucked them up into AD for “easier management and reporting”. On top of that, all of it has remained with no cleanup and companies moved forward adding more permission and DL groups and merging/consolidating more and more domains (or companies), etc. And then on top of THAT, you get companies who used sIDHistory but never went back and cleaned up what the sIDHistory was initially needed for. What should take place is group/permission normalization, ACL cleanup, etc.

Err ok, I just sidetracked myself with a soapbox speech… back to the AD Engineer patiently waiting for me to shut up and listen to what he wants to accomplish…

So part of the problem this engineer is experiencing is that the Active Directory he is concerned about had been through a double hop AD Consolidation after multiple mergers/acquisitions. I.E. OldOldDomain was migrated/collapsed into OldDomain and later OldDomain was migrated/collapsed into ShinyNewDomain[1]. The migrations involved pulling the objects over whole hog and populating sIDHistory in the new accounts. So what you ended up with was (SIDs shortened for readability):

OldOldDomain – Domain SID S-1-5-12345
OldDomain – Domain SID S-1-5-54321
ShinyNewDomain – Domain SID S-1-5-24680

So a migrated object in ShinyNewDomain has objectSid of S-1-5-24680-2500, and has sIDHistory values of S-1-5-54321-78 and S-1-5-12345-19.

Now let’s say some cleanup had actually occurred and any ACLs with references to SIDs from OldOldDomain were believed to be all gone but there definitely were resources using OldDomain SIDs still. Simple right? Target and remove the OldOldDomain SIDs and leave the OldDomain SIDs in place.

Well unfortunately, the engineer had spoken to another engineer about it and was told it wasn’t possible to perform granular sIDHistory cleanup. He was further told that the process he would have to use to perform this cleanup was to go back to OldDomain, clear the sIDHistory attribute of all objects there, then clear all of the sIDHistory attribute of all matching objects in NewDomain, then re-migrate the SIDs from OldDomain to NewDomain…

I was a bit shocked by this and responded that you could indeed remove individual SIDs from the sIDHistory. And while I don’t know how long it would have taken to perform the other process (assuming OldDomain still existed!), using targeted cleaning of individual SIDs could be done relatively quickly. I would shoot from the hip and say that original process would take a couple of days to get everything all lined up and completed where a granular cleanup could be completed in minutes or hours at most.

I then asked around to some other friends that I know to be good admins, people that aren’t dev guys but generally a big step up from “My name is Peggy”, and a majority of them thought the same thing, it was an all or nothing thing when clearing sIDHistory with one person, who shall remain nameless, actually responding, “Why would you ever want to remove sIDHistory values????” Moving on…

One of the guys sent me a couple of links to MSFT web pages that had VBScript and PowerShell examples and they both removed all values with no indication that you could, if you so desired, remove only a subset of the values. Even a blog entry I had written back in 2006 (http://blog.joeware.net/2006/09/16/621/) only mentioned clearing all values from the attributes on all objects. I did have a later blog post in 2009 (http://blog.joeware.net/2009/06/10/1655/) that explained how to clean up SIDs for a specific domain, looking it over I have to admit it is a bit terse. Plus if you are googling for “sIDHistory cleanup”, the 2009 post doesn’t come up (at least not in the first three pages[2]).

Now I don’t think there is any great conspiracy here, I just think that MSFT didn’t really visualize stacking migrations and thereby stacking up sIDHistory values and I don’t think Google is out to make life hard for AD Admins. That being said, I have now personally seen cases where a single object has 3,4 or even up to 6 sIDHistory values. This is likely unusual for most companies but it is occurring out there and I would hate to think admins in those positions thought they were stuck with keeping all of those entries because they need just one or two of them and can’t find guidance on how to do it.

Granted, if you know enough about the vbscript or the powershell commands or even the AdFind/AdMod commands I used in the 2006 blog you could divine that removal of a single SID from sIDHistory is possible because they all clear the attribute by removing individual values. But low and behold, looking around, I didn’t find it stated anywhere except in my 2009 post and again, that post isn’t popping as early as it could for people. Additionally some people just aren’t all that willing to experiment or don’t have a place to experiment or perhaps even the time to experiment.

So based on the idea that if several smart people I have spoken to don’t know/understand something or, as in this case, have an incorrect understanding of it, I assume that the chances are good that a good number of others don’t know either. This led me to sit down and write this new blog post which will hopefully score higher when you search for “sIDHistory cleanup”. So, if you are still with me, let’s work through the process of “sIDHistory cleanup” in a non-terse manner …

Q: Can you remove a single SID from the sIDHistory attribute of an object? I.E. Can I perform targeted sIDHistory cleanup?

A: ABSOLUTELY! You can indeed remove a single SID or even some subset of SIDs from sIDHistory on an object and in fact complete a targeted sIDHistory cleanup.

Here is a real life example of targeted sidHistory cleanup with AdMod:

C:\temp>adfind -default -f name=$joe sidhistory

AdFind V01.45.00cpp Joe Richards (joe@joeware.net) March 2011

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

dn:CN=$joe,OU=Users,OU=My,DC=test,DC=loc
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6569
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6570
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6571
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6572

1 Objects returned

C:\temp>admod -b CN=$joe,OU=Users,OU=My,DC=test,DC=loc SID##sidhistory:-:S-1-5-21-3641047700-3957557241-2644433309-6571

AdMod V01.13.00cpp Joe Richards (joe@joeware.net) April 2010

DN Count: 1
Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003

Modifying specified objects…
   DN: CN=$joe,OU=Users,OU=My,DC=test,DC=loc…

The command completed successfully

C:\temp>adfind -default -f name=$joe sidhistory

AdFind V01.45.00cpp Joe Richards (joe@joeware.net) March 2011

Using server: TEST-DC1.test.loc:389
Directory: Windows Server 2003
Base DN: DC=test,DC=loc

dn:CN=$joe,OU=Users,OU=My,DC=test,DC=loc
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6569
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6570
>sIDHistory: S-1-5-21-3641047700-3957557241-2644433309-6572

1 Objects returned

The key to a targeted sIDHistory cleanup is to specify the actual SID you want removed in the LDAP command. The tricky part of that though is that the SID needs to be specified as a binary SID structure, not the nice friendly string you see above. AdMod is nice in that it allows you to specify the SID## prefix on an attribute to alert AdMod to convert a string SID to a SID structure on your behalf. PowerShell should have something similar (I really don’t know for sure) and vbscript… well you will have to do some digging around on that one. However, to my knowledge, binary structures were never VBScript’s strong point.

Now I did get a follow-up question, “So you can use a wildcard for the SIDs?” I.E. Specify removing any SIDs in sIDHistory that start with the Domain SID of the Domain that is gone? That certainly would be cool but nope, sorry, no such luck. The wildcarding of the SIDs is not possible. If you wanted to clear all of the SIDs from sIDHistory for a specific domain, you would want to dump all sIDHistory values and then filter the strings for the values. This generally just takes a basic string parsing script to perform that filtering for you. Below I walk through some basic steps involved and show how you can quite easily do this with AdFind and AdMod. It is likely that after I post this blog, some PowerShell person somewhere (http://bsonposh.com/) will post a blog on how to do it with PowerShell.

Anyway… now for the interesting stuff…

First… Query the GC with a base of “” for any objects with any value in sIDHistory. Then once that data comes back filter through it for the specific sIDHistory value. Finally mute any records that don’t have any attributes being output (i.e. any objects that don’t have the specified SID listed in sIDHistory).

adfind -gcb -f sidhistory=* sidhistory -mvfilter sidhistory=S-1-5-21-1173133699-2878410131-473346761 -recmute

This generates output like:

AdFind V01.45.00cpp Joe Richards (joe@joeware.net) March 2011

Using server: dc1.sidtest.loc:3268
Directory: Windows Server 2008 R2

dn:CN=group1,OU=TestGroups,DC=sidtest,DC=loc
>sIDHistory: S-1-5-21-1173133699-2878410131-473346761-7912

dn:CN=group2,OU=TestGroups,DC=sidtest,DC=loc
>sIDHistory: S-1-5-21-1173133699-2878410131-473346761-14644

dn:CN=group3,OU=TestGroups,DC=sidtest,DC=loc
>sIDHistory: S-1-5-21-1173133699-2878410131-473346761-15651

dn:CN=group4,OU=TestGroups,DC=sidtest,DC=loc
>sIDHistory: S-1-5-21-1173133699-2878410131-473346761-15662

dn:CN=group5,OU=TestGroups,DC=sidtest,DC=loc
>sIDHistory: S-1-5-21-1173133699-2878410131-473346761-16443

Now visualize hundreds or thousands or tens of thousands of those… You absolutely can parse that by hand if you want but I am lazy, even for five objects so I would go a step further and have AdFind do more of the work by running the following command which is the same as the last but sticks the info into a delimited format using the colon character as the delimiter, oh yeah, don’t output a header…

adfind -gcb -f sidhistory=* sidhistory -mvfilter sidhistory=S-1-5-21-1173133699-2878410131-473346761 -recmute -csv -csvdelim : -nocsvheader

which produces this output

"CN=group1,OU=TestGroups,DC=sidtest,DC=loc":"S-1-5-21-1173133699-2878410131-473346761-7912"
"CN=group2,OU=TestGroups,DC=sidtest,DC=loc":"S-1-5-21-1173133699-2878410131-473346761-14644"
"CN=group3,OU=TestGroups,DC=sidtest,DC=loc":"S-1-5-21-1173133699-2878410131-473346761-15651"
"CN=group4,OU=TestGroups,DC=sidtest,DC=loc":"S-1-5-21-1173133699-2878410131-473346761-15662"
"CN=group5,OU=TestGroups,DC=sidtest,DC=loc":"S-1-5-21-1173133699-2878410131-473346761-16443"

Next you could push that command through a FOR /F loop and generate and write AdMod commands to a text file for your perusal.

C:\qnd\sidtest>for /f "tokens=1,2 delims=:" %i in (‘adfind -gcb -f "sidhistory=*" sidhistory -mvfilter "sidhistory=S-1-5-21-1173133699-2878410131-473346761" -recmute -csv -csvdelim : -nocsvheader’) do @echo admod -b %i SID##sidhistory:-:%j >> SIDHISTORY_CLEANUP.TXT

C:\qnd\sidtest>type SIDHISTORY_CLEANUP.TXT
admod -b "CN=group1,OU=TestGroups,DC=sidtest,DC=loc" SID##sidhistory:-:"S-1-5-21-1173133699-2878410131-473346761-7912"
admod -b "CN=group2,OU=TestGroups,DC=sidtest,DC=loc" SID##sidhistory:-:"S-1-5-21-1173133699-2878410131-473346761-14644"
admod -b "CN=group3,OU=TestGroups,DC=sidtest,DC=loc" SID##sidhistory:-:"S-1-5-21-1173133699-2878410131-473346761-15651"
admod -b "CN=group4,OU=TestGroups,DC=sidtest,DC=loc" SID##sidhistory:-:"S-1-5-21-1173133699-2878410131-473346761-15662"
admod -b "CN=group5,OU=TestGroups,DC=sidtest,DC=loc" SID##sidhistory:-:"S-1-5-21-1173133699-2878410131-473346761-16443"

You can then validate the commands are what you wanted and expected and then batch them to run in phases or through a pilot or run them all at once, just copy the commands to a .CMD file or rename the .TXT file and you are good to go. However… If you just want the commands to directly run you could remove the @echo after the DO and it will execute the commands for you. But in that case… it is simpler to output the information with -ADCSV format and push straight into AdMod like the example in http://blog.joeware.net/2006/09/16/621/

The search command for this case would be adfind -gcb -f "sidhistory=*" sidhistory -mvfilter "sidhistory=S-1-5-21-1173133699-2878410131-473346761" -recmute -adcsv

Which would generate the following output:

~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~
"dn","sidhistory"
"CN=group1,OU=TestGroups,DC=sidtest,DC=loc","S-1-5-21-1173133699-2878410131-473346761-7912"
"CN=group2,OU=TestGroups,DC=sidtest,DC=loc","S-1-5-21-1173133699-2878410131-473346761-14644"
"CN=group3,OU=TestGroups,DC=sidtest,DC=loc","S-1-5-21-1173133699-2878410131-473346761-15651"
"CN=group4,OU=TestGroups,DC=sidtest,DC=loc","S-1-5-21-1173133699-2878410131-473346761-15662"
"CN=group5,OU=TestGroups,DC=sidtest,DC=loc","S-1-5-21-1173133699-2878410131-473346761-16443"

The whole command to cleanup would then be

adfind -gcb -f "sidhistory=*" sidhistory -mvfilter "sidhistory=S-1-5-21-1173133699-2878410131-473346761" -recmute -adcsv | admod sidhistory:-:{{sidhistory}} -unsafe

Not bad for 30 seconds worth of “scripting” eh?

joe

[1] Shiny here refers to the Firefly definition and if you don’t know what Firefly is… You have gotten your nerd/geek card revoked. ;)

[2] I have a three page rule with search engines I tend to follow, if it isn’t on the first three pages, I am not likely to see it because I stop looking.

Rating 4.50 out of 5

[joeware – never stop exploring… :) is proudly powered by WordPress.]