如何在没有硬编码路径的情况下在 Visual Studio 2013 的生成后事件中使用 signtool



我创建了一个构建后事件,用于在成功构建后使用以下构建后脚本对应用程序进行代码签名。

copy $(TargetPath) $(TargetDir)SignedApp.exe
signtool sign /t http://timestamp.verisign.com/scripts/timestamp.dll /a $(TargetDir)SignedApp.exe

我收到错误"signtool"未被识别为内部或外部命令。 因此,用于构建事件的路径似乎不指向 signtool 实用程序。 当我运行VS2013 x86本机工具命令提示符时,我可以运行signtool,因为它包含一个指向以下内容的路径:

C:Program Files (x86)Windows Kits8.1binx86

我可以将此路径硬编码到我的构建事件中

"C:Program Files (x86)Windows Kits8.1binx86signtool" sign /t http://timestamp.verisign.com/scripts/timestamp.dll /a $(TargetDir)SignedApp.exe

然而,这似乎是不可移植的。 如何在不对其进行硬编码的情况下,为本机命令提示符定义的相同路径以供我的后期生成事件使用? 我已经查看了宏列表,但没有找到任何有用的宏。

我首先发现了这个问题,所以我将发布我最终得到的答案。

一路上,我查看了另一个答案和一些文档:

使用 Visual Studio 2012 时 SignTool .exe 或"Windows Kits"目录的路径

https://learn.microsoft.com/en-us/visualstudio/msbuild/property-functions?view=vs-2017

我的解决方案最终是将这个大属性组添加到csproj文件中:

<PropertyGroup>
  <!-- Find Windows Kit path and then SignTool path for the post-build event -->
  <WindowsKitsRoot>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows KitsInstalled Roots', 'KitsRoot10', null, RegistryView.Registry32, RegistryView.Default))</WindowsKitsRoot>
  <WindowsKitsRoot Condition="'$(WindowsKitsRoot)' == ''">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows KitsInstalled Roots', 'KitsRoot81', null, RegistryView.Registry32, RegistryView.Default))</WindowsKitsRoot>
  <WindowsKitsRoot Condition="'$(WindowsKitsRoot)' == ''">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows KitsInstalled Roots', 'KitsRoot', null, RegistryView.Registry32, RegistryView.Default))</WindowsKitsRoot>
  <SignToolPath Condition="'$(SignToolPath)' == '' And '$(Platform)' == 'AnyCPU' and Exists('$(WindowsKitsRoot)binx64signtool.exe')">$(WindowsKitsRoot)binx64</SignToolPath>
  <SignToolPath Condition="'$(SignToolPath)' == '' And Exists('$(WindowsKitsRoot)bin$(Platform)signtool.exe')">$(WindowsKitsRoot)bin$(Platform)</SignToolPath>
  <SignToolPathBin Condition="'$(SignToolPath)' == ''">$([System.IO.Directory]::GetDirectories('$(WindowsKitsRoot)bin',"10.0.*"))</SignToolPathBin>
  <SignToolPathLen Condition="'$(SignToolPathBin)' != ''">$(SignToolPathBin.Split(';').Length)</SignToolPathLen>
  <SignToolPathIndex Condition="'$(SignToolPathLen)' != ''">$([MSBuild]::Add(-1, $(SignToolPathLen)))</SignToolPathIndex>
  <SignToolPathBase Condition="'$(SignToolPathIndex)' != ''">$(SignToolPathBin.Split(';').GetValue($(SignToolPathIndex)))</SignToolPathBase>
  <SignToolPath Condition="'$(SignToolPath)' == '' And '$(SignToolPathBase)' != '' And '$(Platform)' == 'AnyCPU'">$(SignToolPathBase)x64</SignToolPath>
  <SignToolPath Condition="'$(SignToolPath)' == '' And '$(SignToolPathBase)' != ''">$(SignToolPathBase)$(Platform)</SignToolPath>
</PropertyGroup>

我需要很多额外的中介属性,因为我机器上的 Windows SDK 不会在<root>binx64signtool.exe中安装signtool.exe,而是在另一个目录级别下安装,即我绝对不想硬编码的 SDK 版本。

然后在构建后,我可以使用此"$(SignToolPath)signtool.exe"

我决定的解决方案是:

REM If SIGNTOOL environment variable is not set then try setting it to a known location
if "%SIGNTOOL%"=="" set SIGNTOOL=%ProgramFiles(x86)%Windows Kits8.1binx86signtool.exe
REM Check to see if the signtool utility is missing
if exist "%SIGNTOOL%" goto OK1
    REM Give error that SIGNTOOL environment variable needs to be set
    echo "Must set environment variable SIGNTOOL to full path for signtool.exe code signing utility"
    echo Location is of the form "C:Program Files (x86)Windows Kits8.1x86binsigntool.exe"
    exit -1
:OK1
echo Copying $(TargetFileName) to $(TargetDir)SignedApp.exe
copy $(TargetPath) $(TargetDir)SignedApp.exe
"%SIGNTOOL%" sign /t http://timestamp.verisign.com/scripts/timestamp.dll /a $(TargetDir)SignedApp.exe

这是@Dennis Kuypers建议#4的变体。 开发人员必须将环境变量 SIGNTOOL 设置为正确的位置。 如果他们没有这样做,则尝试一个已知的可能位置。 如果失败,则会报告错误,指示他们正确设置 SIGNTOOL env var。

我确实发现有一个环境变量WindowsSdkDir

WindowsSdkDir=C:Program Files (x86)Windows Kits8.1

但同样,这仅在运行本机命令提示符时设置,因此在运行生成后事件脚本时未定义。

我今天一直在看很多不同年份的帖子,其中大多数的问题在于它们在几年后没有始终如一地工作,或者它们涉及大量注册表读取,然后是许多条件硬编码路径。

我终于找到了一些(我认为(可以工作一段时间的东西。 至少在2019年,直到出现问题。

我使我的后期构建事件具有以下效果

call "$(VSAPPIDDIR)..ToolsVsDevCmd.bat"
signtool.exe sign /p <whatever> /f <whatever>.pfx "$(TargetFileName)"

第一行获取所有环境变量的设置,就像您在开发人员命令提示符中一样。 第二个使用该环境进行签名

我在Visual Studio 2012中遇到了同样的问题,并找到了解决此问题的更简单的方法。而不是启动Visual Studio直接启动"VS2012的开发人员命令提示符",然后在命令提示符中键入"devenv"以启动Visual Studio。在那之后,标志工具对我来说工作得很好。

相关内容

  • 没有找到相关文章

最新更新