Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Sn.exe中自动输入密码_C#_Signing_Sn.exe - Fatal编程技术网

C# 在Sn.exe中自动输入密码

C# 在Sn.exe中自动输入密码,c#,signing,sn.exe,C#,Signing,Sn.exe,我需要创建生成后事件以执行以下操作: sn -i MyKey.pfx MyKeyContainerName tlbimp $(ConfigurationName)\MyCom.tlb /out:$(ConfigurationName)\NETMyCom.dll /keycontainer:MyKeyContainerName sn -d MyKeyContainerName 当VisualStudio执行第1条语句时,它需要密码,并等待用户指定密码后失败 Microsoft(R).NET框架强

我需要创建生成后事件以执行以下操作:

sn -i MyKey.pfx MyKeyContainerName
tlbimp $(ConfigurationName)\MyCom.tlb /out:$(ConfigurationName)\NETMyCom.dll /keycontainer:MyKeyContainerName
sn -d MyKeyContainerName
当VisualStudio执行第1条语句时,它需要密码,并等待用户指定密码后失败

Microsoft(R).NET框架强大 名称实用程序版本2.0.50727.42 版权所有(c)微软公司。 版权所有

输入PKCS#12键的密码 文件:无法解析PKCS#12 mykey.pfx中的blob——句柄是 无效

我试图使用sn命令行参数指定密码,但找不到方法

请帮忙

问候,,
Hilmi.

如果像我一样,您没有使用TFS或MSBUILD进行构建,那么至少还有两种其他方法:

a)从脚本运行sn.exe,并将密码写入stdin

有关C#示例,请参见:

注意:对于.NET4版本的sn.exe,似乎不可能将其作为外部进程执行(至少在Windows XP上是这样),也不可能将密码写入stdin(我用python+和C#进行了尝试,sn.exe似乎只是在不等待密码输入的情况下退出)

b)使用已安装的pfx,使用sn.exe重新签署密码。

如果您已经安装了pfx文件,那么您可能知道容器名称(通常VisualStudio使用类似VS_KEY_abab1234; abab1234的名称)

如果像我一样,您不知道或不记得容器名称,则只需重新安装pfx文件:

sn -i myPfxFile VS_KEY_ABAB1234ABAB1234
sn.exe将在pfx文件中安装证书时提示您输入密码

然后,您可以使sn.exe对程序集重新签名,而无需提示输入密码:

sn -Rca myAssembly.dll myVSkey
上述内容可以在构建脚本中使用,因为不需要交互:-)

注意:请记住检查签名是否有效:

sn -v myAssembly.dll

我今天遇到这个问题,我用了C++DLL,在CLIKONC C++应用程序中使用。 我在DLL上设置了延迟签名,然后使用生成后事件运行SN,如下所示:

ECHO <your-password-here> | sn.exe -R $(OutDir)$(TargetFileName) $(MSBuildProjectDirectory)<path-to-pfx-file>
ECHO | sn.exe-R$(OutDir)$(TargetFileName)$(MSBuildProjectDirectory)
我一定喜欢老式的批量生产方法
ECHO
打印您的密码,管道
|
将输出到SN.exe,它接受密码

你可能不会像我那样需要延迟签名和-R开关,但你明白了


编辑:这可能不再有效-我的答案是2013年的,当时我正在使用VS2010

我已经研究了差不多两天了。我尝试了旧版本的sn.exe(最早可以追溯到2.0!),但我无法让
echo密码
技巧发挥作用

最后,我做到了:

[void] [System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")

Start-Process "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\sn.exe " -ArgumentList "-i 
`"Certificate.pfx`" VS_KEY_XXXXXXX" -NoNewWindow -Wait
[System.Windows.Forms.SendKeys]::SendWait("PASSWORDHERE~")
  • SendWait()
    将密钥发送到当前激活的窗口。由于我们正在使用带有
    -nonewindow
    修饰符的
    Start Process
    启动
    sn.exe,因此我们的窗口已经聚焦
  • ~
    是一个特殊字符,表示回车按钮
    {ENTER}
    也可以,但这是键盘上numpad附近的ENTER按钮。可能没什么区别,但我只是想确定一下
我使用的资料来源:

我最终不需要Visual Basic的
AppActivate()
,因为
-nonewindow


更新:使用
-Wait
参数时效果更好

我需要将其自动化并找到这个问题。下面的答案(非常感谢@Thomas Rijsewijk)我已经写了我的版本:

# Start the sn.exe process
Start-Process $SnExePath -ArgumentList "-i $PfxCertificatePath $LocalContainerName" -NoNewWindow
# Wait for the process to start
Start-Sleep 2
# This workaround allows to forward the password to the standard input
[void] [System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")
[System.Windows.Forms.SendKeys]::SendWait("$($PfxCertificatePassword){ENTER}")
Start-Sleep 2
# This ENTER is to return from the sn.exe process
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")

使用
启动进程
命令的
-Wait
开关并没有解决问题,因为PS脚本正在等待sn.exe进程终止,然后再将密码转发给它。

经过长时间的调查,我可以为各种自动化环境(如Azure devops)运行sn.ex。我的代码在这里:

Start-Process cmd.exe 
Sleep 3
$WshShell = New-Object -ComObject WScript.Shell
Sleep 3
$WshShell.sendkeys(".\sn.exe -i  $PfxCertificatePath  VS_KEY_10D1C85C6387479B{Enter}");
Sleep 3;
$WshShell.sendkeys("**password**{Enter}");
Sleep 3;
$WshShell.sendkeys("{Enter}");

不幸的是,这里提到的任何方法都不适用于我。我必须在docker容器中注册几个PFX

所以我重新开发了
sn.exe-i
命令在C#中使用。源和应用程序位于GitHub上的 这个项目

该应用程序接受PFX密钥及其密码。它自动(借用MSBuild源代码)计算密钥容器名称(VS_key_*),并将其安装到强名称CSP

用法:

SnInstallPfx.exe <pfx_infile> <pfx_password>
SnInstallPfx.exe

使用WinAPI,我们可以这样做:

Param(
    [string]  $Password ,
    [string] $CertFilePath 
)

function ExecuteCommand([string]$message)
{
    try{
    foreach ($char in [char[]]$message) {
    [void][WPIA.ConsoleUtils]::PostMessage($handle, [WPIA.ConsoleUtils]::WM_CHAR, [int]$char, 0) 
    }
    [void][WPIA.ConsoleUtils]::PostMessage($handle, [WPIA.ConsoleUtils]::WM_CHAR, 13, 0)
    Sleep 3
    }catch{
    }
}

Add-Type -Name ConsoleUtils -Namespace WPIA -MemberDefinition @'
[DllImport("user32.dll")]
public static extern int PostMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_CHAR = 0x0102;
'@

$Win32API = Add-Type -Name Funcs -Namespace Win32 -PassThru -MemberDefinition @'
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, IntPtr lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className,  string  windowTitle);

    [DllImport("kernel32.dll")]
  public static extern uint GetLastError();
'@

[System.Reflection.Assembly]::Load("Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[System.Reflection.Assembly]::Load("Microsoft.Build.Utilities.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publish = New-Object Microsoft.Build.Tasks.ResolveKeySource
$publish.KeyFile=$CertFilePath
try
{
        $publish.Execute()
}
catch{
        $VsKey= [regex]::match($error[0].Exception,'VS_KEY_[A-F0-9]+').Value
        $VsKey =$VsKey -replace "`n|`r"
}
$quotedCertPath='"'+$CertFilePath+'"'
Write-Host 'VsKey='$VsKey

start cmd
$proc=Get-Process | Where-Object {$_.Name -like "*cmd*"}
$proc.MainWindowTitle
$handle = $proc.MainWindowHandle
'1:'+$handle
if($handle -eq 0){
    $handle=$Win32API::FindWindow([IntPtr]::Zero, 'C:\WINDOWS\system32\cmd.exe')
    '2:'+$handle
}   
if($handle -eq 0){
    $handle=$Win32API::FindWindow('C:\WINDOWS\system32\cmd.exe',       [IntPtr]::Zero)
    '3:'+$handle
}
if($handle -eq 0){
    $proc2 = Start-Process cmd.exe -PassThru
    $proc2
    Get-Process -id $proc2.Id
    Sleep 3;
    $handle = (Get-Process -id $proc2.Id).MainWindowHandle
    $handle
    $proc.MainWindowHandle
    $proc.Refresh()
    Sleep 3;
    $proc.MainWindowHandle
}


Write-Host 'Handle='$handle

ExecuteCommand 'echo Starting > d:\a\1\s\Authenticode\log.txt'  
$SnCommand=[string]::Format(".\sn.exe -i {0} {1}",$quotedCertPath,$VsKey)
ExecuteCommand $SnCommand
ExecuteCommand $Password

有什么原因不能使用VisualStudio自己的密钥签名功能吗?(检查项目的属性。)还有一件非常重要的事情需要知道,我现在才想起:如果您将此命令放入批处理文件中,并且您的密码包含一个
%
符号,则需要使用其中两个。如果您的密码是
super%cool%guy
,则只需在批处理文件中使用
super%%cool%%guy
。这个想法很好,但不适用于批处理文件
sn.exe
不接受控制台输入重定向,并抱怨如下:
控制台输入可能无法重定向密码输入
。有没有办法在批处理文件中实现这一点?我对此没有异议。您可以发布批处理文件内容吗?(我几年前就这么做了,也许最新的SN.exe不允许这样做)这是我的。试图在变量中设置密码并将其导入
sn
命令,但没有成功:(你可能是对的。它在一个旧得多的SN.exe上工作,他们可能认为管道输入存在安全风险。谢谢你!非常有用。太好了,谢谢你的反馈!我已经更新了应用程序的cmdln参数。你可以选择传递容器名称。你简直是一个救世主。与cmd标准管道相同的错误,输入无法重做。)反恐执行局