We're using Windows 2012 Server R2.
We're trying to automate the creation of LetsEncrypt certificates. We're using LetsEncrypt-Win-Simple (https://github.com/Lone-Coder/letsencrypt-win-simple).
Once the cert is created (via LetsEncrypt.exe) we have a .bat script that gets called (using the --script and --scriptparameters flags). This runs powershell.exe and tries to create the necessary IIS binding. The line in the .bat file is:
powershell.exe -file c:\temp\SSLIISBinding.ps1 %1 %2 %3 %4
The %1-4 are args passed in by LetsEncrypt. In the powershell script, the command we're trying to run is:
$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
The args are passed into the .bat fine, as we output them and they are showing correctly.
If we run the .bat file on its own, it works perfectly. If it gets called by LetsEncrypt.exe it fails, reporting the following issue:
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
I've googled, some mentioning something about 32bit vs 64bit powershell, but I've tried using all the different powershell.exe available.
Anyone hit this issue, or know to resolve.
If we call .bat directly from command line it works fine, just as part of being called via LetsEncrypt.exe. A permission problem? Wrong powershell.exe?
That part of your question:
I've googled, some mentioning something about 32bit vs 64bit powershell
is already half of an answer. Some commands do not run properly if bitness of PowerShell process does not match bitness of operation system. So, you need to run powershell.exe, which located in this %windir%\System32\WindowsPowerShell\v1.0\ directory. But there is a little problem described in this documentation topic:
In most cases, whenever a 32-bit application attempts to access %windir%\System32, the access is redirected to %windir%\SysWOW64.
Thus, if 32-bit program on 64-bit OS invoke %windir%\System32\WindowsPowerShell\v1.0\powershell.exe, it will actually invoke 32-bit version of PowerShell from here %windir%\SysWOW64\WindowsPowerShell\v1.0\ instead of 64-bit one. To actually invoke 64-bit PowerShell from 32-bit application you need to use this trick:
32-bit applications can access the native system directory by substituting %windir%\Sysnative for %windir%\System32. WOW64 recognizes Sysnative as a special alias used to indicate that the file system should not redirect the access.
I've got the same error when running the following 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
The reason was because I ran it using Windows PowerShell (x86) on my Windows 10 x64 machine.
When I tried the same but using Windows PowerShell, which is 64 bit version, it worked just fine.
I think your $guid is the issue. The GUID needs to be the GUID of the program to bind the cert to. For your example port 443 is only bound to a random GUID, and not your program's GUID. IIS and other apps have a static GUID that you will want to use. If the GUID for a powershell script then Get-host is the powershell host executing code so that's the GUID you need. It changes for every powershell session and the netsh binding needs to as well.
$appid = "appid={"+(get-host).InstanceId.guid+"}"
$certhash = ls Cert:\LocalMachine\my | where {$.EnhancedKeyUsageList -Match 'Server' -and $.subject -match (hostname)}|sort-object $_.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
Invoke-Expression $cmdline
A google search for "Cannot retrieve the dynamic parameters for the cmdlet" brought me here but my issue was using powershell from the command line, and the answer was to escape the double quotes on the command...
I've got a problem with the same error. This happens when i'm trying to Add-WebBinding to my IIS site remotely, using Invoke-Command from different agent machines at time.
It's worked for me, maybe it helps someone too:
$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()
Related
I am trying to automate windows server update instllation for multiple servers. I have installed the module on all servers and also added the hostnames in winrm trust hosts.
All server hostnames are stored in txt file and are looped trought for each loop with different commands from teh PSwindowswupdate module.
$Hostname = Get-Content -Path "C:\TEMP\powershell_patching_script\module\hostnamesallwsus.txt"
Import-Module PSWindowsUpdate
foreach ($i in $Hostname) {
write-host $i
Get-WUHistory -ComputerName $i -last 3
}
Issue is that randomly the loop is failing for some hostnames, with error :
BGxxxxxxx01 #this is the hostname
Get-WUHistory : BGxxxxxxx01: Unknown failure.
At C:\TEMP\powershell_patching_script\Module\History.ps1:10 char:1
+ Get-WUHistory -ComputerName $i -last 3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [Get-WUHistory], Exception
+ FullyQualifiedErrorId : Unknown,PSWindowsUpdate.GetWUHistory
If I run the command with the hostname instead of variable it is failing again with the same error.
If I run the same but with $ in front of the hostname (even if such varaiable is not defined) the command works!ly appriciated
Get-WUHistory -ComputerName $BGxxxxxxx01 -last 3
Localy executed the commands are also working.
This issue seams to occure on random bases for multiple hostnames form my list.
I am unable find anything helpful regarding this error.
Any help will be highly appriciated!
Thanks in advance!
I found that Invoke-command works.
Just need to put the command in the script block of Invoke-command.
I'm using the Invoke-Parallel CmdLet that can be found at the link here. When I have some dummy code in my script block, it works correctly, but when I add a start-process... command it fails with an error saying
Get-RunspaceData : This command cannot be run due to the error: The system
cannot find the file specified.
At c:\crm\Interfaces\Batches\Invoke-Parallel.ps1:592 char:13
My script block looks like so. Long story short, I'm feeding file names into a block, and I am telling a 3rd party application to use that file as an input for a process. When the start-process line is removed, it works, with it, it fails.
$childFiles| Invoke-Parallel -ImportVariables {
$importformat = '-f ' + '"CU Imp P19 FI"'
$importfile = '-d ' + $_ + " " + $user + " " + $pass
Write-Host $importformat + " " + $_
start-process .\mmim.exe -ArgumentList $user, $pass, '-l:1',
$importformat, $importfile -Wait -NoNewWindow
return "blah"
}
Does anyone have any idea of what might be going on? My PowerShell version is the following
Major:5
Minor:0
Build: 10586
Revision: 117
Any help is greatly appreciated.
Each PowerShell runspace have its own current location. If Invoke-Parallel does not change current location of spawned runspaces to match current location of main runspace, then relative path .\mmim.exe may be resolved to entire different executable or not resolved at all and produce given error.
Having seen examples of BITS being used to transfer files from http addresses as well as regular windows file shares, I thought I'd test pulling and pushing to/from ftp. I used the below powershell commands:
Start-BitsTransfer `
-Source ftp://username:password#ftp.somewhere.com/file.zip `
-Destination c:\temp\file.zip
Start-BitsTransfer `
-Source c:\temp\file2.zip `
-Destination ftp://username:password#ftp.somewhere.com/file2.zip
In both cases I got the error:
Start-BitsTransfer : Cannot find drive. A drive with the name 'ftp' does not exist.
At c:\temp\bits2ftp.ps1:3 char:1
+ Start-BitsTransfer `
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (ftp:String) [Start-BitsTransfer], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.BackgroundIntelligentTransfer.Management.NewBitsTransferCommand
As such, I assume this isn't possible... however thought I'd post on here in case there is a way to do this (e.g. does it work on certain ftp servers)?
Also posting on here since I've seen no mention of anyone attempting this before, so thought I'd provide a Google hit for the next person to wonder.
So far as I can tell, FTP is not currently supported.
HTTP and HTTPS Download Server Requirements: http://msdn.microsoft.com/en-us/library/aa362846(v=vs.85).aspx
HTTP and HTTPS Upload Server (IIS) Requirements: http://msdn.microsoft.com/en-us/library/aa363130(v=vs.85).aspx
I am trying to use powershell to script some tasks within internet explorer. This involves downloading a file from a website after logging in to the site. I have one working test script, but the same code for the actual site gives me this error:
The '=' operator failed: The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED)).
At U:\PowershellScriptProjectSFTP\test.ps1:71 char:22
+ $controlRef = <<<< $browserDoc.getElementByID($controlID)
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : OperatorFailed
$browserDoc
$ie = new-object -com "InternetExplorer.Application"
$ie.navigate("about:blank")
$ie.visible = $true
[System.Threading.Thread]::Sleep(2000)
$ie.navigate($URL)
#get controls
write-host "Getting Document"
$browserDoc=$ie.Document
write-host "Getting Email component"
$email = $browserDoc.getElementById("MainContent_userEmail")
write-host "Getting Password component"
$pass = $browserDoc.getElementById("MainContent_userPassword")
write-host "Getting Button component"
$login = $browserDoc.getElementById("MainContent_submitButton")
The actual error is occuring elsewhere in the code, which I have left out because it is doing the same thing as up here, but during the loop to ensure the page is done loading. This code has worked from the same machine on a different site, but both were .net aspx 2.0 sites.
Basically, once the internet explorer navigates to the specified url, powershell loses the ability to communicate with the object, and this error is followed by several InvokeMethodOnNull and PropertyNotFound errors (these I understand, they are a result of referencing $ie, which has become a null object, the entire problem I am trying to diagnose). I am running Windows 7. Microsoft claims to have a fix for this, but only for XP and Server 03 and 08.
Really, just any explaination for what causes this behavior is all I am looking for. As I said, this same code pointed to some websites works perfectly, and at others fails everytime.
Just ran into this myself and found that running the Powershell window "as administrator" fixed the problem.
I should probably not ask a generic question with a specific example, but I have a hard time translating some basic commands from the PowerShell console to reusable functions and custom cmdlets. Is there a definitive guide to the syntax of PowerShell somewhere, with gotchas, hints and tips?
For instance, I'm trying to create a function in order to automate the administration of BizTalk Host instances. The following function does not work (fails at runtime) whereas each individual line works and performs as expected when individually pasted in a PowerShell console.
function AddNewHostInstance([string]$ServerName, [string]$HostName, [string]$Login, [string]$Password)
{
[System.Management.ManagementObject]$objServerHost = `
([WmiClass]"root/MicrosoftBizTalkServer:MSBTS_ServerHost").CreateInstance()
$objServerHost["ServerName"] = $ServerName
$objServerHost["HostName"] = $HostName
$objServerHost.Map()
$name = "Microsoft BizTalk Server " + $HostName + " " + $ServerName
[System.Management.ManagementObject]$objServerHost = `
([WmiClass]"root/MicrosoftBizTalkServer:MSBTS_HostInstance").CreateInstance()
$objHostInstance["Name"] = $name
$objHostInstance.Install($Login, $Password, $True)
}
By the way, the error I receive in this particular case is this one:
PS C:\Users\username> createHostInstances $server, $host, $user, $pwd
Exception calling "Map" : "Invalid parameter "
At line:14 char:39
+ $objServerHost.Map <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WMIMethodException
Exception calling "Install" : "Instance of the WMI class is not found.
No instance was found with the specified key. This could be the result of the instance being deleted by another BizTalk Admin session."
At line:19 char:29
+ $objHostInstance.Install <<<< ($Login, $Password, $True)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WMIMethodException
PS C:\Users\username>
[Edit] After further investigation, it seems that the function does not like assigning properties to WMI object via a variable. If I hardcode all values (instead of relying on the supplied function parameters), then it works as expected !
Basically, this works:
# Using hard-coded value
$objServerHost["HostName"] = "TestHost"
Whereas this, does not:
# Using function supplied parameter
$objServerHost["HostName"] = $HostName
Still, I don't understand why...
As far as guides go, the best book out there is Windows PowerShell in Action by Bruce Payette. There is a second edition due in February but you can get early access to the electronic draft. There are also a couple of free books out there. Mastering PowerShell by Dr. Tobias Weltner and I also have a short < 60 pages eBook - Effective Windows PowerShell. This last one covers a number of gotchas as well as providing you with a mental model for how PowerShell works.
WRT the error, I wonder if you would have better luck using PowerShell's built-in support for WMI e.g.:
$namespace = 'root/MicrosoftBizTalkServer'
$host = Get-WmiObject -namespace $namespace -class MSBTS_HostInstance
See if the resulting WMI object has the appropriate data & methods (Map & Install):
$host | fl *
$host | Get-Member
Regarding the Map() error, sometimes with WMI you need to drop back and instead do $objServerHost.psbase.Invoke("Map"). Other than that, I've got a few sample PowerShell scripts for BizTalk administration you might find useful as guides.