2

I have a clickonce solution that works on several developer machines with VS 2015 installed. However, it doesn't work on our buildserver it comes with this signFile error. I have installed

  • Build Tools 2015 update 3
  • .Net 4.6.2 SDK
  • Windows Software Development Kit

But apparantly the path to the signtool.exe isn't correctly setup. If I disable signing of manifest it will continue on, but come up with a setup.bin missing error.

Do anyone have a good clue how to solve the SignFile problem ?

[_DeploymentComputeClickOnceManifestInfo] Using "SignFile" task from assembly "Microsoft.Build.Tasks.Core, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
[_DeploymentComputeClickOnceManifestInfo] SignFile
[SignFile] C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(3616, 5): error MSB4018: The "SignFile" task failed unexpectedly.
System.ArgumentNullException: Value cannot be null.
Parameter name: path1
   at System.IO.Path.Combine(String path1, String path2, String path3)
   at Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.GetPathToTool(ResourceManager resources)
   at Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignPEFile(X509Certificate2 cert, Uri timestampUrl, String path, ResourceManager resources, Boolean useSha256)
   at Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFileInternal(X509Certificate2 cert, Uri timestampUrl, String path, Boolean targetFrameworkSupportsSha256, ResourceManager resources)
   at Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile(X509Certificate2 cert, Uri timestampUrl, String path)
   at Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile(String certThumbprint, Uri timestampUrl, String path, String targetFrameworkVersion)
   at Microsoft.Build.Tasks.SignFile.Execute()
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext()
dennis_ler
  • 659
  • 1
  • 9
  • 36

1 Answers1

2

The error is being thrown on line 195 of Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities, which is in the following method:

    internal static string GetPathToTool()
    {
        string pathToDotNetFrameworkSdkFile = ToolLocationHelper.GetPathToDotNetFrameworkSdkFile(ToolName(), TargetDotNetFrameworkVersion.Version35);
        if (pathToDotNetFrameworkSdkFile == null)
        {
            pathToDotNetFrameworkSdkFile = Path.Combine(Environment.CurrentDirectory, ToolName());
        }
        if (!File.Exists(pathToDotNetFrameworkSdkFile))
        {
            pathToDotNetFrameworkSdkFile = null;
        }
        return pathToDotNetFrameworkSdkFile;
    }

The immediate cause was that Environment.CurrentDirectory returned null, but the more salient one was that ToolLocationHelper.GetPathToDotNetFrameworkSdkFile(ToolName(), TargetDotNetFrameworkVersion.Version35) also returned null.

The above code is a only snapshot of a particular version of the class, but the hardcoded enum value TargetDotNetFrameworkVersion.Version35 tells me that the problem is that Build Tools 2015 update 3 depends on a version of the .Net SDK other than 4.6.2.

UPDATE:

To help identify the specific SDK version, I pulled down the source code from the Update 3 release at https://github.com/Microsoft/msbuild/releases.

    internal static string GetPathToTool(System.Resources.ResourceManager resources)
    {
#pragma warning disable 618 // Disabling warning on using internal ToolLocationHelper API. At some point we should migrate this.
        string toolPath = ToolLocationHelper.GetPathToWindowsSdkFile(ToolName, TargetDotNetFrameworkVersion.VersionLatest, VisualStudioVersion.VersionLatest);
        if (toolPath == null)
            toolPath = ToolLocationHelper.GetPathToWindowsSdkFile(ToolName, TargetDotNetFrameworkVersion.Version45, VisualStudioVersion.Version110);
        if (toolPath == null)
            toolPath = Path.Combine(ToolLocationHelper.GetPathToDotNetFrameworkSdk(TargetDotNetFrameworkVersion.Version40, VisualStudioVersion.Version100), "bin", ToolName);
        if (toolPath == null)
            toolPath = Path.Combine(Directory.GetCurrentDirectory(), ToolName);
        if (!File.Exists(toolPath))
            throw new ApplicationException(String.Format(CultureInfo.CurrentCulture, resources.GetString("SecurityUtil.SigntoolNotFound"), toolPath));
        return toolPath;
#pragma warning restore 618
    }

Digging further into the solution, I determined that the latest release of Build Tools (the one you installed) does not include the change to Shared\FrameworkLocationHelper.cs that added support for Framework 4.6.2. So to answer your follow-up question, installing the 4.6.1 SDK should do the trick.

UPDATE 2:

The OP identified an alternative solution: explicitly setting the value of the TargetFrameworkSDKToolsDirectory property, e.g. by adding /p:TargetFrameworkSDKToolsDirectory=PATH TO SIGNTOOL.EXE(?) as an argument when invoking msbuild.exe from the command line.

weir
  • 4,521
  • 2
  • 29
  • 42
  • 1
    I don't know how you figured this out, but thanks. Do you by any chance know which SDK it is dependent on, so I don't need to install all ? Right now I have circumvented this by setting the property /property:TargetFrameworkSDKToolsDirectory when calling msbuild. – dennis_ler Jan 11 '17 at 17:14
  • Answer updated with this info (I hope I am right!). As to how I figured this out, I started by going to the file and line number referenced near the top of your error log. When I saw that the `SignFile` task did not take a parameter for a path to a tool/executable, I knew I would need to see source code for the `SignFile` task. Luckily, MSBuild is now open source! – weir Jan 11 '17 at 20:53
  • @dennis_ler - I have added your `TargetFrameworkSDKToolsDirectory` fix to this answer. – weir Jan 17 '17 at 18:57