Answered Create new computername in AD

  • Thursday, May 17, 2012 6:00 AM
     
     

    Hi

    I'm trying to create a new computername based on a search in AD.

    What I'm trying to accomplish is this:

    Search for all computernames starting with "BS" and pick a number that isn't in use.

    Ex.

    I have some computers named BS001000, BS001002, BS001007.

    Then I want the script to create a computername with the next unused computername: BS001001

    I found this script:

    function GetComputerList($TargetDn)
    {
    # Locates all computer accounts that begins with "BS"
    # Change the value for your needs
     ${tFilter} = '(&(objectClass=computer)(cn=BS*))'
     ${Searcher} = New-Object System.DirectoryServices.DirectorySearcher $tFilter
     ${Searcher}.SearchRoot = "LDAP://${TargetDn}"
     ${Searcher}.SearchScope = [System.DirectoryServices.SearchScope]::Subtree
     # Page size default in Active Directory is 1000
     ${Searcher}.PageSize = 1000
     $Results = $Searcher.FindAll()
     return $Results
    }
     
    # Change OU path for you needs
    $computers = GetComputerList("OU=test,DC=mydomain,DC=local")
    $current  = 0
    $previous = 0
    $new_name = $null
     
    # Run through search result
    foreach( $computer in $computers )
    {
        $cn = "" + $computer.Properties['cn']
        $current = [int]$cn.Substring(6)
     
        # Check for avialable computername
        if( $current.CompareTo($previous+1).Equals( 1 ) )
        {
            $new_name = $previous+1
            break # no need to search anymore
        }
     
        $previous = $current
    }
     
    # If no available computername use next in line
    if( !$new_name )
    {
        $new_name = $current+1
    }
     
    # Prefix number with 0's if needed
    if( $new_name.CompareTo(10).Equals(-1) )
    {
        $new_name = "00" + $new_name
    }
    elseif( $new_name.CompareTo(100).Equals(-1) )
    {
        $new_name = "0" + $new_name
    }
     
    # Prefix name with constant
    # Change the constant "BS" for your needs
    $new_name = "BS" + $new_name
    $new_name
     
    # Do rename
    $oComputerSystem = Get-WmiObject win32_computersystem
    $oComputerSystem.Rename( $new_name )

    But I keep getting this error:

    Cannot index into a null array.
    At C:\Newcomputername1.ps1:24 char:37
    +     $cn = "" + $computer.Properties[ <<<< 'cn']
        + CategoryInfo          : InvalidOperation: (cn:String) [], RuntimeException
        + FullyQualifiedErrorId : NullArray

    You cannot call a method on a null-valued expression.
    At C:\Newcomputername1.ps1:25 char:34
    +     $current = [int]$cn.Substring <<<< (6)
        + CategoryInfo          : InvalidOperation: (Substring:String) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull

    BS001


    __GENUS          : 2
    __CLASS          : __PARAMETERS
    __SUPERCLASS     :
    __DYNASTY        : __PARAMETERS
    __RELPATH        :
    __PROPERTY_COUNT : 1
    __DERIVATION     : {}
    __SERVER         :
    __NAMESPACE      :
    __PATH           :
    ReturnValue      : 2697

All Replies

  • Thursday, May 17, 2012 7:58 AM
     
      Has Code

    $computer.properties['cn'] is not a method for that object so it will return a null object. Try replacing this line:

      $cn = "" + $computer.Properties['cn']

    By this line:

    [string]$cn = ($computer.properties).cn


    Jaap Brasser
    http://www.jaapbrasser.com

  • Thursday, May 17, 2012 8:36 AM
     
     

    Thanks for a quick answer.

    That solved the first error... :-)

    Now I'm getting another one at the line right after:

    Exception calling "Substring" with "1" argument(s): "startIndex cannot be larger than length of string.
    Parameter name: startIndex"
    At C:\Newcomputername1.ps1:25 char:34
    +     $current = [int]$cn.Substring <<<< (6)
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    BS001


    __GENUS          : 2
    __CLASS          : __PARAMETERS
    __SUPERCLASS     :
    __DYNASTY        : __PARAMETERS
    __RELPATH        :
    __PROPERTY_COUNT : 1
    __DERIVATION     : {}
    __SERVER         :
    __NAMESPACE      :
    __PATH           :
    ReturnValue      : 2697

  • Thursday, May 17, 2012 9:57 AM
     
     Answered Has Code

    Hey Michael,

    That is because you are not using the correct format for the Substring method, it should be ('startingvalue','numberofcharacters'), so in your scenario you would use .Substring(6,4) because you want to start at the 6th characters and you want the last four characters. I had a look at your script and I came up with this logic in order to parse the list of computer:

    # Create the $Computernumber array, containing the last four number of the bs00xxxx computer objects.
    $ComputerNumbers = @()
    foreach ($computer in $computers) {
    	[string]$cn = ($computer.properties).cn
    	$ComputerNumbers += [int]$cn.substring(6,4)
    }
    
    # Run through the $ComputerNumbers array to find the first number available for a new computer account
    $count = 1000
    do {
    	if ($ComputerNumbers -notcontains $count) {
    		$new_name = "bs00$count"
    	}
    	$count++
    }
    while ($new_name -eq $null)

    What I am doing here is a 2-step process. In the first Foreach loop I am building an array containg the last four number of the BS00xxxx computer objects and placing all of them in an array. In the do-while loop I have placed a counter, which starts counting up from 1000. For each number it will check if it is found in the $ComputerObjects array. If an unused number is found it will create the $new_name value and exit the loop.


    Jaap Brasser
    http://www.jaapbrasser.com


  • Thursday, May 17, 2012 1:16 PM
     
     

    Hey Jepp

    Thanks for your help so far.

    I must to something completely wrong.. :-)

    Should I implement your suggestion in the existing script..?

    I may not have explained myself very well.

    What I'm trying to accomplish is to search through AD for an available computername.

    Right now my computernames are in the format BS00000x.

    So if the computername BS000009 is not in use it should be picked else just run through the list for the next available.

    Another possibility was to search for the highest computername and then adding +1 to this so the new coputername would be (highest computername + 1)

    Hopes this makes sense.

    As you can see I'm not a scripting guy, at all ;-)

    Best Regards

  • Thursday, May 17, 2012 2:08 PM
     
      Has Code

    Well from what I understood in your original question you were looking for a way to create a new computer based on the availability of computer account in AD. Currently it is counting from 1000 to infinity and comparing that from what you gather in Active Directory. So whether you want to start counting from 0 or from 50000 does not really matter. You would have to adjust the script a bit though depending on what you want. Finding the highest number would actually be even easier, then we could omit the entire do-while loop and use this to determine the highest computer number:

    $ComputerNumbers | Sort-Object | Select-Object -Last 1

    So it really depends on what you want to do, so I recommend you figure out what you want to do exactly before starting to script. Having the requirements beforehand is a major asset as you have a set goal to work towards.


    Jaap Brasser
    http://www.jaapbrasser.com

  • Thursday, May 17, 2012 2:19 PM
     
     

    Hi Jaap (sorry for spelling your name wrong in the last post).

    You're absolutely right. I got a little confused.... ;-). Sorry about that.

    And thanks for your patience so far.

    So my goal is actually to start the count from a specific number.

  • Thursday, May 17, 2012 2:48 PM
     
     Answered

    If you want to start counting from 1000 you can leave the script as it currently is. If you want to start from another number or limit the range in which it counts then you will have to change any of these options:

    • The .Substring method in the first loop
    • The value of $Count
    • Any zeroes you might want to have in front of the $Count variable (hint: "{0:D6}")
    • The while statement

    Let me know what you decided to use and if you are having any other question just let me know and I will try to help you out.

    And about spelling my name wrong, no problem it is not a common name in English language so I have pretty much seen every variant on my name.


    Jaap Brasser
    http://www.jaapbrasser.com

  • Tuesday, May 22, 2012 9:25 PM
     
     

    Hi Japp

    Thank you very much for your help.

    Finally get it to work.

    And learned quite a lot... :-)