, ,

We like to populate the Description attribute of computer accounts in Active Directory with the Description as seen in System Properties of a computer. These are not officially related, so it needs a script to do it. I previously wrote a VBScript to do this that included practically my only foray into ADO and ADSI. I’ve now written a PowerShell function to serve the same purpose.

$OUName = "Desktops"

function Set-ADComputerDescriptions {
    Sets the description on computer accounts in an Active Directory Organisational Unit by examining the actual PCs.
    This function queries one or more Organisational Units for any computer accounts with a blank Description attribute.
    An attempt is then made to contact each in turn and if they are online, their remotely-configured description will be read.
    If this description is not blank, it will be used to set the Active Directory Computer account description attribute.

    (C) Cantoris Computing, August 2014 - https://cantoriscomputing.wordpress.com/
    Specifies the Organisational Unit(s) against which to perform the operation.
    Examines nested Organisational Units too.
    Set-ADComputerDescriptions -OUName "Desktops"
    This will set descriptions for PCs within the Desktops OU.
    "Desktops" | Set-ADComputerDescriptions
    This will set descriptions for PCs within the Desktops OU.
    Set-ADComputerDescriptions -OUName "Desktops" -Subtree
    This will set descriptions for PCs within the Desktops OU and all child OUs.
    param (
                    HelpMessage="Enter one or more Organisational Unit names separated by commas.")]
    BEGIN {
        Write-Verbose "Started function 'Set-ADComputerDescriptions'."
        Import-Module -Name ActiveDirectory -Verbose:$False
        $verboseMode = $PSCmdlet.MyInvocation.BoundParameters.ContainsKey("verbose")
        $OUName | ForEach-Object {
            $TheOU = $_
            Write-Verbose ("Searching for Organisational Unit '{0}'." -f $TheOU)
            [Array]$OUs = Get-ADOrganizationalUnit -Filter "Name -like '$TheOU'"
            if ($OUs -eq $null) {
                Write-Error ("Organisational Unit '{0}' not found." -f $TheOU)
            if ($OUs.Count -ne 1) {
                Write-Error ("Organisational Unit name '{0}' is ambiguous." -f $TheOU)

            Write-Verbose ("Identified Organisational Unit '{0}' as '{1}'." -f $TheOU,$OUs[0].DistinguishedName)
            $totalAD = 0
            $totalOnline = 0
            $totalRemote = 0
            if ($Subtree) {
                Write-Verbose "Searching for computer accounts in the Organisational Unit and its sub-OUs..."
                [Array]$PCs = Get-ADComputer -Filter "*" -SearchBase $OUs[0] -SearchScope Subtree -Properties Description
            } else {
                Write-Verbose "Searching for computer accounts in the Organisational Unit..."
                [Array]$PCs = Get-ADComputer -Filter "*" -SearchBase $OUs[0] -SearchScope OneLevel -Properties Description
            Write-Verbose ("...search returned {0} computer accounts." -f $PCs.Count)
            foreach ($PC in $PCs) {
                $hostname = $PC.Name
                Write-Verbose ("Processing PC '{0}':" -f $hostname)
                # This static method detects $null, "" and "    "
                if ([string]::IsNullOrWhiteSpace($PC.Description)) {
                    Write-Verbose "`t- current account description is blank."
                    $totalAD += 1
                    if (Test-Connection -ComputerName $hostname -Count 1 -Quiet) {
                        Write-Verbose "`t- is online."
                        $totalOnline += 1
                        try {
                            $remoteOS = Get-WmiObject -ComputerName $hostname -Class Win32_OperatingSystem -Property Description -ErrorAction Stop
                        } catch {
                            if ($verboseMode) { Write-Warning ("`t- failed to query WMI: '{0}'." -f $Error[0].Exception.Message) }
                            continue # ie Next PC
                        $description = $remoteOS.Description
                        if ([string]::IsNullOrWhiteSpace($description)) {
                            Write-Verbose "`t- remote description is blank."
                        Write-Verbose ("`t- remote description is '{0}'." -f $description)
                        $totalRemote += 1
                        Write-Host ("Updating account description for PC '{0}' to '{1}'." -f $hostname,$description)
                        Set-ADComputer -Identity $PC -Description $description
                    } else {
                        Write-Verbose "`t- is offline."
                } else {
                    Write-Verbose ("`t- current account description is '{0}'." -f $PC.Description)

            Write-Host ("{0} computer accounts out of a total of {1} under Organisational Unit '{2}' had no description in Active Directory." -f $totalAD,$PCs.Count,$TheOU)
            Write-Host ("Of these, {0} were online." -f $totalOnline)
            Write-Host ("Of those online, {0} had a description set remotely." -f $totalRemote)
    END {
        Write-Verbose "Finished function 'Set-ADComputerDescriptions'."

Set-ADComputerDescriptions -OUName $OUName -Subtree -Verbose

I know I could have written this to accept OUs being piped in from PowerShell AD cmdlets with a different parameter set. It’s been written primarily for non-PowerShelly colleagues to use. They just have to edit the top-line (in the ISE) with the friendly name of the OU as seen in the AD GUI tools and then click the Run button!