659

How can I limit my post-build events to running only for one type of build?

I'm using the events to copy DLL files to a local IIS virtual directory, but I don't want this happening on the build server in release mode.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JC.
  • 11,561
  • 11
  • 41
  • 50

12 Answers12

833

Pre- and Post-Build Events run as a batch script. You can do a conditional statement on $(ConfigurationName).

For instance

if $(ConfigurationName) == Debug xcopy something somewhere
Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
Joseph Daigle
  • 47,650
  • 10
  • 49
  • 73
  • 7
    strange, maybe its just me but I tried adding the if condition, and now I get this error - error exited with code 255 – Michael L Jan 15 '09 at 11:03
  • 7
    you can also use gotos / labels for a fuller solution (see my Jul 24 answwer) – CestLaGalere Jul 24 '09 at 09:59
  • 12
    and you can use brackets with the if command (see my answer for an example) – gbjbaanb Dec 23 '10 at 15:33
  • @RobinM I am looking for similar solution but not on configuration name , is it possible to read some file or command line argument that can be passed and decides whether it should copy from one location or the other – ansar Dec 21 '15 at 09:40
  • 2
    You should use "xcopy /Y", so that the file will be overwritten in the target directory. – Matthias Jan 15 '16 at 13:20
  • 1
    Just tested, but I had to read all posts to build a valid command :(. I added the final command below. – Eric Bole-Feysot Feb 22 '16 at 13:23
  • 1
    Cool trick: I found a hidden variable `$(ActiveDebugProfile)` - which gives you the name of the debug profile you're running i.e. `IIS Express` or any custom profile. – TetraDev Jun 27 '18 at 20:24
572

FYI, you do not need to use goto. The shell IF command can be used with round brackets:

if $(ConfigurationName) == Debug (
  copy "$(TargetDir)myapp.dll" "c:\delivery\bin" /y
  copy "$(TargetDir)myapp.dll.config" "c:\delivery\bin" /y
) ELSE (
  echo "why, Microsoft, why".
)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gbjbaanb
  • 51,617
  • 12
  • 104
  • 148
  • 71
    May I also add, to be careful of the opening parenthesis which needs to immediately follow the if statement, as if it's on the next line an error code will be produced – wonea Mar 15 '11 at 11:16
  • 48
    Use `"$(ConfigurationName)"` (notice the quotes) if you get error code 255 – jgauffin Aug 28 '12 at 13:27
  • 1
    Any ideas on why my `echo` after the `if else` block is not called? – Felipe Sabino Mar 12 '13 at 13:14
  • 25
    note, if you use "" around $(ConfigurationName), you also need quotes around the word Debug too - shell command IF statements are very .. literal ... when it comes to string comparisons. – gbjbaanb Oct 07 '13 at 08:11
  • 1
    This will also fail if you forget the space between the word Debug and the open parenthesis. That one just bit me. – JessieArr Jun 04 '15 at 21:35
  • 9
    Note, To get rid of the 255, I had to use "" around $(ConfigurationName) AND remove spaces around the condition , for example if "$(ConfigurationName)"=="Release" <--No spaces around == – fhilton Nov 11 '15 at 13:19
  • You will also need to have an even number of hairs in your head otherwise you will get error 255, which cannot get any higher because Microsoft was too optimistic and stored error flags in 8 bits. – Sergio Basurco Apr 07 '16 at 15:12
  • @chuckleplant Error codes aren't necessarily bit flags (usually they're an enum of error codes), and they can in fact go over 255 (exit code is an Int32 in C#). This 255 value seems to be a "failure on the script itself" deal, not an exit condition of one of the commands in it. Its error code is most likely a legacy from DOS. – Nyerguds May 20 '16 at 12:40
  • @Nyerguds Thanks for the comment. It was actually a joke, at the time of writing I was pretty frustrated with the amount things I had tried and none seem to work. Kudos to Microsoft for the things they've done right. – Sergio Basurco May 23 '16 at 07:22
  • You just made my day! – myTerminal Dec 14 '16 at 11:16
  • 17
    In my case with Visual Studio 2017 `$(ConfigurationName)` is empty (Post-build event command line). `if "$(Configuration)" == "Debug"` worked for me. BTW, if you want to do something in all other configs, use `if NOT "$(Configuration)" == "Debug"`. – Ralf Hundewadt Jun 29 '17 at 09:46
  • to the editor: its ROUND brackets that are used here, its windows shell command syntax. – gbjbaanb Oct 12 '17 at 19:22
  • #gbjbaanb , round brackets, eh? Though I've never heard that term applied to parentheses, I knew instantly what you meant. – David A. Gray Oct 07 '18 at 23:23
  • @DavidA.Gray In this case I was explaining to the guy who edited the answer, replacing them with curly brackets, what they should be ;-) – gbjbaanb Oct 08 '18 at 15:18
141

Add your post build event like normal. Then save your project, open it in Notepad (or your favorite editor), and add condition to the PostBuildEvent property group. Here's an example:

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <PostBuildEvent>start gpedit</PostBuildEvent>
</PropertyGroup>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Franci Penov
  • 74,861
  • 18
  • 132
  • 169
  • 6
    This works but it forces you do to all of your design work for the events in the project file source. Other conditional build event declarations are hidden from the the IDE also. – Joseph Daigle Sep 29 '08 at 18:55
  • 3
    I would have to say this is the better answer for me, the preferred method just didn't work. – Michael L Jan 15 '09 at 11:19
  • 11
    You don't need to open it in Notepad, you can stay in Visual Studio. You can rightclick the project-file, click "Unload project", then rightclick again and click "Edit". You can now edit the {{csproj}} file with syntax coloring. Rightclick again, but now click "Reload project" to reload. – Abel May 20 '15 at 01:31
  • 2
    This approach did not expand macros in the PostBuildEvent command itself when I tried it. `cd "$(ProjectDir)"` expanded to `cd ""`. – Darryl Mar 25 '16 at 23:46
  • This is a good answer. It does not rely on the post build actually running but just short circuiting and will be more portable across build environments as a result. – S.C. May 16 '18 at 18:53
  • 12
    In VS 2017 you can also do this with ` `. Macro variables and everything work as normal. – S.C. May 16 '18 at 19:02
  • While this is clean and more in line with how the rest of the csproj file looks, be very careful. If you update the csproj in Visual Studio, especially the post build, you may find it has added a second, _non-conditional_ postbuild entry. – Rhumborl Oct 10 '22 at 17:12
111

Alternatively (since the events are put into a batch file and then called), use the following (in the Build event box, not in a batch file):

if $(ConfigurationName) == Debug goto :debug

:release
signtool.exe ....
xcopy ...

goto :exit

:debug
' Debug items in here

:exit

This way you can have events for any configuration, and still manage it with the macros rather than having to pass them into a batch file, remember that %1 is $(OutputPath), etc.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CestLaGalere
  • 2,909
  • 1
  • 20
  • 20
  • 6
    If you get a chance to look at some of your code in reflector, the compiler transforms a lot of switch/case statements into goto's. – StingyJack Mar 31 '11 at 13:16
  • 10
    Most all compilers do translate code into simpler instructions, such as goto. And reverse engineering can't put together simpler instructions into the "nice" more complex instructions you would rather see. I don't see how Microsoft is enforcing us to use goto, or how this is relevant to this post. – TamusJRoyce Sep 06 '11 at 13:55
  • 1
    @StingyJack: if you look at the compiled code, you'll see all of it is turned into JMP instructions :) I don't care what the compiler does under the covers, as long as I get to write nicely readable code. (not that using goto isn't occasionally very easy to read) – gbjbaanb May 24 '12 at 13:23
  • If I put my post-build commands inside a batch I get this error message when press build: `Error 1 The command "C:\MyProject\postbuild.bat" exited with code 99. MyProject ` – Sebastian Aug 07 '14 at 06:37
  • Okay I fixed it by deleting all empty lines and put it directly inside the post-build textbox and it works?! So ignore my last comment :-) – Sebastian Aug 07 '14 at 09:30
  • 4
    if you want, you can remove the `if` and use `goto :$(ConfigurationName)` – Calimero100582 Aug 07 '15 at 19:00
  • 1
    @gbjbaanb This isn't C# though. This is DOS batch script. And `goto` is and has always been completely normal in DOS batch scripting. – Nyerguds May 20 '16 at 12:44
  • @Nyerguds obviously... I was referring to the script, with gotos, having to be used when writing C# programs. It was light-hearted. – gbjbaanb May 20 '16 at 18:09
  • The only solution that actually worked for me! Thanks so much! – Dmitry Avtonomov Jul 18 '18 at 16:33
  • Once upon a time, my batch scripts were full of GOTO statements. However, once I became accustomed to multiline IF blocks, I have all but eliminated them. After all, it's 2018, and GOTO remains as harmful as ever. – David A. Gray Oct 08 '18 at 06:32
  • @DavidA.Gray GOTO was never harmful when it wasn't abused. It was simply maligned by novice developers who didn't know any better and its "harm" has become simply an urban legend. – Suncat2000 Jun 11 '21 at 12:23
50

As of Visual Studio 2019, the modern .csproj format supports adding a condition directly on the Target element:

<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Debug'">
    <Exec Command="nswag run nswag.json" />
</Target>

The UI doesn't provide a way to set this up, but it does appear to safely leave the Configuration attribute in place if you make changes via the UI.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • 10
    This really deserves to be higher, also they really should update the UI to allow you to mark the Build Configuration or at least add the Condition from csproj properties. – DeadlyChambers Jun 02 '20 at 03:04
18

Visual Studio 2015: The correct syntax is (keep it on one line):

if "$(ConfigurationName)"=="My Debug CFG" ( xcopy "$(TargetDir)test1.tmp" "$(TargetDir)test.xml" /y) else ( xcopy "$(TargetDir)test2.tmp" "$(TargetDir)test.xml" /y)

No error 255 here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eric Bole-Feysot
  • 13,949
  • 7
  • 47
  • 53
5

You can pass the configuration name to the post-build script and check it in there to see if it should run.

Pass the configuration name with $(ConfigurationName).

Checking it is based on how you are implementing the post-build step -- it will be a command-line argument.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lou Franco
  • 87,846
  • 14
  • 132
  • 192
4

As of VS 2022, I have found 2 solutions. In my particular case, I want to pack to a different directory depending on Configuration.

Option 1

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="if $(Configuration) == Debug (dotnet pack --no-build -o ~/../../../../../nuget-repo/debug -p:PackageVersion=$(VersionInfo)) else (dotnet pack --no-build -o ~/../../../../../nuget-repo -p:PackageVersion=$(VersionInfo))" />
</Target>

Option 2

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Condition="'$(Configuration)' == 'Debug'" Command="dotnet pack --no-build -o ~/../../../../../nuget-repo/debug -p:PackageVersion=$(VersionInfo)" />
    <Exec Condition="'$(Configuration)' == 'Release'" Command="dotnet pack --no-build -o ~/../../../../../nuget-repo -p:PackageVersion=$(VersionInfo)" />
</Target>

I prefer option 2.

IAbstract
  • 19,551
  • 15
  • 98
  • 146
2

I found that I was able to put multiple Conditions in the project file just like this:

  <Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition=" '$(Configuration)' != 'Debug' AND '$(Configuration)' != 'Release' ">
      <Exec Command="powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File $(ProjectDir)postBuild.ps1 -ProjectPath $(ProjectPath) -Build $(Configuration)" />
  </Target>
plcnut
  • 43
  • 5
  • Funnily enough, not only did this answer my question on Condition, but also solved exactly what I was looking for: running Powershell as part of the VS Build. So I am sending you 100000000000 upvotes and YOU WIN. – Frank Jun 09 '22 at 15:18
-1

This works for me in Visual Studio 2015.

I copy all DLL files from a folder located in a library folder on the same level as my solution folder into the targetdirectory of the project being built.

Using a relative path from my project directory and going up the folder structure two steps with..\..\lib

MySolutionFolder
....MyProject
Lib

if $(ConfigurationName) == Debug (
xcopy /Y "$(ProjectDir)..\..\lib\*.dll" "$(TargetDir)"
) ELSE (echo "Not Debug mode, no file copy from lib")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jaan Marks
  • 19
  • 2
-3

In Visual Studio 2012 you have to use (I think in Visual Studio 2010, too)

if $(Configuration) == Debug xcopy

$(ConfigurationName) was listed as a macro, but it wasn't assigned.

Enter image description here

Compare: Macros for Build Commands and Properties

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mawl
  • 453
  • 1
  • 6
  • 16
-3

Like any project setting, the buildevents can be configured per Configuration. Just select the configuration you want to change in the dropdown of the Property Pages dialog and edit the post build step.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Harald Scheirich
  • 9,676
  • 29
  • 53