Automatically generate description field for computers in Active Directory

Having worked in help-desk roles in the past I know the importance of knowing which user has logged onto which computer. Its simple stuff really, but unless you have 3rd party systems like System Center 2012 (SC12) or client agents, its either hard or time consuming to find out the relation between users and computers. What we needed was an easy way to find out what the last logged on user was for every machine.

In our particular environment we had this very need even more so as we adopt automatic operating system deployments that use generated computer names containing serial numbers. Our support staff could now go to Active Directory and see useful information populated in the description field for all computers. Originally we were hoping to use SC12 reporting but it was too slow and cumbersome to bring up details.
For this simple task I tackled it simply with a log-on script and a small amount of config to Active Directory.

The Requirements

Below are the list of requirements we had for our environment.

  • Include users Full Name – Helps the technician when they call the user
  • Include user name – helps find user in active directory
  • Make and Model – Useful to determine what form factor they are (Laptop/Desktop/Tablet)
  • Serial number – helps to verify quickly with our asset inventory system – not required but useful nonetheless
  • Date – Note I do not use this, but have added it to the script for some that may want to.

There is a lot more information that we could have included, both from WMI and Active Directory easily but we did not have a need for it. Im happy to modify the script if someone can think of something useful to add.

Active Directory Changes (USN)

Active Directory uses Update Sequence Numbers (USN) as its primary mechanism to control replication between Domain Controllers. Each time a change is made on an object (like a computer) the attribute on that object (uSNChanged) increases. Changing the description of a computer object increases the uSNChanged value which allows it to replicate to other domain controllers.

Active Directory replication does not primarily depend on time to determine what changes need to be propagated. Instead it uses update sequence numbers (USNs) that are assigned by a counter that is local to each domain controller. Because these USN counters are local, it is easy to ensure that they are reliable and never run backward (that is, they cannot decrease in value).
REFERENCE: How the Active Directory replication model works
http://technet.microsoft.com/en-us/library/cc772726%28v=ws.10%29.aspx

I could not find the correct documentation or supporting evidence for the below but I believe it is correct – please let me know if I am wrong:

There is a limit to the amount of USN’s that an Active Directory object can have, and this script can cause the USN limit to be reached in a large environment. To counter this problem the script does not change if the value is the same, therefore the majority of object descriptions will stay the same and not affect the USN count in a dramatic way. If you were to include a time/date stamp (for example) in the description field, ever time a user logs in it will increment the USN. if you have 20000 workstations and run this script daily you could exhaust your USN count within a couple of years. WS12 has some differences in this space with the new Active Directory system.

So to sum the above up without scaring you too much, if you have a small environment and little AD changes you could put in the date and you probably wont have any problems for the next 20 years, but if you are a large organisation you need to consider this. I have a smaller environment but still chose to not include the date because I did not find it useful. I would rely on SC12 to provide me with more detailed information if needed.

The Active Directory configuration (required)

You need to allow Authenticated Users to be able to read and write ONLY the Description attribute of the Computer objects. To do this please follow the below steps:

  1. Open Active Directory Users and Computers
  2. Ensure you have ‘Advanced Features’ enabled. To do this click on ‘View’ and make sure there is a tick next to ‘Advanced Features’
  3. Right-click on the domain in the left hand pane, and select properties

  4. Click on the Security tab, and then on ‘Advanced’
  5. Click on Add, and enter ‘Authenticated Users’ in the text box. Click ‘Check Names’ then Ok.
  6. Select ‘Descendant Computer objects’ from the Apply to drop-down box and then click on the ‘Properties’ tab.
  7. Tick Allow next to ‘Read Description’ and ‘Write Description’. Note we need the Read Description property to allow the script to compare existing variables with newly generated one.
  8. Click Ok.

Once you have followed the steps above, any authenticated user can update the description field, either with the below script or using another method. From a security perspective I think this is acceptable for almost all environments.

The script

The below VBScript is what actually sets the Computer Description. This script needs to be run on the client machines for it to work. There are several ways you can achieve this. Ones that come to mind are:

  • Group Policy Log-on script
  • Group Policy Log-off script
  • VPN post connection script
  • Scheduled task on client pc
  • psexec.exe command

By far the easiest will be using Group Policy. This wont be documented here, but basically you create a new Group Policy object, and under the User context you configure the log-on script. Note you do not configure it in the computer context as it will not know who the user is.

' ===================================================================
' Author: Ivan Dretvic
' ivan@dretvic.com
' DATE CREATED: 08/10/2012
'
' Documentation: http://ivan.dretvic.com/2012/10/automatically-generate
'                -description-field-for-computers-in-active-directory/
'
' This script is designed to assist System Administrators by populating
'  description field of Active Directory Computers. The sript can run
'  at log-on and log-off, and is executed by the user. You need to set
'  appropriate permissions on Active Directory for Authenticated Users
'  to have write access to the description field. Refer to documentation
'  for more information.
' ===================================================================

On Error Resume Next
Set objSysInfo = CreateObject("ADSystemInfo")
Set objComputer = GetObject("LDAP://" & objSysInfo.ComputerName)
Set objUser = GetObject("LDAP://" & objSysInfo.UserName)

If left(objComputer.description,1) = "`" Then
	'If a tilda exists the script will terminate. This allows custom
	' descriptions that dont get overwritten.
	Wscript.Quit
Else
	'Sets variables for Computer name, Manufacturer, Model,
	' and Serial number
	strComputer = "."
	Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
	Set colComputerSystem = objWMIService.ExecQuery ("Select * from Win32_computersystem")
	Set colBIOS = objWMIService.ExecQuery ("Select * from Win32_BIOS")
	For each objComputerSystem in colComputerSystem
		GetComputerManufacturer = objComputerSystem.Manufacturer
		GetComputerModel = objComputerSystem.Model
	Next
	For each objBIOS in colBIOS
		GetSerialNumber = objBIOS.SerialNumber
	Next
	'String cleaning - Manufacturer includes only first word, and
	' the serial removes any spaces.
	txtCount = InStr(GetComputerManufacturer," ") - 1
	GetComputerManufacturer = Left(GetComputerManufacturer,txtCount)
	GetSerialNumber = Replace(GetSerialNumber, " ", "")

	'Below are two variants in building the final string. Please chose
	' which you prefer. I did read but could not validate that excessive
	' computer description changes can cause AD change limits to be reached.
	'First one is without dates and second is with dates. Below ar examples.
	' The string is also trimmed to 1024 characters as per AD schema
	' req (just in case).

	'### DESCRIPTION WITHOUT DATE ###
	'Example:
	'John Doe (jdoe) - Dell Optiplex 990 - DRP421S
	strCompDesc = objUser.SAMAccountName & " | " & objUser.CN & " | " & GetComputerManufacturer & " " & GetComputerModel & " | " & GetSerialNumber
	strCompDesc = Left(strCompDesc,1024)
	'Compares AD string and generated string and skips if they are
	' identical. This saves AD change count.
	If strCompDesc = objComputer.description Then
		wscript.Quit
	Else
		objComputer.Description = strCompDesc
		objComputer.SetInfo
	End If

'	'### DESCRIPTION WITH DATE ###
'	'Example:
'	'2012/11/23 - John Doe (jdoe) - Dell Optiplex 990 - DRP421S
'	strDate = Year(Date) & "/" & Month(Date) & "/" & Day(Date) & " | "
'	strCompDesc = strDate & objUser.SAMAccountName & " | " & objUser.CN & " | " & GetComputerManufacturer & " " & GetComputerModel & " | " & GetSerialNumber
'	strCompDesc = Left(strCompDesc,1024)
'	objComputer.Description = strCompDesc
'	objComputer.SetInfo
End If

For those not familiar with VBScript you need to copy the above script to a text editor and save the file as with an extension of .vbs.

If you need to execute the script from a command prompt you can enter run the following from a command prompt:
wscript script.vbs

Attached is the original vbs script file for reference. Be sure to rename extension of file.
set_comp_desc.vbs

Comments and feedback welcome.
Ivan

Leave a comment ?

26 Comments.

  1. Neil Gascoigne

    Hi Ivan, a copy ‘n’ paste produces the following output when run:

    C:\Users\ngascoigne\Desktop\computer-description2.vbs(43, 2) Microsoft VBScript
    runtime error: Invalid procedure call or argument: ‘left’

    I by the way use the following script to output date time :: full name :: serial number:

    Dim objSysInfo, objUser, objComputer, colSMBIOS, objWMIService, objSMBIOS
    Set objWMIService = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2”)
    Set objSysInfo = CreateObject(“ADSystemInfo”)
    Set objComputer = GetObject(“LDAP://” & objSysInfo.ComputerName)
    Set objUser = GetObject(“LDAP://” & objSysInfo.UserName)
    ‘ WMI query to find the entries needed
    Set colSMBIOS = objWMIService.ExecQuery (“Select * from Win32_SystemEnclosure”)
    For Each objSMBIOS in colSMBIOS
    sAssetTag = objSMBIOS.SMBIOSAssetTag
    Next
    objComputer.Description = Now & ” :: ” & objUser.CN & ” :: (” & sAssetTag & “).”
    objComputer.SetInfo

    • Hi Neil,
      When you say a copy ‘n’ paste, how did you do that? When you load this page, go to the code and in the top right corner of the source code click the first icon. It will open a new window with the raw text for you to copy/paste in. This code i have used almost exactly with no problems on my end.
      What OS are you using?

      The code you posted above is different to mine, where you have added SMBIOSAssetTag. I believe the problem may occur if there is no AssetTag value so you need to either do some validating or give the variable a value before you commit it to objComputer.Description.

      Cheers,
      Ivan

  2. Ivan i have tried this script in my environment(All computers are Win XP SP3) and it works fine for some computers and for some it gives following error.

    Script: set_comp_desc.vbs
    Line: 43
    Char: 2
    Error: Invalid procedure call or argument: “left”
    Code: 800A0005
    Source: Microsoft VBScript runtime error

    I really appreiciate if you could help me to solve this error.

    Regards,
    Hozefa

    • Hi Hozefa,

      Sorry for not looking into this sooner. Have you had any luck resolving this?
      The left() command can be removed from the script if you like.
      Note: I did read up around this couple of weeks ago but don’t remember what I found about it.

      Let me know how you went.
      Ivan

  3. Nice script 🙂 just reading through the comments – I’m not that experienced with vbscript but I think the problem with this “left” issue is perhaps this part:

    txtCount = InStr(GetComputerManufacturer,” “) – 1
    GetComputerManufacturer = Left(GetComputerManufacturer,txtCount)

    If the GetComputerManufacturer variable does not have a space in it, then InStr is going to return 0 and then you’re going to subtract 1 from it, giving your txtCount variable a value of -1 and I’m pretty sure you can’t pass a value of -1 in to the Left function. I think you need to just have an IF statement in there that checks to see if InStr returned greater than 0 before you subtract 1 from it.

    I could be way off but just thought it might be worth mentioning.

    • Hi Chris,
      I think you are correct – i never expect that field to be blank, however if wmi is not working properly, or poorly made hardware might not have it. I think i revise the script and update it in the coming week.
      Thanks,
      Ivan
      P.S. Im not a programmer – it took me a while to get it to work for me the way i wanted it.

  4. Awesome work, all! I’m using this for a few of our clients now. I’ve actually added a section to pull out the installed anti virus product too, as that can be a pain to keep track of.
    It checks the OS first, as the SecurityCenter value is different from XP to later OSes.

    ‘Get AV
    strComputer = “.”
    Set shell = CreateObject(“WScript.Shell”)
    Set getOSVersion = shell.exec(“%comspec% /c ver”)
    version = getOSVersion.stdout.readall
    Select Case True
    Case InStr(version, “n 5.”) > 1 : Set oWMI = GetObject _
    (“winmgmts:{impersonationlevel=impersonate}!\\” & strComputer & “\root\SecurityCenter”)
    Case InStr(version, “n 6.”) > 1 : Set oWMI = GetObject _
    (“winmgmts:{impersonationlevel=impersonate}!\\” & strComputer & “\root\SecurityCenter2”)
    End Select

    Set colAV = oWMI.ExecQuery _
    (“Select * from AntiVirusProduct”)

    If colAV.Count = 0 Then
    strAV = “AV not installed”
    End If

    For Each objAntiVirusProduct In colAV
    strAV = objAntiVirusProduct.displayName

    Next

    Then just add & strAV to the end of the “strCompDesc = ”

    As may be obvious, I’m not a scripter though. I’ve done some serious Frankenscripting here, so it’d be great if someone wanted to work it in a bit more elegantly.

  5. Hello Ivan,

    Thank you for posting this great script,

    I’ve a few questions having to do with modifying your script:

    Is there a way to pull the Phone Number Field for the User from AD, and place it after the user’s First Last Name?

    Also, I’ve changed my format to to display:

    First Name (LoginName) – Computer Manufacturer – Computer Model – Serial Number

    strCompDesc = objUser.CN & ” (” & objUser.SAMAccountName & “) – ” & GetComputerManufacturer & ” – ” & GetComputerModel & ” – ” & GetSerialNumber

    I do this in my environment as the login can be a couple of different formats, and being able to search for First Last easily by sorting on the Description field in an OU is more convenient .

    What I would like to see is the following:

    First Name – 123-555-1212 – (LoginName) – Computer Manufacturer – Computer Model – Serial Number (DATE)

    Moving the date, I’m sure is simple, I’ll attempt to move that on my own.

    I’m not a programmer, so pulling the Phone number out of AD for the User logging off/on might be a bit beyond what my script hacking can accomplish.

    thank you for your time,
    Stephen

    • Hi Stephen,

      Hope the below can help – note I have not tested this and will rely on your feedback.

      RE TELEPHONE:

      The field in Active Directory you want to interrogate is telephoneNumber. Note I have not tested this but expect it to work.
      http://www.selfadsi.org/ads-attributes/user-telephoneNumber.htm
      To see the full list of fields you can use, I suggest:
      1. Open “Active Directory Users and Computers”
      2. Click on View – Advanced Features
      3. Right Click on a user object (one of your users) and select properties
      4. Click on a new tab that appears, called Attribute Editor.
      This will give you the Attribute names that you can call.

      Amend line 56 in my code to look like this:

      strCompDesc = objUser.CN & " – " & objUser.telephoneNumber & " - (" & objUser.SAMAccountName & ") - " & GetComputerManufacturer & " - " & GetComputerModel & " - " & GetSerialNumber

      RE DATE:
      NOTE: refer to my comment on that blog:
      If you were to include a time/date stamp (for example) in the description field, ever time a user logs in it will increment the USN. if you have 20000 workstations and run this script daily you could exhaust your USN count within a couple of years. WS12 has some differences in this space with the new Active Directory system.

      If you want the date at the end you would do replace line 56 with two lines below.
      strDate = " – " & Year(Date) & "/" & Month(Date) & "/" & Day(Date)
      strCompDesc = objUser.CN & " – " & objUser.telephoneNumber & " - (" & objUser.SAMAccountName & ") - " & GetComputerManufacturer & " - " & GetComputerModel & " - " & GetSerialNumber & strDate

      Lastly, I am not a programmer. I am a scripter who trolls the internet for scripts written by others and mash them together and change them to suit my needs, and that of others. If you are interested in scripting and use Windows machines in your environment, I urge you to learn PowerShell. Very powerful and there are a ton of existing scripts to do many things.

      If you have any issues with the script above, remember that the “ can be altered by Outlook and web browsers so sometimes it is best to retype them, otherwise you may get syntax errors.

      Please if you can repost your question on my blog so I can post up the reply for others to have access to it.

      Kind Regards,
      Ivan

      • Hello Ivan, the I tested the first string:

        strCompDesc = objUser.CN & ” – ” & objUser.telephoneNumber & ” – (” & objUser.SAMAccountName & “) – ” & GetComputerManufacturer & ” – ” & GetComputerModel & ” – ” & GetSerialNumber

        and that meets my needs I did change the ” – ” for a ” – ” for uniformity:

        strCompDesc = objUser.CN & ” – ” & objUser.telephoneNumber & ” – (” & objUser.SAMAccountName & “) – ” & GetComputerManufacturer & ” – ” & GetComputerModel & ” – ” & GetSerialNumber

        If the field is blank, I get a “- -” which for my need is fine, and a ‘reminder’ that this user needs a phone number input in AD.

        Thank you for your assistance on this, very much appreciated!

        Stephen

        • Apologies for the hyphen that was converted incorrectly.
          As for the double hyphen “- -” this can be mitigated (if you wanted to) with the IF statement that I submitted above.
          Cheers,
          Ivan

  6. Ivan,
    Will your Phone ‘solution’ work ok if and when the phone number field is blank?

    • Hi Stephen,

      It could be something like this, but would need testing:
      If objUser.telephoneNumber = "" Then
      strTelephoneNumber = ""
      Else
      strTelephoneNumber = " – " & objUser.telephoneNumber
      EndIf
      strCompDesc = objUser.CN & strTelephoneNumber & " - (" & objUser.SAMAccountName & ") - " & GetComputerManufacturer & " - " & GetComputerModel & " - " & GetSerialNumber

      This should check if its blank and set it to blank.
      If it exists then it should add a hyphen then the phone number.
      Again I have not tested any of this so please let me know via the comments.

      Kind Regards,
      Ivan Dretvic

  7. Ivan,
    I have been using your script for a couple years. For some reason, it is not pulling the serial number of the machines

  8. hi i need only Computer Description to be populate in AD

  9. Hi Ivan,

    Need to pull out the Computer Description value from the local computer System Properties and then populate this into AD computer Description fiels.

    Does this scrip do the trick?

    Thanks,

    • Hi Marius,
      The script does not do this currently but it should be fairly easy to do. Even though the script runs in the user context it should be able to read the local computer description.
      I’m on holidays now so you may have to reach out elsewhere to get some help. If you find the solution please post it up here.
      Ivan

Leave a Reply

QR Code Business Card
%d bloggers like this: