Improve your .NET code quality with NDepend

A Visual Studio script that saves time and pain

After years of pain, I finally found a clean-and-definitive way to get rid of the dreadful issue Could not copy assembly, the process cannot access the file because it is used by another process!

Locked assembly

I have no idea how many .NET developers are coping with this issue, but on our side it used to be daily and there are many situations where an assembly file gets locked:

  • sometimes VS just load in-process the assembly, or the PDB file or the .xml documentation file, for an unknown reason (usually after a debug session)
  • sometimes the culprit seems to be vshost.exe
  • sometimes the culprit is the test runner process
  • sometimes, after a smoke test session, one just forgets to close all processes that hold assemblies…
  • …or sometimes it is just a zombie process that should have stopped but just didn’t!
  • and when developing a VS extension, all of those situations are happening more often

When the culprit process was not obviously identified, I started Process Explorer to kill it! And when the culprit process is my current VS instance, it means I need to restart it and interrupt current work for significant time and then lose my mental focus!!

The clean-and-definitive solution to this problem, is this script to copy in a .bat file. This script must be invoked from the VS project pre-build-events. It just moves the assembly file, the .pdb file and the .xml documentation file to a temporary location (if the .pdb or .xml file is missing no problem).

The key is that when a process locks a file, Windows authorizes to move and rename the file. I found the original idea from this stackoverflow answer, that itself found it from a Keyvan Nayyeri blog post that seems to have been removed.

To invoke this script just add this in all your VS project pre-build events command line. If you wish the script name and location to be different, just adapt $(SolutionDir)\BuildProcess\PreBuildEvents.bat.


Notice that this script does the job no matter the actual configuration (Debug or Release) and no matter if the compilation is started from VS or from any other script.


My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend in 2004.

Nowadays NDepend is a full-fledged Independent Software Vendor (ISV). With more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.


    1. I don’t guarantee it works for all VS users, but at least it works for us 🙂
      What problem exactly are you dealing with?

      1. Compile complete — 0 errors, 1303 warnings
        $(TargetPath) is “E:\Bistro\bin\Debug\Bistro.exe”
        $(TargetFileName) is “Bistro.exe”
        $(TargetDir) is “E:\Bistro\bin\Debug\”
        $(TargetName) is “Bistro”
        Se han movido 1 archivos.
        Se han movido 1 archivos.
        El sistema no puede encontrar el archivo especificado.
        C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3102,5): warning MSB3112: Two or more assemblies have the same identity ‘Bistro, Version=, Culture=neutral, ProcessorArchitecture=x86’.
        C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3102,5): warning MSB3181: Two or more files have the same target path ‘E:\Bistro\bin\Debug\Bistro.exe’.
        C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3390,5): warning MSB3026: Could not copy “obj\x86\Debug\Bistro.exe” to “bin\Debug\Bistro.exe”. Beginning retry 1 in 1000ms. The process cannot access the file ‘bin\Debug\Bistro.exe’ because it is being used by another process.
        C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3390,5): error MSB3027: Could not copy “obj\x86\Debug\Bistro.exe” to “bin\Debug\Bistro.exe”. Exceeded retry count of 10. Failed.
        C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3390,5): error MSB3021: Unable to copy file “obj\x86\Debug\Bistro.exe” to “bin\Debug\Bistro.exe”. The process cannot access the file ‘bin\Debug\Bistro.exe’ because it is being used by another process.

  1. I was struggling with this (worst?) issue and lost almost a day (Earlier whenever I faced this issue, it used to drive me crazy and I ended up doing all sort of things). However, this time it was different as I could figure out a way to solve the issue.

    The solution was to : Click on Project Properties and DESELECT “Enable Visual Studio Hosting Process”
    That’s it 🙂

    1. But then you loose the Visual Studio Hosting Process benefits, with this astute you don’t 🙂

  2. Hi,

    “I started Process Explorer to kill it!”
    Sometimes, the culprit is the Process explorer itself. Especially when you open the Properties window for the process and navigate through the tabs (probably it’s the Threads tab), then it may happen that the Process Explorer loads the PDB and does not free it up anymore.
    As a result, you see that specific error in VS, eg. when you try to re-build your solution.
    To fix that, just close the Process Explorer process (and also its taskbar icon).

    1. Indeed, Process Explorer can also be the culprit, hopefully this astute fixes all situations 🙂

Comments are closed.