My Solution to the Impractical One-liner Challenge
I recently participated in an Impractical One-liner Challenge that Stephen Owen posted on his blog site where he challenged his readers to come up with a PowerShell one-liner that would allow the person running it to select a single OU (Organizational Unit) from a list of all the OU's in Active Directory and then move a list of computer accounts that are contained in a text file to that OU.
My solution requires the Active Directory PowerShell module and at least PowerShell version 3.
I decided to do a little extra work and add some additional functionality to my solution. I start
out by getting a list of all OU's and giving you a human readable OU name and also the distinguished
name for that OU since the same name could exist in more than one place in Active Directory. I
display that information to the user with Out-GridView
:
1Get-ADOrganizationalUnit -Filter * -Properties OU |
2Select-Object -Property @{label='OU';expression={$_.OU -replace '{|}'}},
3 DistinguishedName |
4Out-GridView -OutputMode Single -Title 'Select Destination OU'
As shown in the previous example, the -OutputMode Single
parameter and value prevents the user
from selecting more than one OU. I also set the title of the Out-GridView
windows throughout this
solution so the user has an idea of what they're suppose to do.
I know that only one item will be returned at this point, but in order to make this command a
one-liner, I pipe the results of the OU that the user selected to the ForEach-Object
cmdlet, then
get the contents of the text file that contains the computer names. Those results (the list of
computer names) are piped to Get-ADComputer
because we need the computer's distinguished name to
be able to move it with the Move-ADObject
cmdlet. Those results are then piped to Out-GridView
because I also wanted to allow the user to be able to select the computers to be moved instead of
blindly moving all computers that were listed in the text file. The -OutputMode Multiple
parameter and value is specified this time to allow the user to pick more than one computer to be
moved if they so desire:
1ForEach-Object {
2 Get-Content -Path .\computers.txt |
3 Get-ADComputer |
4 Out-GridView -OutputMode Multiple -Title 'Select Computers to Move' |
Those results are piped to Move-ADObject
and the target OU is specified via parameter input and
the value is used from the first portion of the command (what was piped to ForEach-Object
). By
default Move-ADObject
doesn't return any results, it just "makes it so" without any feedback
unless there's a problem. I wanted to know what computers were moved, where they were moved from,
and what OU they were moved to so I added the PassThru
parameter to Move-ADObject
so it would
return results:
1Move-ADObject -TargetPath $_.DistinguishedName -PassThru
I only wanted those specific items returned so I piped the results of the previous command to
Select-Object
specifying the Name
property and since I already had the computer name, I wanted
that portion of the distinguished name removed which required a custom property to be created and
the easiest way to remove it was with a regular expression:
1Select-Object -Property Name,
2 @{label='DestinationOU';expression={$_.DistinguishedName -replace '^(.*?),'}
I also wanted to know where the computer account was before it was moved, so I went back and added
the PipelineVariable
parameter to the end of the command just prior to Move-ADObject
to obtain
those results by storing them in a variable named info
:
1Out-GridView -OutputMode Multiple -Title 'Select Computers to Move' -PipelineVariable info |
Another custom property later and I had what I needed:
1@{label='SourceOU';expression={$info.DistinguishedName -replace '^(.*?),'}},
Here's the PowerShell code for my solution in it's entirety:
1Get-ADOrganizationalUnit -Filter * -Properties OU |
2Select-Object -Property @{label='OU';expression={$_.OU -replace '{|}'}},
3 DistinguishedName |
4Out-GridView -OutputMode Single -Title 'Select Destination OU' |
5ForEach-Object {
6 Get-Content -Path .\computers.txt |
7 Get-ADComputer |
8 Out-GridView -OutputMode Multiple -Title 'Select Computers to Move' -PipelineVariable info |
9 Move-ADObject -TargetPath $_.DistinguishedName -PassThru |
10 Select-Object -Property Name,
11 @{label='SourceOU';expression={$info.DistinguishedName -replace '^(.*?),'}},
12 @{label='DestinationOU';expression={$_.DistinguishedName -replace '^(.*?),'}} |
13 Out-GridView -Title 'Results'
14}
Although the command shown in the previous block of code is on more than one physical line, it is still a PowerShell one-liner command because it is one continuous pipeline.
When that command is run, you're prompted with a selection of OU's:
After clicking
I've selected all of my SQL servers and when I click <OK>
, the computer accounts are moved to the OU
we previously selected and the results of what was done are displayed:
µ