It is a hectic day today with people shoulder tapping me all day long in the office until someone highlighted me a case on a newly commissioned XenApp server not belonging to the correct Organization Unit in Active Directory. First question came to my mind, who build that? Why did he/she forgotten to move the Computer Object to the correct Organization Unit so that the appropriate Group Policy can is applied to the server.
Eventually, I decided to modify this simple personal PowerShell script which I wrote for my self usage into a Set-ComputerObjectOU Cmdlet and imported this module to the server building automation process. Ahhh… Maybe adding some kind of logging as an audit trail in C:\Temp folder will be good so that I know what is happening when the Computer Object is being moved to another Organization Unit. As my thought process keeps going, I remembered that moving the Computer Object does not mean that the Group Policy will be applied immediately. A GPUpdate /Force command is needed on that machine and I added this command into it after the Computer Object has moved to the desired Organization Unit.
So what is next? Hmmm… A type of output on the applied Group Policy will be ideal and comprehensive since we need to know if those Group Policy has been applied after the GPUpdate /Force command has been initiated. OK, fine. I added the GPResult /H command to output of the Group Policy Result in HTML format in C:\Temp folder so that an engineer could check it. And that’s how this Set-ComputerObjectOU came about…
But another feature creep thought came to me, must I remote console to that machine to run the command or would it be better if I modify this to allow it perform the same task to a machine remotely. Sigh… I guess being a script project manager cum script developer role usually has its pros and cons… But that’s another story to tell…
I suppose alot of PowerShell savvy engineer do know how to use the PowerShell to move a Computer Object to an Organization Unit. But if anyone is also having a nauseous day at work like me today and is looking for the same solution to make life abit easier. Go download this Set-ComputerObjectOU Cmdlet on the link below. Hope I’m saving another engineer in this world. 🙂
Download Link – http://gallery.technet.microsoft.com/Set-ComputerObjectOU-ab8f8b3a
The Set-ComputerObjectOU Cmdlet allows Administrator to move the Computer Object to a designated Organization Unit in Active Directory on the local machine or remotely to a remote machine and apply group policy update on the machine to retrieve Group Policy linked to the Organization Unit in Active Directory.
Requirements
1.Active Directory Domain Controller must have Windows Remote Management configured
2.Active Directory Domain Controller and Computer must have PowerShell 2.0 or higher
KnowledgeBase for Windows Remote Management
1.Windows Remote Management – http://msdn.microsoft.com/en-us/library/aa384426%28v=vs.85%29.aspx
2.about_Remote_Requirements – http://technet.microsoft.com/library/hh847859.aspx
3.Installation and Configuration for Windows Remote Management – http://msdn.microsoft.com/en-us/library/aa384372%28v=vs.85%29.aspx
function Set-ComputerObjectOU { <# .SYNOPSIS Set the Computer Object that has joined the Domain to the designated Organization Unit from the local machine or remotely. .DESCRIPTION Allows Administrator to move the Computer Object to the designated Organization Unit .PARAMETER ComputerName ALIAS -CN This parameter allows the Administrator to specify the Computer Name of the Computer Object that should be moved in the Domain. .PARAMETER OrganizationUnitDN ALIAS -OU This parameter allows the Administrator to specify the Organization Unit Distinguished Name where the Computer Object should belong to in the Domain. .PARAMETER DomainController ALIAS -DC This parameter allows the Administrator to specify the Domain Controller of the Domain that will execute the moving of the Computer Object to the Organization Unit. .PARAMETER Username ALIAS -U This parameter allows the Administrator to specificy the username that has the security right to perform the task in the Domain to move the Computer Object. .PARAMETER Password ALIAS -P This parameter allows the Administrator to specify the password for the user that has the security right to perform the task in the DOmain to move the Computer Object. .EXAMPLE Set-ComputerObjectOU -OrganizationUnitDN "OU=XenApp,OU=Member Servers,DC=Redmond,DC=CO,DC=NZ" -DomainController RedmondAD -Username Redmond\Administrator -Password R3dmond This example shows how to actually move the local machine to the XenApp OU within the Member Server OU using the RedmondAD domain controller hostname. .EXAMPLE Set-ComputerObjectOU -ComputerName Contoso -OrganizationUnitDN "OU=XenApp,OU=Member Servers,DC=Redmond,DC=CO,DC=NZ" -DomainController RedmondAD -Username Redmond\Administrator -Password R3dmond This example shows how to actually move the remote machine to the XenApp OU within the Member Server OU using the RedmondAD domain controller hostname. .NOTES Title : Powershell Move Computer Object Filename: Set-ComputerObjectOU.psm1 Date : 10/05/2012 Author : Ryen Kia Zhi Tang Blog : ryentang.wordpress.com Version : 0.1 #> param ( # Computer Name [Alias('CN')] $ComputerName = $Env:ComputerName, # Organization Unit Distinguished Name [Alias('OU')] [String] $OrganizationUnitDN = "", # Domain Controller Hostname [Alias('DC')] [String] $DomainController = "", # Domain Admin Username [Alias('U')] [String] $Username = "", # Password [Alias('P')] [String] $Password = "" ) # Set Credential $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$(ConvertTo-SecureString $Password -asplaintext -force) # Force Group Policy Update Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($ComputerName,$OrganizationUnitDN,$DomainController,$Credential) # Define CONSTANT $LogFile = "C:\Temp\Set-ComputerObjectOU.log" # Check that C:\Temp Exist if($(Test-Path -Path "C:\Temp\") -eq $FALSE) { # Create a C:\Temp Folder New-Item -ItemType Directory -Path "C:\Temp\" -Force } "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - Query Computer Object Distinguished Name" | Out-File -FilePath $LogFile -Append # Get Current Computer Object Distinguished Name $ComputerObjectDN = Invoke-Command -ComputerName $DomainController -ScriptBlock{param($ComputerName) Import-Module ActiveDirectory; Get-ADComputer $ComputerName | Select -ExpandProperty DistinguishedName } -Args $ComputerName -Credential $Credential -Verbose if($ComputerObjectDN -eq $null) { "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - Computer Object Distinguished Name - Fail" | Out-File -FilePath $LogFile -Append }else{ "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - Computer Object Distinguished Name - Success" | Out-File -FilePath $LogFile -Append "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - Current Distinguished Name = $ComputerObjectDN" | Out-File -FilePath $LogFile -Append } Write-Verbose "[ATTEMPT TO MOVE OBJECT] $ComputerObjectDN [TO] $OrganizationUnitDN" "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - [ATTEMPT TO MOVE OBJECT] $ComputerObjectDN [TO] $OrganizationUnitDN" | Out-File -FilePath $LogFile -Append # Move Computer Object To Default Organization Unit Invoke-Command -ComputerName $DomainController -ScriptBlock { param($ComputerObjectDN, $OrganizationUnitDN) Import-Module ActiveDirectory; Move-ADObject -Identity $ComputerObjectDN -TargetPath $OrganizationUnitDN -Verbose } -Args $ComputerObjectDN, $OrganizationUnitDN -Credential $Credential | Out-File -FilePath $LogFile -Append # Get Current Computer Object Distinguished Name $ComputerObjectDN = Invoke-Command -ComputerName $DomainController -ScriptBlock{param($ComputerName) Import-Module ActiveDirectory; Get-ADComputer $ComputerName | Select -ExpandProperty DistinguishedName } -Args $ComputerName -Credential $Credential -Verbose if($ComputerObjectDN -ne $("CN=$ComputerName," + $OrganizationUnitDN )) { "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - [ATTEMPT TO MOVE OBJECT] - Fail" | Out-File -FilePath $LogFile -Append }else{ "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - [ATTEMPT TO MOVE OBJECT] - Success" | Out-File -FilePath $LogFile -Append "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - New Distinguished Name = $ComputerObjectDN" | Out-File -FilePath $LogFile -Append } "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - Initiate GPUPDATE /Force" | Out-File -FilePath $LogFile -Append # Force Group Policy Update Start-Process -FilePath C:\Windows\System32\GPUPDATE.EXE -ArgumentList /FORCE -Wait -PassThru -RedirectStandardOutput C:\Temp\GPUpdate_output.txt -RedirectStandardError C:\Temp\GPUpdate_error.txt Get-Content C:\Temp\GPUpdate_output.txt | Where-Object {$_.length -gt 0} | Out-File -FilePath $LogFile -Append Get-Content C:\Temp\GPUpdate_error.txt | Where-Object {$_.length -gt 0} | Out-File -FilePath $LogFile -Append Remove-Item C:\Temp\* -Include *.txt # Construct Group Policy Result Output Filename $FileName = [string]::join("",("C:\Temp\", $(Get-Date -uformat "%Y-%m-%d_%H-%M-%S") ,"_", $ComputerName, "_GPResult.html")) # Generate Group Policy Result if User has RSoP data Start-Process -FilePath C:\Windows\System32\GPRESULT.EXE -ArgumentList /H, $FileName, /F -Wait -PassThru If($(Test-Path -Path $FileName) -eq $TRUE) { "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - GPO Result - Please refer to $FileName" | Out-File -FilePath $LogFile -Append }else{ "$(Get-Date -uformat "%Y-%m-%d %H:%M:%S") - GPO Result - No Output" | Out-File -FilePath $LogFile -Append } } -Args $ComputerName,$OrganizationUnitDN,$DomainController,$Credential -Credential $Credential -Verbose }