Microsoft plays a practical joke on the Visual Studio user unfamiliar with the build events usage of robocopy. Until last week I never really had need of robocopy in post build events since xcopy using “$(TargetDir)$(TargetName)*” moves the dll, pdb and the xml documentation file. However, in the quest to get the community more engaged by building what Microsoft calls starter kits to provide starter application templates across the AppMagic for .NET platform that changed. In this case I had the MVC 5.1 referenced in my assembly AppMagic.MVC where some base controller classes reside, so I wanted to place my assemblies in the AppMagic directory of the project template and the MVC 6.1 and the Json.NET binaries to go in the ThirdParty directory directly from a local build until I can get it documented for manufacturing. This requires the ability to exclude files which xcopy will not provide.

That source syntax “$(TargetDir)$(TargetName)*” is the reason for the dance required to use robocopy. The reason is that xcopy takes an expression as a first parameter that may consist of a pattern as well as a path $(TargetDir)$(TargetName)* while robocopy takes a path $(TargetDir) and allows a pattern in its own parameter. And robocopy has no love at all for the trailing slash built into $(TargetDir). Don’t worry examples follow, but you may be on this page on a search for “exited with code 16”. That’s your baby there. If you have a trailing slash whether rendered out of a macro or hardcoded there must be a space after it and quotes around it like this “$(TargetDir) “.

But wait. If that was not enough fun for you now that you figured that out Visual Studio then says that the build failed over a build event that exited with code 3. Well that is because robocopy is a know-it-all that just can’t answer yes or no. Robocopy is verbose and needs a wrapper.

 ^& IF %ERRORLEVEL% LEQ 3 exit 0

is that wrapper as any return below 4 copied successfully. Our 3 means there are other files in the environment. But we know that, so 3 is not a fail as Visual Studio interprets it, so the above gives us a contextually correct exit code when separating and aggregating files using robocopy.

rem fails - maybe exit with code 16 - add space after $(TargetDir)

robocopy "$(TargetDir)" "C:\Users\user\path\to\starterProject\ThirdPartyAsms" /xf *AppMagic* *.tmp /is

rem fails - exit with code 3 - false fail - add exit code wrapper

robocopy "$(TargetDir) " "C:\Users\user\path\to\starterProject\ThirdPartyAsms" /xf *AppMagic* *.tmp /is

rem copy success and Visual Studio reports build success - if exited with code -1 check for space after / or $(TargetDir)

(robocopy "$(TargetDir) " "C:\Users\user\path\to\starterProject\ThirdPartyAsms" /xf *AppMagic* *.tmp /is) ^& IF %ERRORLEVEL% LEQ 3 exit 0