VS Post Build Event - visual-studio

I would like to implement a post build event that performs the following actions
A relative path copy of the DLL output (1 file, not all the debug jazz)
A register the output DLL to GAC
How is this done?

Does that do you want?
copy $(TargetPath) $(TargetDir)..\..\someFolder\myoutput.dll
regasm $(TargetPath)
(Entered into the field for post-build step under project properties)

Enter following into "Project properties->Build events->Post build events command line:"
xcopy "$(TargetPath)" "target path" /Y && regasm "$(TargetPath)"
or add following snippet to project (e.g. csproj) file
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "target path" /Y && regasm "$(TargetPath)"</PostBuildEvent>
</PropertyGroup>
Note that it is recommended to add "" around copy command arguments to avoid problems with paths containing whitespaces. Also note that multiple commands can be combined using &&

Are you sure you want to do this as part of a compile? I would recommend using project references in solutions rather than the GAC if you can avoid it. Copying files is one thing, but registering in the GAC is fairly intrusive and you may want to consider the other environments your code is compiled in. Things like other developers' machines, and test environments/build servers etc. If you have a build server really you should be using something like NAnt with some sort of continuous integration server.

I had to same issue and I struggled a bit to make it works.
In my case, I wanted to do the other way around which is copying the SDL dll into my output folder.
copy "$(SolutionDir)SDL\lib\x86\SDL.dll" "$(SolutionDir)$(Configuration)\"
Note that, $(Configuration) will be your output folder (e.g. Debug or Release).
The quotes was what I was missing, apparently you need them when the right hand side end with a \. Thus, it might be safer to always use them.
Hope to save someone else a 5 minutes!
P.S. I use Visual Studio 2010

you may want to look at MS Build. Its what we use here at work.
CodeProject Link &
MSDN Ref

For step 2 in the question I seem to prefer the following:
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil" /f /i $(TargetPath)
Note: this requires the Windows SDK to be installed on your development machine.
More info on the available macros, such as $(TargetPath), on MSDN.

Ran into a related issue. The answers here helped (thanks!).
My scenario was in debugging an MEF-reliant application I needed to have the related DLLs in a particular location. I ran into issue with overwriting the prior build so did need to add a delete to the script.
delete $(SolutionDir)FileService\$(ProjectName).dll
copy $(TargetPath) $(SolutionDir)FileService\$(ProjectName).dll
Hope that helps someone, too!

This question is old. The easiest way is to add something like this on your .csproj file. For example I am running some tests on a virtual machine and its nice to have it sent to it after I compile:
<Project>
...
<!-- Upload to virtual machine -->
<Target Name="rsync" AfterTargets="Build">
<Exec Command="C:\Windows\System32\wsl.exe rsync -azv -e 'ssh -i /path/to/my/private/key' --delete /mnt/c/repos/MyProject/bin/Debug/net7.0/ root#vm.ublux.com:/usr/share/foo/" />
</Target>
</Project>

Related

.Net Core 2.0 "Generate Nuget package on build" issue with Post-build events

The new .NET Core 2.0 projects provide and easy and convenient way to create Nuget Package from the project output. Just click on the "Generate Nuget package on build" check box and it is done.
It works fine but I have an issue with Post-build events.
I want to copy all of the packages from a solution after each build to a specific folder. So I use the "Post-build event command line" with a script:
xcopy "$(ProjectDir)$(OutDir)..*.nupkg" "$(SolutionDir)..\WebServicePracticesNuget\" /Y /I
And sometimes it works fine sometimes not at all. So far my investigation concluded that the Nuget package creation is not part of the build process itself. So the script (sometimes) will triggered before the package was generated and it is unpredictable. My solution is to add some delay. Unfortunately "timeout x" is not working with Post-build events. So I used the fallback option:
ping 127.0.0.1 -n 4 > NUL
Which makes it almost reliable (~95%) but I think it is "poor man's" solution. And looks ridiculous in a Post-build event script. I have already reported this issue to the VS team. But not much comments or solution so far.
So my question is: does anybody have the same issue? Or any idea for a better solution then I have now?
Thanks.
The GeneratePackageOnBuild feature executes the Pack target after Build so the post build event will potentially run before the NuGet packages have been created. In VS 15.3+, when you create a post-build event, it will create a Target element in the project file. You can change the AfterTargets attribute on it to AfterTargets="Pack" to run after packing and not after the core .net build. But it is a bit of a fragile approach.
The pack target will respect the PackageOutputPath msbuild property, which is what dotnet pack's --output parameter would set.
Since xcopy only works on windows, the most versatile solution would be to use msbuild to set up the property during the build.
For example you could put a Directory.Build.props file next to the solution file (directory above all projects) with the following contents:
<Project>
<PropertyGroup>
<PackageOutputPath>$(MSBuildThisFileDirectory)nupkgs</PackageOutputPath>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
</Project>
This file will be automatically imported into all project files in the directory hierarchy blow this file and set the target directory for the generated .nupkg files to a folder named nupkgs next to the Directory.Build.props file. It also enables the "generate package build" feature for all projects that support it ("sdk-based" projects like .net standard / .net core libraries) so you don't have to set it up in VS or edit all project files.
You can configure msbuild task order inside the project file.

Cumulative Custom Build Steps in Visual Studio

Is it possible to have cumulative custom build steps in Visual Studio?
What I want to do is have a
if not exist "$(OutDir)" mkdir "$(OutDir)"
as a custom step for ALL configurations (current and possible future ones)
But for a specific configuration (say Deploy) I want to ADDITIONALLY do this
xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
Is this possible? I have tried adding a property sheet in Deploy with the xcopy command, but the All Configurations "custom build step" property (with the mkdir command) seems to completely overshadow the xcopy one!
Alternative solution: you can easily have this functionality by using for instance
<Target Name="MyTarget" BeforeTargets="BscMake">
<Exec Command="xcopy ..."/>
</Target>`
That will run right before BscMake, which is when a custom build step with default options also runs. Or you could also use AfterTargets="CustomBuildStep" to make it run after your CustomBuildStep, etc. Note this method also makes it easy to add more steps without interfering with others.
It seems that you need to have a %(Command) added at the end of EVERY commands list to make the commands inheritable.
Answer found here:
https://stackoverflow.com/a/22749337/113718
Having to add an extra "command" feels very hackish, if there is another, better solution, please share.

How to make Visual Studio copy a DLL file to the output directory?

I have a Visual Studio C++ project that relies on an external DLL file. How can I make Visual Studio copy this DLL file automatically into the output directory (debug/release) when I build the project?
Use a post-build action in your project, and add the commands to copy the offending DLL. The post-build action are written as a batch script.
The output directory can be referenced as $(OutDir). The project directory is available as $(ProjDir). Try to use relative pathes where applicable, so that you can copy or move your project folder without breaking the post-build action.
$(OutDir) turned out to be a relative path in VS2013, so I had to combine it with $(ProjectDir) to achieve the desired effect:
xcopy /y /d "$(ProjectDir)External\*.dll" "$(ProjectDir)$(OutDir)"
BTW, you can easily debug the scripts by adding 'echo ' at the beginning and observe the expanded text in the build output window.
The details in the comments section above did not work for me (VS 2013) when trying to copy the output dll from one C++ project to the release and debug folder of another C# project within the same solution.
I had to add the following post build-action (right click on the project that has a .dll output) then properties -> configuration properties -> build events -> post-build event -> command line
now I added these two lines to copy the output dll into the two folders:
xcopy /y $(TargetPath) $(SolutionDir)aeiscontroller\bin\Release
xcopy /y $(TargetPath) $(SolutionDir)aeiscontroller\bin\Debug
To do it with the GUI, first add the file(s) to the project: right-click the project, select "Add...", then "Existing Item", then browse to the file or files you want to add and click "Add". Next, tell Visual Studio to copy the file when you build: right-click the file you want to copy, select "Properties". You'll see a list of properties, including "Item Type". Change the "Item Type" to "Copy File". Hit OK and you're done.
Here's the file properties dialog:
Looking in the *.vcxproj file, the steps above add something like this:
<ItemGroup>
<CopyFileToFolders Include="libs\a.dll" />
<CopyFileToFolders Include="libs\a.dll" />
</ItemGroup>
I couldn't find any official documentation for <CopyFileToFolders>, but clearly it's supported or the GUI wouldn't use it. But, if you're doing it by hand and an undocumented item type makes you uncomfortable you can always use the well known but slightly more verbose <Content> type:
<ItemGroup>
<Content Include="libs\a.dll" >
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libs\b.dll" >
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
Add builtin COPY in project.csproj file:
<Project>
...
<Target Name="AfterBuild">
<Copy SourceFiles="$(ProjectDir)..\..\Lib\*.dll" DestinationFolder="$(OutDir)Debug\bin" SkipUnchangedFiles="false" />
<Copy SourceFiles="$(ProjectDir)..\..\Lib\*.dll" DestinationFolder="$(OutDir)Release\bin" SkipUnchangedFiles="false" />
</Target>
</Project>
(This answer only applies to C# not C++, sorry I misread the original question)
I've got through DLL hell like this before. My final solution was to store the unmanaged DLLs in the managed DLL as binary resources, and extract them to a temporary folder when the program launches and delete them when it gets disposed.
This should be part of the .NET or pinvoke infrastructure, since it is so useful.... It makes your managed DLL easy to manage, both using Xcopy or as a Project reference in a bigger Visual Studio solution. Once you do this, you don't have to worry about post-build events.
UPDATE:
I posted code here in another answer https://stackoverflow.com/a/11038376/364818
xcopy /y /d "$(ProjectDir)External\*.dll" "$(TargetDir)"
You can also refer to a relative path, the next example will find the DLL in a folder located one level above the project folder. If you have multiple projects that use the DLL in a single solution, this places the source of the DLL in a common area reachable when you set any of them as the Startup Project.
xcopy /y /d "$(ProjectDir)..\External\*.dll" "$(TargetDir)"
The /y option copies without confirmation.
The /d option checks to see if a file exists in the target and if it does only copies if the source has a newer timestamp than the target.
I found that in at least newer versions of Visual Studio, such as VS2109, $(ProjDir) is undefined and had to use $(ProjectDir) instead.
Leaving out a target folder in xcopy should default to the output directory. That is important to understand reason $(OutDir) alone is not helpful.
$(OutDir), at least in recent versions of Visual Studio, is defined as a relative path to the output folder, such as bin/x86/Debug. Using it alone as the target will create a new set of folders starting from the project output folder. Ex: … bin/x86/Debug/bin/x86/Debug.
Combining it with the project folder should get you to the proper place. Ex: $(ProjectDir)$(OutDir).
However $(TargetDir) will provide the output directory in one step.
Microsoft's list of MSBuild macros for current and previous versions of Visual Studio
I had a similar question. In my project, there were couple of external DLLs. So I created a new folder in the project called "lib" and copied all the external dlls to this folder.
Add a reference to these DLLs.
Go to Project References>dll properties and change the following properties
enter image description here

Visual Studio Post Build Event - Copy to Relative Directory Location

On a successful build, I wish to copy the contents of the output directory to a different location under the same "base" folder. This parent folder is a relative part and can vary based on Source Control settings.
I have listed a few of the Macro values available to me ...
$(SolutionDir) = D:\GlobalDir\Version\AppName\Solution1\build
$(ProjectDir) = D:\GlobalDir\Version\AppName\Solution1\Version\ProjectA\
I want to copy the Output Dir contents to the following folder :
D:\GlobalDir\Version\AppName\Solution2\Project\Dependency
The base location "D:\GlobalDir\Version\AppName" needs to be fetched from one of the above macros. However, none of the macro values list only the parent location.
How do I extract only the base location for the post build copy command ?
Here is what you want to put in the project's Post-build event command line:
copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)lib\$(ProjectName).dll"
EDIT: Or if your target name is different than the Project Name.
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)lib\$(TargetName).dll"
If none of the TargetDir or other macros point to the right place, use the ".." directory to go backwards up the folder hierarchy.
ie. Use $(SolutionDir)\..\.. to get your base directory.
For list of all macros, see here:
http://msdn.microsoft.com/en-us/library/c02as0cs.aspx
You could try:
$(SolutionDir)..\..\
I think this is related, but I had a problem when building directly using msbuild command line (from a batch file) vs building from within VS.
Using something like the following:
<PostBuildEvent>
MOVE /Y "$(TargetDir)something.file1" "$(ProjectDir)something.file1"
start XCOPY /Y /R "$(SolutionDir)SomeConsoleApp\bin\$(ConfigurationName)\*" "$(ProjectDir)App_Data\Consoles\SomeConsoleApp\"
</PostBuildEvent>
(note: start XCOPY rather than XCOPY used to get around a permissions issue which prevented copying)
The macro $(SolutionDir) evaluated to ..\ when executing msbuild from a batchfile, which resulted in the XCOPY command failing. It otherwise worked fine when built from within Visual Studio. Confirmed using /verbosity:diagnostic to see the evaluated output.
Using the macro $(ProjectDir)..\ instead, which amounts to the same thing, worked fine and retained the full path in both build scenarios.
Would it not make sense to use msbuild directly? If you are doing this with every build, then you can add a msbuild task at the end? If you would just like to see if you can’t find another macro value that is not showed on the Visual Studio IDE, you could switch on the msbuild options to diagnostic and that will show you all of the variables that you could use, as well as their current value.
To switch this on in visual studio, go to Tools/Options then scroll down the tree view to the section called Projects and Solutions, expand that and click on Build and Run, at the right their is a drop down that specify the build output verbosity, setting that to diagnostic, will show you what other macro values you could use.
Because I don’t quite know to what level you would like to go, and how complex you want your build to be, this might give you some idea. I have recently been doing build scripts, that even execute SQL code as part of the build. If you would like some more help or even some sample build scripts, let me know, but if it is just a small process you want to run at the end of the build, the perhaps going the full msbuild script is a bit of over kill.
Hope it helps
Rihan
I solved my problem by reinstall VS and then download .Net Core (3.x and 2.x) sdk packages
Here is my post build script
Creates the custom path for my own. Including library and version.
Copies the .dll (target file)
Copies the *.md files.
script:
md c:\_References\$(ProjectName)\$(AssemblyVersion)
xcopy $(ProjectDir)$(OutDir)$(TargetFileName) c:\_References\$(ProjectName)\$(AssemblyVersion) /y
xcopy $(ProjectDir)*.md c:\_References\$(ProjectName)\$(AssemblyVersion) /y

How to copy a build to test server?

Hope someone can assist me with this. Have TeamCity up and running and doing builds on various projects. I'd like to be able to copy/deploy a successful TeamCity ran build to a test server automatically.
I was thinking of using PowerShell to do this but, am open to other ideas. Can some provide me with info on how I can accomplish this.
Thanks.
I use WGet. Here are the instructions for forming the team city URL. You can do a WGet in powershell, but if you only wanted powershell for this functionality, you can just use a plain wget utility for windows.
EDIT: Here is an example from our QA deployment (names changed to protect the guilty):
"C:\Program Files (x86)\NcFTP\wget.exe" "http://teamcityserver.domain.com:8111/guestAuth/repository/download/bt6/.lastFinished/Artificat.ear"
The location of the wget isn't relevant, that is just where it happens to be. The guestAuth part of the parameter specifies the authentication type (in our case we enabled guest authorization to not have to bother with passwords - it is an internal server only anyway and protected by firewalls). The options are in the documentation I linked to.
The other interesting feature of the parameters is the bt6. That is the unique key of the build, and is different for every project. You can discover what it is by navigating the team city website to the configuration of that build - it will be there. There are also instructions for referencing the configuration by name, but we found that was too verbose to bother with.
I've been implementing this for our applications today. Using msbuild. I have found this very useful as we can add in custom steps such as modifying config files, archiving live builds and notifying people of changes.
Here is a build script you may find useful. It precompiles the application and then copies it into the deploy directory.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Deploy">
<PropertyGroup>
<WebsitePublishDirectory>Artifacts\Website</WebsitePublishDirectory>
<WebsiteDeployDirectory>\\SERVERNAME\Path\to\web\root</WebsiteDeployDirectory>
<WebsiteProject>[Project name here]</WebsiteProject>
</PropertyGroup>
<Target Name="Deploy">
<RemoveDir Directories="$(WebsitePublishDirectory)" />
<AspNetCompiler
VirtualPath="test"
PhysicalPath="$(WebsiteProject)"
TargetPath="$(WebsitePublishDirectory)"
Force="true"
Debug="false" />
<ItemGroup>
<PublishedFiles Include="$(WebsitePublishDirectory)\**" />
</ItemGroup>
<Copy SourceFiles="#(PublishedFiles)" DestinationFolder="$(WebsiteDeployDirectory)\%(RecursiveDir)" />
</Target>
</Project>
You could also install a TeamCity agent on the test server. That's actually how TeamCity was intented to be used.
I created a Post Build Script in Visual Studio like this:
c:\TeamCityBuild\pt_build.bat
exit 0
Then on the TC-server I have a .bat that looks like this:
net use r: \192.168.16.85\WebSite password /USER:domain.com\administrator
xcopy "C:\TeamCityBuild\path\WebSite*" "r:\" /R /Y /E
r: \192.168.16.85\WebSite /DELETE
if errorlevel 1 goto buildFAILED
:buildOK
echo Wehej!!!
exit 0
:buildFAILED
echo Oh NOOO!!!
exit 1
'R:' is a mapped drive to the test server.
The error handling is only needed to avoid script errors when someone builds the project on a environment without the correct folder structure.
So far everyting is working great!

Resources