I got an e-mail from a forum buddy yesterday asking about a quick and easy way to change the OU that a deployed virtual machine (or any machine for that matter) belongs to.
When machines are added to an Active Directory domain, they are automatically joined to the Computers OU. Well, actually, Computers is a Container, but that’s semantics.
Group Policy Objects can’t be applied to the Computers container, and as a result, they cannot be leveraged on computers in that container. That is, with the exception of a domain wide GPO.
So what is a Windows/VM admin supposed to do when deploying 100+ VDI Desktops, 10 new guests, or the like, and they want to ensure that they have the deployed systems in the right OU?
I worked on part of the puzzle last night, and felt pretty good about the work I had done. Then when I awoke this morning, a couple more concerns came to mind.
Well, there’s 2 ways to tackle this problem (one secure and inflexible, another insecure and flexible).
Let’s start with the insecure one:
Create a local script or executable that will move the Computer to a new OU
1. Easy to use, can be very flexible, depending on how coded
2. Add the ability to accept command line parameters to change the target OU
Different OU paths could be implemented by different .bat files in the RunOnce registry key.
One .bat for one path, another for a different one, etc.
3. Is run from the deployed system, and can be pretty much automated.
4. Is run dynamically, and automatically is run as new templates are deployed
1. The script cannot make changes to Active Directory, unless the logged in account has AD privileges.
2. To run the script as a non-authorized user, the script would have to be run with an alternate user’s credentials
3. Is there any secure way to store this process where it cannot be exploited?
Create an admin script/exe that a privileged user runs outside of the VM
1. The script is only run by an authorized user, outside of the VM
2. Leveraging existing tools, and an administrative user’s security can be better protected
2. Someone has to know to run it
So is there a way to have your cake and eat it too?
In a perfect world, yes. In the real world, not without some finagling.
An imperfect method, a local script with elevated privileges:
I did write a vbscript that will handle the move (minus the elevated credentials piece), but decided to turn it into an executable using AutoITScript. After downloading the AutoITScript package, and installing it, save the script below as an .au3 file, and use the AutoITScript package to compile it.
Here’s the AutoITScript:
AutoIt Version: 126.96.36.199
Author: Jase McCarty
Script Name: moveou.au3
Take a computer out of the Computer Org Unit,
and place it in a specific target Org Unit
Syntax: moveou.exe “OU=Target,DC=domain,DC=com”
; Setup constants for writing to the
; event log
Global Const $SUCCESS = 0
Global Const $ERROR =1
; Setup our variables so we can have
; space to work
; Create a Windows Shell object,
; so we can write to the event log
$WshShell = ObjCreate(“WScript.Shell”)
; Create an AutoIT Error handler,
; for error trapping
$oMyError = ObjEvent(“AutoIt.Error”, “ComError”)
; Grab the local computer name
$sComputer = @ComputerName
; Grab the destination Org Unit’s
; Distinguished Name
$sTargetDN = “LDAP://” & $Cmdline
; Grab the DefaultNamingContext so we have
; DC=company,DC=com or whatever
$sRootDSE = ObjGet(“LDAP://RootDSE”)
$sDomain = $sRootDSE.Get(“DefaultNamingContext”)
; Set the Short and Long Distinguished Name values
$sCompShortDN = “CN=” & $sComputer
$sCompLongDN = “LDAP://CN=” & $sComputer & “,CN=Computers,” & $sDomain
; Load the Target Org Unit as an object
$objCont = ObjGet($sTargetDN)
; Move the Computer into the Target Org Unit
; If we were successful, write to the event log as such
If $sErrorSet <> 1 Then
$WshShell.LogEvent ($SUCCESS, $sComputer & ” moved to the ” & $sTargetDN & ” organizational unit”)
;COM Error function
; If we weren’t successful, write to the event log as such
$WshShell.LogEvent ($ERROR, “Error running MoveOU script” )
$sErrorSet = 1
Again, this doesn’t handle the elevated credentials piece. After the script is compiled into an exe, it would be run from the command line like this:
moveou.exe “OU=Destination Org Unit,”
And yes, the following comma is necessary.
To do this with “runas”, there is one caveat. The password cannot be passed as part of a script.
To do this with CPAU, a batch file with the following contents would have to be used:
CPAU -u user [-p password] -ex “moveou.exe ‘”OU=Destination Org Unit,'”
And the destination org unit has double quotes on the outside, and single quotes on the inside.
To do this with AutoITScript, another au3/exe would have to be created that can elevate the credentials. Here’s one that would do that for you:
Runas($CmdLines,$CmdLines,$CmdLines,0,”Drive:PathTomoveou.exe ” & $CmdLines)
This would be run as
moveelevated.exe username domain password ‘”OU=Destination Org Unit,'”
*Disclaimer… I haven’t tested this, but it should work.
Two of these three options (not runas, due to the password limitation) could be put in a RunOnce registry key, and would accomodate the move once the guest has been joined to the domain, and rebooted.
If used with a VMware VirtualCenter’s Customization Specification, this line could be put in a runonce instruction. The data (including the password) would be stored in the VC database, and not be sent across the network, except through the customization package dropoff during a guest deployment.
A better method, being run by an admin (on the back end):
1. Using DSADD (before the guest is added to the domain)
A preferred method, would be to add the computer accounts into Active Directory, in the appropriate OU beforehand, and as a result when the new machine is added to AD, it will already be in the correct OU.
This can easily be done using the dsadd command.
dsadd computer “cn=ComputerName,ou=Test Servers, dc=domain,dc=com”
Or it can be put in a batch file that will accept a parameter
dsadd computer “cn=%1,ou=Test Servers, dc=domain,dc=com”
Which would be run like this:
This method is very easy if you know the name of the computer you wish to add. And keep in mind, this would have to be run before the guest is joined to the domain.
2. Using the previously mentioned moveou.exe (after the guest is on the domain)
By modifying the moveou.exe script to accept the computername as a command line parameter, an administrator could run the command with the destination OU, as well as the computername, and have the script move the computer to the desired OU.
moveou.exe “OU=Destination Org Unit,” ComputerName
As before, the admin would have to do this manually.
3. Use the existing Active Directory Users & Computers interface.
I shouldn’t have to say anything about this.
How VMware could help us out:
Now, if VMware could add a piece to the deployment process, where after a machine is run, a command could be run (outside of the guest) with the rights of the VirtualCenter user that deployed the machine.
Mass deployment of guests and assignment to an appropriate OU is somewhat problematic right now. Until we get a little extra functionality from VirtualCenter, we’ll have to continue the hacking.
Update, I forgot to mention… There’s a PDF on viops.vmware.com by Chris Skinner, that also addresses this issue.