Tag Archives: PowerShell

How Powershell helped me to solve the assembly conflict

In one of my test projects the tests suddenly started to fail. Which is a bad thing. What was was worse and strange was the reason why they were failing

System.TypeInitializationException : The type initializer for 'RMReportingPortalDataLayer.Strategies.ReportDeliveryStrategy' threw an exception.
----> System.IO.FileNotFoundException : Could not load file or assembly 'log4net, Version=, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a' or one of its dependencies. The system cannot find the file specified.}}

First I checked the bin directory and the assembly was not there. Then I checked the build log and found this line

No way to resolve conflict between "log4net, Version=, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" and "log4net, Version=, Culture=neutral, PublicKeyToken=692fbea5521e1304". Choosing "log4net, Version=, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" arbitrarily.

Ok, there is a conflict between incompatible versions of log4net assembly. But which of the assemblies referenced in my project are suspects? How to check all the referenced assemblies of references assemblies? It’s task nobody would like to perform manually. I like Powershell so I googled around and found this post and made few changes – build the hash and write the formatted output to console:

$hash = $references | Group-Object Name, Version -AsString -AsHashTable

$hash.GetEnumerator() | Sort-Object Name | % { 
  $key = $_.Key.ToString().Trim()
  $value = $_.Value
  Write-Host $key
  $s = [string]::join([Environment]::NewLine + '   * ', ($value | Select-Object -ExpandProperty Who | Get-Unique | Sort-Object Who))
  Write-Host '   *', $s

Which produces nice output and all is clearer now :)

* Lib.Shared.Admin, Version=, Culture=neutral, PublicKeyToken=3941ae83427745cf
* Lib.Shared, Version=, Culture=neutral, PublicKeyToken=3941ae83427745cf
* Lib.Common, Version=, Culture=neutral, PublicKeyToken=null

I was referencing older version of Lib.Common library, so I updated it to latest version and problem was solved!

Note that the Powershell loads all the assemblies in the folder and keeps them loaded until the Powershell window is closed. Or you can spawn new Powershell process:

$command = [System.IO.File]::ReadAllText("path to dependencies.ps1")
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell -NoProfile -EncodedCommand $encodedCommand # |%{$_}

The script is not perfect and you have to change the path to bin directory …

Fix an error in PowerShell script in NuGet package without redeployment

Recently I created a NuGet package that has a little bit complicated install.ps1 script. The package did not add any references to project, but imported a .targets file.

The structure of the package is

  content (empty)
  libs (empty)

During the installation the relative path to the my.targets file had to be resolved. This took me some time until I found the proper solution and I had to

  1. install the package
  2. see that an error occurred
  3. uninstall the package
  4. fix the error
  5. rebuild the package in another VS.NET window (unfortunately this package was loaded from NuGet feed published on TeamCity, when deploying the package locally to a directory that emulated NuGet feed it is much easier)
  6. repeat this until there’s no error

In case you don’t want to rebuild the package whenever you have fixed an error in PowerShell script, you have to have solution with 2 or more projects. You will have to install the package to 2 (or more) projects. When you spot the error just fix the install.ps1 file located in the directory where package was created (usually `packages\Package.version\tools\install.ps1′).

Then just reinstall the package in one of yours projects. Because the package is now used in 2 or more projects it is not uninstalled and its directory is not removed. when Uninstall-Package is invoked. On Install-Package NuGet finds out that it is already installed in packages directory and gets the files from there.

Note that this will work only for files in package that are used by NuGet package manager without redeploying, like PowerShell scripts, text files, etc.