Moving AD Objects using Powershell, Subnets, or Active directory Sites and Services

This week I was working on a script that pulls from the Computers container and places the computer object in the OU by subnet. The goal was for simple configuration and the method I came up with for configuration was using hashtables.

$Org_List = @{"" = "ou=site1,dc=test,dc=local";

“” = “ou=site2,dc=test,dc=local”;

“” = “ou=site2,dc=test,dc=local”}


$Computer_List = get-adcomputer -filter { Enabled -eq $true } -searchbase “CN=computers,DC=test,dc=local” | select DnsHostName, DistinguishedName

The complete script for this can be found on Pastebin  or on my github.

Adding new subnets and ou’s is just a matter of modifying the existing hash table and the script parses that data and moves the computer objects.

This works well, but then a friend pointed out how he needed to re-ip a whole office floor and this particular design would then need him to go back and update it. I thought about it and realized that the correct way to handle this was to piggyback it onto another maintenance task that would need to happen anyway. So I tied the script to sites and services:

$Org_List = @{"Office1" = "ou=site1,dc=test,dc=local";

“Office2” = “ou=site2,dc=test,dc=local”}

#Configure Computer search and limitations

$Computer_List = get-adcomputer -filter { Enabled -eq $true } -searchbase “CN=computers,DC=test,dc=local” | select DnsHostName, DistinguishedName


I still used the hash table, but now it matches the site names in my test environment:














Now when an office or floor is redone the normal maintenance done in Sites and Services will make sure the script will continue to drop the computer objects in the correct OU.

The full script can be found on Pastebin  or on github.

A quick breakdown of key functions in both scripts :



function find-ipcidr() {

Param( [Parameter(Mandatory = $true)]$IP_Cidr )

$Ip_Cidr = $IP_Cidr.Split("/")

$Ip_Bin = ($IP_Cidr[0] -split '\.' | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}).ToCharArray()

for($i=0;$i -lt $Ip_Bin.length;$i++){

if($i -ge $Ip_Cidr[1]){

$Ip_Bin[$i] = "1"



[string[]]$IP_Int = @()

for($i = 0;$i -lt $Ip_Bin.length;$i++) {

$PartIpBin += $Ip_Bin[$i]

if(($i+1)%8 -eq 0){

$PartIpBin = $PartIpBin -join ""

$IP_Int += [Convert]::ToInt32($PartIpBin -join "",2)

$PartIpBin = ""



$IP_Int = $IP_Int -join "."

return $IP_Int



find-ipcidr gets the ending IP of a cidr range. For example becomes More information on CIDR can be” target=”_blank”>found here.



function ip_to_int32(){

Param( [Parameter(Mandatory = $true)]$IP_int32 )

$IP_int32_arr = $IP_int32.split(".")

$return_int32 = ([Convert]::ToInt32($IP_int32_arr[0])*16777216 +[Convert]::ToInt32($IP_int32_arr[1])*65536 +[Convert]::ToInt32($IP_int32_arr[2])*256 +[Convert]::ToInt32($IP_int32_arr[3]))

return $return_int32



This converts the ip into a 32 bit integer. I use this in the scripts in order to tell if an ip is within a range. The code:

if(($search_ip_int32 -ge $start_of_range_int32) -and ($search_ip_int32 -le $end_of_range_int32))

Simply checks if the ip I am looking at is greater than / equal to the Start of the CIDR, or if it is with in the end of the CIDR. This is far better than other methods such as for loops and much simpler to work with.

The rest of the script is simply breaking up hashtable, running the above functions, or checking the range and performing an action.

Though my 2 scripts may not work perfectly in your environment, feel free to use any part or let me know how you have kept OU’s organized in the comments.

Thanks for reading.

Sharing is caring!

2 thoughts on “Moving AD Objects using Powershell, Subnets, or Active directory Sites and Services

  1. Function Find-CidrRange not defined.
    I get error: Find-CidrRange : The term ‘Find-CidrRange’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, v
    erify that the path is correct and try again.

  2. Sorry for the delay on getting back to you.

    I called Find-CidrRange when I meant to call find-ipcidr. I’ve corrected the pastebin and githubs in the post.

Leave your comment

2 + 3 =