Tuesday, June 14, 2011

PowerShell script to Dynamically choose a Domain Controller

I write a lot of scripts that require a domain controller to be specified. Problem is, I have over 90 domain controllers to choose from and they seem to be adding and removing them all the time. So I figured, the best way would be to create a dynamic list of domain controllers in the same site as the updates I am trying to apply. So if I am creating a mailbox in a site called NewYork, I would only want the domain controllers in the NewYork site to show up. I chose to do this through a function so the code could be easily reused for the many scripts that require a domain controller be specified.

The function looks as follows:

Function ChooseDC
#This funtion dynamically creates a list of Domain Controllers in a specific site (within the current forest) and lets you set the $DC value to one of them.
 #Prompt the user to select a domain controller
 Write-Host "Please select a domain controller:" -fore Yellow
 #Create an array that list all domain controllers in site called SITENAME (replace with your site)
 @([Array]$myServers = (([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).Sites | Where {$_.Name -eq "SITENAME"}).Servers)

 #sort the Array on the server names 
 [Array]$Servers = $myServers | Sort-Object Name
 #Iterate through each server in the array (starting at array item 0 through the last item in the array)
 For ($s = 0;  $s -le ($Servers.Count -1); $s +=1)
  #Capture the server name to the $ServerName variable
  [String]$ServerName = $Servers[$s].Name
  #Create a string to output to the screen saying to pick that number for that server
  [String]$Out = "Enter " + ($s +1) + " for " + $ServerName
  #Output the string to the screen
  Write-Host -Fore Yellow $out 
 #After all domain controllers are listed, prompt user to choose which domain controller by it's number that they want to work with.
 [int]$Result = Read-Host "Make your choice now"
 #Set an integer variable to the result of their choice minus 1. This will sync the choice with the proper array item for that Domain Controller.
 [int]$item = ($Result -1)
 #set $DC to equal that server name
 [String]$DC = $Servers[$item].Name
 #return the value of the variable, $DC, to the calling script.
 Return $DC


So, if you needed to see if a specific user had replicated yet to a specific domain controller, you could create a simple script that includes the function above and then the following after the closing "}".

#run the function and assign it's result to $DC
$DC = ChooseDC

#replace UserName with the User Name of the user you are checking for.
get-User -id "UserName" -domaincontroller $DC |fl DisplayName

Save the script as something like c:\finduser.ps1 and open powershell (in this case the Exchange Management Shell). Change directory to C: (CD\).
Running the script would look as follows:
[PS] C:\>.\finduser
Please select a domain controller:
Enter 1 for NY0DC01.domain.com
Enter 2 for NY0DC02.domain.com
Enter 3 for NY0DC03.domain.com
Enter 4 for NY0DC04.domain.com
Enter 5 for NY0DC05.domain.com
Enter 6 for NY0DC06.domain.com
Make your choice now: 2
If the user does not exist on the domain controller, you will get an error similare to the one below:
Get-User : The operation could not be performed because object 'UserName' could not be found on domain controller 'NY0DC02.
At C:\test.ps1:36 char:9
+ get-User <<<<  -id "UserName" -domaincontroller $DC |fl DisplayName
    + CategoryInfo          : InvalidData: (:) [Get-User], ManagementObjectNotFoundException
    + FullyQualifiedErrorId : 41716ACC,Microsoft.Exchange.Management.RecipientTasks.GetUser
If the user does exist, it would return the DisplayName of the user. You can save the function in a dot sourced function file and make it accessible to all of your scripts without having to put it in each one. To dot source it, just save the function in a file and call it something like functions.ps1. To make it even more available, let's save it to a shared folder. So \\servername\scripts would be a good place to put it. Now, my script that uses the dot sourced function script would look as follows:
#call the dot sourced function script
. \\NYFileSrv01\Scripts\functions.ps1
#this makes all functions in the functions.ps1 script available to your script.

#call your function
$DC = choosedc
#use the result of the function ($dc) in your get-user statement
get-User -id "UserName" -domaincontroller $DC |fl DisplayName

All in all, this is a pretty useful function. Also, using dot sourcing is an excellent way to keep all your functions organized and available without having to rewrite or cut and paste them every time. I highly recommend dot sourcing all functions.

No comments:

Post a Comment