This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Script Search - divide 1000 computers into 9 groups based on attribute value

I have what should be a very simple task on my plate that I can't seem to hit with a fork.

I have 9 groups and 2000 servers.  I need to split the servers between the groups ...

and as a maintenance workflow, when a new server comes online, after update of the OS value, move it into the least populated of the 9 groups.

I have a script started, that populates a native attribute on server objects with their AD site.  I divide the collected site names into two collections.  Each collection contains a couple thousand servers mapped to those sites.  I have 9  AD groups for each site collection..  I can split 2000 by 9, but here's the black hole in my logic, Nested Loops..

Do you have any scriptlets or script samples that demonstrate how to loop foreach group, add 1/9th of the 2000 servers into said group, then for the next group, grab the next 1/9th of the servers, etc ...  until done, amen.

fun times.

thanks in advance 

  • We don't have enough information about your problem to provide any guidance.

    Can you use a Switch() to populate Groups in series and avoid a Nested Loop?

    Can you post your existing code?
  • No matter how start writing this response, it quickly devolves into convolutions.

    I have a collection of objects returned from - $ALLServer = (get-qadcomputer -searchroot 'top OU for wintel servers' -includedproperties customAttribute8 -sizelimit 0 )

    I filter $ALLServers again into two collections of objects based on AD Site value (family of geographically similar AD sites lumped together.
    So, I threw this against the wall, and found that you can chunk out a collection of objects with PowerShell - two ways. (that know of)

    using Select ... wih 'first' and 'skip'
    $ALLServers | select -first 90 | to something
    $ALLServers | select -skip 90 -first 90 | do something
    $ALLServers | select -skip 180 -first 90 | do something
    ... until you have all 9 chunks

    For this example $Chunk_split value would be 100 if the $ALLServers.count was 900.

    Using 'ranges' ... i.e. 0..9
    $ALLServers[(($Chunk_split * 0) + 0)..($Chunk_split * 1)] | do something
    $ALLServers[(($Chunk_split * 1) + 1)..($Chunk_split * 2)] | do something
    $ALLServers[(($Chunk_split * 2) + 1)..($Chunk_split * 3)] | do something
    ... until you have processed all 9 chunks



    Either method above gives me a subset of the whole "foreach" chunk of objects which I pipe tot he following.

    | %{add-QADGroupMember -identity "CN of Group" -add-QADGroupMember -Member $_.dn -control @{OperationReason="MyReasonForDoingThis"} -proxy}

    so, I have a foreach, increment the value of $i++ - essentially sliding the window that I focus on - adding those servers to a group, then slide the window to the next chunk of servers in $ALLServers and add them to the list.

    I can do this with repetition of the same lines with incremented numbers ... I was hoping to automate.

    If that's still clear a mud, I can sanitize the script-in-progress and share so you can see for yourself how little I know of what I'm talking about.

    switch() time to google.
  • A sanitized script or pseudo-code would be extremely useful.
  • The bit that I am scratching my head about is the groupings of the servers - is it random / arbitrary or is there some correlation with the site side of things?

    If it doesn't matter which server goes in which group then I believe you could accomplish fairly easily with a single loop that iterates the list of servers and sequentially pops them into one of your 9 groups until you are done.
  • GEOWest = ("ADSITE1","ADITE2","ADSITE3")
    GEOEast = ("ADSITEAB","ADSITEBA","ADSITEAC")
    $EastServers = $ALLWINServers.where{$GEOEast -match $_.extensionattribute8}
    $WestServers = $ALLWINServers.where{$GEOWest -match $_.extensionattribute8}

    The only meaningful difference in the servers is used to separate the servers by matching site-family.

    Other than that any server in that matching collection could end up in any group - it just needs to be relatively balanced.

  • It appears that you have 6 sites. Yet you have 9 groups. Why not have 6 groups? Or 12 groups?

    The site affinity *seems* like a logical way to carve up the servers?

    So why not have your groups setup thus:

    ADSITE1_1 Servers
    ADSITE1_2 Servers
    ADSITE2_1 Servers
    ADSITE2_2 Servers
    ADSITE3_1 Servers
    ADSITE3_2 Servers

    ...and so on?

    Maybe there's some reason not to do it this way?

    (I clearly struggle with the notion of randomly distributing the servers among various groups)
  • Yep - all randomly distributed between two sets of 9 groups for like-ad-sites. This is to distribute the load on the brain-dead application the customer will be using to collect eventlogs for/from.
  • Here's a Switch based approach:

    $Servers = Get-QADComputer -SearchRoot "OU=SomeOU,DC=MyDomain,DC=Local" | select distinguishedname

    Foreach ($ServersItem In $Servers)

    {

    # Increment the server counter

    $ServerNumber += 1

    # Figure out which group server 'x' should go into

     

    Switch ($ServerNumber)

    { # Beginning of server group selection Switch

    {($ServerNumber -le 111)} { $ServerGroup="FirstServerGroup" }

    {(($ServerNumber -ge 112) -and ($ServerNumber -le 222))} { $ServerGroup="SecondServerGroup" }

    {(($ServerNumber -ge 223) -and ($ServerNumber -le 333))} { $ServerGroup="ThirdServerGroup" }

    # ...and so on for as many groups as you want

    } # End of server group selection Switch

     

    Add-QADGroupMember -Identity $ServerGroup -Member $($ServersItem.distinguishedname)

     

    } # End of Servers loop

  • This is excellent, but I would suggest a modification to the sorting logic.

    Using the modulus operator, if you iterate the collection, you will only ever receive a value of 0, 1 , 2 , 3 , 4, 5, 6 , 7 or 8. Use these as your switch cases, and there is your sort.

    The pseudo-code would look like this:

    $Servers = Get-QADComputer -SearchRoot "OU=SomeOU,DC=MyDomain,DC=Local" | select distinguishedname

    Foreach ($ServersItem In $Servers)

    {

    # Increment the server counter

    $ServerNumber += 1

    # Figure out which group server 'x' should go into


    Switch ($ServerNumber % 9)

    { # Beginning of server group selection Switch

    0{ $ServerGroup="FirstServerGroup" }
    1{ $ServerGroup="SecondServerGroup" }
    2{ $ServerGroup="ThirdServerGroup" }
    3{ $ServerGroup="FourthServerGroup" }
    4{ $ServerGroup="FifthServerGroup" }
    5{ $ServerGroup="SixthServerGroup" }
    6{ $ServerGroup="SeventhServerGroup" }
    7{ $ServerGroup="EighthServerGroup" }
    8{ $ServerGroup="NinthServerGroup" }


    } # End of server group selection Switch

    Add-QADGroupMember -Identity $ServerGroup -Member $($ServersItem.distinguishedname)

    } # End of Servers loop