Error MSB4062 when trying to use ServiceController - visual-studio-2010

I use Visual Studio 2010 with TFS 2010 on a x64 machine.
I am trying to use the MSBuild Community Tasks target in my build. This target exists in source control. So in my csproj file i am import that particular target but i now get the following error:
error MSB4062: The "MSBuild.Community.Tasks.Attrib" task could not be loaded from the assembly C:\Program Files (x86)\MSBuild\MSBuildCommunityTasks\MSB
uild.Community.Tasks.dll. Could not load file or assembly 'file:///C:\Program F
iles (x86)\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll' or one of
its dependencies. The system cannot find the file specified. Confirm that the
declaration is correct, that the assembly and all its dependencies
are available, and that the task contains a public class that implements Micros
oft.Build.Framework.ITask. [C:\SampleTest\SampleTest.csproj]
Here is my code:
<Import Project="..\..\Builds\Common\MSBuildTasks\MSBuild.Community.Tasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
<PropertyGroup>
<MyService>ServiceName</MyService>
</PropertyGroup>
<ServiceController ServiceName="$(MyService)" Action="Stop" />-->
</Target>
Any thoughts on the above?
Why is MSBuild trying to look for the dll elsewhere when i have specified it in the project file?
Thanks in advance,

I think the problem comes from within the MSBuild.Community.Tasks.Targets file - it is this file that actually references the MSBuild.Community.Tasks.dll assembly.
If you open the file you can see a bunch of UsingTask elements, such as:
<UsingTask AssemblyFile="$(MSBuildCommunityTasksLib)" TaskName="MSBuild.Community.Tasks.Attrib" />
The $(MSBuildCommunityTasksLib) property is defined at the top of the file as:
<PropertyGroup>
<MSBuildCommunityTasksPath Condition="'$(MSBuildCommunityTasksPath)' == ''">$(MSBuildExtensionsPath)\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
<MSBuildCommunityTasksLib>$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.dll</MSBuildCommunityTasksLib>
</PropertyGroup>
So it looks like you need to set the $(MSBuildCommunityTasksPath) property before calling <Import>.

Related

MSBuild - want to get the output assembly

I have a .targets file in a folder named .pack I have this:
<PropertyGroup>
<TaskAssembly>$(OutputPath)netstandard2.1\Test.dll</TaskAssembly>
</PropertyGroup>
Why instead of MyProject\bin\Debug\netstandard2.1\MyProject.dll it locates like the below line?
MyProject\.pack\bin\Debug\netstandard2.1\MyProject.dll
Why .pack is there!?
Then wanted to use it with a Using task
<UsingTask
TaskName="brand.ProBuild.Tasks.TestFunction"
AssemblyFile="$(TaskAssembly)"
/>
Defined as inline address, played with slashes, cleared bin/obj, restarted, don't why it can't understand some addresses.
Defined and used several path variables in my targets files, some working correctly and some are troublesome especially when want to use parents or some problems with slashes '/', don't know maybe some addresses are working randomly. But what is wrong with the $(OutputPath) ?!
Visual-studio 2019, .Net Standard 2.1 (It has multiple targets I want to get that specific dll)
You should check in your main project, before the import node like <Import Project=".pack\xxx.targets" />, check whether you defined the outputpath property again like
<outputpath>.pack\bin\Debug\</outputpath>
Suggestion
From your description, you created a custom MSBuild task dll to use its new custom task in another project, first, please make sure that the Test.dll is in the output folder of your project called MyProject.
Then, check whether you have redefined the outputpath before the import xml node.
Like this:
<PropertyGroup>
<outputpath>.pack\bin\Debug\</outputpath>
</PropertyGroup>
..........
<Import Project=".pack\xxx.targets" />
........
<UsingTask
TaskName="brand.ProBuild.Tasks.TestFunction"
AssemblyFile="$(TaskAssembly)"
/>
If so, you should change OutputPath to bin\Debug\.
In addition, if it does not help you, please share the xxx.csproj of project MyProject with us so that we can troubleshoot your issue more quickly.
Update 1
Since you have only one targets file in your project, I suggest you could follow these suggestions:
1) close VS Instance, enter your project folder, delete the .vs hidden folder under the solution folder, bin and obj folder. Then ,restart your project to test again.
2) you can define the correct value in the xxx.csproj file before the imports xml node to force the correct value of outputPath.
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<OutputPath>bin\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<OutputPath>bin\Release\</OutputPath>
</PropertyGroup>
.......
<Import Project="xxx.targets"/>

Difficulty using <Import> to modularize a Visual Studio project file

I'm attempting to modularize a Visual Studio project file, but it's not working. This is for Visual Studio 2008 with .Net 3.5.
Shown below, the first example works, but the second one does not. How can I make it work..?
I'm new to this topic and probably missing something. I first became aware of it while reading a 3rd-party blog, and then found it in the documentation too. I've googled for more help, but there's too much information for me to find a relevant answer.
The main project file:
...
<!-- main project file -->
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Target Name="AfterBuild">
<Message Text="This is a message from the *.vbproj file."/> ... this works
</Target>
</Project>
...but if <Import> is used, with the same <Target> and <Message> in the imported file, it doesn't work. MSBuild seems to process everything correctly, but nothing happens...
The main project file:
...
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Import Project="$(MSBuildProjectDirectory)\CustomBuildEvents.targets" /> ... new tag
<Target Name="AfterBuild">
<Message Text="This is a message from the *.vbproj file."/> ... this still works
</Target>
</Project>
The imported targets file:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild">
<Message Text="Hello from the imported file." Importance ="high"/> ... doesn't work
</Target>
</Project>
And the build output, with Verbosity set to Diagnostic:
### Halfway through the output, this is the only mention of the imported file. ###
None
CustomBuildEvents.targets ... custom file
My Project\Application.myapp
My Project\Settings.settings
### And then at the end, no mention of the imported file or its message. ###
Done building target "CoreBuild" in project "MsBuildCustomTargetTester.vbproj".
Target "AfterBuild" in file "C:\Visual Studio 2008\Solutions\MsBuildCustomTargetTester\MsBuildCustomTargetTester\MsBuildCustomTargetTester.vbproj":
Task "Message"
Hello from the *.vbproj file. ... message from main file
Done executing task "Message".
Done building target "AfterBuild" in project "MsBuildCustomTargetTester.vbproj".
Target "Build" in file "c:\WINDOWS\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets":
Building target "Build" completely.
No input files were specified.
Done building target "Build" in project "MsBuildCustomTargetTester.vbproj".
Done building project "MsBuildCustomTargetTester.vbproj".
Project Performance Summary:
109 ms C:\Visual Studio 2008\Solutions\MsBuildCustomTargetTester\MsBuildCustomTargetTester\MsBuildCustomTargetTester.vbproj 1 calls
The problem with AfterBuild is that it can only be defined once. So if you import it and then later in the project file define it again, the last definition wins and becomes the only definition.
To solve this you need to use the more advanced way to register events. Given that you are using Visual Studio 2008 (WHY?!), you need to use the more advanced syntax for your custom targets files:
<Project>
<!--
Redefines the original build order, includes the standard targets and
adds your new custom target to the end of the list.
-->
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomTarget
</BuildDependsOn>
</PropertyGroup>
<CustomTarget>
<!-- Imported after Build -->
<Message Text="Hello from the imported file." Importance ="high"/>
</CustomTarget>
</Project>
There are other ways to do this which were introduced in MsBuild 4 with the BeforeTargets and AfterTargets attributes on any target, but If I'm remembering correctly the above syntax should also work with the version of MsBuild that ships with Visual Studio 2008.
See also:
What is the difference between 'DependsOnTargets' and 'AfterTargets'?
https://blogs.msdn.microsoft.com/msbuild/2006/02/10/how-to-add-custom-process-at-specific-points-during-build-method-2/

Why does overriding the Build target in msbuild work for C++ projects but fail for C# projects?

I am overriding the Build target like this in my file OverrideBuild.targets:
<Target Name="OriginalBuild" DependsOnTargets="$(BuildDependsOn)">
<Message Text="Finished running target OriginalBuild" Importance="High" />
</Target>
<Target Name="Build" >
<CheckArtifacts ProjectGuid = "$(ProjectGuid)" SolutionPath = "$(SolutionPath)" >
<Output PropertyName = "ArtifactsHaveChanged" TaskParameter = "Result" />
</CheckArtifacts>
<Message Text="ArtifactsHaveChanged = $(ArtifactsHaveChanged)" Importance="high" />
<!-- if the artifacts.props file has not just been updated then we can run the original build target -->
<Message Condition="'$(ArtifactsHaveChanged)' == 'false'" Text="Running target OriginalBuild" Importance="High" />
<CallTarget Condition="'$(ArtifactsHaveChanged)' == 'false'" Targets="OriginalBuild" />
<!-- Otherwise we need to run a new msbuild to avoid using an out-of-date cached version of the artifacts.props file.
To force the msbuild process not to use the cached values from this process we must pass at least one property.
-->
<Message Condition="'$(ArtifactsHaveChanged)' == 'true'" Text="Running target OriginalBuild in nested msbuild" Importance="High" />
<MSBuild Condition="'$(ArtifactsHaveChanged)' == 'true'" Targets="OriginalBuild"
Projects="$(MSBuildProjectFullPath)" Properties="InNestedMsbuild=true" />
<!-- Visual Studio doesn't pick up on the modified artifacts.props file unless we force it to reload the solution -->
<Touch Condition="'$(ArtifactsHaveChanged)' == 'true' and '$(BuildingInsideVisualStudio)' == 'true'" Files = "$(SolutionPath)" />
<Message Text="Finished running build target override" Importance="High" />
</Target>
and each of my .vcxproj or .csproj files includes this file at the end:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\OverrideBuild.targets" />
</Project>
This works as I want it to for the C++ projects but fails with the C# projects. When building a C# project via msbuild it fails because the command line to the C# compiler is missing reference arguments for local assemblies. For example, a C# file that has a line like this at the top of the file:
using My.Utils.Common;
fails with the following error message:
error CS0234: The type or namespace name 'Common' does not exist in the namespace 'My.Utils' (are you missing an assembly reference?)
And looking at the compiler command used it is missing this line:
/reference:C:\Code\scratch\Build\My.Utils.Common\Bin\Release\My.Utils.Common.dll
That missing line is present when I comment out my override of the Build target. And weirdly enough it will build fine from within Visual Studio even with my Build override in place. It only fails when building using msbuild from the command line and only for C# projects.
I thought that the way I had overriden the Build target would be completely transparent but apparently it isn't. Can anybody shed some light on what is going wrong ?
It seems that when project A depends on project B with a project reference, the outputs of the Build target of B are used to deduce what should be passed as a reference to the compiler when building A. This is presumably somewhere in the ResolveAssemblyReferences logic.
Therefore to get your replacement Build target working, you need to make its outputs match those of the standard Build.
Here is how you can achieve this:
<Target
Name="Build"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="GetTargetPathWithTargetPlatformMoniker"
Returns="#(TargetPathWithTargetPlatformMoniker)" >
</Target>
Here Returns="#(TargetPathWithTargetPlatformMoniker)" is what the Returns of the standard Build in the SDK is. But the item array #(TargetPathWithTargetPlatformMoniker) is initially empty, so you need to run the Target GetTargetPathWithTargetPlatformMoniker to populate it before hand.
These are implementation details of the build system, so they may vary by SDK version, but you can always inspect the logic in C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.target or equivalent.
Note that this cannot be used directly with C++ projects, their default Build target is a bit different. You may need to vary by the project type to support both. The Condition on a Target does not stop it from overwriting the existing one, it only stops it from executing, so if you need a target overwrite to differ, you need to put the alternatives in files and import them conditionally. I don't know of a more convenient way, but that at least works.
Why does overriding the Build target in msbuild work for C++ projects but fail for C# projects?
After test your sample, I found the error not comes from the overriden the Build target, it should be related to the project type which you referenced.
Because I have tried comment the import line in the HelloWorld project file:
<Import Project="..\..\OverrideBuild.targets" />
Then MSBuild command line still throw that error.
Besides, I found your referenced project HelloWorldHelper is a Console application project, which output type is Class library.
To resolve this issue, I have created a new Class library instead of Console application, then build it from MSBuild command line, it works fine.
So, please try to convert your referenced project to Class library.
Hope this helps.

Visual Studio 2017 not loading AjaxMin MSBuild Task from specified path

I'm attempting update an existing application so that it will load in Visual Studio 2017 (Enterprise - V15.2 (26430.12)) from Visual Studio 2015 (Enterprise) and having issues with the AjaxMin build task.
In Visual Studio 2015, the AjaxMin build task is found in C:\Program Files (x86)\MSBuild\Microsoft\MicrosoftAjax. Visual Studio 2017 looks for it in C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft. Given that all developers on the team may not have VS2017 Enterprise and we've had issues in the past with developers installing the wrong version, I'd like to have it use the AjaxMin NuGet package referenced in the solution.
There are 3 projects in the solution that use the AjaxMin task. I've updated all of them to have the following import:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
...
<Import Project="$(MSBuildProjectDirectory)\..\..\..\packages\AjaxMin.5.14.5506.26202\tools\net40\AjaxMin.targets" />
<Target Name="BeforeBuild">
<ItemGroup>
<JS Include="..." Exclude="..." />
</ItemGroup>
<ItemGroup>
<CSS Include="..." Exclude="..." />
</ItemGroup>
<AjaxMin Switches="..." JsSourceFiles="#(JS)" JsCombinedFileName="..." CssSourceFiles="#(CSS)" CssCombinedFileName="..." />
</Target>
...
</Project>
However, when the build happens, I receive an error saying it can't find the AjaxMin task in the default build extensions directory:
The "AjaxMin" task could not be loaded from the assembly C:\Program
Files (x86)\Microsoft Visual
Studio\2017\Enterprise\MSBuild\Microsoft\MicrosoftAjax\AjaxMinTask.dll.
Could not load file or assembly 'file:///C:\Program Files
(x86)\Microsoft Visual
Studio\2017\Enterprise\MSBuild\Microsoft\MicrosoftAjax\AjaxMinTask.dll'
or one of its dependencies. The system cannot find the file specified.
Confirm that the declaration is correct, that the assembly
and all its dependencies are available, and that the task contains a
public class that implements Microsoft.Build.Framework.ITask.
I've used the MSBuild Message Task to output the path and verified that it is correct by navigating to it from the command prompt. I also tried using the UsingTask with no luck there.
Why is Visual Studio not looking for the AjaxMin DLL in the location I specified?
Update:
I moved the import tag for AjaxMin to the top (right under the project tag) and it works now. I don't understand why.
I resolved this issue by installing the .Net 3.5 framework
The issue turned out being another import for another third party build task. It appears that build task alters the build process such that the AjaxMin build task won't work after it. Having the AjaxMin build task after the Microsoft.CSharp.Targets import but before the other third party build task did the trick.
I moved the import tag for AjaxMin to the top (right under the project tag) and it works now. I don't understand why.
If I understand your question correctly, that is because you have two reference sources for the AjaxMinTask.dll, one is the default assembly source:C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\MicrosoftAjax, another is the import reference, you will notice that the AjaxMinTask.dll is used in the AjaxMin.targets:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMin" />
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMinBundleTask" />
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMinManifestTask" />
<UsingTask AssemblyFile="AjaxMinTask.dll" TaskName="AjaxMinManifestCleanTask" />
...
</Project>
So when set the import reference behind your task, MSBuild will use the default assembly source (under the VS2017 installation directory), when you set the import reference before you task, the AjaxMin.targets will rewrite the path of reference source.

Is there an MSBuild macro for the SharePoint project type package name?

I have a Visual Studio 2010/2012 solution with several SharePoint 2010 projects. On build or package event I want VS to auto-copy the output WSP and PDB files to a common folder at the root of my solution so I don't have to manually grab them from each project's bin\$(Configuration) folder.
I added the following elements to each project file:
<Target Name="CopyPackage">
<Exec WorkingDirectory="$(PackagePath)" Command="copy "$(TargetDir)$(TargetName).wsp" "$(SolutionDir)Builds\$(TargetName).wsp"" ContinueOnError="False" />
<Exec WorkingDirectory="$(PackagePath)" Command="copy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)Builds\$(TargetName).pdb"" ContinueOnError="False" />
</Target>
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn);CreatePackage;CopyPackage</BuildDependsOn>
</PropertyGroup>
So far so good, that works fine.
Each project Package name controls the name of the output WSP file and can be different than the name of the output assembly DLL file.
Visual Studio SharePoint Project Package Name http://imageshack.us/a/img842/322/vsspprojectpackagename.png
In this example the WSP will be named Acme.Edms.SP.ContentTypes.WSP.
It happens that I want my WSP to use a somewhat different name from the project and assembly. But if I change the Package name it breaks the CopyPackage target which uses $(TargetName) that maps to the assembly name.
Is there an MSBuild macro for the (SharePoint) package name so I can fix the above MSBuild elements in my project files?
More generally, does MSBuild have a set of macros specific to the SharePoint project and item types?
Something equivalent to Macros for Build Commands and Properties.
Thanks
Here is the list of SharePoint specific MSBuild properties and there is nothing about package name. So you have to use workaround for that e.g.
First you get lists of package files and pdb files like that:
<ItemGroup>
<PackageFiles Include="$(BasePackagePath)\*.$(PackageExtension)" />
<PdbFiles Include="$(BasePackagePath)\*.pdb)" />
</ItemGroup>
And then you can use it in regular copy command.
I didn't test it but it should work.

Resources