New-WebBinding:无法检索cmdlet

时间:2016-10-13 22:08:30

标签: windows powershell batch-file iis-8 lets-encrypt

我们正在使用Windows 2012 Server R2。

我们正在尝试自动创建LetsEncrypt证书。我们正在使用LetsEncrypt-Win-Simple(https://github.com/Lone-Coder/letsencrypt-win-simple)。

一旦创建了证书(通过LetsEncrypt.exe),我们就会调用一个.bat脚本(使用--script和--scriptparameters标志)。这将运行powershell.exe并尝试创建必要的IIS绑定。 .bat文件中的行是:

powershell.exe -file c:\temp\SSLIISBinding.ps1 %1 %2 %3 %4

%1-4是LetsEncrypt传入的args。在powershell脚本中,我们尝试运行的命令是:

$iis_host_name = $args[0]
$iis_site_name = $args[1]
$certificate_hash = $args[2]
$certificate_store = $args[3]

"IIS Host Name: " + $iis_host_name
"IIS Site Name: " + $iis_site_name
"Certificate Hash: " + $certificate_hash
"Certificate Store: " + $certificate_store

$guid = [guid]::NewGuid().ToString("B")
netsh http add sslcert hostnameport="${iis_host_name}:443" certhash=$certificate_hash certstorename=$certificate_store appid="$guid"
New-WebBinding -name $iis_site_name -Protocol https  -HostHeader $iis_host_name -Port 443 -SslFlags 1

args传入.bat罚款,因为我们输出它们并且它们正确显示。

如果我们自己运行.bat文件,它会完美运行。如果它被LetsEncrypt.exe调用则失败,报告以下问题:

New-WebBinding : Cannot retrieve the dynamic parameters for the cmdlet.
Retrieving the COM class factory for component with CLSID
{688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} failed due to the following error:
80040154 Class not registered (Exception from HRESULT: 0x80040154
(REGDB_E_CLASSNOTREG)).
At C:\temp\SSLIISBinding.ps1:13 char:1
+ New-WebBinding -name $iis_site_name -Protocol https  -HostHeader
$iis_host_name  ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
    + CategoryInfo          : InvalidArgument: (:) [New-WebBinding], Parameter
   BindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.IIs.Powe
   rShell.Provider.NewWebBindingCommand

我用Google搜索过,有些人提到了32位与64位PowerShell的内容,但我尝试使用所有不同的powershell.exe。

任何人遇到此问题,或知道要解决。

如果我们直接从命令行调用.bat它可以正常工作,就像通过LetsEncrypt.exe调用一样。许可问题? powershell.exe错在?

5 个答案:

答案 0 :(得分:10)

你的问题的一部分:

  

我用Google搜索,有些人提到了32位与64位PowerShell的相关内容

已经是答案的一半了。如果PowerShell进程的位数与操作系统的位数不匹配,则某些命令无法正常运行。因此,您需要运行位于此powershell.exe目录中的%windir%\System32\WindowsPowerShell\v1.0\。但是this documentation topic中描述了一个小问题:

  

在大多数情况下,只要32位应用程序尝试访问%windir%\ System32,就会将访问权限重定向到%windir%\ SysWOW64。

因此,如果64位操作系统上的32位程序调用{​​{1}},它实际上将从此处%windir%\System32\WindowsPowerShell\v1.0\powershell.exe而不是64位调用PowerShell的32位版本。要从32位应用程序实际调用64位PowerShell,您需要使用此技巧:

  

32位应用程序可以通过将%windir%\ Sysnative替换为%windir%\ System32来访问本机系统目录。 WOW64将Sysnative识别为一个特殊别名,用于指示文件系统不应重定向访问。

答案 1 :(得分:0)

运行以下cmdlet时遇到相同的错误:

PS> Remove-WebAppPool -Name 'Test'

Remove-WebAppPool : Cannot retrieve the dynamic parameters for the cmdlet. Retrieving the COM class factory for
component with CLSID {688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} failed due to the following error: 80040154 Class not
registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
At line:1 char:1
+ Remove-WebAppPool -Name 'Test'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Remove-WebAppPool], ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.IIs.PowerShell.Provider.RemoveAppPoolCommand

原因是因为我在Windows 10 x64计算机上使用Windows PowerShell(x86)来运行它。

当我尝试相同的操作但使用Windows PowerShell(64位版本)时,效果很好。

答案 2 :(得分:0)

我认为您的$ guid是问题。 GUID必须是将证书绑定到的程序的GUID。对于您的示例,端口443仅绑定到随机GUID,而不绑定到程序的GUID。 IIS和其他应用程序具有您要使用的静态GUID。如果Powershell脚本的GUID,则Get-host是执行代码的Powershell主机,因此这就是您需要的GUID。对于每个Powershell会话,它都会更改,并且netsh绑定也需要更改。

$ appid =“ appid = {” +(get-host).InstanceId.guid +“}”

$ certhash = ls证书:\ LocalMachine \ my |其中{$ .EnhancedKeyUsageList-匹配'Server'-和$ .subject -match(hostname)} |排序对象$ _。NotAfter | select -expand Thumbprint -last 1

$ cmdline ='netsh http add sslcert ipport = 0.0.0.0:443 certhash ='+ $ certhash +'“'+ $ appid +'”'

netsh http delete sslcert ipport = 0.0.0.0:443

调用表达式$ cmdline

答案 3 :(得分:0)

谷歌搜索“无法获取cmdlet的动态参数”将我带到这里,但是我的问题是从命令行使用Powershell,答案是在命令中转义双引号 ...

答案 4 :(得分:0)

我也遇到了同样的错误。当我尝试同时使用来自不同代理计算机的Invoke-Command远程将WebBinding添加到IIS站点时,会发生这种情况。

这对我有用,也许对某人也有帮助:

$Mutex = New-Object -TypeName System.Threading.Mutex($false, "Global\Mutex")    
if ($Mutex.WaitOne(300000)) {
   #For example
   #$Command = {
        #New-WebBinding -name $iis_site_name -Protocol https -HostHeader             
           #$iis_host_name -Port 443 -SslFlags 1
   #}
   #Invoke-Command -Command $Command
} else {
   Write-Warning "Timed out acquiring mutex!"
}
    
$Mutex.Dispose()