While catching up on blogs this morning I ran across a little PowerShell gem on Walking Dependencies in Powershell. Chris outlines a problem that has popped up a few times in DotNetNuke. Usually it revolves around CountryListBox or DotNetNuke.WebUtility. Finding the offending assembly is always trial and error. Chris’s solution should help resolve that issue. I found a few minor bugs in Chris’s script which I have fixed. The reflection call is a static method and is missing a “]::” and the Convert-Path is unneeded if you call ReflectionOnlyLoadFrom with $_.FullName (this will become important in a minute).
In reviewing the original script, I found that it still requires a manual step of reviewing a list to identify discrepancies. In the case of a typical DotNetNuke installation, this could be hundreds of lines. Since this is PowerShell, I thought it would be better to allow the user to supply a filter for the assembly references they were interested in. For example, if my error is telling me that there is a conflict with CountryListBox, then I only really care to see the assemblies with a dependency on CountryListBox.
DotNetNuke supports the use of Probing paths for limiting the number of assemblies which must load at startup. Nik Kalyani
discusses this in several blogs here, here and here. As a result of the use of probing paths, to really find all assemblies which might be causing dependency conflicts, I really need to be able to recursively find all assemblies in a DotNetNuke installation. To aid in this effort I have added a Recurse switch. Now I can just set my current directory to the website root and do a recursive search for all assemblies. Very cool.
After reworking Chris’s original one liner a little bit, this is the function I came up with:
function get-references(
[string]$Filter,
[switch]$Recurse,
[switch]$HideHeader)
{
if($Recurse) {$assemblies = dir -Filter *.dll -Recurse }
else { $assemblies = dir -Filter *.dll }
$assemblies `
| foreach { [System.Reflection.Assembly]::ReflectionOnlyLoadFrom($_.FullName) } `
| foreach { if (
(($_.GetReferencedAssemblies() | where { $_.Name -like $Filter }) -ne $null) `
-or [string]::IsNullOrEmpty($Filter) ) `
{ if (!$HideHeader) {"`n{0}`n{1}" -f $_.FullName, "".PadLeft($_.FullName.Length, '-')}; `
$_.GetReferencedAssemblies() | `
where { ($_.Name -like $Filter) -or [string]::IsNullOrEmpty($Filter)} | `
foreach {$_.FullName}
}
}
}
I am still a relative light-weight when it comes to heavy duty PowerShell scripting, so if anyone has any ideas on how to remove the requirement to create the $assemblies temp variable I would appreciate the help.