How to handle post-build events in an Azure pipeline? - visual-studio

I can build a solution locally and in one project I have post-build events:
xcopy "$(SolutionDir)pluginfolder\bin\Debug\net48\pluginname.*" "$(TargetDir)" /Y
I do this because the target project doesn't have a reference to the plugin projects.
Now I'm trying to move to an Azure pipeline. I created an MSBuild task that builds just the target project and not the complete solution, and I get the following error on running in a self-hosted agent:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(5266,5): Error MSB3073: The command "xcopy "Undefinedpluginfolder\bin\Debug\net48\pluginname.*" "C:\agent_work\5\s\myproj\bin" /Y ended with Code 4.
What is the best approach to solve this issue?

"Undefinedpluginfolder\bin\Debug\net48\pluginname.*"
The $(SolutionDir) is recognized as Undefined, this is because msbuild has no knowledge about the solution when building a single project.
As workaround, you can insert the following script above the script of PostBuild event. Something like:
<PropertyGroup>
<ProjectFolder>$([System.IO.Directory]::GetParent($(ProjectDir)))</ProjectFolder>
<MySolutionDir>$([System.IO.Directory]::GetParent($(ProjectFolder)))\</MySolutionDir>
It's recommended to add my script and PostBuildEvent in same propertyGroup
<PostBuildEvent>echo $(MySolutionDir)</PostBuildEvent>
</PropertyGroup>
Command line:
xcopy "$(MySolutionDir)pluginfolder\bin\Debug\net48\pluginname.*" "$(TargetDir)" /Y
You can refer to this ticket with similar issue.

Related

Is it possible to run a postbuildevent in an Azure Devops .yaml pipeline build event containing macros such as $(TargetPath)?

I'm trying to automatically rename the .dll resulting from VSBuild so it includes the version number. In order to do this I've tried to create a postbuild event in DevOps.
- task: VSBuild#1
inputs:
solution: '$(solution)'
msbuildArgs: '/p:PostBuildEvent="rename $(TargetPath) $(TargetDir)$(TargetName).$(buildNumber)$(TargetExt)"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
This post build event works fine when I put it in Visual Studio and run it locally. However, I don't want users to be able to change it, so I don't want to define it in Visual Studio but in the pipeline(.yaml) itself. On DevOps I get the following result:
PostBuildEvent:
rename $(TargetPath) $(TargetDir)$(TargetName).20221003.8$(TargetExt)
The system cannot find the file specified.
##[error]C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(5707,5): Error MSB3073: The command "rename $(TargetPath) $(TargetDir)$(TargetName).20221003.8$(TargetExt)" exited with code 1.
It seems as though the postbuild event macros, such as $(TargetPath), which are recognized in Visual Studio are not recognized when running the post build event through DevOps pipelines. Is this correct? If so, is there any way around it? I'd prefer not to hardcode anything since I want to reuse the pipeline for multiple repos/solutions with a variable number of projects and project names.
Thanks a lot!

MSB3073 exited with code 3 - Post Build Event in Visual Studio 2017

I am trying to perform registration of the DLL which was created during Build.
In project properties -> Build Events -> Post-Build-Event i have added the below command to perform registration,
regsvr32 /s /c "$(TargetPath)"
This command is used to perform registration of the DLL specified in Target Path.
When i try to Build my code, i am facing following error,
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(138,5):
error MSB3073: The command "regsvr32 /s /c "D:\Project\Debug\x64\SDK.dll"
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(138,5):
error MSB3073: :VCEnd" exited with code 3.
On clicking the error, it navigates to below tags within Microsoft.CppCommon.targets
<Target Name="PostBuildEvent" Condition="'$(PostBuildEventUseInBuild)'!='false'">
<Message Text="%(PostBuildEvent.Message)" Condition="'%(PostBuildEvent.Message)' != '' and '%(PostBuildEvent.Command)' != ''" Importance="High" />
<Exec Command="%(PostBuildEvent.Command)$(_BuildSuffix)" Condition="'%(PostBuildEvent.Command)' != ''"/>
I searched for error MSB3073: :VCEnd" exited with code 3 in few links and found that it occurs when the path specified is invalid or could not be found.
However, the path of the DLL was in the location i specified. I even tried to provide absolute path of DLL within the Post-Build-Event. Yet i'm facing same error.
Am i missing something while performing Post-Build-Event or is there anything to do with regsvr32 command?
MSB3073 exited with code 3 - Post Build Event in Visual Studio 2017
The issue is related to your dynamic library project and not related to VS.
And when you want to register a com dll, the dll project should contain a ID to register into system. However, the dynamic library project does not have the ID by default. So this type of project cannot used as DLLs that will to be registered.
If you still want to use dynamic library project, you should implement DllRegisterServer to add the ID.
You can use ATL projects which contain the ID as dll projects .
This is a similar issue about it.
Solution
1) Instead, you should create ATL projects.
2) Then, in the command, you should remove /c which was abandoned so far.
Or use like this command:
regsvr32 /n /i "$(TargetPath)" as command in post-build event.
=====================
Update 1
Since your project is an old WRT project, you can just create a new WRT runtime component project in VS2017 and then migrate the content of your old project into the new one. It will save you a lot of time and avoid a lot of tedious mistakes.
1) Please install C++/WinRT vs extension first.
2) Then create a new windows runtime componment project and then migrate your old project's content into the new one.
In my side, the project can works well with command regsvr32 /n /i "$(TargetPath)".

Post build event not working with msbuild

I have a solution that references multiple projects. In one of those referenced project I added the following Post-Event (to copy it's .exe file to the solution output).
xcopy /y "$(TargetName).*" "$(SolutionDir)UIBackendSSRSReports\$(OutDir)"
This works perfectly when compiling from Visual Studio, but when running from msbuild it fails (exited with code 4).
Seems like when using msbuild the values of OutDir (as well as the other macros) are different.
ex: $(OutDir)
In VS = D:\Workspace-ET\source_SSRSBackEnd\Common\BackEnd Automation\BackEndSSRSReports\UIBackendSSRSReports\bin\Debug
In msbuild = " D:\B\1\Src_PMC-QA-Automation\BackEndSSRSReports_ssrsBranch\bin\
Not sure why they are so different, any ideas? We build with a buildAgent and buildController TFS setup

devenv.com won't start without a desktop session

I'm setting up a Jenkins job for a Windows 10 application.
I need to compile one of the four projects inside the solution with devenv.com executable because it is a project with .vdproj extension (setup project).
The other projects are built successfully with MSBuild without any problem.
The Jenkins job ends successfully when I'm logged in as root on a Jenkins target node, but, fails when I run the job from Jenkins and I'm not logged in.
Need your help or workaround to solve the issue.
PS: we are using ant as task runner and we have a specific task that start the build process.
EDIT 26/01/2017
I would like to provide you other informations like the error message and one step that I've skipped before.
The error message provides a link to a Microsoft Page and reports a configuration problem.
As solved by this StackOverflow post, I've added a new DWORD registry key under
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0_Config\MSBuild\EnableOutOfProcBuild
Can the problem be that this value can't be readed when the User is'nt logged in ?
EDIT 27/01/2017
I'm going crazy with this issue.
The command devenv /? work fine when i run it locally but wont work when i run it from Jenkins with the same error as before: Microsoft Visual Studio found a configuration problem. To fix it restart as administrator or visit http://go.microsoft.com/fwlink/?LinkId=659046 for further information.
So the devenv.com cannot be executed when i'm not logged in ??
UPDATED 31/01/2017#
Here's my .bat file called from a target by ant build.xml
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat"
#set MSBUILD="C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe"
%MSBUILD% "%cd%\src\AutomatedSetupBuild.proj"
pause
Where the AutomatedSetupBuild.proj is an MSBuild script
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="Build">
<PropertyGroup>
<DevEnv>C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.com</DevEnv>
<SolutionFile>$(MSBuildProjectDirectory)\MySolution.sln</SolutionFile>
<ProjectFile>MySetupProject\MySetupProject.vdproj</ProjectFile>
<Configuration>Release</Configuration>
</PropertyGroup>
<Exec
Command=""$(DevEnv)" "$(SolutionFile)" /Rebuild "$(Configuration)" /Project "$(ProjectFile)" /ProjectConfig "$(Configuration)" /Log vs.log /useenv"
ContinueOnError="false"
IgnoreExitCode="false"
WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
</Project>
As you can see, I'm loading the environment variable before run devenv.com but i receive the same error.
Do you use a free style job or do you use a Jenkinsfile for a pipeline project? In any case, for devenv.com to work, environment variables have to be set up.
Please go to the Windows start menu and look for something like Visual Studio XX -> Visual Studio Tools -> Developer Command Prompt for VS20XX. Press right mouse bottom and select properties. There look for target. In my case this field contains the following string:
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat""
If you use e.g. a Jenkinsfile, change the call to devnenv.com, which probably looks like
bat "devenv.com my_solution_file.sln /project my_project /build \"Release|x64\""
to
bat "call \"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat\"; devenv.com my_solution_file.sln /project my_project /build \"Release|x64\""
It is important, that the call to the VsDevCmd.bat is within the same bat command. Otherwise the environment variable settings get lost and are not seen by a second call to bat.
Open the dev command prompt type "where devenv" then call the full path with the .com version... e.g.
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.com" /Rebuild "RELEASE|Win32" "F:\project.sln"
For my part, I had to convert the Visual Studio 2015 SSRS project to SSRS Visual Studio 2017. Then I installed the 2017 SSDT for VS 2017, and use MSBUILD. Everything works well without open remote session.

Publish a Web Application from the Command Line

I've got a series of .NET 4 based web applications (WCF and Web) within the same solution, but need to selectively publish, from the command line.
I've tried various things so far, MSBuild, aspnet_compiler, but nothing, to date has worked.
I need to be able to specify the Project, not the solution, have any transforms run and have the output redirected to a folder...basically mimick the right mouse click 'Publish' option, using the File System.
In addition to all of this, I'd like to leave the projects alone - not adding msbuild files all over the place, as this is a specific build, and not necessarily related to the project.
Stuff I've tried:
Publish ASP.NET MVC 2 application from command line and Web.config transformations
Equivalent msbuild command for Publish from VS2008
Save the following script as publishProject.bat
rem publish passed project
rem params: %configuration% %destDir% %srcDir% %proj%
#echo off
SET DestPath=d:\projects\Publish\%2
SET SrcPath=d:\projects\Src\%3\
SET ProjectName=%4
SET Configuration=%1
RD /S /Q "%DestPath%" rem clear existed directory
:: build project
MSBuild "%SrcPath%%ProjectName%.vbproj" /p:Configuration=%Configuration%
:: deploy project
::/t:TransformWebConfig
MSBuild "%SrcPath%%ProjectName%.vbproj" /target:_CopyWebApplication /property:OutDir=%DestPath%\ /property:WebProjectOutputDir=%DestPath% /p:Configuration=%Configuration%
xcopy "%SrcPath%bin\*.*" "%DestPath%\bin\" /k /y
echo =========================================
echo %SrcPath%%3.vbproj is published
echo =========================================
I call it from another batch file
#echo off
rem VS2010. For VS2008 change %VS100COMNTOOLS% to %VS90COMNTOOLS%
call "%VS100COMNTOOLS%\vsvars32.bat"
SET ex=.\publishProject.bat Release
call %ex% KillerWebApp1 KillerWebApp1\KillerWebApp1 KillerWebApp1
call %ex% KillerWebApp2 KillerWebApp2\KillerWebApp2 KillerWebApp2
call %ex% KillerWebApp3 KillerWebApp3\KillerWebApp3 KillerWebApp3
call %ex% KillerWebApp4 KillerWebApp4\KillerWebApp4 KillerWebApp4
EDIT:
Code above works for most cases but not for all. I.e. we use another asp .net application and link it as virtual folder in IIS. For this situation VS2008 worked fine with code above but VS2010 also copy files from virtual directory while deploying. The following code works properly also in VS2010 (solution was found here)
Add to your project file (*.csproj, *.vbproj)
<Target Name="PublishToFileSystem" DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
<Error Condition="'$(PublishDestination)'==''" Text="The PublishDestination property must be set to the intended publishing destination." />
<MakeDir Condition="!Exists($(PublishDestination))" Directories="$(PublishDestination)" />
<ItemGroup>
<PublishFiles Include="$(_PackageTempDir)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(PublishFiles)" DestinationFiles="#(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="True" />
</Target>
Change publishProject.bat to:
rem publish passed project
rem params: %configuration% %destDir% %srcDir% %proj%
#echo off
SET DestPath=d:\projects\Publish\%2
SET SrcPath=d:\projects\Src\%3\
SET ProjectName=%4
SET Configuration=%1
:: clear existed directory
RD /S /Q "%DestPath%"
:: build and publish project
MSBuild "%SrcPath%%ProjectName%.vbproj" "/p:Configuration=%Configuration%;AutoParameterizationWebConfigConnectionStrings=False;PublishDestination=%DestPath%" /t:PublishToFileSystem
I know this is an old question, but I just learned something, so I decided I'd share: While it is 100% true that the "_CopyWebApplication" target exists and works, as of .NET 4.0 it has been superseded by the "_WPPCopyWebApplication" target in Microsoft.Web.Publishing.targets, which supports new features like web.config transformation syntax, etc.
Have you checked out WebDeploy?
This should do all the steps you need to have - it can bundle up a web app into a deployable file (a ZIP, basically), and there's an "engine" on the server that can interpret that deployable package and do all the heavy lifting for you.
Also see Scott Hanselman's Web Deployment Made Awesome: If You're Using XCopy, You're Doing It Wrong blog post - very enlightening!
My solution for CCNET with the Web.config transformation:
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe</executable>
<workingDirectory>E:\VersionesCC\Trunk_4\SBatz\Gertakariak_Orokorrak\GertakariakMS\Web</workingDirectory>
<projectFile>GertakariakMSWeb2.vbproj</projectFile>
<targets>Build</targets>
<timeout>600</timeout>
<logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll</logger>
<buildArgs>
/noconsolelogger /p:Configuration=Release /v:diag
/p:DeployOnBuild=true
/p:AutoParameterizationWebConfigConnectionStrings=false
/p:DeployTarget=Package
/p:_PackageTempDir=E:\Aplicaciones\GertakariakMS2\Web
</buildArgs>
</msbuild>
</tasks>

Resources