Monthly Archive

Not the comma!

There is a habit among some AD administrators to create their users so that the name is surname, firstname   - Note the comma between the two names. As an example the name would be

Brown, Bill

instaead of

Bill Brown


If you’re just using the GUI tools it doesn’t matter too much and has the arguable advantage of ordering the users by surname. But when it comes to scripting against AD this practice is a complete pain.

Compare these 2 distinguished names

CN=Brown, Bill,OU=Testing,DC=Manticore,DC=org

CN=Dave Green,OU=Testing,DC=Manticore,DC=org


Notice the extra comma in the first one. That destroys any chance of splitting the distinguished name on commas – which are the element separators in distinguished names.

You have to escape the comma in the name with a \


The GUI tools (at least in Windows server 2012 R2) do this for you so the distinguished name looks like this:

CN=Brown\, Bill,OU=Testing,DC=Manticore,DC=org


If you want to get a user by distinguished name this will work:

Get-ADUser -Identity 'CN=Dave Green,OU=Testing,DC=Manticore,DC=org'


This won’t

Get-ADUser -Identity 'CN=Brown, Bill,OU=Testing,DC=Manticore,DC=org'


You have to use the escaped version:

Get-ADUser -Identity 'CN=Brown\, Bill,OU=Testing,DC=Manticore,DC=org'


In my last post I showed how to extract the users OU from the distinguished name

Get-ADUser -Filter * -Properties DisplayName |
select Name, DisplayName, UserPrincipalname, @{N= "Organanisational Unit" ;
E = {($_.DistinguishedName -split ',', 2)[1]}}


That code breaks down if you have a comma in the name and you get


for the OU instead of



Its probably possible to do some regex voodoo to deal with this but as the Universe doesn’t have enough life left in it for me to figure this out I’ll resort to a brute force approach:

Get-ADUser -Filter * -Properties DisplayName |
foreach {
$ouf = ($_.DistinguishedName -split ',', 2)[1]
if (-not ($ouf.StartsWith('OU') -or $ouf.StartsWith('CN') )){
  $ou = ($ouf -split ',', 2)[1]
else {
  $ou = $ouf
$psitem | select Name, DisplayName, UserPrincipalname, @{N= "Organanizational Unit" ;E = {$ou}}


Do the inital split as previously but then test the reasults to see if it starts with CN= or OU=. If it doesn’t then split again.

Its not elegant but it works.

It sa lot easier if you don’t use the comma in the first place Smile

Some thoughts on finding a users OU

Back in this post


I showed how to get the OU of a user from the distinguished name of the user object. if you want to display that as part of your output you can create a calculated field

Get-ADUser -Filter * -Properties DisplayName |
select Name, DisplayName, UserPrincipalname, @{N= "Organanisational Unit" ;
E = {($_.DistinguishedName -split ',', 2)[1]}}


In your select statement take the Distinguishedname and split it on the comma – make sure you split it into 2 parts – the second is the OU


Don’t rely on the Displayname alone as its not present for some built in accounts such as administrator

AD Management MoL Deal – – 3 February 2016

My Learn Active Directory Management in a Month of Lunches will be part of Manning’s Deal of the Day on 3 February 2016.


Half off my book Learn Active Directory Management in a Month of Lunches. Use code dotd020316au at


As usual the deal starts at midnight US ET and is usually active for about 48 hours

PowerShell Summit 2016 – – 3 day registration open

Three day registration is now open

Scripting Game puzzle – – January 2016

Here’s how I’d solve the puzzle

function get-starttime {
        [Alias('CN', 'Computer')]
        [string[]]$computername = $env:COMPUTERNAME
        foreach ($computer in $computername){
            $props = [ordered]@{
                ComputerName = $computer
                StartTime = ''
                'UpTime (Days)' = 0.0
                Status = 'OFFLINE'
            if (Test-WSMan -ComputerName $computer -ErrorAction SilentlyContinue) {
                $lbt = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $computer -ErrorAction SilentlyContinue
                if ($lbt) {
                    $props['StartTime'] = $lbt.LastBootUpTime
                    $upt = [math]::round(((Get-Date) - $lbt.LastBootUpTime).TotalDays, 1)
                    $props['UpTime (Days)'] = $upt
                    $props['Status'] = 'OK'
                else {
                    $props['Status'] = 'ERROR'
            } ## endif
            New-Object -TypeName PSObject -Property $props
        } ## end foreach
    } ## end PROCESS

Create an advanced function. Yes I know I’ve used lower case for the function name. I always do to visually separate my code from cmdlets and other functions.


Use the [parameter] decorator to enable pipeline input. Only a single parameter so don’t need to bother woth positional parameters. Function is supposed to default to local machien so can’t make parameter mandatory.


Requirement to process multiple computers at once presumably means the computername parameter has to take an array – sumultaneous processing implies a work flow which negates the initial requirement to create a function


Use the PROCESS block to run a foreach loop that iterates over the collection of computernames.


Create a hash table for the results – I’ve used an ordered hash table to preserve the property order. Set the values to a failed connection.


use Test-Wsman to see if can reach the computer. If can’t the output object is created. If you can reach the machine then run Get-CimInstance - preferred over Get-WmiObject because it returns the date ready formatted


Assuming that works set the start time and status properties. Calculate the uptime in days. I’d prefer to see  just an integer here – tenths of days doesn’t mean anything to most people


If the call to Get-CimInstance  fails then set the status to ERROR

Output the object.


The requirement to add a proeprty for patching is not clear but I’m assuming it means if the machine has been up for more than 30 days with the 1/10 month as a typo

if you want to add that then


Add a property

MightNeedPatching = $false

to the hash table when you create it


and add this line

if ($upt -ge 30){$props['MightNeedPatching'] = $true}


$upt = [math]::round(((Get-Date) - $lbt.LastBootUpTime).TotalDays, 1)
$props['UpTime (Days)'] = $upt

PowerShell Deal of the Day – – 31 January 2016

PowerShell in Action, Third Edition is Manning’s Deal of the Day Sunday 31 January 2016


Deal of the Day January 31: Half off Windows PowerShell in Action, Third Edition. Use code dotd013116au at


PowerShell in Depth, Second Edition is also available as part of the deal


Deal of the Day January 31: Half off my book PowerShell in Depth, Second Edition. Use code dotd013116au at


The deal will go live at Midnight US ET and will stay active for about 48 hours to account for time zones.

PowerShell editing options

I’ve used the ISE since it first appeared in PowerShell 2.0 but there are a couple of recent annocements that increase your code editing options


ISE previews will become available out of band rather than being tied to WMF/OS releases


The preview ISE is a module you can download from the PowerShell gallery and runs side-by-side with your existing version of ISE

Currently this is a PowerShell 5.0 only option

The current preview  hasn’t changed much – its just to test the delivery mechanism. Look for updates approximately monthly.


The second interesting editing option is Visual Studio Code which has PowerShell support


as well as a host of other languages. if you have to work across multiple languages this may be an option for you


Alternativley, if you use Visual Studio a lot you have the PowerShell Tools for Visual Studio option

Which filter

Get-ADUser has 2 filter parameters.

The –Filter takes a PowerShell syntax filter e.g.

Get-ADUser -Filter {Name -eq 'Richard'}

The –LDAPfilter takes an LDAP search filter e.g.

Get-ADUser -LDAPFilter "(Name=Richard)"

Mixing them up will ensure you don’t get the results you want

Rescuing IE favourites

I received the new Windows Insider Windows 10 build over the wekend and have just discovered that installing it wiped out my IE favourites – or at least those in folders.


I’d copied my favourites to Microsoft Edge when installing Windows 10 so I can copy everything back


IE favourites are stored at

Get-ChildItem -Path 'C:\Users\<user>\Favorites'


You can clean out the favourites:

Get-ChildItem -Path 'C:\Users\<user>\Favorites' | Remove-Item –Force


You will be asked to confirm the action.


Microsft Edge favourites are at

Get-ChildItem -Path 'C:\Users\<user>\AppData\Local\Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\AC\MicrosoftEdge\
User\Default\Favorites' –Recurse


Copy them into the IE favourites folder

Get-ChildItem -Path 'C:\Users\<user>\AppData\Local\Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\AC\MicrosoftEdge\
User\Default\Favorites' | Copy-Item -Destination 'C:\Users\<user>\Favorites' -Force -Recurse


Job done


How do you find the FQDN of the machine you’re using. 

The simplest way is to combine a couple of environmental variables:



If you like using CIM (and who doesn’t) you can try this

PS> Get-CimInstance -ClassName Win32_ComputerSystem |
>> select @{N='FQDN'; E={"$($_.DNSHostName).$($_.Domain)"}}



This could easily be used for remote machines as well by adding the –ComputerName parameter to Get-CimInstance


If you want to go down the .NET route you have:

PS> [System.Net.Dns]::GetHostByName('').HostName