27 February 2017

How do I - Validate an Assembly is Loaded in Powershell?

Recently, I ran into an issue when auditing TFS.  The issue was related to an intermittent problem where the Powershell script would sometimes work, and sometimes fail.  From a developer perspective, this is an impossibility.  Code either works or it doesn't.  If it sometimes work, then there is most likely something else at play.
Inevitably this lead me down the path of dependencies.  I had to ensure that we had the right TFS DLLs loaded for the script.  This can easily be done with reflection via the GetAssemblies() method of the CurrentDomain within the AppDomain object in Powershell.  The simple command:

[AppDomain]::CurrentDomain.GetAssemblies()

returns a comprehensive list of loaded DLLs.  From here you can identify if your DLL is loaded, or as was the case in another session for me, identify that wrong versions of the target DLL is loaded.  That's good, but how do I use that logically in Powershell code e.g. when I want to see if a DLL is already loaded before attempting to load it again.  (As we know, that throws ugly red text that the operator might mistake for an error rather than the EXPECTED error it is.)

Therefore, using the pipe, we could do something like this:

([AppDomain]::CurrentDomain.GetAssemblies() | where {$_ -match "Microsoft.TeamFoundation.Client"}).Location -eq ""

As you can see, we pipe the output from GetAssemblies() to the where clause attempting to match with the DLL partial name, e.g. "Microsoft.TeamFoundation.Client" in this case.
By wrapping the entire statement in parentheses, we can access the .Location property of the returned object, provided there is one.  If there is none, the location value would be blank and by doing an equal check for blank, we can get a boolean result statement that identifies if a given DLL is loaded. :-)

Enjoy
C

20 February 2017

Beware of [System.Reflection.Assembly]::LoadWithPartialName!!!

If you've been in the Powershell world for any length of time, you will most certainly be familiar with this construct:

[System.Reflection.Assembly]::LoadWithPartialName(...)

This is how we quickly add DLL references to Powershell scripts without having to know the entire name of the DLL in question e.g.

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint");

which loads the Microsoft.SharePoint.dll and makes all the SharePoint cmdlets available to Powershell.

BEWARE!!!  In some cases, quickly = lazy = bad.

If you are referencing a DLL that may have more than hone version on the host system, it becomes imperative that you ensure you are actually loading the right DLL.  I recently ran into this kind of thing when a script was trying to execute some TFS 2015 commands.  The script would fail however, apparently without any logical reason.
It turns out, the reason was quite logical after all.  The script was loading the "Microsoft.VisualStudio.TeamFoundation.dll" using the LoadWithPartialName() method.  Even with the TFS SDK installed, the script would load the wrong version of the DLL since the 2013 version of the exact same named DLL was in the GAC.  Since the GAC trumps everything else, the script would load the old version of the DLL from the GAC and then try to use it with newer versions of related DLLs, hence the failure to execute correctly.

If there's ever any doubt, rather use the best practice LoadFrom() method thus:

[System.Reflection.Assembly]::LoadFrom("C:\Program Files\Common Files\Microsoft Shared\web server extensions\15\ISAPI\Microsoft.SharePoint");

This way, you're 100% guaranteed the proper DLL is loaded and leveraged in your Powershell script.

Enjoy
C

Microsoft Authentication Library (MSAL) Overview

The Microsoft Authentication Library (MSAL) is a powerful library designed to simplify the authentication process for applications that conn...