Set-ComputerObjectOU Cmdlet

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 
 
}
Advertisement