Posts RSS Comments RSS 117 Posts and 170 Comments till now

Further Testing with S.DS.P (~1 sec slower)

I have to say I am in awe. I never expected to get so close to ADFind.exe in performance, but if you look below you will notice how close s.ds.p really got.

Before I show the results I want to respond to some of joe’s comments on his blog entry here: PowerShell + S.DS.Protocols Versus AdFind…
btw… I STRONGLY recommend reading this entry… actually subscribing to his blog. While he does spout off random quotes… he provides some incredibly useful info from time to time.

note: References to joe as joe (case intentional) is not ment as disrespect, but simply the way joe refers to himself. If you have the pleasure of getting to know him… you will understand this.

[1] I understand fully that joe really wants .NET and Powershell to succeed, but finds it unlikely.

[2] My testing (although possibly not perfect) was much more precise and I assume his testing had to be skewed by something. Its just not possible. I tried this on 4 completely different systems. Different OS’s, x64 and x86, Hyper-v and ESX, and different domain sizes. By the end of the testing.. I ran approximately 600 test (although I only documented 240.)

[3] While I can appreciate his lack of faith in measure-command. It was the only way I could remove human error and maintain an unbiased count for each test. Measure-command’s overhead is maintained completely outside of the measured expression.

[4] MOST IMPORTANTLY: Perhaps the reason joe questions my purpose of doing these tests is because I did not make it clear. My purpose in these test was to determine if it is feasible to reach the same performance of adfind.exe in Powershell. Why? adfind.exe works great, why not just that. Simply put, if I can achieve close to the same performance, I’m able to get the speed while maintaining the benefit of dealing with objects. While this concept may escape people, once you grasp it… it is key to easy and fast scripts or commands. Nothing more, nothing less. While I will not argue I like a good debate, that is not my soul reason for being.

To be clear, this is only the first step. I now need to process some properties and see if s.ds.p/powershell can compete in that area. As I was with the count I am skeptical about achieving performance even close to adfind, but perhaps that will surprise me as the search did.

[5] My count was NOT off :P The logic of using userclass=* vs userclass=user was.

For those inclined to do so… Here is the COMPLETE output of the results without the average
Prod700kResults
Results Prod 400k VM
Small 200k Domain on Local Hardware
Small 200k Domain on VM

This first test was done in a LARGE environment with 700k+ userclass objects.

Prod 700k

This test was done on a production quality VM with approx 400k users.

Prod 400k

This test was on my Home Win2k8 DC. I only have about 200k userclass objects at home, but it is a beefy box.

Local 200k

This is on my laptop that has about 200k userclass objects as well.

VM 200k

Here are the scripts I ran for the testing

This is the actual worker code

  1. [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null
  2.  
  3. $domainDN = ([ADSI]"").distinguishedName
  4. $domain = $domainDN -replace  ",","." -replace "dc=",""
  5.  
  6. [int]$pageCount = 0
  7. [int]$pageSize = 1000
  8. [int]$count = 0
  9.  
  10. $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($domain)  
  11. $subtree = [System.DirectoryServices.Protocols.SearchScope]"Subtree"
  12. $filter = "(objectclass=*)"
  13.  
  14. $searchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest($DomainDN,$filter,$subtree,"1.1")  
  15. $pagedRequest = New-Object System.DirectoryServices.Protocols.PageResultRequestControl($pageSize)
  16. $searchRequest.Controls.add($pagedRequest) | out-null
  17. $searchOptions = New-Object System.DirectoryServices.Protocols.SearchOptionsControl([System.DirectoryServices.Protocols.SearchOption]::DomainScope)
  18. $searchRequest.Controls.Add($searchOptions) | out-null
  19.  
  20. while ($True)
  21. {
  22.     # Increment the pageCount by 1
  23.     $pageCount++
  24.  
  25.     # Cast the directory response into a SearchResponse object
  26.     $searchResponse = $connection.SendRequest($searchRequest)
  27.  
  28.     # Display the retrieved page number and the number of directory entries in the retrieved page
  29.     # "Page:{0} Contains {1} response entries" -f $pageCount,$searchResponse.entries.count
  30.     $count += ($searchResponse.entries).count
  31.    
  32.     # Display the entries within this page
  33.     $searchResponse.Entries | select distinguishedName
  34.     # if this is true, there are no more pages to request
  35.     if ($searchResponse.Controls[0].Cookie.Length -eq 0){write-Output $count;break}
  36.  
  37.     # Set the cookie of the pageRequest equal to the cookie of the pageResponse to request the next
  38.     # page of data in the send request and cast the directory control into a PageResultResponseControl object
  39.     $pagedRequest.Cookie = $searchResponse.Controls[0].Cookie
  40. }

Script I used to automate the 60 test per Environment.

  1. Param($count=30)
  2.  
  3. $dn = ([ADSI]"").distinguishedName
  4.  
  5. function TestOne {
  6.     Write-Host "  + Test ${i}.1"
  7.     Write-Host "    + Running ADFind Test"
  8.     $joeTime      = Measure-Command { D:\Scripts\adfind -b "$dn" -c -f "(objectclass=user)" 2>&1 | out-Null }
  9.     Write-Host "      - $($joetime.TotalSeconds)"
  10.     Write-Host "    + Running DSP Test"
  11.     $DSPTime11    = Measure-command { D:\Scripts\Test-DSProtocalsSP.ps1 }
  12.     Write-Host "      - $($DSPTime11.TotalSeconds)"
  13.     $myresults  = "" | select @{n="ADFind"           ;e={$joeTime.TotalSeconds}},
  14.                               @{n="DSP Using 1.1"    ;e={$DSPTime11.TotalSeconds}}
  15.     $myresults
  16. }
  17. function TestTwo {
  18.     Write-Host "  + Test ${i}.2"
  19.     Write-Host "    + Running DSP Test"
  20.     $DSPTime11    = Measure-command { D:\Scripts\Test-DSProtocalsSP.ps1 }
  21.     Write-Host "      - $($DSPTime11.TotalSeconds)"
  22.     Write-Host "    + Running ADFind Test"
  23.     $joeTime      = Measure-Command { D:\Scripts\adfind -b "$dn" -c -f "(objectclass=user)" 2>&1 | out-Null }
  24.     Write-Host "      - $($joetime.TotalSeconds)"
  25.     $myresults  = "" | select @{n="ADFind"           ;e={$joeTime.TotalSeconds}},
  26.                               @{n="DSP Using 1.1"    ;e={$DSPTime11.TotalSeconds}}
  27.     $myresults
  28. }
  29.  
  30. Write-Host
  31. for($i = 0 ; $i -le $count ; $i++)
  32. {
  33.     Write-Host "+ Test $i"
  34.     TestOne
  35.     TestTwo
  36. }
  37. Write-Host

My First Venture into S.DS.P and Powershell

There has be much debate and agony on the the slowness of System.DirectoryServices.DirectorySearcher Class. This has lead me down the path of playing with System.DirectoryServices.Protocols (aka s.ds.p.)

By far the best tool out there right now is ADFind by joe Richards. So I used this for my target (although I didnt expect to get close.)

Here is the Guide I used in my Journey:
Introduction to System.DirectoryServices.Protocols (S.DS.P)

I started by writing the script you will find below and tested in a domain with well over 700k users and one with 200K. I did the test three different times in each Domain changing the order so cache hits wouldn’t be an issue. I also use objectclass on all three so index wouldn’t be a factor. I should NOTE that my script ONLY returns the count ATM. I am going to add properties next.

As you will see by the test results below… I got pretty darn close to adfind.exe in regards to perf. I was quite impressed with S.DS.P. Now to be fair, this was just counting objects. I am sure adfind.exe will start sneaking ahead abit further when we start processing properties and such. Can’t wait to see! Understand these test were just to see what tests I should focus on. I will posting another entry on more extensive count test with just DSP Using 1.1 and Adfind.

Test 1 700K Users done Remote

DirectorySearcher : 125.9123257
ADFind : 46.3763349
DSP Using DN : 69.5628776
DSP Using 1.1 : 49.4458161

Test 2 700K Users done Remote

DirectorySearcher : 125.0230257
ADFind : 46.4486472
DSP Using DN : 68.9255288
DSP Using 1.1 : 49.0780736

Test 3 700K Users done Remote

DirectorySearcher : 125.0230257
ADFind : 47.9162918
DSP Using DN : 79.6885386
DSP Using 1.1 : 54.152966

Test 1 200K done Local

DirectorySearcher : 121.1063569
ADFind : 55.2775406
DSP Using DN : 67.897922
DSP Using 1.1 : 28.5441615

Test 2 200K done Local

DirectorySearcher : 80.0894455
ADFind : 23.558696
DSP Using DN : 54.3111576
DSP Using 1.1 : 42.3485998

Test 3 200K done Local

DirectorySearcher : 99.1125363
ADFind : 80.1497852
DSP Using DN : 64.3716824
DSP Using 1.1 : 64.1940421

Summary: adfind.exe was faster (by bout 4sec on Avg.) remotely and larger domain, but protocals was faster (by bout 8 sec on Avg.) local on smaller domain.
Remote

ADFind: 46.92
DSP Using 1.1: 50.89
DSP Using DN: 72.73
DirectorySearcher: 125.32

Local

DSP Using 1.1: 45.03
ADFind: 52.99
DSP Using DN: 62.19
DirectorySearcher: 100.10

Here the script I ran for the test and how I measured the commands. I am going to play with passing the stats control and see what the server says later.

  1. $SearcherExpression = @’
  2. $searcher = new-object System.DirectoryServices.DirectorySearcher([ADSI]"","(objectclass=user)",@("distinguishedName"))
  3. $searcher.pagesize = 1000
  4. $searcher.findall()
  5. ‘@
  6.  
  7. Write-Host "Test 1"
  8. Write-Host ("-"*40)
  9. $myresults1 = "" | select @{n="DirectorySearcher";e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
  10.                          @{n="ADFind";e={(Measure-Command { .\adfind -b "dc=corp,dc=lab" -c -f "(objectclass=user)" }).TotalSeconds}},
  11.                          @{n="DSP Using DN";e={(Measure-command { .\Test-DSProtocals.ps1 }).TotalSeconds}},
  12.                          @{n="DSP Using 1.1";e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}}
  13. $myresults1 | fl
  14.  
  15. Write-Host "Test 2"
  16. Write-Host ("-"*40)
  17. $myresults2 = "" | select @{n="ADFind";e={(Measure-Command { .\adfind -b "dc=corp,dc=lab" -c -f "(objectclass=user)" }).TotalSeconds}},
  18.                          @{n="DSP Using 1.1";e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}},
  19.                          @{n="DSP Using DN";e={(Measure-command { .\Test-DSProtocals.ps1 }).TotalSeconds}},
  20.                          @{n="DirectorySearcher";e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}}
  21.  
  22. $myresults2 | fl
  23.  
  24. Write-Host "Test 3"
  25. Write-Host ("-"*40)
  26. $myresults3 = "" | select @{n="DSP Using DN";e={(Measure-command { .\Test-DSProtocals.ps1 }).TotalSeconds}},
  27.                          @{n="DSP Using 1.1";e={(Measure-command { .\Test-DSProtocalsSP.ps1 }).TotalSeconds}},
  28.                          @{n="DirectorySearcher";e={(Measure-command {invoke-expression $SearcherExpression}).TotalSeconds}},
  29.                          @{n="ADFind";e={(Measure-Command { .\adfind -b "dc=corp,dc=lab" -c -f "(objectclass=user)" }).TotalSeconds}}
  30. $myresults3 | fl
  31.  
  32. $myresults1,$myresults2,$myresults3
  33.  

Here is what the output of that Script looks like

S.DS.P : MyTest.ps1 Output

Here is the System.DirectoryServices.Protocols Code

  1. [System.Reflection.assembly]::LoadWithPartialName("system.directoryservices.protocols") | Out-Null
  2. $domain = ([ADSI]"").distinguishedName -replace  ",","." -replace "dc=",""
  3. $DomainDN = "DC=" + $Domain -replace "\.",",DC="
  4. [int]$pageCount = 0
  5. [int]$pageSize = 1000
  6. [int]$count = 0
  7. $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($domain)  
  8. $subtree = [System.DirectoryServices.Protocols.SearchScope]"Subtree"
  9. $filter = "(objectclass=user)"
  10. $searchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest($DomainDN,$filter,$subtree,@("1.1"))  
  11. $pagedRequest = New-Object System.DirectoryServices.Protocols.PageResultRequestControl($pageSize)
  12. $searchRequest.Controls.add($pagedRequest) | out-null
  13. $searchOptions = new-object System.DirectoryServices.Protocols.SearchOptionsControl([System.DirectoryServices.Protocols.SearchOption]::DomainScope)
  14. $searchRequest.Controls.Add($searchOptions) | out-null
  15.  
  16. while ($true)
  17. {
  18.     ## increment the pageCount by 1
  19.     $pageCount++
  20.     ## cast the directory response into a
  21.     ## SearchResponse object
  22.     $searchResponse = $connection.SendRequest($searchRequest)
  23.     ## verify support for this advanced search operation
  24.     if (($searchResponse.Controls.Length -lt 1) -or
  25.         !($searchResponse.Controls[0] -is [System.DirectoryServices.Protocols.PageResultResponseControl]))
  26.     {
  27.         Write-Host "The server cannot page the result set"
  28.         return;
  29.     }
  30.     ## cast the diretory control into
  31.     ## a PageResultResponseControl object.
  32.     $pageResponse = $searchResponse.Controls[0]
  33.     ## display the retrieved page number and the number of
  34.     ## directory entries in the retrieved page                    
  35.     #"Page:{0} Contains {1} response entries" -f $pageCount,$searchResponse.entries.count
  36.     $count += $searchResponse.entries.count
  37.     ## display the entries within this page
  38.     ## foreach($entry in $searchResponse.entries){$entry.DistinguishedName}
  39.     ## if this is true, there
  40.     ## are no more pages to request
  41.     if ($pageResponse.Cookie.Length -eq 0){write-Host $count;break}
  42.     ## set the cookie of the pageRequest equal to the cookie
  43.     ## of the pageResponse to request the next page of data
  44.     ## in the send request
  45.     $pagedRequest.Cookie = $pageResponse.Cookie
  46. }

More AD CMDLets from SDMSoftware

It includes snapins to get and re-animate tombstones

Darren discusses this on his blog: Powershell Hits The Morgue

Looking for interesting Citrix Problems

I am working on some blog entries and content for Citrix CDN and was curious what you guys thought.

If you have time, please leave some comments on problems or suggestions of things you would like to see. Specifically I am looking for some “real” world scenarios that I can present and provide solutions for.

Test-Host (WMI Ping -or Port Check)

I often find (specifically when using WMI) the need to ping the machine first before performing any queries. WMI takes FOREVER to timeout. I decided that I should use a script/function to test a host before passing it down the pipe.

There are a couple of problems with this approach that I had to consider.
1) How do I know what to test without corrupting the pipe or using foreach?
- For this I added a “-property” parameter that would allow the user to pick what property to check against, but still output the entire object that was inputted.

2) What about firewalls that block ping?
- Added TestPort function that does a TCP connect and returns $true or $false

3) What if I want a conditional port check.
- Added the ability to Change the Default Port for TCP Connection Test

Here is the script that I came up with and some of things it does.
Parameters
- $property: The Property to Ping or Test (Default is none.)
- $tport: The Port to test against (Default is 135. Used with -port)
- $timeout: The timeout for the connection (Default is 1000 ms, Used with -port)
- [switch]$port: Switch to Test a port instead of Ping
- [switch]$verbose: Provides Verbose Output.
Features
- Will Ping ‘$_’ by default
- Can pass the property that contains the Host to test using -property
- Can use -port to test a port instead of ping. (Uses TCP)
- Maintains the Object that is tested and passes it down the pipe if connection is passed.

A Demo of the script in action

Best Viewed Full Screen
Get the Flash Player to see this player.

Script CODE

  1. Param($property,$tport=135,$timeout=1000,[switch]$port,[switch]$verbose)
  2. Begin{
  3.     function TestPort {
  4.         Param($srv)
  5.         $error.Clear()
  6.         $ErrorActionPreference = "SilentlyContinue"
  7.         $tcpclient = new-Object system.Net.Sockets.TcpClient
  8.         $iar = $tcpclient.BeginConnect($srv,$tport,$null,$null)
  9.         $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
  10.         # Traps    
  11.         trap {if($verbose){Write-Host "General Exception"};return $false}
  12.         trap [System.Net.Sockets.SocketException]
  13.         {
  14.             if($verbose){Write-Host "Exception: $($_.exception.message)"}
  15.             return $false
  16.         }
  17.         if(!$wait)
  18.         {
  19.             $tcpclient.Close()
  20.             if($verbose){Write-Host "Connection Timeout"}
  21.             return $false
  22.         }
  23.         else
  24.         {
  25.             $tcpclient.EndConnect($iar) | out-Null
  26.             $tcpclient.Close()
  27.         }
  28.         if(!$error[0]){return $true}
  29.     }
  30.     function PingServer {
  31.         Param($MyHost)
  32.         $pingresult = Get-WmiObject win32_pingstatus -f "address=’$MyHost’"
  33.         if($pingresult.statuscode -eq 0) {$true} else {$false}
  34.     }
  35. }
  36. Process{
  37.     if($_)
  38.     {
  39.         if($port)
  40.         {
  41.             if($property)
  42.             {
  43.                 if(TestPort $_.$property){$_}  
  44.             }
  45.             else
  46.             {
  47.                 if(TestPort $_){$_}
  48.             }
  49.         }
  50.         else
  51.         {
  52.             if($property)
  53.             {
  54.                 if(PingServer $_.$property){$_}  
  55.             }
  56.             else
  57.             {
  58.                 if(PingServer $_){$_}
  59.             }
  60.         }
  61.     }
  62. }

If you want this as a function use this code

  1. function Test-Host{
  2. Param($property,$tport=135,$timeout=1000,[switch]$port,[switch]$verbose)
  3. Begin{
  4.     function TestPort {
  5.         Param($srv)
  6.         $error.Clear()
  7.         $ErrorActionPreference = "SilentlyContinue"
  8.         $tcpclient = new-Object system.Net.Sockets.TcpClient
  9.         $iar = $tcpclient.BeginConnect($srv,$tport,$null,$null)
  10.         $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
  11.         # Traps    
  12.         trap {if($verbose){Write-Host "General Exception"};return $false}
  13.         trap [System.Net.Sockets.SocketException]
  14.         {
  15.             if($verbose){Write-Host "Exception: $($_.exception.message)"}
  16.             return $false
  17.         }
  18.         if(!$wait)
  19.         {
  20.             $tcpclient.Close()
  21.             if($verbose){Write-Host "Connection Timeout"}
  22.             return $false
  23.         }
  24.         else
  25.         {
  26.             $tcpclient.EndConnect($iar) | out-Null
  27.             $tcpclient.Close()
  28.         }
  29.         if(!$error[0]){return $true}
  30.     }
  31.     function PingServer {
  32.         Param($MyHost)
  33.         $pingresult = Get-WmiObject win32_pingstatus -f "address=’$MyHost’"
  34.         if($pingresult.statuscode -eq 0) {$true} else {$false}
  35.     }
  36. }
  37. Process{
  38.     if($_)
  39.     {
  40.         if($port)
  41.         {
  42.             if($property)
  43.             {
  44.                 if(TestPort $_.$property){$_}  
  45.             }
  46.             else
  47.             {
  48.                 if(TestPort $_){$_}
  49.             }
  50.         }
  51.         else
  52.         {
  53.             if($property)
  54.             {
  55.                 if(PingServer $_.$property){$_}  
  56.             }
  57.             else
  58.             {
  59.                 if(PingServer $_){$_}
  60.             }
  61.         }
  62.     }
  63. }}

Build Lab w/ Quest AD CMDLets

Earlier I wrote a post about a script that I used to build my AD Lab Build Lab (v1 w/out Quest Tools) and I mentioned I
would post a Quest version. I had some time run it (took about 6hrs.) So without further ado:

Whats it do Again?
# Creates A TestOU OU
# Creates A TestComputers OU
# Creates A TestUsers OU
# Creates A TestGroups OU
# Creates 10K OU’s Under TestOU
## Each of the 10k OUs will have 4 Child OUs
### Each OU should have 5 users Accounts and 5 Machines Accounts
# Create 500 Group Policies.
# Link 100 policies on the 10k Base OUs
# Create 2000 Users in the TestUser OU
# Create 2000 Computers in the TestComputer OU
# Create 2K Groups

Note: Added Write-Progress for OU/User Creation

  1. # Adding Required Snapins
  2. Add-PSSnapin SDMSoftware.PowerShell.GPMC -ea 0
  3. Add-PSSnapin Quest.ActiveRoles.ADManagement -ea 0
  4.  
  5. $DomainDN = (([ADSI]"").distinguishedName[0])
  6. $DomainDNS = (([ADSI]"").distinguishedName[0]) -replace "DC=","" -replace ",","."
  7. $users = @()
  8.  
  9. # A TestOU OU
  10. $BaseOU = New-QADObject -Type OrganizationalUnit -ParentContainer $DomainDN  -Name TestOU
  11.  
  12. # A TestComputers OU
  13. $TestComps = New-QADObject -Type OrganizationalUnit -ParentContainer $DomainDN -Name TestComputers
  14.  
  15. # A TestUsers OU
  16. $TestUsers = New-QADObject -Type OrganizationalUnit -ParentContainer $DomainDN -Name TestUsers
  17.  
  18. # A TestGroups OU
  19. $TestGrps = New-QADObject -Type OrganizationalUnit -ParentContainer $DomainDN -Name TestGroups
  20.  
  21. # 10K OUs Under TestOU
  22. foreach($i in 1..10000)
  23. {
  24.     $lvl1Child = New-QADObject -Type OrganizationalUnit -ParentContainer $BaseOU.dn -Name "LvL1ChildOU$i"
  25.     Write-Progress "Creating OUs LvL1ChildOU$i" -status "Updating" -perc ($i/10000*100)
  26.     ## Each of the 10k OUs will have 4 Child OUs
  27.     foreach($x in 1..4)
  28.     {
  29.         $lvl2Child = New-QADObject -Type OrganizationalUnit -ParentContainer $lvl1Child.dn -Name "LvL2Child${i}${x}"
  30.         Write-Progress "Creating Child OUs LvL2Child${i}${x}" -status "Updating" -perc ($x/4*100) -id 1  
  31.         foreach($y in 1..5)
  32.         {
  33.             ## Each OU should have 5 users Accounts and 5 Machines Accounts
  34.             Write-Progress "Creating Child Users/Computers" -status "Updating" -perc ($y/5*100) -id 2
  35.             New-QADUser -ParentContainer $lvl2Child.dn -Name "usr${i}${x}${y}" -SamAccountName "usr${i}${x}${y}" -UserPrincipalName "usr${i}${x}${y}@$DomainDNS" -UserPass "!P@ssw0rd22!" | Out-Null
  36.             New-QADObject -ParentContainer $lvl2Child.dn -name "srv${i}${x}${y}" -objectAttributes @{"sAMAccountName"="srv${i}${x}${y}`$"} -type "Computer" | out-Null
  37.         }
  38.     }
  39. }
  40.  
  41. # Create 500 Group Policies.
  42. 1..500 | %{New-SDMgpo "TestGPO$_"}
  43.  
  44. # Link 100 policies on the 10k Base OUs
  45. 1..100 | %{Add-SDMgpLink -name "TestGPO$_" -scope "OU=LvL1ChildOU$i,$($BaseOU.DN)"}
  46.  
  47. # Create 2000 Users in the TestUser OU
  48. 1..2000 | %{New-QADUser -ParentContainer $TestUsers.dn -Name "Testusr$_" -SamAccountName "Testusr$_" -UserPrincipalName "Testusr$($_)@$DomainDNS" -UserPass "!P@ssw0rd22!"}
  49.  
  50. # Create 2000 Computers in the TestComputer OU
  51. 1..2000 | %{New-QADObject -ParentContainer $TestComps.dn -name "TestComp$($_)" -objectAttributes @{"sAMAccountName"="TestComp$($_)`$"}}
  52.  
  53. # Create 2K Groups
  54. 1..2000 | %{New-QADGroup -ParentContainer $TestGrps.dn -name "TestGrp$_" -sAMAccountName "TestGrp$_"}

Get-CitrixApplication (Playing Around Series)

Here is a quick demo of getting a Citrix Application and playing with its properties.

Best Viewed Full Screen
Get the Flash Player to see this player.

Demo File

  1. #
  2. # First we need to create the MFCOM Object
  3. #
  4. $mfapp = new-object -com MetaFrameCom.MetaFrameApplication
  5. #
  6. # To initialize we need to pass the app we want to accesss
  7. #
  8. $mfapp.Initialize(3,"Applications\Powershell")
  9. #
  10. # With Applications we need to load the data
  11. #
  12. $mfapp.loaddata(1)
  13. #
  14. # Lets see what we have
  15. #
  16. $mfapp | Get-Member -type Properties
  17. #
  18. # Lets look at Users and Groups
  19. #
  20. $mfapp | select Users,Groups
  21. #
  22. # How bout Servers
  23. #
  24. $mfapp.Servers | Select ServerName
  25. #
  26. # Sessions?
  27. #
  28. $mfApp.Sessions | ft SessionID,AppName,ClientAddress,ClientHRes,ClientVRes -auto

Get-CitrixFarm (Playing Around Series)

I wanted to show how EASY it is to play with Citrix MFCom so here is a little video.

I also want to note how most of the properties (like Servers,Applications,Zones) all return objects that have their own properties and methods. So you could very easily have these lines in your profile and always have everything just sitting there waiting to be used.

  1. $farm = New-Object -Com ‘MetaframeCOM.MetaFrameFarm’
  2. $farm.Initialize(1)
  3. Write-Host "Loaded Farm Info from $($farm.FarmName)

Best Viewed Full Screen
Get the Flash Player to see this player.

Demo File

  1. # Get Citrix Farm Object
  2. #
  3. $farm = New-Object -Com ‘MetaframeCOM.MetaFrameFarm’
  4. #
  5. # Initialize Farm
  6. #
  7. $farm.Initialize(1)
  8. #
  9. # Now that we have are farm. Lets make sure we have the one we want by Getting the FarmName
  10. $Farm.FarmName
  11. #
  12. # Lets see what we have to play with
  13. #
  14. $farm | Get-Member -type Properties
  15. #
  16. #
  17. # We have the Farm we want. Some of the Info we want is Admins. So lets Start there
  18. #
  19. $farm.Admins
  20. #
  21. # To View just a list
  22. #
  23. $farm.Admins | Select FriendlyName
  24. #
  25. # Lets see what Applications we have
  26. #
  27. $farm.Applications | ft BrowserName,ParentFolderDN
  28. #
  29. # To View the Servers
  30. #
  31. $farm.Servers | ft ServerName,IPAddress,SessionCount
  32. #
  33. # How bout Sessions?
  34. $farm.Sessions
  35. #
  36. # Lets look at Print Drivers we Have installed
  37. #
  38. $farm.Drivers
  39. #
  40. # If you have multiple Zones you can get the Names Servers and DataCollector for the Zone
  41. $farm.Zones
  42. #

Get-CitrixServer (Playing Around Series)

This is a quick run through a MFCOm Citrix Server Object

Best Viewed Full Screen
Get the Flash Player to see this player.

Demo File

  1. #
  2. # We start by creating a Server Object
  3. #
  4. $mfsrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
  5. #
  6. # Initializing Server
  7. #
  8. $mfsrv.Initialize(6,$ENV:ComputerName)
  9. #
  10. # Now we have are server… Lets see what we have to play with
  11. #
  12. $mfsrv | Get-Member -type Properties
  13. #
  14. # Lets start by looking at the current sessions on the server
  15. #
  16. $mfsrv.Sessions | ft SessionID,AppName,ClientAddress,ClientHRes,ClientVRes -auto
  17. #
  18. # What about what Zone it is in?
  19. #
  20. $mfsrv.ZoneName
  21. #
  22. # Printers?
  23. #
  24. $mfsrv.Printers
  25. #
  26. # Lets see what Processes are running
  27. #
  28. $mfsrv.Processes | ft SessionID,ProcessID,UserName,ProcessState -auto
  29. #
  30. # A common task is Server Load
  31. #
  32. $mfsrv.WinServerObject.ServerLoad
  33. #
  34. # Last (and perhaps most important) What applications?
  35. #
  36. $mfsrv.Applications | ft BrowserName,ParentFolderDN

Vmotion with VI ToolKit (Playing Around Series)

I wanted to show you how simple it was to VMotion with new CMDLets. I also want to point out the most if not all the VMware CMDLets return VM Objects so you could easily do something like
Get-VM MyVM | Stop-VM | Remove-CDDrive | Move-VM -Dest $EsxHost | New-CDDrive -isoPath $isoPath -StartConnected | Start-VM

Best Viewed Full Screen
Get the Flash Player to see this player.

Demo File

  1. # Connect to Virtual Center
  2. Get-VC home.halr9000.com
  3. # Get ESX host
  4. $esxHost = Get-VMHost 192.168.0.55
  5. # Verify we got the correct ESX Host
  6. $esxHost
  7. # Get Virtual Machine
  8. $vm = Get-VM SDK-XPSP2
  9. # Verify We have the correct VM
  10. $vm
  11. # Test VM move with -whatif
  12. Move-VM -VM $VM -Destination $EsxHost -whatif
  13. # Lets do it for real
  14. Move-VM -VM $VM -Destination $EsxHost

« Previous PageNext Page »