Powershell: Load assembly without locking file.
I have a set of PowerShell build scripts and ran into a case where I needed to load an assembly (to get the assembly’s version) and still (at a later time) work with the assembly file on disk.
A typical way to load an assembly within PowerShell is to use the Assembly.LoadFrom(filePath)
# Powershell
[System.Reflection.Assembly]::LoadFrom($assemblyPath)
Except the problem with this (in my case) was it would lock the file for the lifespan of the PowerShell console instance. I didn’t want to have to close and re-open the PowerShell console every time I need to run a build so there had to be a work-around for this.
After searching the web for a solution, I couldn’t find anything that was “easy” and worth the effort to get it to work.
EX: One solution was to create a new AppDomain, do the necessary work and the close the AppDomain which would release the lock on the file.
I’ve never done this myself, and even thought there is example code out there to get this accomplished, it just seemed over the top for what I was trying to do, and back to my previous criteria it wasn’t “worth the effort to get it to work”
Then I remembered in a previous life I used an overload that took an array of bytes to load the an assembly.
[System.Reflection.Assembly]::Load($assemblyBytes)
After spiking it in PowerShell with the below test. I was quite happy with the solution, so I thought I’d throw it out there.
Just stream the assembly from disk into a byte array manually, and call assembly load from there.
Here’s my test case which shows that the file is not locked after it was loaded into the PowerShell runtime
$file = ".\Moq.dll" $tempFileName = ".\Moq-Renamed.dll" $fileStream = ([System.IO.FileInfo] (Get-Item $file)).OpenRead(); $assemblyBytes = new-object byte[] $fileStream.Length $fileStream.Read($assemblyBytes, 0, $fileStream.Length); $fileStream.Close(); $assemblyLoaded = [System.Reflection.Assembly]::Load($assemblyBytes); # notice that we can move the file on disk after # it's loaded into the powershell runtime Move-Item $file $tempFileName Move-Item $tempFileName $file # and display the assembly information to show we still have it in memory echo $assemblyLoaded
After that test passed, and the main reason I wanted to do this, I wrote the “get-assembly-version” PowerShell function.
Hope this helps someone out there!function get-assembly-version() { param([string] $file) # load the assembly bytes quickly - as to not lock the file for too long $fileStream = ([System.IO.FileInfo] (Get-Item $file)).OpenRead() $assemblyBytes = new-object byte[] $fileStream.Length $fileStream.Read($assemblyBytes, 0, $fileStream.Length) | Out-Null #out null this because this function should only return the version & this call was outputting some garbage number $fileStream.Close() # return the version of the assembly [System.Reflection.Assembly]::Load($assemblyBytes).GetName().Version; } $version = get-assembly-version(".\Moq.dll") echo "Loaded v$($version.Major).$($version.Minor).$($version.Build).$($version.Revision) version of $file"
UPDATE:
Martin commented below on a much better solution to the assembly version info problem. Amazing how complicated we can make things if we don’t know the path.
function get-assembly-version() {
param([string] $file)
$version = [System.Reflection.AssemblyName]::GetAssemblyName($file).Version;
#format the version and output it...
$version
}


