0

Its pretty "simple" what i want to achieve. I have people creating Computer Objects on my AD and leaving there without moving them to the appropiate OU.

I would like a powershell script to read the list of computers from the Computers OU, and depending the first 5 or 6 letters from the Computer name, move it to the appropiate OU, reading the list of destination OUs from a CSV or txt or whatever file type.

I need to move more than 100 computers and I would like to scan them, and move them to their corresponding OU.

I've thought to use a variable for the computer accounts, then a foreach and a switch or something similar, and 1-by-1 start moving the accounts. But I'm stuck.

Thank you!!!!

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
Dioxido
  • 3
  • 3
  • Computer Accounts. Computer Objects – Dioxido Oct 17 '19 at 15:59
  • 2
    Gotcha. In the question you say that "But I'm stuck." - where are you stuck? Please share the code you've tried so far and what problems it gave (including error messages, if any), or what exact next step you're having problems with. – Mathias R. Jessen Oct 17 '19 at 16:01
  • Well the real thing is that im totally mentally stuck. I thought about starting with something like: $ComputerName= Get-ADComputer -Filter * -SearchBase "Cn=computers,DC=Contoso,dc=com"| Select-Object -Property Name And then use a switch that can look on the first 6 letters like: Switch ($ComputerName.Substring(0,6)) { 'INCCU1*' { Move-ADObject -Targetpath "ou=INCCU1,dc=India,DC=Contoso,dc=com" } Default { Write-host "Server $Computername couldn't be found" } } Like if there is any computer name that starts with INCCU1 and needs to be moved to that OU. – Dioxido Oct 17 '19 at 17:09
  • But now my teammates are requesting me to do it differently. Like the same way to scan the Computers OU, but instead of manually fill the Switch with the different OUs, do it dinamically reading the OU paths and lists from a CSV file. Im thinking of 2 variables (Computers and OUs) with a for each get object from the AD, do another for each for every OU path to see if it matches (The destination OUs starts with the first 6 characters of the computer object name) and then move it. Then the second computer object from the list scan again the destination ou list and so on..... – Dioxido Oct 17 '19 at 17:24
  • You could use the [Get-ADOrganizationalUnit](https://learn.microsoft.com/en-us/powershell/module/addsadministration/get-adorganizationalunit?view=win10-ps) cmdlet and fill a Hashtable for lookups with Key being the OU name and Value the DistinghuishedName of the OU. Then check the first 6 characters of the computername against this Hash with `.ContainsKey` and if true, move the computer to that OU using the appropriate hashes Value. – Theo Oct 18 '19 at 14:43

2 Answers2

0

This should be dynamic enough. You can replace the Map object with a CSV.

$Map = [PSCustomObject]@{
        AABBCC = "OU=ABC,DC=Contoso,DC=com";
        CCBBAA = "OU=CBA,DC=Contoso,DC=com"
    }

    $Prefixlist = ($Map.PSObject.Members | Where-Object { $_.MemberType -eq "NoteProperty" }).Name
    $Report = @()
    $MissingPrefix = @()

    Get-ADComputer -filter * -searchbase "CN=Computers,DC=Contoso,DC=com" -Properties Name | ForEach-Object {
        $obj = $_
        $Prefix = ($obj.Name).Substring(0, 6)
        if ($Prefixlist -contains $Prefixlist) {
            try {
                $obj | Move-AdObject -Targetpath $Map.$Prefix -erroraction stop
                $Report += [PSCustomObject]@{
                    Name = $Obj.Name
                    Move = $true
                }
            }
            catch {
                $_.Exception.ErrorRecord
                $Report += [PSCustomObject]@{
                    Name = $Obj.Name
                    Move = $false
                }
            }

        }
        else {
            $MissingPrefix += $Prefixlist
            $Report += [PSCustomObject]@{
                Name = $Obj.Name
                Move = $false
            }
        }
    }

    "Result"
    $Report | Format-Table -AutoSize

    "Not found prefix list"
    $MissingPrefix

Option 2 to make the path based on the prefix

$Report = @()

Get-ADComputer -filter * -searchbase "CN=Computers,DC=Contoso,DC=com" -Properties Name | ForEach-Object {
    $obj = $_
    $Prefix = ($obj.Name).Substring(0, 6)

    try {
        $obj | Move-AdObject -Targetpath "OU=Computers,OU=$Prefix,DC=Contoso,DC=com" -erroraction stop
        $Report += [PSCustomObject]@{
            Name = $Obj.Name
            Move = $true
        }
    }
    catch {
        $_.Exception.ErrorRecord
        $Report += [PSCustomObject]@{
            Name = $Obj.Name
            Move = $false
        }
    }

}


"Result"
$Report | Format-Table -AutoSize
Cezary P
  • 1
  • 2
  • Thank you a lot i will check this!!!! What if i want to do this more automatic, and i "read" the entire OUs from the domain to match the exact 6 letters and move to the OU depending the names of the computers, instead from a csv with the target paths? Thank you!!! – Dioxido Oct 18 '19 at 14:15
0

Turning my comment into an answer. You could create a lookup Hashtable for this:

# create a lookup Hashtable for all OU's in your organisation
# You can limit this using parameters like '-SearchScope' and '-SearchBase' depending on the structure in your AD environment
$allOUs = @{}
Get-ADOrganizationalUnit -Filter 'Name -like "*"' | ForEach-Object {
    $allOUs[$_.Name] = $_.DistinguishedName 
}

# next, get all computers in the default Computers OU
$result = Get-ADComputer -Filter * -SearchBase "CN=Computers,DC=Contoso,DC=com" | ForEach-Object {
    $computerName = $_.Name
    $found = $false
    if ($computerName.Length -ge 6) {
        $targetOU = $computerName.Substring(0,6)
        $found    = $allOUs.ContainsKey($targetOU)
    }
    if (!$found -and $computerName.Length -ge 5) {
        $targetOU = $computerName.Substring(0,5)
        $found    = $allOUs.ContainsKey($targetOU)
    }
    if ($found) {
        try {
            $_ | Move-ADObject -TargetPath $allOUs[$targetOU] -ErrorAction Stop -WhatIf
            # add success to the $result
            [PsCustomObject]@{
                'Computer' = $computerName
                'TargetOU' = $targetOU
                'Result'   = 'Moved'
            }
        }
        catch {
            # add exception to the $result
            [PsCustomObject]@{
                'Computer' = $computerName
                'TargetOU' = $targetOU
                'Result'   = 'Not moved. {0}' -f $_.Exception.Message
            }
        }
    }
    else {
        # add failure to the $result
        [PsCustomObject]@{
            'Computer' = $computerName
            'TargetOU' = ''
            'Result'   = 'Not moved. Computername does not begin with a valid OU name'
        }
    }
}

# output on screen
$result

# output to file
$result | Export-Csv -Path 'ComputersMoved.CSV' -NoTypeInformation

Remove the -WhatIf switch if you are satisfied with the results shown in the console.

Theo
  • 57,719
  • 8
  • 24
  • 41