Posts RSS Comments RSS 117 Posts and 170 Comments till now

Fun with Active Directory (Playing Around Series)

This is the first in a series of posts call “Playing Around Series.” This series will basically be demo Videos of different Snapins/.NET Classes and their use.

In this entry I run through creating a DirectoryEntry, DirectorySearcher, and using the System.DirectoryServices.ActiveDirectory.Domain Class.

Note: This is a fast run through. I STRONGLY recommend pausing and reading the Comments. Best Viewed Full Screen

Get the Flash Player to see this player.

Special Shout-out to JayKul and Jeffrey Snover for the Start-Demo script.
http://www.powershellcentral.com/scripts/302

Demo Text

  1. #
  2. # Lets start off by looking at DirectoryEntry
  3. #
  4. $DE = New-Object System.DirectoryServices.DirectoryEntry("LDAP://CN=tstUsr101,OU=MyUsers,DC=corp,DC=lab")
  5. #
  6. # First lets see what we have access to
  7. #
  8. $DE | Get-Member
  9. #’
  10. # Hmmm.. doesn’t seem like much. OH WAIT! Remember Powershell abstracts the class… Lets add psbase
  11. #
  12. $DE.psbase | Get-Member
  13. #
  14. # Lets look at what properties are available.
  15. #
  16. $DE.psbase.Properties
  17. #
  18. # Thats more like it. You may also note that some AD properties are still missing.
  19. # That is because that LDAP doesnt return all the properties. For these you need to "GET" them.
  20. $DE.psbase.InvokeGet(‘msExchUMFaxID’)
  21. #
  22. # Using DirectoryEntry is fine if you know the DN of the object, but what if you need to search?
  23. # Lets look at System.DirectoryServices.DirectorySearcher
  24. #
  25. # The Searcher needs some info so put that in variables first
  26. #
  27. $root = [ADSI]""  ## This is using the Type Accelerator we spoke about earlier… This is Gets the base
  28. $filter = "(&(objectcategory=user))"
  29. #
  30. # Now Lets create the searcher
  31. #
  32. $searcher = New-Object System.DirectoryServices.DirectorySearcher($root,$filter)
  33. #
  34. # That gets the searcher ready, but to execute we need to call findall() or findone()
  35. #
  36. $users = $searcher.findAll()
  37. #
  38. # Lets see what we got. We have alot so lets only pick the first 10
  39. #
  40. $users | select -first 10
  41. #
  42. # Tons of info, but notice that this is NOT the same as DirectoryEntry
  43. #
  44. $users | get-Member
  45. #
  46. # It still has the properties property, Lets look (but only the first 3)
  47. #
  48. $users | select -first 3 | %{$_.Properties}
  49. #
  50. # Finally Lets look at System.DirectoryDervices.ActiveDirectory.Domain
  51. #
  52. # We can use this to interactively browse around
  53. #
  54. [system.directoryservices.activedirectory.domain]::GetCurrentDomain()
  55. #
  56. # Lets assign that to variable to play with
  57. #
  58. $domain = [system.directoryservices.activedirectory.domain]::GetCurrentDomain()
  59. $domain
  60. #
  61. # Lets see what this has to offer
  62. #
  63. $domain | get-member
  64. #
  65. # Tons of cool stuff here.
  66. #
  67. # We can find all domain controllers
  68. $domain.FindAllDomainControllers()
  69. #
  70. # We Can look at our Domain FSMO
  71. #
  72. $domain | ft PdcRoleOwner,RidRoleOwner,InfrastructureRoleOwner
  73. #
  74. # I can even step the tree and get my forest root
  75. #
  76. $forest = $domain.Forest
  77. $forest
  78. #
  79. # With our new found $forest object… what can do we do?
  80. #
  81. $forest | Get-Member
  82. #
  83. # WE can find all our GCs
  84. #
  85. $forest.FindAllGlobalCatalogs()
  86. #
  87. # We can look at the Forest Mode
  88. #
  89. $forest.ForestMode
  90. #
  91. # Look at the Forest FSMO
  92. #
  93. $forest | ft SchemaRoleOwner,NamingRoleOwner
  94. #
  95. # Even look at sites
  96. $forest.Sites
  97. #
  98. # We can go on forever and ever. If you would like we can revisit this later.
  99. #

The transition is complete (man that was NOT fun!)

I still have some minor adjustments, but all the content has been moved and the RSS links redirected. Please Let me know if you have any issues. I will be adding a contact form tomorrow.

More userAccountControl Flag Fun (Convert-ToUACFlag.ps1)

A question on the NG made me think about this. While I personally prefer the decimal that comes from userAccountControl, others may prefer to actually see the FLAGS that are set.

Here is the script I came up with. It will output and array by default, but -toString will output a “,” delimited string.

It has a great -help function with -verbose output that explains each UAC Flag

Convert-ToUACFlag.ps1

  1. # Convert-ToUACFlag.ps1
  2. Param([int]$uac,[switch]$ToString,[switch]$help,[switch]$verbose)
  3. function HelpMe{
  4.     Write-Host
  5.     Write-Host " Convert-ToUACFlag.ps1:" -fore Green
  6.     Write-Host "   Converts UAC from Decimal or Hex to User Account Control Flags (described verbose help)"
  7.     Write-Host
  8.     Write-Host " Parameters:" -fore Green
  9.     Write-Host "   -UAC                   : Parameter User Account Control Value"
  10.     Write-Host "   -toString              : [SWITCH]  Output to String instead of Array"
  11.     Write-Host "   -Help                  : [SWITCH]  Displays This"
  12.     Write-Host "   -Verbose               : [SWITCH]  Displays This and User Account Control Definitions"
  13.     Write-Host
  14.     Write-Host " Examples:" -fore Green
  15.     Write-Host "   Convert to Flag getting back array" -fore White
  16.     Write-Host "     .\Convert-ToUACFlag.ps1 69649" -fore Yellow
  17.     Write-Host "   Convert to Flag getting back string" -fore White
  18.     Write-Host "     .\Convert-ToUACFlag.ps1 69649 -toString" -fore Yellow
  19.     Write-Host
  20.     if($verbose)
  21.     {
  22.         Write-Host " User Account Control Flags and Definition" -fore Green
  23.         Write-Host "  + SCRIPT" -fore Yellow
  24.         Write-Host "    - The logon script will be run."
  25.         Write-Host
  26.         Write-Host "  + ACCOUNTDISABLE" -fore Yellow
  27.         Write-Host "    - The user account is disabled."
  28.         Write-Host
  29.         Write-Host "  + HOMEDIR_REQUIRED" -fore Yellow
  30.         Write-Host "    - The home folder is required."
  31.         Write-Host
  32.         Write-Host "  + PASSWD_NOTREQD" -fore Yellow
  33.         Write-Host "    - No password is required."
  34.         Write-Host
  35.         Write-Host "  + PASSWD_CANT_CHANGE" -fore Yellow
  36.         Write-Host "    - The user cannot change the password."
  37.         Write-Host "    - This is a permission on the user’s object."
  38.         Write-Host
  39.         Write-Host "  + ENCRYPTED_TEXT_PASSWORD_ALLOWED" -fore Yellow
  40.         Write-Host "    - The user can send an encrypted password."
  41.         Write-Host
  42.         Write-Host "  + TEMP_DUPLICATE_ACCOUNT" -fore Yellow
  43.         Write-Host "    - This is an account for users whose primary account is in another domain."
  44.         Write-Host "    - This account provides user access to this domain,"
  45.         Write-Host "      but not to any domain that trusts this domain."
  46.         Write-Host "    - This is sometimes referred to as a local user account."
  47.         Write-Host
  48.         Write-Host "  + NORMAL_ACCOUNT" -fore Yellow
  49.         Write-Host "    - This is a default account type that represents a typical user."
  50.         Write-Host
  51.         Write-Host "  + INTERDOMAIN_TRUST_ACCOUNT" -fore Yellow
  52.         Write-Host "    - This is a permit to trust an account for a system domain that trusts other domains."
  53.         Write-Host
  54.         Write-Host "  + WORKSTATION_TRUST_ACCOUNT" -fore Yellow
  55.         Write-Host "    - This is a computer account for a computer that is running"
  56.         Write-Host "    - Microsoft Windows NT 4.0 and above and is a member of this domain."
  57.         Write-Host
  58.         Write-Host "  + SERVER_TRUST_ACCOUNT" -fore Yellow
  59.         Write-Host "    - This is a computer account for a domain controller that is a member of this domain."
  60.         Write-Host
  61.         Write-Host "  + DONT_EXPIRE_PASSWD" -fore Yellow
  62.         Write-Host "    - Represents the password, which should never expire on the account."
  63.         Write-Host
  64.         Write-Host "  + MNS_LOGON_ACCOUNT" -fore Yellow
  65.         Write-Host "    - This is an MNS logon account."
  66.         Write-Host
  67.         Write-Host "  + SMARTCARD_REQUIRED" -fore Yellow
  68.         Write-Host "    - When this flag is set, it forces the user to log on by using a smart card."
  69.         Write-Host
  70.         Write-Host "  + TRUSTED_FOR_DELEGATION" -fore Yellow
  71.         Write-Host "    - When this flag is set, the service account (the user or computer account)"
  72.         Write-Host "      under which a service runs is trusted for Kerberos delegation."
  73.         Write-Host "    - Any such service can impersonate a client requesting the service."
  74.         Write-Host "    - To enable a service for Kerberos delegation, you must set this flag on the"
  75.         Write-Host "      userAccountControl property of the service account."
  76.         Write-Host
  77.         Write-Host "  + NOT_DELEGATED" -fore Yellow
  78.         Write-Host "    - When this flag is set, the security context of the user is not delegated to"
  79.         Write-Host "      a service even if the service account is set as trusted for Kerberos delegation."
  80.         Write-Host
  81.         Write-Host "  + USE_DES_KEY_ONLY" -fore Yellow
  82.         Write-Host "    - (Windows 2000/Windows Server 2003) Restrict this principal to use only"
  83.         Write-Host "      Data Encryption Standard (DES) encryption types for keys."
  84.         Write-Host
  85.         Write-Host "  + DONT_REQUIRE_PREAUTH" -fore Yellow
  86.         Write-Host "    - (Windows 2000/Windows Server 2003) This account does not require"
  87.         Write-Host "      Kerberos pre+authentication for logging on."
  88.         Write-Host
  89.         Write-Host "  + PASSWORD_EXPIRED" -fore Yellow
  90.         Write-Host "    - (Windows 2000/Windows Server 2003) The user’s password has expired."
  91.         Write-Host
  92.         Write-Host "  + TRUSTED_TO_AUTH_FOR_DELEGATION" -fore Yellow
  93.         Write-Host "    - (Windows 2000/Windows Server 2003) The account is enabled for delegation."
  94.         Write-Host "    - This is a security-sensitive setting."
  95.         Write-Host "    - Accounts with this option enabled should be tightly controlled."
  96.         Write-Host "    - This setting allows a service that runs under the account to assume a client’s"
  97.         Write-Host "      identity and authenticate as that user to other remote servers on the network."
  98.     }
  99.     Write-Host
  100. }
  101.  
  102. if(!$uac -or $help){HelpMe;Return}
  103. $flags = @()
  104. switch ($uac)
  105. {
  106.     {($uac -bor 0×0002) -eq $uac}    {$flags += "ACCOUNTDISABLE"}
  107.     {($uac -bor 0×0008) -eq $uac}    {$flags += "HOMEDIR_REQUIRED"}
  108.     {($uac -bor 0×0010) -eq $uac}    {$flags += "LOCKOUT"}
  109.     {($uac -bor 0×0020) -eq $uac}    {$flags += "PASSWD_NOTREQD"}
  110.     {($uac -bor 0×0040) -eq $uac}    {$flags += "PASSWD_CANT_CHANGE"}
  111.     {($uac -bor 0×0080) -eq $uac}    {$flags += "ENCRYPTED_TEXT_PWD_ALLOWED"}
  112.     {($uac -bor 0×0100) -eq $uac}    {$flags += "TEMP_DUPLICATE_ACCOUNT"}
  113.     {($uac -bor 0×0200) -eq $uac}    {$flags += "NORMAL_ACCOUNT"}
  114.     {($uac -bor 0×0800) -eq $uac}    {$flags += "INTERDOMAIN_TRUST_ACCOUNT"}
  115.     {($uac -bor 0×1000) -eq $uac}    {$flags += "WORKSTATION_TRUST_ACCOUNT"}
  116.     {($uac -bor 0×2000) -eq $uac}    {$flags += "SERVER_TRUST_ACCOUNT"}
  117.     {($uac -bor 0×10000) -eq $uac}   {$flags += "DONT_EXPIRE_PASSWORD"}
  118.     {($uac -bor 0×20000) -eq $uac}   {$flags += "MNS_LOGON_ACCOUNT"}
  119.     {($uac -bor 0×40000) -eq $uac}   {$flags += "SMARTCARD_REQUIRED"}
  120.     {($uac -bor 0×80000) -eq $uac}   {$flags += "TRUSTED_FOR_DELEGATION"}
  121.     {($uac -bor 0×100000) -eq $uac}  {$flags += "NOT_DELEGATED"}
  122.     {($uac -bor 0×200000) -eq $uac}  {$flags += "USE_DES_KEY_ONLY"}
  123.     {($uac -bor 0×400000) -eq $uac}  {$flags += "DONT_REQ_PREAUTH"}
  124.     {($uac -bor 0×800000) -eq $uac}  {$flags += "PASSWORD_EXPIRED"}
  125.     {($uac -bor 0×1000000) -eq $uac} {$flags += "TRUSTED_TO_AUTH_FOR_DELEGATION"}
  126. }
  127. if($toString){$flags | %{if($mystring){$mystring += ",$_"}else{$mystring = $_}};$mystring}else{$flags}

Oisin the “obsessive programmer” sent me this as another option

  1. param
  2. ([int]$value)
  3. $flags = @("","ACCOUNTDISABLE","", "HOMEDIR_REQUIRED",
  4. "LOCKOUT", "PASSWD_NOTREQD","PASSWD_CANT_CHANGE", "ENCRYPTED_TEXT_PWD_ALLOWED",
  5. "TEMP_DUPLICATE_ACCOUNT", "NORMAL_ACCOUNT", "","INTERDOMAIN_TRUST_ACCOUNT", "WORKSTATION_TRUST_ACCOUNT",
  6. "SERVER_TRUST_ACCOUNT", "", "", "DONT_EXPIRE_PASSWORD", "MNS_LOGON_ACCOUNT", "SMARTCARD_REQUIRED",
  7. "TRUSTED_FOR_DELEGATION", "NOT_DELEGATED","USE_DES_KEY_ONLY", "DONT_REQ_PREAUTH",
  8. "PASSWORD_EXPIRED", "TRUSTED_TO_AUTH_FOR_DELEGATION")
  9. 1..($flags.length) | ? {$value -band [math]::Pow(2,$_)} | % { $flags[$_] }

An Interactive Case for Powershell (Yet more Citrix Fun!)

I was recently in a discussion on Brian Madden Forums about listing Citrix Information and exporting to CSV. It seemed like a
perfect fit for Powershell so I converted the VBScripts to Powershell (of course taking an 85 line script to 3 lines. Convert is
hardly the correct term.)

Here is the Forum Topic
http://www.brianmadden.com/Forum/Topic/95285

Here is my Code. There were three scripts, so I made three as well.

  1. # Apps by Server CTXApps_by_Server_w_Users
  2. $MF = (New-Object -com MetaFrameCOM.MetaFrameFarm)
  3. $MF.Initialize(1)
  4. $MF.Servers | Select-Object ServerName -expand Applications | Select-Object ServerName,AppName,DistinguishedName,
  5.        @{n=‘Users’;e={$_.Users | %{$_.UserName}}},
  6.        @{n=‘Groups’;e={$_.Groups | %{$_.GroupName}}} | export-Csv C:\AppsByServer.Csv -noType
  1. # Apps with Servers
  2. $MF = New-Object -com MetaFrameCOM.MetaFrameFarm
  3. $MF.Initialize(1)
  4. $MF.Applications | Select-Object AppName,DistinguishedName,
  5.       @{n="Servers";e={$_.Servers | foreach{$_.ServerName}}} | export-Csv C:\AppsWithServer.Csv -noType
  1. # Apps with Servers and Users CTXApps_w_Servers_w_Users
  2. $MF = New-Object -com MetaFrameCOM.MetaFrameFarm
  3. $MF.Initialize(1)
  4. $MF.Applications | Select-Object AppName,DistinguishedName,
  5.       @{n="Servers";e={$_.Servers | foreach{$_.ServerName}}},
  6.       @{n=‘Users’;e={$_.Users | %{$_.UserName}}},
  7.       @{n=‘Groups’;e={$_.Groups | %{$_.GroupName}}} | export-Csv C:\AppsWithServerandUsers.Csv -noType

If you notice in my three scripts they all start with the same two lines. Effectively these are one liners that could be used
interactively. I think this does a great job of showing Citrix Admins how nicely Powershell will fit in to their daily lives.
Things that use to take 100s of lines of script writing can now be done interactively at a shell.

Get-Uptime (fun with Write-Host)

I am a BIG fan of Write-Host. Think of Write-Host like wscript.Echo (vbscript) or echo (cmd.exe,) on steroids. I know I know… you want to know what I think is the best feature and funny enough… its COLOR!!! Yes, COLOR, no more two color schemes. With Write-Host you can do all sorts of colors with foreground and background.

To celebrate, I wanted to write a post illustrating just how wonderful write-host can be and I thought it would be best to use a script that I wrote. This is a script to get the uptime of server.

  1. Function Get-Uptime {
  2.     Param([string]$server)
  3.     Begin {
  4.         function Uptime {
  5.             param([string]$srv)
  6.             $os = Get-WmiObject Win32_OperatingSystem -ComputerName $srv
  7.             $uptime = $os.LastBootUpTime
  8.             return $uptime
  9.         }
  10.         function ConvertDate {
  11.             param([string]$date)
  12.             $year = $date.substring(0,4)
  13.             $Month = $date.Substring(4,2)
  14.             $Day = $date.Substring(6,2)
  15.             $hour = $date.Substring(8,2)
  16.             $min = $date.Substring(10,2)
  17.             $sec = $date.Substring(12,2)
  18.             $RebootTime = new-Object System.DateTime($year,$month,$day,$hour,$min,$sec)
  19.             $now = [System.DateTime]::Now
  20.             $uptime = $now.Subtract($RebootTime)
  21.             Write-Host "==> Uptime: " -NoNewLine
  22.             Write-Host "$($uptime.days)" -NoNewLine -ForeGroundColor Green
  23.             Write-Host " days, " -NoNewLine
  24.             Write-Host "$($uptime.Hours)" -NoNewLine -ForeGroundColor Green
  25.             Write-Host " hours, " -NoNewLine
  26.             Write-Host "$($uptime.Minutes)" -NoNewLine -ForeGroundColor Green
  27.             Write-Host " minutes, " -NoNewLine
  28.             Write-Host "$($uptime.seconds)" -NoNewLine -ForeGroundColor Green
  29.             Write-Host " seconds, "
  30.         }
  31.         Write-Host
  32.         $process = @()
  33.     }
  34.     Process {
  35.         if($_){
  36.             if($_.ServerName ){
  37.                 $process += $_.ServerName
  38.             }
  39.             else{
  40.                 $process += $_
  41.             }
  42.         }
  43.     }
  44.     End {
  45.         if($Server){$process += $server}
  46.         foreach ($Server in $process){
  47.             $result = uptime $server
  48.             Write-Host "Uptime for Server [" -NoNewline
  49.             Write-Host $server  -NoNewline -foregroundcolor Cyan
  50.             Write-Host "]"
  51.             ConvertDate $result
  52.             Write-Host
  53.         }
  54.         Write-Host
  55.     }
  56. }

As you can see I use Write-Host numerous times so let me explain a couple of the lines so you can see what is happening.

  1. Write-Host "==> Uptime: " -NoNewLine
  2. Write-Host "$($uptime.days)" -NoNewLine -ForeGroundColor Green
  3. Write-Host " days, " -NoNewLine
  4. Write-Host "$($uptime.Hours)" -NoNewLine -ForeGroundColor Green
  5. Write-Host " hours, " -NoNewLine
  6. Write-Host "$($uptime.Minutes)" -NoNewLine -ForeGroundColor Green
  7. Write-Host " minutes, " -NoNewLine
  8. Write-Host "$($uptime.seconds)" -NoNewLine -ForeGroundColor Green
  9. Write-Host " seconds, "

What I wanted was to have the output look like uptime.exe, but I wanted to add a little flare so I decided highlighting the numbers in a different color would make it easier to read.

There are two switches that I use here -NoNewLine and -ForeGroundColor. These are pretty self explanatory, but I will explain anyway.
-NoNewLine: This tells Write-Host not to add a New Line at the end of the string.

-ForeGroundColor: This tells you the color you want the text to display in (Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White.)

There are few other useful switches I didn’t use.
-BackGroundColor: Same available colors as ForeGroundColor, but this applies to the background color. So if you want the text to be Green on Black you would do
[code]Write-Host “Hello World” -ForeGroundColor Green -BackGroundColor Black[/code]

-Separator: This applies only if you pass an array of strings to write-host. This will prepend the “separator” to each string.

  1. write-host ("hello","this","is","Separated","by","`"-`"") -Separator "-"

As you can see Write-Host is pretty useful, especially when you need your output to be nice and neat.

OH! Before I go… there is one thing to watch out for. Although for most people write-host behaves exactly as expected when you start working with PowerShell and start understanding Pipes its important to understand that Write-Host does NOT write to the pipeline. It writes to stdout. This is very important if you are trying to write stuff the pipe. To write to the pipe you need to use write-output.