Copy your Active Directory OU structure to ControlUp

Missing some structure?

ControlUp’s organization tree offers a nice way of organizing your monitored computers, much like in many IT management systems. One limitation of this tree is the fact that it needs to be created and maintained manually. Usually, admins base their ControlUp organizational structure on the existing OU structure in Active Directory, which makes perfect sense. So wouldn’t it be nice if we could automagically take the Active Directory OU structure along with the computers in it, and replicate it into ControlUp? Now we can!

This post will explain the basics on ControlUp v7 PowerShell module and then provide a PowerShell script that syncs a given Active Directory OU structure into ControlUp. Here’s a video of the script in action:

Add Computer

The full PowerShell script can be found below, but first let’s explain briefly how it works.

ControlUp PowerShell Module

Starting with version 7.0, ControlUp includes a few PowerShell cmdlets which are meant to provide automation capabilities for manipulating the organizational tree. The following cmdlets are supported:

  • Add-CUComputer – adds a computer to your organization
  • Remove-CUComputer – removes a computer from your organization
  • Move-CUComputer – relocates a computer to a different folder in your organization
  • Add-CUFolder – creates a new folder in your organization
  • Remove-CUFolder – removes a folder from your organization

The above cmdlets are supported by means of a new PowerShell module (ControlUp.PowerShell.User.dll) which is deployed automatically when you install a ControlUp Monitor instance in your organization. A monitor instance is a mandatory prerequisite for using this module.

In order to use the cmdlets, perform the following steps:

  • Log on locally on your ControlUp Monitor computer or create a remote PowerShell session to that computer
  • Import the module by using the following command:
    • Import-Module “C:Program FilesSmart-XControlUpMonitorVersion <x>ControlUp.PowerShell.User.dll”
    • (<x> above corresponds to the current version of ControlUp)
  • Ensure the cmdlets are available by using the following command:
    • Get-Command -Module controlup*
    • You should see the five cmdlets
  • Read the help for the cmdlets by using the following commands:
    • Get-Help Add-CUComputer
    • Get-Help Remove-CUComputer
    • Get-Help Move-CUComputer
    • Get-Help Add-CUFolder
    • Get-Help Remove-CUFolder

Replicating Active Directory OU Structure

In many environments it makes sense for the ControlUp organization tree to reflect the structure of your Active Directory OUs in which computer accounts are currently located. For example, consider the following basic OU layout:

For the purpose of this demo, we’ll assume that the OU structure under Datacenter2 needs to be managed in ControlUp. I have created a PowerShell script which will create the same directory structure in ControlUp, populating it with computers as shown.

To achieve this task, we will use the ControlUp PowerShell module described above in tandem with the Active Directory PowerShell module. To install the Active Directory PowerShell Module, use the Server Manager to add the Remote Server Administration Tools feature (or specifically Active Directory module for Windows PowerShell).

So to summarize, here’s what you’ll need to run the script:

  • A ControlUp Monitor instance running v7 or later. You should execute the script locally on the monitor machine or using PowerShell remoting
  • Active Directory Module for PowerShell
  • The distinguished name of the root OU which you would like to copy into ControlUp (in the example pictured above that will be “OU=Datacenter2,DC=qa,DC=local”)

The script will basically cycle recursively through all child OUs of the specified root OU, add the OUs as ControlUp folders and then add the computer accounts as managed ControlUp computers. I’m sure many things can be improved about this script, and many other use cases are possible with those cmdlets. For example, this code can be adapted to retrieve the folder structure from different sources, e.g Citrix XenDesktop delivery groups or Vmware Horizon desktop pools.

Feel free to use the script below and comment. Until next time…

Full PowerShell script


<#
Description: This script retrieves the structure of a given Active Directory OU and syncs it to ControlUp, while including all computers in the OU
and its child OUs. This is useful for keeping the ControlUp configuration in sync with the Active Directory structure and the computer accounts in it.

Prerequisites:
This script has to be executed on a computer on which ControlUp Monitor v7 or later is installed.
The Active Directory PowerShell module is also a mandatory prerequisite
PowerShell commandlets to add it: Add-WindowsFeature RSAT-AD-PowerShell
also run: Import-Module ActiveDirectory

Known issues: In ControlUp v7.0, an attempt to re-add a computer which was previously added and removed may result in an "internal error"

Last revision: Nov 9, 2017 by ek@controlup.com

A couple of lines were borrowed from the Get-Canonical cmdlet by Sean Kearney from Microsoft TechNet Script Center:

https://gallery.technet.microsoft.com/scriptcenter/04e4e149-519a-4834-9626-02275de57ea6
#>
# The following parameters are mandatory
$BaseOUDN = "OU=Citrix_XenApp_7.x,OU=vdi_and_sbc,DC=acme,DC=local" # Enter the DN of the root AD OU you would like to sync to ControlUp
$OUFilter = "*" # Pattern to search for eligible OUs, by default "*" will match all child OUs under the root OU specified above

$CUOrgName = $(Get-ItemProperty HKLM:SOFTWARESmart-XControlUpAgent).OrgName
$VerbosePreference = "Continue"
function Get-CUPath {
# This function receives an Active Directory distinguished name and converts it to the ControlUp folder format
param([string]$DN)
$Parts=$DN.Split(",")
$NumParts=$Parts.Count
$FQDNPieces=($Parts -match ‘DC’).Count
$Middle=$NumParts-$FQDNPieces
$CN = $CUOrgName
if ($Middle -gt 1) {
foreach ($x in ($Middle-1)..1) {
$CN+=""+$Parts[$x].SubString(3)
}
}
Return $CN
}
# Initialize the Actvie Directory objects. Failure on loading these objects will cause the main logic of the script to be skipped
Import-Module ActiveDirectory
$BaseOU = Get-ADOrganizationalUnit $BaseOUDN
$AllOUs = Get-ADOrganizationalUnit -Filter $OUFilter -SearchBase $BaseOUDN -SearchScope Subtree
$DomainName = $(Get-ADDomain).DNSRoot
Write-Verbose "Domain name = $DomainName"
Write-Verbose "BaseOU = $BaseOUDN"
Write-Verbose "ControlUp Organization Name: $CUOrgName"
if ($CUOrgName -and $BaseOU) {
# Importing the latest ControlUp PowerShell Module
$pathtomodule = (Get-ChildItem "C:Program FilesSmart-XControlUpMonitor*ControlUp.PowerShell.User.dll" -Recurse | sort LastWriteTime -Descending)[0]
Import-Module $pathtomodule
if (Get-Module ControlUp.PowerShell.User) {
foreach ($OU in $AllOUs) { # Loop for all computers in the root OU
$FolderName = $null
$FolderParentName = $null
$foldercreated = $false
$FolderName = $($OU.Name)
$FolderParentName = $(Get-CUPath $OU.DistinguishedName)
Write-Verbose "Adding folder `t $FolderParentName >>>`t $FolderName"
try { # Try to add a folder to ControlUp
$verbosecommand = ‘Add-CUFolder -Name ‘ + $FolderName + ‘ -ParentPath "‘ + $FolderParentName + ‘" -ErrorAction Stop’
Write-Verbose $verbosecommand
Add-CUFolder -Name $FolderName -ParentPath $FolderParentName -ErrorAction Stop
if ($?) {
$foldercreated = $true
}
} catch { # If folder addition fails, show a message
$ExceptionMessage = $null
$ExceptionMessage = $_.Exception.Message
if ($ExceptionMessage -match "already exists") {
Write-Warning "Folder already exists, skipping."
$foldercreated = $true
} else {
Write-Error "Error adding folder $FolderName : $ExceptionMessage"
}
} finally {
if ($foldercreated) { # If folder addition was successful, proceed to add computers from it
$computerstoadd = $null
# Only computers with valid DNS names and enabled AD accounts will be added
$computerstoadd = Get-ADComputer -Filter {(dNSHostName -like "*") -and (Enabled -eq "True")} -SearchBase $OU.DistinguishedName -SearchScope OneLevel
$fullfolderpath = $null
$fullfolderpath = $FolderParentName + "" + $FolderName
if ($computerstoadd) {
foreach ($computertoadd in $computerstoadd) { # Cycle through all computers in the OU
Write-Verbose "Adding computer `t $($computertoadd.Name) `t to folder: `t $fullfolderpath"
try { # Try to add the computers
$verbosecommand = ‘Add-CUComputer -Name ‘ + $($computertoadd.Name) + ‘ -FolderPath "‘ + $fullfolderpath +'" -Domain ‘ + $DomainName + ‘-ErrorAction Stop’
Write-Verbose $verbosecommand
Add-CUComputer -Name $($computertoadd.Name) -FolderPath $fullfolderpath -Domain $DomainName -ErrorAction Stop
} catch { # Show a message if addition fails
$ExceptionMessage = $null
$ExceptionMessage = $_.Exception.Message
if ($ExceptionMessage -match "already exists") {
Write-Warning "Computer already exists, skipping."
$foldercreated = $true
} else {
Write-Error "Error adding computer $($computertoadd.Name): $ExceptionMessage"
}
} # end try-catch block for adding computers
} # end foreach computer
} # end if computers were found in the OU
} # end if folder created
} # end try-catch-finally block for adding folders
} # end foreach $OU
} else { # else for when there’s a problem loading the powershell module
Write-Error "Error loading ControlUp PowerShell Module. This should work if you are running on a ControlUp Monitor machine."
}
} else { # else for when there’s a problem initializing AD objects
Write-Error "Insufficient AD information. Please ensure the Active Directory PowerShell module is installed and that Active Directory is accessible."
}