Posts RSS Comments RSS 117 Posts and 170 Comments till now

Set-CitrixServerLogon.ps1 (Citrix Top 10)

Here is a useful little script. This Creates a MFCom Server Object and disables or Enables Logons for that Server.

  1. # Set-CitrixServerLogon.ps1
  2. # Brandon Shell [MVP]
  3. # www.bsonposh.com
  4. # Sets the Server to Enable or Disable Logons
  5. Param($Server,[switch]$enable,[switch]$disable,[switch]$help)
  6. function HelpMe{
  7.     Write-Host
  8.     Write-Host " Set-CitrixServerLogon.ps1:" -fore Green
  9.     Write-Host "   Sets the Server to Enable or Disable Logons"
  10.     Write-Host
  11.     Write-Host " Parameters:" -fore Green
  12.     Write-Host "   -Server                  : Optional. Server to Set Logon"
  13.     Write-Host "   -Enable                  : Optional. Checks Hours of Idle Time (Default)"
  14.     Write-Host "   -Disable                 : Optional. Checks Minutes of Idle Time"
  15.     Write-Host "   -Help                    : Optional. Displays This"
  16.     Write-Host
  17.     Write-Host " Examples:" -fore Green
  18.     Write-Host "   To disable the Logon for a Server" -fore White
  19.     Write-Host "     Set-CitrixServerLogon.ps1 -server <serverName> -Disable" -fore Yellow
  20.     Write-Host
  21. }
  22.  
  23. if(!$Server -or $help){helpme;Write-Host;return}
  24.  
  25. Write-Host
  26.  
  27. Write-Host " Getting Server [$Server]"
  28. $mfsrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
  29.  
  30. Write-Host " - Initializing Server"
  31. $mfsrv.Initialize(6,$Server)
  32.  
  33. if($enable)
  34. {
  35.     Write-Host " - Setting to EnableLogon = 1"
  36.     $mfSrv.WinServerObject.EnableLogon = 1
  37. }
  38. if($disable)
  39. {
  40.     Write-Host " - Setting to EnableLogon = 0"
  41.     $mfSrv.WinServerObject.EnableLogon = 0
  42. }
  43.  
  44. Write-Host " - Server [$($mfSrv.ServerName)] is set to [$($mfSrv.WinServerObject.EnableLogon)] for EnableLogon"
  45.  
  46. Write-Host

Another option would be to remove the Apps from the Server all together.

  1. # Unpublish-CitrixServer.ps1
  2. # Brandon Shell [MVP]
  3. # www.bsonposh.com
  4. # Removes all App from Server
  5. Param($Server)
  6. $mfsrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
  7. $mfsrv.Initialize(6,$Server.ToUpper())
  8. $mfsrv | foreach{$_.Applications} | foreach{$_.LoadData(1);$_.RemoveServer($Server.ToUpper());$_.SaveData()}

Find-CitrixIdleUser.ps1 (Citrix Top 10)

This is one of the more useful scripts (at least for me.) It will query the farm and tell you all the user who have exceeded the idle time specified. I also combined another script that logged off users.

Name: Find-CitrixIdleUser.ps1
Purpose: Finds users with idle time greater than value passed and logs them off if -logoff is passed

  1. # Find-CitrixIdleUser.ps1
  2. # Brandon Shell [MVP]
  3. # www.bsonposh.com
  4. # Finds users with idle time greater than value passed
  5. Param($time,[switch]$day,[switch]$hour,[switch]$minute,[switch]$logoff,[switch]$verbose,[switch]$help)
  6. function HelpMe{
  7.     Write-Host
  8.     Write-Host " Find-CitrixIdleUser.ps1:" -fore Green
  9.     Write-Host "   Finds users with idle time greater than value passed"
  10.     Write-Host
  11.     Write-Host " Parameters:" -fore Green
  12.     Write-Host "   -Time                  : Optional. Server to Get Print Info From "
  13.     Write-Host "   -Day                   : Optional. Checks Days of Idle Time "
  14.     Write-Host "   -Hour                  : Optional. Checks Hours of Idle Time (Default)"
  15.     Write-Host "   -Minute                : Optional. Checks Minutes of Idle Time"
  16.     Write-Host "   -Logoff                : Optional. Logs User off if Idle Time exceeds Time"
  17.     Write-Host "   -Verbose               : Optional. Show Verbose Output"
  18.     Write-Host "   -Help                  : Optional. Displays This"
  19.     Write-Host
  20.     Write-Host " Examples:" -fore Green
  21.     Write-Host "   Finds Users who have been idle 2 hours and return AppName, UserName, SessionID, and ClientName" -fore White
  22.     Write-Host "     Find-CitrixIdleUser.ps1 2 -hour | ft AppName,UserName,SessionID,ClientName -auto" -fore Yellow
  23.     Write-Host
  24.     Write-Host "   Finds Users who have been idle 2 hours and Logs them Off" -fore White
  25.     Write-Host "     Find-CitrixIdleUser.ps1 2 -hour -logoff" -fore Yellow
  26.     Write-Host
  27. }
  28. if($verbose){$verbosepreference = "Continue"}
  29. Write-Host
  30. if(!$time -or $help){helpme;Write-Host;Return}
  31.  
  32. # Get Citrix Farm Object
  33. Write-Verbose " - Creating MFFarm Object"
  34. $farm = new-Object -com "MetaframeCOM.MetaframeFarm"
  35. $farm.Initialize(1)
  36.  
  37. # Parse Sessions
  38. Write-Verbose " - Parsing Sessions. Total of [$($farm.Sessions.count)] Sessions"
  39. foreach($session in $farm.Sessions)
  40. {
  41.     Write-Verbose "   - Processing Session ID [$($Session.SessionId)]"
  42.     $shouldLogOff = $false
  43.  
  44.     # Getting Citrix Session Idle Time and Convert to System.DateTime
  45.     Write-Verbose "   - Getting LastInputTime"
  46.     $ctxDate = $session.LastInputTime(1)
  47.     Write-Verbose "   - Checking if idle time is -gt 0"
  48.     if(($ctxDate.HighPart -ne 0) -and ($ctxDate.LowPart -ne 0))
  49.     {
  50.         $date = "{0,4}{1,2:00}{2,2:00}{3,2:00}{4,2:00}" -f $ctxDate.year,$ctxDate.Month,$ctxDate.Day,$ctxDate.Hour,$ctxDate.Minute
  51.         Write-Verbose "   - Converted LastInputTime to [$date]"
  52.         $SessionIdleTime = [system.DateTime]::ParseExact($date,‘yyyyMMddHHmm’,$null)
  53.  
  54.         # Get Current Time in System.DateTime
  55.         Write-Verbose "   - Getting Current Date"
  56.         $now = Get-Date
  57.         Write-Verbose "   - Current Date is [$now]"
  58.  
  59.         # Find Difference
  60.         Write-Verbose "   + Getting Time Difference"
  61.         $diff = $now - $SessionIdleTime
  62.         Write-Verbose "     - Found Days [$($diff.TotalDays)] Hours [$($diff.Totalhours)] Minutes [$($diff.TotalMinutes)]"
  63.  
  64.         # Output Sessions that match
  65.         if($day)   {    if($diff.TotalDays    -gt $time)    {$session;$shouldLogOff = $true}  }
  66.         if($hour)  {    if($diff.Totalhours   -gt $time)    {$session;$shouldLogOff = $true}  }
  67.         if($minute){    if($diff.TotalMinutes -gt $time)    {$session;$shouldLogOff = $true}  }
  68.  
  69.         Write-Verbose "     - Set `$shouldLogOff to [$shouldLogOff]"
  70.  
  71.         # Logging Off User
  72.         if($logoff -and $shouldLogOff)
  73.         {
  74.             Write-Verbose "   - Logging Off Session ID [$($Session.SessionId)]"
  75.             $session.Logoff($false)
  76.         }
  77.     }
  78.     else
  79.     {
  80.         Write-Verbose "   - Session ID [$($Session.SessionId)] NOT Idle"
  81.     }
  82.     Write-Host
  83. }

Check Active Directory Latency

The other day I had a need to see how long it took for an object to be replicated to all the Domain Controllers in my Environment.

Here is the script I came up with. It does the following:
- Finds all Domain Controllers in the Domain (using .NET)
- Creates a contact object in a specified OU (Default is users container for the Domain)
- Gets the start Time
- Loops and Checks each DC for the object.
- Once all DCs have the object it gets End Time
- Outputs the results

Some extra features
- re-writes screen using $host.UI.RawUI.CursorPosition. No scrolling text :) - Outputs a custom object with Name and Time to Replicate (-table)

Parameters/Switches
-target: DC to create object on. (Default: it will find one for you)
-fqdn: Used to Find Domain Controllers (Default: Use current Domain)
-ou: DN of the path to create contact objects (Default Users Container)
-remove: If $true it removes the temp object (default is $true)
-table: switch that will return a table with the DC and Time it took to replicate (as output)

Here is the code:

  1. Param($target = (([ADSI]"LDAP://rootDSE").dnshostname),
  2.       $fqdn = (([ADSI]"").distinguishedname -replace "DC=","" -replace ",","."),
  3.       $ou = ("cn=users," + ([ADSI]"").distinguishedname),
  4.       $remove = $true,
  5.       [switch]$table
  6.       )
  7.  
  8. $context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$fqdn)
  9. $dclist = [System.DirectoryServices.ActiveDirectory.DomainController]::findall($context)
  10. if($table)
  11. {
  12.     $DCTable = @()
  13.     $myobj = "" | select Name,Time
  14.     $myobj.Name = ("$target [SOURCE]").ToUpper()
  15.     $myobj.Time = 0.00
  16.     $DCTable += $myobj
  17. }
  18.  
  19. $name = "rTest" + (Get-Date -f MMddyyHHmmss)
  20. Write-Host "`n  Creating Temp Contact Object [$name] on [$target]"
  21. $contact = ([ADSI]"LDAP://$target/$ou").Create("contact","cn=$Name")
  22. $contact.SetInfo()
  23. $dn = $contact.distinguishedname
  24. Write-Host "  Temp Contact Object [$dn] Created! `n"
  25.  
  26. $start = Get-Date
  27.  
  28. $i = 0
  29.  
  30. Write-Host "  Found [$($dclist.count)] Domain Controllers"
  31. $cont = $true
  32.  
  33. While($cont)
  34. {
  35.     $i++
  36.     $oldpos = $host.UI.RawUI.CursorPosition
  37.     Write-Host "  =========== Check $i ===========" -fore white
  38.     start-Sleep 1
  39.     $replicated = $true
  40.     foreach($dc in $dclist)
  41.     {
  42.         if($target -match $dc.Name){continue}
  43.         $object = [ADSI]"LDAP://$($dc.Name)/$dn"
  44.         if($object.name)
  45.         {
  46.             Write-Host "  - $($dc.Name.ToUpper()) Has Object [$dn]" (" "*5) -fore Green
  47.             if($table -and !($dctable | ?{$_.Name -match $dc.Name}))
  48.             {
  49.                 $myobj = "" | Select-Object Name,Time
  50.                 $myobj.Name = ($dc.Name).ToUpper()
  51.                 $myobj.Time = ("{0:n2}" -f ((Get-Date)-$start).TotalSeconds)
  52.                 $dctable += $myobj
  53.             }
  54.         }
  55.         else{Write-Host "  ! $($dc.Name.ToUpper()) Missing Object [$dn]" -fore Red;$replicated  = $false}
  56.     }
  57.     if($replicated){$cont = $false}else{$host.UI.RawUI.CursorPosition = $oldpos}
  58. }
  59.  
  60. $end = Get-Date
  61. $duration = "{0:n2}" -f ($end.Subtract($start).TotalSeconds)
  62. Write-Host "`n    Took $duration Seconds `n" -fore Yellow
  63.  
  64. if($remove)
  65. {
  66.     Write-Host "  Removing Test Object `n"
  67.     ([ADSI]"LDAP://$target/$ou").Delete("contact","cn=$Name")
  68. }
  69. if($table){$dctable | Sort-Object Time | Format-Table -auto}

Sync Folder Script.

I initially wrote this for a guy on the NG, but I decided to use at work to sync some application folders I used to store tools and scripts and such. Please Try it out and tell me what you think.

Basic Flow
- Checks for Folders that Source has the Destination Does NOT and Creates.
- Checks for Folders that Destination has the Source Does NOT and Creates.
- Checks for files that Source has the Destination Does NOT and Copies.
- If the file is found in both, the MD5 of both files are checked… Last Write Wins
- Checks for Folders that Destination has the Source Does NOT
- It does NOT Delete anything yet… I am considering using a mirror switch

  1. Param($Source,$Destination)
  2. function Get-FileMD5 {
  3.    Param([string]$file)
  4.    $mode = [System.IO.FileMode]("open")
  5.    $access = [System.IO.FileAccess]("Read")
  6.    $md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
  7.    $fs = New-Object System.IO.FileStream($file,$mode,$access)
  8.    $Hash = $md5.ComputeHash($fs)
  9.    $fs.Close()
  10.    [string]$Hash = $Hash
  11.    Return $Hash
  12. }
  13. function Copy-LatestFile{
  14.     Param($File1,$File2,[switch]$whatif)
  15.     $File1Date = get-Item $File1 | foreach-Object{$_.LastWriteTimeUTC}
  16.     $File2Date = get-Item $File2 | foreach-Object{$_.LastWriteTimeUTC}
  17.     if($File1Date -gt $File2Date)
  18.     {
  19.         Write-Host "$File1 is Newer… Copying…"
  20.         if($whatif){Copy-Item -path $File1 -dest $File2 -force -whatif}
  21.         else{Copy-Item -path $File1 -dest $File2 -force}
  22.     }
  23.     else
  24.     {
  25.         Write-Host "$File2 is Newer… Copying…"
  26.         if($whatif){Copy-Item -path $File2 -dest $File1 -force -whatif}
  27.         else{Copy-Item -path $File2 -dest $File1 -force}
  28.     }
  29.     Write-Host
  30. }
  31.  
  32. if(!(test-Path $Destination))
  33. {
  34.     New-Item $Destination -type Directory -force | out-Null
  35. }
  36.  
  37. # Getting Files/Folders from Source and Destination
  38. $SrcEntries = Get-ChildItem $Source -Recurse
  39. $DesEntries = Get-ChildItem $Destination -Recurse
  40.  
  41. # Parsing the folders and Files from Collections
  42. $Srcfolders = $SrcEntries | Where-Object{$_.PSIsContainer}
  43. $SrcFiles = $SrcEntries | Where-Object{!$_.PSIsContainer}
  44. $Desfolders = $DesEntries | Where-Object{$_.PSIsContainer}
  45. $DesFiles = $DesEntries | Where-Object{!$_.PSIsContainer}
  46.  
  47. # Checking for Folders that are in Source, but not in Destination
  48. foreach($folder in $Srcfolders)
  49. {
  50.     $SrcFolderPath = $source -replace "\\","\\" -replace "\:","\:"
  51.     $DesFolder = $folder.Fullname -replace $SrcFolderPath,$Destination
  52.     if($DesFolder -ne ""){
  53.         if(!(test-path $DesFolder))
  54.         {
  55.             Write-Host "Folder $DesFolder Missing. Creating it!"
  56.             new-Item $DesFolder -type Directory | out-Null
  57.         }
  58.     }
  59. }
  60.  
  61. # Checking for Folders that are in Destinatino, but not in Source
  62. foreach($folder in $Desfolders)
  63. {
  64.     $DesFilePath = $Destination -replace "\\","\\" -replace "\:","\:"
  65.     $SrcFolder = $folder.Fullname -replace $DesFilePath,$Source
  66.     if($srcFolder -ne "")
  67.     {
  68.         if(!(test-path $SrcFolder))
  69.         {
  70.             Write-Host "Folder $SrcFolder Missing. Creating it!"
  71.             new-Item $SrcFolder -type Directory | out-Null
  72.         }
  73.     }
  74. }
  75.  
  76. # Checking for Files that are in the Source, but not in Destination
  77. foreach($entry in $SrcFiles)
  78. {
  79.     $SrcFullname = $entry.fullname
  80.     $SrcName = $entry.Name
  81.     $SrcFilePath = $Source -replace "\\","\\" -replace "\:","\:"
  82.     $DesFile = $SrcFullname -replace $SrcFilePath,$Destination
  83.     if(test-Path $Desfile)
  84.     {
  85.         $SrcMD5 = Get-FileMD5 $SrcFullname
  86.         $DesMD5 = Get-FileMD5 $DesFile
  87.         If($srcMD5 -ne $desMD5)
  88.         {
  89.             Write-Host "The Files MD5’s are Different… Checking Write Dates"
  90.             Write-Host $SrcMD5
  91.             Write-Host $DesMD5
  92.             Copy-LatestFile $SrcFullname $DesFile
  93.         }
  94.     }
  95.     else
  96.     {
  97.         Write-Host "$Desfile Missing… Copying from $SrcFullname"
  98.         copy-Item -path $SrcFullName -dest $DesFile -force
  99.     }
  100. }
  101.  
  102. # Checking for Files that are in the Destinatino, but not in Source
  103. foreach($entry in $DesFiles)
  104. {
  105.     $DesFullname = $entry.fullname
  106.     $DesName = $entry.Name
  107.     $DesFilePath = $Destination -replace "\\","\\" -replace "\:","\:"
  108.     $SrcFile = $DesFullname -replace $DesFilePath,$Source
  109.     if($SrcFile -ne "")
  110.     {
  111.         if(!(test-Path $SrcFile))
  112.         {
  113.             Write-Host "$SrcFile Missing… Copying from $DesFullname"
  114.             copy-Item -path $DesFullname -dest $SrcFile -force
  115.         }
  116.     }
  117. }
  118.  
  119. Write-Host