├── .gitattributes ├── .gitignore ├── .idea └── .idea.custom-msbuild-task │ └── .idea │ └── runConfigurations │ ├── Pack__Unix_.xml │ ├── Publish_CustomTasks__Unix_.xml │ ├── Publish_CustomTasks__Win_net472_.xml │ ├── Publish_CustomTasks__Win_netcoreapp6_0_.xml │ ├── Run_TestProject__Unix_.xml │ ├── Run_TestProject__Win_net472_.xml │ └── Run_TestProject__Win_netcoreapp6_0_.xml ├── ExecTask ├── Class1.cs └── ExecTask.csproj ├── Final ├── Final.csproj └── Program.cs ├── InlineTask └── InlineTask.csproj ├── README.md ├── custom-msbuild-task.sln ├── debugging.png ├── global.json ├── pack.cmd └── src ├── CustomTasks ├── ContextAwareTask.cs ├── CustomTask.cs ├── CustomTasks.csproj ├── CustomTasks.props └── CustomTasks.targets ├── Directory.Build.props ├── MainLibrary ├── MainLibrary.csproj ├── MainLibrary.props ├── MainLibrary.targets └── Utility.cs └── TestProject ├── Program.cs ├── TestProject.csproj └── msbuild.binlog /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | *.DotSettings text eol=lf 7 | *.sh text eol=lf 8 | 9 | ############################################################################### 10 | # Set default behavior for command prompt diff. 11 | # 12 | # This is need for earlier builds of msysgit that does not have it on by 13 | # default for csharp files. 14 | # Note: This is only used by command line 15 | ############################################################################### 16 | #*.cs diff=csharp 17 | 18 | ############################################################################### 19 | # Set the merge driver for project and solution files 20 | # 21 | # Merging from the command prompt will add diff markers to the files if there 22 | # are conflicts (Merging from VS is not affected by the settings below, in VS 23 | # the diff markers are never inserted). Diff markers may cause the following 24 | # file extensions to fail to load in VS. An alternative would be to treat 25 | # these files as binary and thus will always conflict and require user 26 | # intervention with every merge. To do so, just uncomment the entries below 27 | ############################################################################### 28 | #*.sln merge=binary 29 | #*.csproj merge=binary 30 | #*.vbproj merge=binary 31 | #*.vcxproj merge=binary 32 | #*.vcproj merge=binary 33 | #*.dbproj merge=binary 34 | #*.fsproj merge=binary 35 | #*.lsproj merge=binary 36 | #*.wixproj merge=binary 37 | #*.modelproj merge=binary 38 | #*.sqlproj merge=binary 39 | #*.wwaproj merge=binary 40 | 41 | ############################################################################### 42 | # behavior for image files 43 | # 44 | # image files are treated as binary by default. 45 | ############################################################################### 46 | #*.jpg binary 47 | #*.png binary 48 | #*.gif binary 49 | 50 | ############################################################################### 51 | # diff behavior for common document formats 52 | # 53 | # Convert binary document formats to text before diffing them. This feature 54 | # is only available from the command line. Turn it on by uncommenting the 55 | # entries below. 56 | ############################################################################### 57 | #*.doc diff=astextplain 58 | #*.DOC diff=astextplain 59 | #*.docx diff=astextplain 60 | #*.DOCX diff=astextplain 61 | #*.dot diff=astextplain 62 | #*.DOT diff=astextplain 63 | #*.pdf diff=astextplain 64 | #*.PDF diff=astextplain 65 | #*.rtf diff=astextplain 66 | #*.RTF diff=astextplain 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | 8 | # User-specific files 9 | *.suo 10 | *.user 11 | *.sln.docstates 12 | *.cache 13 | 14 | # Build results 15 | /output 16 | [Dd]ebug/ 17 | [Rr]elease/ 18 | 19 | /.vs 20 | /.idea 21 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Pack__Unix_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Publish_CustomTasks__Unix_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Publish_CustomTasks__Win_net472_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Publish_CustomTasks__Win_netcoreapp6_0_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Run_TestProject__Unix_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Run_TestProject__Win_net472_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /.idea/.idea.custom-msbuild-task/.idea/runConfigurations/Run_TestProject__Win_netcoreapp6_0_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /ExecTask/Class1.cs: -------------------------------------------------------------------------------- 1 | namespace ExecTask; 2 | 3 | public class Class1 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /ExecTask/ExecTask.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Final/Final.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Final/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | Console.WriteLine("Hello, World!"); 4 | 5 | MainLibrary.Utility.Foo(); 6 | -------------------------------------------------------------------------------- /InlineTask/InlineTask.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Custom MSBuild Task 2 | 3 | Run Configurations for [JetBrains Rider](https://jetbrains.com/rider) are included and allow seamless debugging: 4 | 5 | ![Run Configurations for JetBrains Rider](debugging.png) 6 | 7 | ⚠️ Note that the [specific SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1#3.1.6) according to the [`global.json` file](https://github.com/matkoch/custom-msbuild-task/blob/master/global.json#L3) must be installed. The best way is to use the [InstallSdkGlobalTool](https://www.nuget.org/packages/InstallSdkGlobalTool/) and call `dotnet-install-sdk` inside the repository. 8 | -------------------------------------------------------------------------------- /custom-msbuild-task.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomTasks", ".\src\CustomTasks\CustomTasks.csproj", "{92C7175C-5076-4FEC-8B37-23D433F91694}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MainLibrary", "src\MainLibrary\MainLibrary.csproj", "{E005996F-DD54-49E7-B79C-171B6157F752}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "src\TestProject\TestProject.csproj", "{11ABD319-FF4C-47A5-A55D-7C91A9AF77C1}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InlineTask", "InlineTask\InlineTask.csproj", "{04F8FABF-1D31-4C2F-85AC-9DDAC165BCEF}" 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "alternatives", "alternatives", "{4C83D913-5F05-49D2-8B52-3802999C9200}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecTask", "ExecTask\ExecTask.csproj", "{F032095F-8850-4CEE-A141-6B1A35F008F6}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Final", "Final\Final.csproj", "{E9D1045C-8D0B-4E70-94C9-54CE37D1E416}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {92C7175C-5076-4FEC-8B37-23D433F91694}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {92C7175C-5076-4FEC-8B37-23D433F91694}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {92C7175C-5076-4FEC-8B37-23D433F91694}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {92C7175C-5076-4FEC-8B37-23D433F91694}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {E005996F-DD54-49E7-B79C-171B6157F752}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {E005996F-DD54-49E7-B79C-171B6157F752}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {E005996F-DD54-49E7-B79C-171B6157F752}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {E005996F-DD54-49E7-B79C-171B6157F752}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {11ABD319-FF4C-47A5-A55D-7C91A9AF77C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {11ABD319-FF4C-47A5-A55D-7C91A9AF77C1}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {11ABD319-FF4C-47A5-A55D-7C91A9AF77C1}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {11ABD319-FF4C-47A5-A55D-7C91A9AF77C1}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {04F8FABF-1D31-4C2F-85AC-9DDAC165BCEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {04F8FABF-1D31-4C2F-85AC-9DDAC165BCEF}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {04F8FABF-1D31-4C2F-85AC-9DDAC165BCEF}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {04F8FABF-1D31-4C2F-85AC-9DDAC165BCEF}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {F032095F-8850-4CEE-A141-6B1A35F008F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {F032095F-8850-4CEE-A141-6B1A35F008F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {F032095F-8850-4CEE-A141-6B1A35F008F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {F032095F-8850-4CEE-A141-6B1A35F008F6}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {E9D1045C-8D0B-4E70-94C9-54CE37D1E416}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {E9D1045C-8D0B-4E70-94C9-54CE37D1E416}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {E9D1045C-8D0B-4E70-94C9-54CE37D1E416}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {E9D1045C-8D0B-4E70-94C9-54CE37D1E416}.Release|Any CPU.Build.0 = Release|Any CPU 47 | EndGlobalSection 48 | GlobalSection(NestedProjects) = preSolution 49 | {04F8FABF-1D31-4C2F-85AC-9DDAC165BCEF} = {4C83D913-5F05-49D2-8B52-3802999C9200} 50 | {F032095F-8850-4CEE-A141-6B1A35F008F6} = {4C83D913-5F05-49D2-8B52-3802999C9200} 51 | {E9D1045C-8D0B-4E70-94C9-54CE37D1E416} = {4C83D913-5F05-49D2-8B52-3802999C9200} 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matkoch/custom-msbuild-task/94fe4f658777dc01a35078ea6933c440fe92cc5e/debugging.png -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "6.0.100", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /pack.cmd: -------------------------------------------------------------------------------- 1 | dotnet publish ./src/CustomTasks --framework netcoreapp6.0 2 | dotnet publish ./src/CustomTasks --framework net472 3 | dotnet pack ./src/MainLibrary --output ./ 4 | -------------------------------------------------------------------------------- /src/CustomTasks/ContextAwareTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Microsoft.Build.Utilities; 6 | #if NETCOREAPP 7 | using System.Runtime.Loader; 8 | using Microsoft.Build.Framework; 9 | #endif 10 | 11 | namespace CustomTasks; 12 | 13 | public abstract class ContextAwareTask : Task 14 | { 15 | protected virtual string ManagedDllDirectory => Path.GetDirectoryName(new Uri(GetType().GetTypeInfo().Assembly.Location).LocalPath); 16 | 17 | protected virtual string UnmanagedDllDirectory => null; 18 | 19 | public sealed override bool Execute() 20 | { 21 | #if NETCOREAPP 22 | var taskAssemblyPath = new Uri(GetType().GetTypeInfo().Assembly.Location).LocalPath; 23 | var context = new CustomAssemblyLoader(this); 24 | var inContextAssembly = context.LoadFromAssemblyPath(taskAssemblyPath); 25 | var innerTaskType = inContextAssembly.GetType(GetType().FullName); 26 | var innerTask = Activator.CreateInstance(innerTaskType); 27 | 28 | var outerProperties = GetType().GetRuntimeProperties().ToDictionary(i => i.Name); 29 | var innerProperties = innerTaskType.GetRuntimeProperties().ToDictionary(i => i.Name); 30 | var propertiesDiscovery = 31 | from outerProperty in outerProperties.Values 32 | where outerProperty.SetMethod != null && outerProperty.GetMethod != null 33 | let innerProperty = innerProperties[outerProperty.Name] 34 | select new { outerProperty, innerProperty }; 35 | 36 | var propertiesMap = propertiesDiscovery.ToArray(); 37 | var outputPropertiesMap = propertiesMap.Where(pair => pair.outerProperty.GetCustomAttribute() != null).ToArray(); 38 | 39 | foreach (var propertyPair in propertiesMap) 40 | { 41 | var outerPropertyValue = propertyPair.outerProperty.GetValue(this); 42 | propertyPair.innerProperty.SetValue(innerTask, outerPropertyValue); 43 | } 44 | 45 | var executeInnerMethod = innerTaskType.GetMethod(nameof(ExecuteInner), BindingFlags.Instance | BindingFlags.NonPublic); 46 | var result = (bool) executeInnerMethod.Invoke(innerTask, new object[0]); 47 | 48 | foreach (var propertyPair in outputPropertiesMap) 49 | propertyPair.outerProperty.SetValue(this, propertyPair.innerProperty.GetValue(innerTask)); 50 | 51 | return result; 52 | #else 53 | // On .NET Framework (on Windows), we find native binaries by adding them to our PATH. 54 | if (UnmanagedDllDirectory != null) 55 | { 56 | var pathEnvVar = Environment.GetEnvironmentVariable("PATH"); 57 | var searchPaths = pathEnvVar.Split(Path.PathSeparator); 58 | if (!searchPaths.Contains(UnmanagedDllDirectory, StringComparer.OrdinalIgnoreCase)) 59 | { 60 | pathEnvVar += Path.PathSeparator + UnmanagedDllDirectory; 61 | Environment.SetEnvironmentVariable("PATH", pathEnvVar); 62 | } 63 | } 64 | 65 | return ExecuteInner(); 66 | #endif 67 | } 68 | 69 | protected abstract bool ExecuteInner(); 70 | 71 | #if NETCOREAPP 72 | private class CustomAssemblyLoader : AssemblyLoadContext 73 | { 74 | private readonly ContextAwareTask loaderTask; 75 | 76 | internal CustomAssemblyLoader(ContextAwareTask loaderTask) 77 | { 78 | this.loaderTask = loaderTask; 79 | } 80 | 81 | protected override Assembly Load(AssemblyName assemblyName) 82 | { 83 | var assemblyPath = Path.Combine(loaderTask.ManagedDllDirectory, assemblyName.Name) + ".dll"; 84 | return File.Exists(assemblyPath) 85 | ? LoadFromAssemblyPath(assemblyPath) 86 | : Default.LoadFromAssemblyName(assemblyName); 87 | } 88 | 89 | protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) 90 | { 91 | var unmanagedDllPath = Directory.EnumerateFiles( 92 | loaderTask.UnmanagedDllDirectory, 93 | $"{unmanagedDllName}.*").Concat( 94 | Directory.EnumerateFiles( 95 | loaderTask.UnmanagedDllDirectory, 96 | $"lib{unmanagedDllName}.*")) 97 | .FirstOrDefault(); 98 | 99 | return unmanagedDllPath != null 100 | ? LoadUnmanagedDllFromPath(unmanagedDllPath) 101 | : base.LoadUnmanagedDll(unmanagedDllName); 102 | } 103 | } 104 | #endif 105 | } 106 | -------------------------------------------------------------------------------- /src/CustomTasks/CustomTask.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using Microsoft.Build.Framework; 6 | using Microsoft.Build.Utilities; 7 | 8 | namespace CustomTasks; 9 | 10 | public class CustomTask : ContextAwareTask 11 | { 12 | [Required] public string StringParameter { get; set; } 13 | public ITaskItem[] FileItems { get; set; } 14 | 15 | [Output] public string OutputParameter { get; set; } 16 | [Output] public ITaskItem[] OutputItems { get; set; } 17 | 18 | protected override bool ExecuteInner() 19 | { 20 | string GetFile([CallerFilePath] string path = null) => path; 21 | 22 | Log.LogWarning( 23 | subcategory: "subcategory", 24 | warningCode: "CT1337", 25 | helpKeyword: "helpKeyword", 26 | helpLink: "helpLink", 27 | file: GetFile(), 28 | lineNumber: 100, 29 | columnNumber: 5, 30 | endLineNumber: 0, 31 | endColumnNumber: 0, 32 | message: "message"); 33 | 34 | BuildEngine.LogWarningEvent( 35 | new BuildWarningEventArgs( 36 | subcategory: "subcategory", 37 | code: "code", 38 | file: GetFile(), 39 | lineNumber: 100, 40 | columnNumber: 10, 41 | endLineNumber: 0, // ignored if 0 42 | endColumnNumber: 0, // ignored if 0 43 | message: Assembly.GetExecutingAssembly().Location, 44 | helpKeyword: "helpKeyword", 45 | senderName: "senderName")); 46 | 47 | OutputParameter = StringParameter; 48 | OutputItems = new[] { new TaskItem($"{StringParameter}.cs") }.Concat(FileItems).ToArray(); 49 | 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/CustomTasks/CustomTasks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp6.0;net472 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | PreserveNewest 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/CustomTasks/CustomTasks.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Default 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/CustomTasks/CustomTasks.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)\$(MSBuildThisFileName).dll 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | latest 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/MainLibrary/MainLibrary.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net472 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/MainLibrary/MainLibrary.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)\netcore 5 | $(MSBuildThisFileDirectory)\netfx 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/MainLibrary/MainLibrary.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/MainLibrary/Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MainLibrary; 4 | 5 | public static class Utility 6 | { 7 | public static void Foo() 8 | { 9 | Console.WriteLine("Should we clap now? 🤔"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/TestProject/Program.cs: -------------------------------------------------------------------------------- 1 | using MainLibrary; 2 | 3 | Utility.Foo(); 4 | -------------------------------------------------------------------------------- /src/TestProject/TestProject.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp6.0 5 | Exe 6 | False 7 | $(MSBuildThisFileDirectory)\..\CustomTasks\bin\Debug\$(TargetFramework)\publish 8 | 9 | 10 | 11 | 12 | 13 | Custom 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/TestProject/msbuild.binlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matkoch/custom-msbuild-task/94fe4f658777dc01a35078ea6933c440fe92cc5e/src/TestProject/msbuild.binlog --------------------------------------------------------------------------------