Tags

, ,


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 {
<#
.SYNOPSIS
    Sets the description on computer accounts in an Active Directory Organisational Unit by examining the actual PCs.
.DESCRIPTION
    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/
.PARAMETER OUName
    Specifies the Organisational Unit(s) against which to perform the operation.
.PARAMETER Subtree
    Examines nested Organisational Units too.
.EXAMPLE
    Set-ADComputerDescriptions -OUName "Desktops"
    This will set descriptions for PCs within the Desktops OU.
.EXAMPLE
    "Desktops" | Set-ADComputerDescriptions
    This will set descriptions for PCs within the Desktops OU.
.EXAMPLE
    Set-ADComputerDescriptions -OUName "Desktops" -Subtree
    This will set descriptions for PCs within the Desktops OU and all child OUs.
#>
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$True,
                    ValueFromPipeline=$True,
                    HelpMessage="Enter one or more Organisational Unit names separated by commas.")]
        [ValidateNotNullOrEmpty()]
        [string[]]$OUName,
        [switch]$Subtree
    )
    BEGIN {
        Clear-Host
        Write-Verbose "Started function 'Set-ADComputerDescriptions'."
        Import-Module -Name ActiveDirectory -Verbose:$False
        $verboseMode = $PSCmdlet.MyInvocation.BoundParameters.ContainsKey("verbose")
    }
    PROCESS {
        $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)
                return
            }
            if ($OUs.Count -ne 1) {
                Write-Error ("Organisational Unit name '{0}' is ambiguous." -f $TheOU)
                return
            }

            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."
                            continue
                        }
                        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)
                    #continue
                }
            }

            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!

Advertisements