Powershell Code That Literally Writes Itself - Automaception

I amused myself with Powershell today and thought I'd share. I might have also named today's post, "Write-Host does have a use after all!"

Today, I had the task of synchronizing the country attributes of thousands of users from a non-Microsoft LDAP server into multiple Active Directories.  This non-Microsoft LDAP server stored the country attribute ("c" in LDAP parlance) of each user as an ISO 3166 Alpha-3 three-letter abbreviation.  I wanted to convert that into the ISO 3166 alpha-2 two-letter notation before I imported it into Active Directory, as well as fill out the rest of the country-related attributes at the same time.

As most AD administrators know, when you want to programmatically set a user's country, you have to make the change in three different places if you want to be thorough.  You have to change co (Text-Country,) c (Country-Name,) and countryCode (Country-Code.)  Those three fields are a free-form text entry, an ISO-3166 A2 or A3 abbreviation, and a numeric value, respectively.

So the first thing I do is track down the ISO 3166 list.  It looks like this:

AALAND ISLANDS                                  AX      ALA     248
AFGHANISTAN                                     AF      AFG     004
ALBANIA                                         AL      ALB     008
ALGERIA                                         DZ      DZA     012
...

And on and on... for 240 countries.

I was thinking I'd want a Switch statement in my script... the idea is that I Switch($x) where $x is the three-letter country abbreviation that came from the LDAP server. Visions flashed through my mind of me staying up all night writing this monotonous switch block with 240 cases in it.  And then I thought, "Hey, Powershell is the most powerful automation framework there is. Surely I can use it to automate the automation!"  And so I set out to have my Powershell script literally write itself.

First, save that ISO 3166 country code list to a text file. That the list is already in a fixed-width format is going to make this extremely simple.

$Countries = Get-Content C:\Users\Ryan\Desktop\3166.txt

Write-Host "Switch (`$Transaction.NewValue.ToUpper().Trim())" #E.g. 'USA' or  'BEL'
Write-Host "{"
Foreach ($Line In $Countries)
{
    [String]$CountryCode = $Line[64] + $Line[65] + $Line[66]
    [String]$ThreeLetter = $Line[56] + $Line[57] + $Line[58]
    [String]$TwoLetter   = $Line[48] + $Line[49]
    [String]$FreeForm    = $Line.Substring(0, 46).Trim().Replace("'", $Null)

    Write-Host "    '$ThreeLetter'"
    Write-Host "    {"
    Write-Host "        Set-ADUser -Identity `$Transaction.ObjectGUID -Replace @{ countryCode = $CountryCode } -ErrorAction Stop"
    Write-Host "        Set-ADUser -Identity `$Transaction.ObjectGUID -Replace @{ co = '$FreeForm' } -ErrorAction Stop"
    Write-Host "        Set-ADUser -Identity `$Transaction.ObjectGUID -Replace @{ c = '$TwoLetter' } -ErrorAction Stop"
    Write-Host "    }"
}
Write-Host "    Default { Write-Error `"`$(`$Transaction.NewValue) was not recognized as a country.`" }"
Write-Host "}"

When I ran the above script, it printed out all the code for my massive switch block, so that all I had to do was copy the text out of the Powershell window, and paste it into the middle of the script I was working on.  It came out looking like this:

Switch ($Transaction.NewValue.ToUpper().Trim()) #E.g. 'USA' or  'BEL'
{
    'ALA'
    {
        Set-ADUser -Identity $Transaction.ObjectGUID -Replace @{ countryCode = 248 } -ErrorAction Stop
        Set-ADUser -Identity $Transaction.ObjectGUID -Replace @{ co = 'AALAND ISLANDS' } -ErrorAction Stop
        Set-ADUser -Identity $Transaction.ObjectGUID -Replace @{ c = 'AX' } -ErrorAction Stop
    }
    #
    # ... 238 more countries ...
    #
    'ZWE'
    {
        Set-ADUser -Identity $Transaction.ObjectGUID -Replace @{ countryCode = 716 } -ErrorAction Stop
        Set-ADUser -Identity $Transaction.ObjectGUID -Replace @{ co = 'ZIMBABWE' } -ErrorAction Stop
        Set-ADUser -Identity $Transaction.ObjectGUID -Replace @{ c = 'ZW' } -ErrorAction Stop
    }
    Default { Write-Error "$($Transaction.NewValue) was not recognized as a country." }
}

And there we have it.  Now I don't have any employees from Burkina Faso, but it's nice to know that I'd be able to classify them if I did.  Now with all the time I saved myself from having to type all that out by hand, I figured I'd write a blog entry about it.

Comments (1) -

For ease of copy-pasta, change Write-Host to Write-Output, enclose the generator-code in a script-block and pipe it to the clip.exe command line utility:

&{
    # Codeception stuff
   Write-Output "Set-ADUser $($Hepdi.Dep)"
} | clip

Comments are closed