The PowerShell Pay-it-Forward Award

As I was going through some things, I realized that I have a handful of author copies of my PowerShell Cookbook remaining. There are several of the first edition, several of the second edition, and several of the pocket references.

After thinking about what to do with them, I hereby announce the PowerShell Pay-it-Forward Award.

If you would like a free signed copy of any of these books, I have a simple request. Go forth on the internet: Stack Overflow, blogs, Twitter, whatever. Find a PowerShell newbie with a gnarly problem. Not just a syntax problem, but some hairy business problem. Work with them to solve it.

Post your results back here in the comments (with a link to the interaction,) and I’ll give books to those that have helped a user (or users) the most.

I’ll announce the winners on December 1st.

Good luck!

Breaking Hash Codes – Part I

When we last left off, we discussed hash codesa small unique identifier for an item based on its properties or features.

There are many different ways to calculate unique identifiers for items. These different ways are called Hash Algorithms. Each serves a different purpose, but some popular ones right now are are MD5, SHA1, and SHA256.

Why so many?

The reason is security. Our last post finished with the question:

Using hash codes for simple content verification is one thing. But what if an attacker is trying to trick you with hash code collisions? For example, can you use that Visual Studio download if it’s from your worst enemy – but the hash code still matches? It depends on the algorithm!

The security industry first started touching on the importance of “secure” hash algorithms in the 1970s. There were a flurry of proposals in the 80s that were immediately dismissed with security problems, but one called “MD5” was introduced in the early 90s that seemed like it might last the test of time.

In 2004, however, advances in security research found issues in MD5 – thus “breaking MD5”. While you can still use MD5 just fine when security is not a concern, you cannot trust a version of Visual Studio from your enemy just because the MD5 hash value matches.

Here are the four features of an ideal cryptographic hash algorithm:

  • it is easy (but not necessarily quick) to compute the hash value for any given message
  • it is infeasible to generate a message that has a given hash
  • it is infeasible to modify a message without changing the hash
  • it is infeasible to find two different messages with the same hash

If you get #2, then for the most part you get #3 and #4 automatically.

How does one “break” a hash algorithm? Let’s take a look a a few from the .NET Framework for an interesting exercise in reverse engineering.

As a background, every object in the .NET Framework supports a method called “GetHashCode()”. It does a good job of returning a small random(ish) identifier for an object, so it is used primarily for putting objects into hash tables. This method returns a 32-bit integer, and is not designed for security purposes:

publicvirtualint GetHashCode()

The HashAlgorithm class is designed for security purposes, however, and should be used when security is a concern. We won’t use that class as an example, because if I can break that class in this blog, then it wouldn’t be in the .NET Framework!

Breaking Int32

Let’s see how this works on integers, and see how it would fare as a cryptographic hash algorithm:

PS > (1).GetHashCode()
1
PS > (2).GetHashCode()
2
PS > (1337).GetHashCode()
1337
PS > (-1337).GetHashCode()
-1337

I think we see a pattern :) It looks like .NET is returning our input right back at us. It’s a sure way to prevent collisions, that’s for sure! If we open Int32.GetHashCode() in .NET Reflector (or ILSpy), we can see why:

public override int GetHashCode()

{

    return this;

}

The score sheet?

it is easy to compute the hash value for any given message
it is infeasible to generate a message that has a given hash
it is infeasible to modify a message without changing the hash
it is infeasible to find two different messages with the same hash

Not bad, but you can’t do much with just integers.

Breaking Int64

That wasn’t too challenging to break. What about Int64? That doesn’t fit in 32 bits by definition, so let’s see if there is any pattern:

PS > ([Int64] 1).GetHashCode()
1
PS > ([Int64] 1337).GetHashCode()
1337
PS > ([Int64] 12345678987654321).GetHashCode()
1656367333

For “low” numbers (below 32 bits?) it seems to be the same as the input number. After that, not quite sure. We can’t break this one by intuition. Let’s see the source:

public override int GetHashCode()

{

    return (int)this ^ (int)(this >> 32);

}

What the .NET Framework is doing here is pretty simple:

(int)this Takes the lower 32-bits of the 64-bit number.
(int)(this >>32) Shifts the number to the right by 32 places, and then takes the lower 32 bits of the number. That is the same thing as taking the upper 32 bits of the number.
(int)this ^(int)(this >>32) Uses the binary XOR operator to combine the upper 32 bits and the lower 32 bits.

The first row explains why all of our “low” numbers seemed to just return themselves. The low numbers were the lower 32 bits, and there were no upper 32 bits.

Let’s take a look at:

PS > ([Int64] 12345678987654321).GetHashCode()
1656367333

If we convert this to the upper and lower 32 bits, we get:

PS > [Convert]::ToString(12345678987654321, 2)
101011110111000101010001100010100100011111010010110001
PS > [Convert]::ToString(12345678987654321, 2).PadLeft(64, "0")
0000000000101011110111000101010001100010100100011111010010110001

Now, split them into the top and bottom 32 bits take the binary exclusive OR (either bit is 1, but not both):

Upper 32 00000000001010111101110001010100
Lower 32 01100010100100011111010010110001
XOR 01100010101110100010100011100101

Taking a look at the final result, it looks like we have the same as what .NET gave us:

PS > [Convert]::ToInt32("01100010101110100010100011100101", 2)
1656367333

PS > ([Int64] 12345678987654321).GetHashCode()
1656367333

Now that we understand the algorithm, let’s see how we might break the strongest guarantee of a hash algorithm – namely, “it is infeasible to generate a message that has a given hash.”

Let’s pretend we want to generate a 64-bit number with the hash value of 1337. That has the following binary value:

PS > [Convert]::ToString(1337, 2).PadLeft(32, "0")
00000000000000000000010100111001

Since the 64-bit hash is generated by combining the upper and lower halves of the number, the simplest way is to simply ignore the upper 32 bits:

Upper 32 00000000000000000000000000000000
Lower 32 00000000000000000000010100111001
XOR 00000000000000000000010100111001

That was simple enough. What about breaking the next strongest feature: “it is infeasible to find two different messages with the same hash.

Given that we know how to find an Int64 for any given hash value, how can we find multiple Int64s that have the same hash value?

To figure this out, we’ll use a trick from the XOR operation frequently used in XOR cyphers and XOR encryption:

If A XOR B = C

Then A = B XOR C

And B = A XOR C

If we pretend that A is the upper 32 bits of a number, B is the lower 32 bits of a number, and C is the hash code, then we have the following options:

Upper 32 bits = (Lower 32 bits) XOR (Hash code)

or

Lower 32 bits = (Upper 32 bits) XOR (Hash code)

Given that, here’s all we have to do to find a number with a specific hash code:

  • Pick an arbitrary number for the lower (or upper) 32 bits
  • XOR it with the hash code
  • The result will be the other 32 bits you need

Let’s look at an example, using 10001011001010110101101011010111 as a randomly-chosen number:

Upper 32 10001011001010110101101011010111
Hash Code 00000000000000000000010100111001
XOR (= Lower 32) ?

PowerShell has the “-bxor” operator, so let’s make this easier on ourselves:

PS > $upper32 = [Convert]::ToInt32("10001011001010110101101011010111", 2)
PS > $hash = [Convert]::ToInt32("00000000000000000000010100111001", 2)
PS > $lower32 = $upper32 -bxor $hash
PS > [Convert]::ToString($lower32, 2)
10001011001010110101111111101110

So now we have a hash collision – let’s be sure:

PS > $number = [Convert]::ToInt64(
>>     "10001011001010110101101011010111" +
>>     "10001011001010110101111111101110", 2)
>>
PS > $number
-8418535196639666194

Let’s see:

PS > ([Int64] -8418535196639666194).GetHashCode()
1337

Bingo. We can now generate hash collisions for arbitrary hash codes. What does that mean?

it is easy to compute the hash value for any given message
it is infeasible to generate a message that has a given hash
it is infeasible to modify a message without changing the hash
it is infeasible to find two different messages with the same hash

Bonus question: how many hash collisions can you generate for a given hash code? And how might you do so systematically?

Chew on that a bit – in our next post, we’ll take a crack at reverse-engineering String.GetHashCode().

Ubisoft Rocksmith Review

On Tuesday of last week, Ubisoft released Rocksmith: an XBOX / PS3 / PC guitar game with a twist.

You play a real guitar.

You learn the real notes.

Your fingers hurt just like every great guitarist before you.

 

image

For some context, guitar has been part of my life for a long time – although my proficiency with it has waxed and waned (currently waning). I made the most progress with classical guitar, but ran into a cliff of frustration when songs started calling for notes out of the basic first few positions. A couple of editions of the PowerShell Cookbook will put a dent in your free time, so that may have something to do with it, too :)

This kind of “Guitar Hero but with real guitar” game has been a pipe dream for a long time. A few years ago, the Music Wizard folks started shopping around a new game called “Guitar Wizard”. After hearing about it, I promptly signed up for their mailing list – but they’ve now removed all of the product pages from their site and I suspect have abandoned the project entirely.

The primary reason behind this lack of advancement in the field has long been technical. Most software that tries to convert raw guitar sounds into something that a computer can understand ends up failing pretty fast. The note recognition ends up being glitchy, inaccurate, and frustrating. Things have heated up recently, with applications like JamGuru (PC) and Rock Prodigy (iPad) that help you learn the tablature versions of songs through sophisticated note recognition.

Rock Band 3 introduced “Pro Mode” for guitar (which has been getting good reviews), but there have been mixed feelings about the way the guitar interface is presented. Also, they took another approach to resolving the technical issues by making you use their specific guitar. That second point really hurts if you have a well-loved (or unloved!) guitar already.

While computer scientists are out flogging and publishing minor advances in audio recognition, Rocksmith and this new breed of apps have somehow just quietly and magically figured it out, and shipped it. The note recognition truly does feel magical, and never crosses your mind after that.

After getting a brief intro on how to use the system, Rocksmith starts you off with a simple lead part to “(I Can’t Get No) Satisfaction” by the Rolling Stones.

image

It’s really you

At even its simplest levels, you truly feel like you’re playing the song. This is where Rocksmith stands out as a music game. In rhythm games like Rock Band, you use the guitar controller (or real guitar) to hit the right notes at the right time. As long as you do that correctly, the game continues to replace you with the pre-recorded guitar track of the song. If you make a mistake, it replaces you with a squelchy sound of a guitar mistake. What kind of mistake, you might ask? Were you off by a fret? Too late? Too early? Who knows!

Rocksmith, on the other hand, plays the actual sounds from your guitar. They send it through a virtual amplifier and effects chain so that you have the same tone as the guitar from the original song, but you’ll hear it immediately if you’re off by a fret. The note will sound too high or low (just as it does in real guitar), so you can easily correct by ear alone.

Don’t be afraid to experiment

If you’ve played other rhythm games like Rock Band, you’ve probably looked down the “Note Highway” with dread as 2 minutes of the same boring pattern approach.

Rocksmith solves this problem wonderfully. Want to noodle around for the beginning of the song? Add some trills, double-plucks or experimental harmonies? Go ahead! Rocksmith doesn’t penalize you for these – as long as you still at least hit the notes that it’s displayed.

Speaking of noodling around, Rocksmith has the best load screen I’ve ever seen. It activates the virtual amp whenever it’s “Loading…”, so you can take that time to warm up, play around, or experiment with new ideas.

As I mentioned earlier, Rocksmith creates your in-game sound by sending your guitar through a virtual amplifier and effects chain. Once you start completing songs, Rocksmith makes these components available to you in a free-form playground called “Amp Mode”. You can pick pre-set sounds from any of the songs you earned them from, or mix and match components (pedals, amps, etc.) to make something completely different. Spend a minute, spend an hour, either way you’ll have fun.

image

You learn actual guitar

After playing the songs for awhile, you’ll amaze yourself by picking up the guitar when it’s not even plugged in. You’ll play the same thing you’ve been playing all along, but then realize the sounds of the song are coming from your guitar, not your video game. They don’t include Stairway to Heaven in the song list, so you’ll be safe playing these at the local guitar shop, too!

After you’ve been playing songs for a while, Rocksmith opens up a handful of guitar trainers / challenge games. These games let you practice specific techniques (chords, scales, neck position, bends) that improve your actual guitar skill, as well as in-game performance.

image

So, far I’ve only unlocked two challenge games: Ducks (which teaches you how to find fret positions quickly) and Dawn of the Chordead (which teaches you to play and recall chords). Dawn of the Chordead unquestionably teaches you transferrable guitar skills. Being able to quickly find and play a chord (and then smoothly transition to the next one) is crucial for playing many songs. Ducks makes you a much better game player, but offers limited benefit for real guitar (see My One Big Complaint).

What’s not to like?

While I’m a big fan of the game, there are some rough edges. First off, you need to use your regular game controller to navigate through the game. When you’ve got a guitar strapped around your neck and the wireless controllers are going to sleep, this is just annoying. Why you can’t just use the guitar to control the entire game is beyond me – Rocksmith has already proven that it can accurately recognize input from a real guitar!

Second is practice mode. When a song starts to prove challenging, they offer a neat set of trainers that let you just practice through a difficult section. These trainers let you gradually increase difficulty or speed for a specific section. It would be nice if there was a more holistic practice mode that let you master a song section-by-section by increasing difficulty and then speed for each section. What’s most annoying about the practice mode is that you’ve got five “lives”. If you can’t play it fast enough or accurately enough in five attempts, then it kicks you back to the practice screen. From there, you have to click through all the menus, loading screen, tuning process, etc. It’s just a lot of process for something that should be the most forgiving in the entire game.

My One Big Complaint

My One Big Complaint stems from wanting the skills from the game to have more benefit to my real guitar playing.

As I mentioned before, guitar mastery is heavily influenced by how well you know the fretboard. To show you where to put your fingers when you play, Rocksmith sends fret numbers down the Note Highway:

image

This is very similar to Guitar tablature, and is a great way to learn a song. The alternative is the traditional music staff, which even professional musicians have difficulty sight-reading and would be a deal breaker for the game.

However, becoming a lightning-fast tablature reader hits a dead-end at some point. It’s like becoming a god at watercolour paint-by-numbers. Just as you need to learn to draw and choose pigment at some point while becoming an artist, a guitarist will eventually need to know what notes they are playing (C,D,E, etc.) On this point, Rocksmith misses a great opportunity. If they simply offered an option to replace the coloured blocks with coloured letters (i.e.: yellow on the 5th fret = D), they’d unlock a vast world of true musicianship to millions of fledgling guitarists. Rock Prodigy offers this in their interface, and it help immensely:

image

 

I bought it, and would buy it again

When you add up all the pros and cons, there isn’t really a question in my mind. If my cat ate the game tonight, I would buy it again tomorrow.

Morser – Keyboard Morse Input Device

[Download: Morser.zip, 155kb]

[Updated 10/04/2011 – V2 includes support for audio input]

 

If you’re interested in Morse Code as a hobby or just as a neat lo-fi communication mechanism, one thing that might set you back is the lack of practical opportunities to use it.

You can find lots of Morse Code apps that let you practice into a little text box, but nothing that you can tweet with, blog with chat with, etc.

Morser is a simple little program that solves this need.

image

After launching it, press Control-Alt-M to enable or disable it. It works no matter what application you have running, so you can minimize it and switch to an application that you want to use it with. When enabled, Morser acts as a straight keyer. It listens for presses of your keyboard’s down arrow and automatically types the letter that corresponds to your Morse code input.

If you hook up any audio device (i.e.: a real actual keyer) to an input jack, Morser converts the audio input to text as well.

If you have funny characters to enter, just type them on your keyboard as you normally would.

The Control-Alt-M hotkey also works in any application, so you don’t need to switch back to Morser to enable or disable it.

Here’s an example of it interpreting somebody’s YouTube video. I hooked my audio output to my Mic Input.

Enjoy!

PowerShell Wallpapers

Shay Levy, one of our great MVPs, has been crafting sweet PowerShell desktop backgrounds for years now. One thing I’ve always loved is that they seem to carry a message.

His first wallpaper was a screaming crowd. In my head, they are people chanting for the power of PowerShell, or the IT rock star that saved the deployment. It’s been my background since he posted it, and has graced many a conference presentation.

He’s just created another two with a Superman theme. It makes me think of a bunch of out-of-date
systems out there needing automation – so the PowerShell IT admin superhero kicks into action :)

 

Check out his post on the PowerShell Magazine site for the full resolution downloads!

Developing for an International Audience

One aspect of software development (scripting included) that burns every single developer is developing for an international audience. The most common cause of problems come from incorrect handling of dates and numbers, but there are many more.

I first cut my teeth on the topic when working on Encarta Online, via bugs teaching me the hard way! After that, I took some time to read the excellent documentation on MSDN that describes many of the intricacies: Developing World-Ready Applications, and especially Best Practices for Developing World-Ready Applications.

Of course, these principles don’t just apply to C# software developers. They apply equally well to PowerShell scripters! While PowerShell handles most of the complexity for you, there are some important things to be aware of. “Write Culture-Aware Scripts” in Chapter 13 of the PowerShell Cookbook describes the issues around writing world-ready PowerShell scripts.

If you REALLY want to understand some of the crazy issues in international software development, Michael Kaplan has a great MSDN blog to follow: Sorting it all Out.

Now, once you think you’ve got it all down, consider this harmless form that anybody might add to an application:

First Name: ___________________
Last Name: ___________________

If you’re writing this for an international audience, you’re going to alienate and confuse a huge portion of your audience. This W3C Internationalization document describes the problem with amazing clarity: Personal names around the world. As Reddit so clearly puts it, “If you’re asking for a first and last name, you’re doing it wrong!”

Enforcing Single-User Access to PowerShell Remoting

I got a question today with an interesting request – “How do I ensure that only one user can access a machine via PowerShell Remoting at a time?”

We do have direct functionality to limit multiple sessions, but it that limit applies to sessions by the same user – see: MaxShellsPerUser for full detail about that setting. If you are doing some sort of self-service portal where everybody shares the same local username / password, MaxShellsPerUser is one way to solve the problem.

More commonly, though, you might want to enforce this restriction across all users on the machine. One useful thing to configure then is MaxConcurrentUsers. Set MaxConcurrentUsers = 1 and MaxShellsPerUser = 1, and you’ve enforced single-user access.

If your needs are more complex than this, we can solve this with a custom PowerShell session configuration. Perhaps we’d like to offer unrestricted access to administrators on the (default) Microsoft.PowerShell configuration, but enforce throttling on a new one called “Contoso.Build”.

If you’ve never set up a custom session configuration before, there are many great resources. Ravikanth Chaganti, one of our awesome MVPs, has written a great introduction to them here:

This is also covered in the PowerShell Cookbook, recipe 29.20.

Now, once you’ve got a startup script for your custom session configuration, you can use a system-wide Named Mutex to enforce your quota limits. This is pretty advanced scripting, so don’t be worried if it looks intimidating.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025

function IsMachineIdle
{
   
$sessionHandle = New-Object System.Threading.Mutex $false,"PowerShellSessionMutex"
    $isAvailable = $false

    try
    {
       
$isAvailable = $sessionHandle.WaitOne(1000
)
    }
   
catch [System.Threading.AbandonedMutexException]
    {
       
$isAvailable = $true
    }

    $isAvailable
}

if(-not IsMachineIdle)
{
   
"Sorry, the machine is in use. Try again in 5 minutes."
    exit
}

## Continue on with preparing a session

If you want to get more advanced (saying who is logged on, etc.), roll up your sleeves and dig in!

Organizational Awareness with PowerShell

One of the things that’s always unsettled me a bit in a big organization is keeping yourself informed about changes that you care about, even when those changes never end up making it through the grape vine. For example:

  • Promotions. Of course you want to congratulate them!
  • Transfers. Finding out that a team has moved to another manager, but no “re-org” mail to let you know.
  • Leaving the company. Finding out that a co-worker has left the company or division.

Naturally, PowerShell is here to save the day! I’ve been running a script I call “OrgDiff” as a scheduled task now for a long time – it came about organically, and I look forward to its results every Monday.

Here a couple of great examples of a few little bits of code (75 lines) coming together to make something of surprising utility.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
param($User = ‘mybigboss’, $Limit = [Int32]::MaxValue, [Switch] $IncludeManager)

$depth = 0

## A list of all the domains that you want to search for
## a given user’s alias. Try to organize them in order
## of popularity so that your script runs as quick as possible.

$domains = "LDAP://DC=domain1,DC=corp,DC=contoso,DC=com",
    "LDAP://DC=vendors,DC=corp,DC=contoso,DC=com",
    "LDAP://DC=international,DC=corp,DC=contoso,DC=com"
   
## Find all of the direct reports for a given user
function GetReports($username, $depth
)
{
   
if(-not $username) { return
 }
   
if($depth -gt $Limit) { return
 }

    ## Go through all of the domains and try to find the user
    ## account in that domain
    foreach($domain in $domains
)
    {
       
$adsi = [ADSI] $domain

        $searcher = New-Object System.DirectoryServices.DirectorySearcher $adsi
        $searcher.Filter = "(&(objectClass=User)(mailnickname=$username))"
        $user = $searcher.
FindOne()
       
       
if($user) { break
 }
    }
   
   
if(-not $user
)
    {
       
Write-Error "Could not find $username"
        return
    }

    ## If we want the report to include information about the user’s manager,
    ## prepare that portion of the output.
    if($IncludeManager
)
    {
       
$manager = " – " +
            (($user.Properties.manager -split ‘,’)[0] -replace ‘CN=’,
)
    }
   
   
## Display the user’s name, alias, title, and (optionally) manager -
    ## indented according to how deep we’re investigating
    (" " * ($depth * 2)) + $user.Properties.name +
        " (" + $user.Properties.mailnickname +
        ") – $($user.Properties.title)$manager"
   
   
$depth++

    ## If the user has direct reports, call this function again to show
    ## their portion of the organization.
    foreach($directReport in @($user.Properties.
directreports))
    {
        
$report = [ADSI] "GC://$directReport"
         GetReports ($report.mailNickname) $depth
    }
}

GetReports $user $depth

Normal output looks like this:

Some Body (somebody) – GENERAL MANAGER
  Jeffrey Snover (jsnover) – DISTINGUISHED ENGINEER
  Cool Person (coolbeans) – BUSINESS ADMINISTRATOR
  Super Developer (superdev) – DIRECTOR OF DEVELOPMENT
    Dev Manager (devmgr) – DEVELOPMENT MANAGER
      Dev Lead (devlead) _ DEVELOPMENT LEAD
    Dev Manager2 (devmgr2) – DEVELOPMENT MANAGER
(etc)

Now, if you run a weekly script to generate this report into a text file on your hard drive, you can use PowerShell to compare last week’s file with this week’s file. However, when we just compare files line-by-line, you’ll lose the indentation – and therefore the context of who their manager is. That leads to the need for the “-IncludeManager” switch, which generates output more like this:

Some Body (somebody) – GENERAL MANAGER
  Jeffrey Snover (jsnover) – DISTINGUISHED ENGINEER – Some Body
  Cool Person (coolbeans) – BUSINESS ADMINISTRATOR – Some Body
  Super Developer (superdev) – DIRECTOR OF DEVELOPMENT – Some Body
    Dev Manager (devmgr) – DEVELOPMENT MANAGER – Super Developer
      Dev Lead (devlead) _ DEVELOPMENT LEAD – Dev Manager
    Dev Manager2 (devmgr2) – DEVELOPMENT MANAGER – Dev Manager
(etc)

Here’s “Compare-OrgChart.ps1”, a script that starts to show useful differences between two files:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
param($BeforePath, $AfterPath)

## Get the content from the first file and the second file, then sort them by name.
## This lets Compare-Object focus primarily on changes to people, and not be
## impacted by random orderings that might come back from Active Directory

$chart1 = Get-Content $BeforePath | % { $_.Trim() } | Sort-Object
$chart2 = Get-Content $AfterPath | % { $_.Trim() } | Sort-Object

## The format of the lines are:
## Super Developer (superdev) – DIRECTOR OF DEVELOPMENT
## So we tell Compare-Object to look for any changes, sort by only their name,
## and after that sort by "Before" then "After"

Compare-Object $chart1 $chart2 |
    Sort { ($_.InputObject -split ‘-’)[0] },SideIndicator

Now, pretend the following happens:

  • Jeffrey gets promoted to Technical Fellow (congrats!)
  • “Dev Manager” leaves the group
  • “Dev Lead” moves under “Dev Manager2”

Here’s the org chart:

Some Body (somebody) – GENERAL MANAGER
  Jeffrey Snover (jsnover) – TECHNICAL FELLOW – Some Body
  Cool Person (coolbeans) – BUSINESS ADMINISTRATOR – Some Body
  Super Developer (superdev) – DIRECTOR OF DEVELOPMENT – Some Body
    Dev Manager2 (devmgr2) – DEVELOPMENT MANAGER – Dev Manager
      Dev Lead (devlead) _ DEVELOPMENT LEAD – Dev Manager2

(etc)

From there, we get this output:

PS C:\Users\Lee> Compare-OrgChart C:\temp\org_before.txt C:\temp\org_after.txt

InputObject                                                   SideIndicator
———–                                                   ————-
Dev Lead (devlead) _ DEVELOPMENT LEAD – Dev Manager           <=
Dev Lead (devlead) _ DEVELOPMENT LEAD – Dev Manager2          =>
Dev Manager (devmgr) – DEVELOPMENT MANAGER – Super Developer  <=
Jeffrey Snover (jsnover) – DISTINGUISHED ENGINEER – Some Body <=
Jeffrey Snover (jsnover) – TECHNICAL FELLOW – Some Body       =>

That’s pretty cool! Now all we need is a little way to stitch it all together. Here’s a very simple “Update-OrgDiff.ps1” script. All it does is fetch the newest org chart, run the comparison, and email me the results.

001
002
003
004
005
006
007
008
009
010
$mailRecipient = "me@example.com"

$file = "OrgChart-{0}-{1}-{2}.txt" -f (Get-Date).Month,(Get-Date).Day,(Get-Date).Year
Get-OrgChart somebody -IncludeManager > "c:\temp\$file"
$results =  dir c:\temp\OrgChart-* | Sort LastWriteTime | Select -Last 2
$report = Compare-OrgChart $results[0].FullName $results[1].FullName |
    Format-Table -Auto | Out-String -Width 100

Send-MailMessage -To $mailRecipient -From $mailRecipient -Subject OrgDiff `
   
-BodyAsHtml "<html><body><pre>$report</pre></body></html>" -SmtpServer smtphost

Set this up as a scheduled task, and you’re golden!

WMRRA Taste of Racing

Last week, a co-worker mentioned a event being offered again by WMRRA (Washington Motorcycle Road Racing Association) – the “Taste of Racing”.

227781_1684774685881_1433050347_31322912_7171556_n[1]

For $20, you get to bring your bike on the track for 20 minutes. A handful of control riders take you through some familiarity laps (and keep things under control during the ride.)

222216_1684774925887_1433050347_31322913_1833109_n[1]

But then it’s just you and wide-open road.

You know those days when you get an on-ramp all to yourself and smile? Imagine 2 twisty miles of that, designed and shared by people who love it just as much as you do.

This was the "Bus Stop", a set of chicanes to slow things down before the main straightaway.

The straightaway leads to a beautiful sweeping left that you get to take with great speed, and finally get to enjoy all of the rubber in your tires.

From my GPS – a great mix of slow technical twisties, combined with long stretches of wide-open throttle :)

Morser – Keyboard Morse Input Device

[Edit: Please see V2 here: http://www.leeholmes.com/blog/2011/10/04/morser-keyboard-morse-input-device-2/]