The Life and Times of a Dev

Yes, we're really that weird
posts - 187 , comments - 337 , trackbacks - 106

My Links



Tag Cloud


Post Categories



Wednesday, November 7, 2012

Remote Desktop Connection Manager

For years, I’ve been using the “Remote Desktops” mmc plugin to manage servers in our infrastructure.  I’ve upgraded to Windows 8 and Remote Desktops is nowhere to be found!  I search and searched and came across a forum listing saying “Why don’t you just use Remove Desktop Connection Manager?”

I downloaded it and started using it and its WAY better than Remote Desktops!  I’m glad they took it out and I discovered this tool.  I wish I had discovered this two years ago!

Technorati Tags:

Posted On Wednesday, November 7, 2012 9:16 AM | Comments (2) |

Tuesday, October 23, 2012

Directory Synchronization

We’re using federated security with Office 365 and everything was running swimmingly and then I started getting the following error when trying to synchronize security information:

“An unknown error occurred with the Microsoft Online Services Sign-in Assistant. Contact Technical Support.”

Great.  Very descriptive.  In the event viewer, you get a bit more detail:

GetAuthState() failed with -2147186688 state. HResult:0. Contact Technical Support.  (0x80048831)

If you do some searching, you’ll find that there are a couple of MSDN articles about this error.  In KB2502710 you’re told to reinstall sign in assistant.  This one requires a reboot.  In KB2517393 you’re told to make sure that your proxy settings are working correctly.  I’m not using a proxy and everything was set up right.

Rather frustrating and I couldn’t figure out what was going on.  What finally keyed me in was the error number being presented.  Rather than 80048800, which is listed in the second article, I was getting 80048831.  I did a quick search and found something that was seemingly unrelated here.  Could it really be so simple as the password having expired for my synchronization user?

Turns out, it was that simple.  Once the password was reset and reentered, everything worked great again.

Since this isn’t a user that humans use, I also don’t want the password to expire.  You can find the instructions for that (use Set-MsolUser –UserPrincipalName <user ID> –PasswordNeverExpires $true) here.

Technorati Tags:

Posted On Tuesday, October 23, 2012 10:12 AM | Comments (2) |

Thursday, September 27, 2012

On iOS 6

“Introducing Windows ME, reimagined as iOS6 and by Apple!”

Remember, it just works, and when it doesn’t, you’re holding it wrong.

Posted On Thursday, September 27, 2012 10:56 AM | Comments (0) |

Thursday, August 16, 2012

Well That Was Fun (The wrong way to migrate mailboxes in Office 365)



First, I want everyone know know that this was a self-inflicted problem.  I thought I knew what I was doing, but really didn’t know.  I do wish that there were warnings letting you know you were about to ruin your life, but there isn’t, so this is an easy mistake to make.

Our company is moving to office 365 from Exchange 2010.  We want to keep a local on premise version for various reasons, so we’ve set up a hybrid exchange configuration.  We tested it by moving a couple of mailboxes over and everything appeared to be working great.

However, the person helping me quit his job at the company we were outsourcing our IT stuff to.  I thought I knew what he had done, but didn’t.

Here’s our configuration:

  1. Exchange 2010
  2. Office 365
  3. Federated Security for Single Sign On
  4. Active Directory Synchronization

The big mistake that I made was when we were ready to move mailboxes to the cloud, I used the Email Migration tool in the Office 365 Tenant Portal.  If you have a HYBRID exchange configuration with with active directory synchronization, DO NOT USE THE E-MAIL MIGRATION image BUTTON!!! You’ll be hosed if you do.  Instead, use the Remote Move Request feature of EMC or powershell.

Note that the pain will be somewhat mitigated if you leave your MX records pointing at your on premise server, since all mail will continue to be delivered to your on premise server.  However, if you moved it, like I did, you have more work.

Here’s some of the symptoms that you did the wrong thing:

  1. Archive folders (personal archives) don’t appear to have migrated.
  2. Users can log into both and access outlook AND your on premises OWA site, and both still work.
  3. Autodiscover sends people, seemingly at random, to your on premise server and to the office 365 servers.
  4. You have mailboxes for users on both your on premise servers and in office 365.

As soon as you realize what you’ve done, you’ll want to crawl under a rock and die.  There is NO easy solution.  After many hours on the phone with Microsoft Tech Support, here are the steps you need to take to recover:

  1. Ensure that you have Rollup 3 for service pack 2 installed on your on premises internet facing hybrid server.
  2. If you’ve moved your MX record, MOVE IT BACK! Smile  Seriously, you’ll have to send it back to your on premise server.
  3. If you moved your MX record, you’ll need to export all new mail that is in office 365 into PST’s.  THIS IS REALLY IMPORTANT!  YOU’RE ABOUT TO PERMENENTLY DELETE DATA! 
    1. To do this, grant a NON-FEDERATED user (and admin user) full access to the mailboxes.  You can do this using EMC’s Manage Full Access permission, or by using a powershell script to do the same.  You’ll need to create the user in office 365.
    2. Set up an outlook profile (I set up an entire VM) and connect it to the user in step one.
    3. Wait forever for the mail to synchronize down to the outlook profile (you probably want to avoid Cached Exchange Mode).  If you’ve got lots of mail, you’re going to have to do this in groups.
    4. Using outlook, export the new mail to a pst (file, open, import, export to file, outlook pst, select the top level mailbox, put a filter in, change the filename to the name of the mailbox, no password, export . . . and yes, that was from memory . . .)
      1. I’d name the file after the user whose mailbox you’re exporting
    5. After PST creation, create a new profile (control panel, Mail, Show Profiles) for an on premise user THAT DOES NOT HAVE A 365 MAILBOX.  Again, you’ll probably need to create the user.
    6. Import the PST’s into the appropriate location in outlook (File, import, import from a file, outlook data file (.pst), select the pst file to import, select the appropriate mailbox from the dropdown list).
    7. Wait forever for mail to sync (you’ll probably want to avoid Cached Exchange Mode).
    8. You’re done.  Wasn’t that fun?
  4. Next, deactivate active directory synchronization in the Office 365 portal and then wait for up to 72 hours for it to complete.  Yup, 72 hours . . . sucks to be you right now.  (It actually took about 7 hours.  I’m not sure if MS made it happen faster because I was already in the tech support queue or not)
  5. Once deactivation is complete, delete the offending users and mailboxes.  You may need to use the Remove-Mailbox powershell command in remote powershell to get rid of the offending mailboxes. (See the additional details below)
  6. Once the users are gone, turn Active Directory synchronization back on and synchronize.
    1. This may take up to 24 hours.
  7. Move the mailboxes the RIGHT way using EMC and Remote Move requests.

I’m at Step 4 right now.  If anything else exciting comes up, I’ll update this post.  I couldn’t find many posts on this “fun” so I thought I’d create one.  I guess others are just more experienced than I am. Smile



So step 5 needs way more detail.  After several more hours on the phone with Microsoft Support, we ended up doing the following to get rid of the bad mailboxes:

Did I mention that by following these steps you’re going to lose data if you don’t have it backed up?

  1. Remove the mailboxes using whatever means you desire (powershell, whatever, doesn’t really matter), which will also delete the users from the system
    1. At this point, you can still recover the users.  If you turn on ADSynch, the users will recover and be re-associated with the deleted mailboxes, which leaves you back where you started.
  2. Using remote powershell for microsoft online, get a list of all online users using the get-msolUser | fl DisplayName, ObjectId command
  3. One by one, delete the users from office 365 using Remove-MSOLUser –ObjectId {Guid from step 2}
    1. If you don’t want to permanently delete your users, you’ll need to get to the operations level at Microsoft.  Yeah, not much you can do about it.
  4. Once the users are deleted that have the duplicate mailboxes, flush the recycle bin using the following command:  Get-MsolUser –ReturnDeletedUsers | Remove-MsolUser –RemoveFromRecycleBin –force
  5. Once this is done, re-enable active directory synchronization, synchronize and your done.  Easy, no?


This link might be helpful.  It talks about how to delete a user even with ADSynch turned on.


BIG Props to FP from Microsoft Support.  Without him I’d have been sunk!

Technorati Tags:

Posted On Thursday, August 16, 2012 8:54 AM | Comments (0) |

Wednesday, July 11, 2012

Reading Credit Card Data from a MagTek Card Swipe Device

Sometimes as developers we’re spoiled by third parties that do a lot of the heavy lifting for us.  However, sometimes we’re NOT spoiled and we have to get our hands dirty.

Today, I spent much of the day getting my hands dirty.  I’m working on a project that uses a MagTek credit card swiper and all MagTek provides you in terms of dlls is a c++ dll and an ActiveX dll.  What fun is that?  I wanted to avoid com interop (no, I don’t have a good reason) and write a C# class that handled talking with their C++ dlls directly.

This ended up being a good lesson in P/Invoke and how to deal with unsafe (I’m guessing strcat) code in a dll that I don’t control.

1207 lines of code (and comments) later, I have the final result completed.  I’m not going to post the entire post, since it would be WAY to long, but here are the key bits:

Here’s the dll imports you’ll need:

/// <summary>
///   Clears the data buffer
/// </summary>
private static extern void MTUSCRAClearBuffer();

/// <summary>
///   Opens the MTUSCRA Device
/// </summary>
/// <returns> A uint that is an <see cref="ErrorValuesEnum" /> </returns>
private static extern uint MTUSCRACloseDevice();

/// <summary>Gets the card data from the reader.</summary>
/// <param name="cardData">The card data structure for holding the card information. </param>
/// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
private static extern uint MTUSCRAGetCardData(ref MTMSRDATA cardData);

//// This has been removed because it requires unsafe code.
/////// <summary>Gets the card data delimited by the provided string.</summary>
/////// <param name="data">The string result that will be sent back. </param>
/////// <param name="delimiter">The delimiter for the string </param>
/////// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
////private static extern unsafe uint MTUSCRAGetCardDataStr(byte* data, string delimiter);

/// <summary>Opens the MTUSCRA Device</summary>
/// <param name="deviceName">The name of the device to open </param>
/// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
private static extern uint MTUSCRAOpenDevice(string deviceName);

/// <summary>Opens the MTUSCRA Device</summary>
/// <param name="command">The command to send </param>
/// <param name="commandLength">The length of the command sent. </param>
/// <param name="result">The result of the command </param>
/// <param name="resultLength">The length of the result. </param>
/// <returns>A uint that is an <see cref="ErrorValuesEnum"/> </returns>
private static extern uint MTUSCRASendCommand(string command, uint commandLength, ref string result, ref uint resultLength);

/// <summary>
/// Raised when the card state data changes.
/// </summary>
/// <param name="callBack">The call back for card data state changing.</param>
private static extern void MTUSCRACardDataStateChangedNotify(CardDataStateChangedCallBack callBack);

/// <summary>
/// Raised when the device state changes
/// </summary>
/// <param name="callBack">The call back for card data state changing.</param>
private static extern void MTUSCRADeviceStateChangedNotify(DeviceStateChangedCallBack callBack);

/// <summary>
/// Gets the current device state.
/// </summary>
/// <param name="deviceState">The device state</param>
private static extern void MTUSCRAGetDeviceState(ref uint deviceState);

/// <summary>
/// Gets the current data state.
/// </summary>
/// <param name="dataState">The data state</param>
private static extern void MTUSCRAGetCardDataState(ref uint dataState);

/// <summary>
/// Gets the cproduct id of the card reader.
/// </summary>
/// <param name="productId">The product id</param>
private static extern void MTUSCRAGetPID(ref uint productId);

You’ll need a couple of delegates as well:

/// <summary>
///   A delegate for handling the card data state callback.
/// </summary>
/// <param name="dataState"> The data state </param>
private delegate void CardDataStateChangedCallBack(uint dataState);

/// <summary>
///   A delegate for handling the device state callback.
/// </summary>
/// <param name="deviceState"> The device state </param>
private delegate void DeviceStateChangedCallBack(uint deviceState);

And then you’ll want to wire those up like so:


this.CardDataStateChanged = new CardDataStateChangedCallBack(this.OnCardDataStateChanged);
this.DeviceStateChanged = new DeviceStateChangedCallBack(this.OnDeviceStateChanged);


And finally, you’ll want the Struct that you’ll need to use to get the card data:

public struct MTMSRDATA
    /// <summary>The default data size for tracks.</summary>
    private const int DEF_MSR_DATA_LEN = 256;

    /// <summary>The card data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN * 3)]
    public string m_szCardData;

    /// <summary>masked card data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN * 3)]
    public string m_szCardDataMasked;

    /// <summary>Track 1 Data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack1Data;

    /// <summary>Track 2 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack2Data;

    /// <summary>Track 3 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack3Data;

    /// <summary>Masked track 1 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack1DataMasked;

    /// <summary>masked track 2 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack2DataMasked;

    /// <summary>masked track 3 data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szTrack3DataMasked;

    /// <summary>MagnePrint data.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szMagnePrintData;

    /// <summary>Card encode type.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szCardEncodeType;

    /// <summary>MagnePrint Status.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szMagnePrintStatus;

    /// <summary>DUKPT Session ID.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szDUKPTSessionID;

    /// <summary>Device Serial Number.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szDeviceSerialNumber;

    /// <summary>DUKPT Key Serial Number.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szDUKPTKSN;

    /// <summary>First Name from Track 1.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szFirstName;

    /// <summary>Last Name from Track 1.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szLastName;

    /// <summary>PAN from Track 2.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szPAN;

    /// <summary>The Expiration Month.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szMonth;

    /// <summary>The Expiration Year.</summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DEF_MSR_DATA_LEN)]
    public string m_szYear;

    /// <summary>Reader product ID.</summary>
    public uint m_dwReaderID;

    /// <summary>MagnePrint length.</summary>
    public uint m_dwMagnePrintLength;

    /// <summary>MagnePrint Status.</summary>
    public uint m_dwMagnePrintStatus;

    /// <summary>Track 1 data length.</summary>
    public uint m_dwTrack1Length;

    /// <summary>Track 2 length.</summary>
    public uint m_dwTrack2Length;

    /// <summary>Track 3 length.</summary>
    public uint m_dwTrack3Length;

    /// <summary>Track 1 length masked.</summary>
    public uint m_dwTrack1LengthMasked;

    /// <summary>Track 2 length masked.</summary>
    public uint m_dwTrack2LengthMasked;

    /// <summary>Track 3 length masked.</summary>
    public uint m_dwTrack3LengthMasked;

    /// <summary>Card encode type.</summary>
    public uint m_dwCardEncodeType;

    /// <summary>Track 1 decode status.</summary>
    public uint m_dwTrack1DcdStatus;

    /// <summary>Track 2 decode status.</summary>
    public uint m_dwTrack2DcdStatus;

    /// <summary>The m_dw track 3 dcd status.</summary>
    public uint m_dwTrack3DcdStatus;

    /// <summary>Card swipe status.</summary>
    public uint m_dwCardSwipeStatus;

Hopefully, this will help you get started and will save you some time.  I know it would have saved me quite a bit!

Good luck!

Technorati Tags: ,,

Posted On Wednesday, July 11, 2012 5:25 PM | Comments (4) |

Monday, July 2, 2012

Easy Scaling in XAML (WPF)

Ran into a problem that needed solving that was kind of fun.  I’m not a XAML guru, and I’m sure there are better solutions, but I thought I’d share mine.

The problem was this:  Our designer had, appropriately, designed the system for a 1920 x 1080 screen resolution.  This is for a full screen, touch screen device (think Kiosk), which has that resolution, but we also wanted to demo the device on a tablet (currently using the AWESOME Samsung tablet given out at Microsoft Build).  When you’d run it on that tablet, things were ugly because it was at a lower resolution than the target device.

Enter scaling.  I did some research and found out that I probably just need to monkey with the LayoutTransform of some grid somewhere.  This project is using MVVM and has a navigation container that we built that lives on a single root view.  User controls are then loaded into that view as navigation occurs.

In the parent grid of the root view, I added the following XAML:

            <ScaleTransform ScaleX="{Binding ScaleWidth}" ScaleY="{Binding ScaleHeight}" />

And then in the root View Model, I added the following code:

/// <summary>
/// The required design width
/// </summary>
private const double RequiredWidth = 1920;

/// <summary>
/// The required design height
/// </summary>
private const double RequiredHeight = 1080;
/// <summary>Gets the ActualHeight</summary>
public double ActualHeight
        return this.View.ActualHeight;

/// <summary>Gets the ActualWidth</summary>
public double ActualWidth
        return this.View.ActualWidth;

/// <summary>
/// Gets the scale for the height.
/// </summary>
public double ScaleHeight
        return this.ActualHeight / RequiredHeight;

/// <summary>
/// Gets the scale for the width.
/// </summary>
public double ScaleWidth
        return this.ActualWidth / RequiredWidth;

Note that View.ActualWidth and View.ActualHeight are just pointing directly at FrameworkElement.ActualWidth and FrameworkElement.ActualHeight.

That’s it.  Just calculate the ratio and bind the scale transform to it.

Hopefully you’ll find this useful.

Update (7-2-2012):

Note that I tried a ViewBox before, but it didn’t work because of the navigation.  Basically, we needed the following structure in the grid:

                        <ColumnDefinition Width="1920"/>
                        <ColumnDefinition Width="1920"/>
                        <ColumnDefinition Width="1920"/>

The first column is the Last Screen.  The second column is the Currently displayed screen, and the last column is the “Next” screen.  When moving next, the “next” screen is loaded into the last column, then the animation is fired to slide in the screen, and then the current panel has the current view replaced and is refocused without animation.  Navigating back is similar in flow.

The total screen space isn’t consumed by the navigation grid.

When using a ViewBox, the entire 5760 pixels are compressed into the available screen space.  A picture would make this more clear, but I can’t show that without revealing stuff you shouldn’t know. Smile

Basically, I needed a single column of the grid to be scaled, not the entire grid, which is what my solution does, where the viewbox attempts to scale everything.

Make sense?

Technorati Tags: ,

Posted On Monday, July 2, 2012 4:29 PM | Comments (3) |

Wednesday, March 21, 2012

Why I LOVE Dell

We recently ordered a laptop for an employee.  It was delivered yesterday and we realized it had no web cam and wasn’t the 1080p resolution.  He wasn’t happy.

So, this morning, I sent an e-mail to our rep and asked him what we could do.  Within an hour or two, he called me, arranged a replacement laptop with the corrected specs, set up a return and had everything arranged and charged us only for the difference.  No pain, no silly questions.  We won’t loose use of the laptop either.  The return and the new laptop will overlap so that we can just pack up the old laptop in the box of the new one, slap some labels on and away we go.

This has been my experience with Dell over the past 10 years.  Their corporate service has always been fantastic, and it’s made me a huge fan.  Keep up the good work, Dell!

Technorati Tags:

Posted On Wednesday, March 21, 2012 11:21 AM | Comments (3) |

Tuesday, February 21, 2012

Converting Hyper-V to VMWare

Our company is standardizing on VMWare for a number of reasons.  I won’t list them here, but wanted to write about a problem that I had using VMWare Standalone Converter version 5.0 to convert Hyper-V virtual machines.

There were four problems:

  1. The converter needs to be run as an administrator
  2. You have to be connected to localhost or you’ll be prompted to install the standalone agent first
  3. Domain credentials don’t work as expected
  4. You need to give explicit permissions to Everyone the directory where the virtual machines are stored

Running as an Administrator

The first problem is the easiest to figure out what’s going on.  Basically, when you run it, you get the error:  A general system error occurred:  Crypto Exception: error:02001005Confused smileystem library:fopen:Input/output error:unable to load C:\ProgramData\VMWare\VMware vCenter Converter Standalone\ssl\rui.crt


Easy to fix, just run as an administrator.

Connect as LocalHost

If you try to connect to the full domain name of the machine when you’re running the converter from the hyper-v machine, you’ll be prompted to install the Standalone agent, which will promptly fail because another version is already installed.  It’ll look something like this:


The fix to this is easy to.  Just connect as localhost.

Domain Credentials Don’t Work

This one is tougher to figure out because basically, you get no help understanding what the problem is.  What happens is that you’re able to connect to Hyper-V and see a list of the machines, but when you select ANY machine on the server, you get the error:

Unable to obtain hardware information for the selected machine. 


This one is a pain.  Basically, the solution to this is to create a new local user and make them part of the Administrators group.  Then, you’ll need to log in on the machine using that user name and use that user name for the permissions when connecting to the Hyper-V.

Once you’ve done that, you’ll think that you can get past this error, but then you run into issue #4.

Changing the Directory Permissions

In our case, our vms were stored in f:\VirtualMachines.  You’d think that a domain admin/admin would have the ability to read information from anywhere but something that the standalone converter is doing prevents it.  You’ll get the same error as above in #3.  The fix to this is to make sure that “Everyone” has full control permissions to the directory where your files are stored and all of the sub directories.  I also did the same through the share, but I’m not sure if that was needed or not.


After addressing all of these items, we’re converting quite happily.  Hopefully, this will help you as well.

Technorati Tags: ,

Posted On Tuesday, February 21, 2012 6:24 PM | Comments (2) |

Friday, January 13, 2012

DBDeploy.Net 2

We’ve used on a number of projects and have found it to be a useful tool, especially around CI environments.  We recently started a Windows Azure project that uses SQL Server and discovered that DbDeploy.Net didn’t work.

There have been a few nagging issues with DbDeploy.Net as well, like the lack of support for recursive script directories, and when we looked into the code base, we discovered that it’s not really written to modern software development standards, and that getting it there would take quite a bit of work, almost as much as just rewriting it, and not much effort has gone into the original version lately.

Not wanting to shirk from a challenge, we rewrote it. Smile  We didn’t use any code from the original.  Some of the concepts are similar, but for the most part, it’s a complete rewrite.

You can download the new version at There’s still plenty of work to do, but its fully functional (and unit tested) for Sql Server and Sql Azure environments, provided that your scripts are Sql Azure friendly (the scripts that Sql Server Management Studio generates are not, but easy to fix).

We look forward to your feedback.

Technorati Tags: ,

Posted On Friday, January 13, 2012 12:08 PM | Comments (0) |

Physician, Heal Thyself–ScrumMaster, Master Thyself

In the New Testament in Luke 4:23 Jesus speaks of a proverb, “Physician, Heal Thyself.”  What, you may ask, does this have to do with being a good developer or a good ScrumMaster?  In my experience, it has quite a bit to do with it, actually, and recently, it’s had far more meaning to me than it used to have in the past.  In large part, my own increased awareness has stemmed from reading Lyssa Adkins fantastic book, “Coaching Agile Teams.”

My Command and Control Roots

My dad owns several independent telephone companies in the west.  Growing up was a lesson in business.  I saw him grow the business from a small company of only about 500 customers to now thousands of customers in Oregon, Kansas, Utah, and Idaho.  In many ways, he’s been quite successful.  I’ve participated in lobbying congress, seen him work on advisory boards for independent telephone companies and watched him interact with his employees.

From there, I went to Idaho State University and received my Bachelors of Business Administration majoring in computer information systems.  I even started my MBA.  All of this was fantastic for me to learn and taught me quite a bit.  However, it all also taught me how to be an expert at Motivation 2.0.  Many also know this as Command and Control. They taught me how to be a manager.  If I could hold everything in my head, and tell people exactly what to do, I was being a good manager.  I was taught that employee’s weren’t to be trusted, because they’d cheat and look for ways skip on doing work.  I was taught that timesheet’s in 15 minute increments so that you knew what people were doing at any given point in the day was a good thing.

I was so bad, that I even once installed a time system that used the employee’s fingerprints to clock in and out.

Ghastly, I know, and I’m deeply ashamed of that period in my life.

My Transformation

About 10 years ago, I started to realize the error of my ways.  I didn’t understand it at first.  My dad’s company had a consulting firm come in and do an evaluation of why they were struggling with morale, and almost refused to work with us as a company because of the results of a survey that they took of the employees.  It was/is that bad.  That was the catalyst for me to start learning.  It’s what I needed to hear to try and become better.

I left my dad’s company and moved to a government agency, which didn’t help my understanding of command and control.  I could see the problems it was causing in the teams, but still didn’t understand why.  Finally, I ended up as CTO of a local firm and started running my own team.  I got the chance to practice not being command and control.  I read about the agile thing it was hard, but I was doing better. Not good, but better.  I still didn’t get it.  I thought I was Agile, was using a RUP derivative (sort of), had heard of Scrum and thought I was doing what was needed, except that the entire thing blew up in my face and I didn’t know why.

Finally, I started a new job as a project manager for Veracity Solutions.  Almost immediately, things started to go downhill, similar to my last company.  My response was, “O.k., I just need to control things tighter and everything will be o.k.”  It wasn’t.  I was scared.  I didn’t want another failure.

I became very introspective and I realized that the problem wasn’t the team, wasn’t the process, wasn’t the other people.  The problem was me.


I put that big and bold so that every time I see it, I can ask myself the question,


Each day, I’m striving to continue the transformation.

Heal Thyself

Recently, I read much of Lyssa’s book and realized that I still have a long way to go.  I had become a master of the mechanics of Scrum, but I hadn’t yet mastered the people side of scrum.  I am still using violent language, I’m still not as aware of my emotions as I’d like to be.  I’ve discovered that I have a growing edge (the rough boundary between things I’ve mastered and things that I stink at) that is much closer than I want it to be.

Coaching is all about helping PEOPLE become better than they currently are.  It’s not about the mechanics of some process.  It’s not about process at all.  It’s about becoming a better person.  When I wasn’t introspective, I was trying to make people become just like me, controlling, terrible people.  I had to heal myself first.  I had to recognize that people around me have the same wants, needs, and desires that I have and that I can only be successful when they are also successful.

I’m still not perfect, but I am growing closer to that vision of myself that I’ve always had.  I’ve gone from having the bubonic plague to having the bird flu, and I’m getting better, hopefully every day.  At least I’ve never been turned into a newt.  That would have been a much harder starting place.

If you want to coach others, please take the time to understand yourself and make sure you don’t have any lingering patterns that will cause you to be ineffective as a coach.  For the software development world, Lyssa’s book can help.  For the religious world, Christ’s example can help.

Whatever your source of inspiration, seek to make those around you better and together, we can move into a better world.

Technorati Tags:

Posted On Friday, January 13, 2012 11:54 AM | Comments (0) |

Powered by: