Trying to automate Exchange 2010 certificate renewal

Hi,

I am using 2011SBS (ie. 2008R2 server). I want to automatically replace the exchange server certificate - and the default powershell script that ships with CertifyTheWeb looks like it should be able to do it.

However, I get the error:
An unexpected error has occurred and a watson dump is being generated: mixed mode assembly is built against verison ‘v2.0.50727’ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.
Enable-ExchangeCertificate: Value cannot be null.
Parameter name: serverSettings
At c:…

Google is not really giving me great answers, and I’m no powershell expert so any help gratefully received.

Thanks

Richard

Hi Richard,

If you manually run any of the Exchange powershell cmdlets from a 64-bit powershell prompt so they work OK? This error is saying that we’re running .Net 4.x but the command it’s trying to run is .net 2.x (…net 2 to 3.5). Can you identify which version of Powershell you have installed? This is installed as part of the Windows Management Framework. https://docs.microsoft.com/en-us/powershell/wmf/overview

I’m actually looking at closer integration of services like Exchange with a new ‘deployment tasks’ feature: https://github.com/webprofusion/certify/issues/440 having said that though it’s unlikely that we will officially support SBS 2011 as we can only support products still supported/patched by their vendors (e.g. Microsoft) and that appears to have a max end of life of Jan 2020.

Another thing you might want to try is spawning a new powershell process within the script, then running the commands you need:

Same issue here. I’m aware its not supported any more and we should get rid of this server but until then its still a pain having no auto-renewal.

Anyone found a solution on this already?
(sorry for the german log)

2021-05-30 15:23:59.873 +02:00 [INF] Deployment Tasks did not complete successfully.
2021-05-30 15:49:50.611 +02:00 [INF] ---- Beginning Request [Limaks.at Default Webseite] ----
2021-05-30 15:49:50.612 +02:00 [INF] Certify/5.4.3.0 (Windows; Microsoft Windows NT 6.1.7601 Service Pack 1)
2021-05-30 15:49:50.617 +02:00 [INF] Beginning Certificate Request Process: xxx Default Webseite using ACME Provider:Certes
2021-05-30 15:49:50.617 +02:00 [INF] Requested identifiers to include on certificate: xxx
2021-05-30 15:49:50.617 +02:00 [INF] Beginning certificate order for requested domains
2021-05-30 15:49:50.618 +02:00 [INF] BeginCertificateOrder: creating/retrieving order. Retries remaining:2
2021-05-30 15:49:52.015 +02:00 [INF] Created ACME Order: xxx
2021-05-30 15:49:52.404 +02:00 [INF] Fetching Authorizations.
2021-05-30 15:49:53.946 +02:00 [INF] Got http-01 challenge xxx
2021-05-30 15:49:55.443 +02:00 [INF] Got http-01 challenge xxx
2021-05-30 15:49:56.855 +02:00 [INF] Got http-01 challenge xxx
2021-05-30 15:49:57.187 +02:00 [INF] Order authorizations already completed.
2021-05-30 15:49:57.193 +02:00 [INF] Requesting Certificate via Certificate Authority
2021-05-30 15:50:01.476 +02:00 [INF] Completed Certificate Request.
2021-05-30 15:50:01.507 +02:00 [INF] Performing Automated Certificate Binding
2021-05-30 15:50:02.778 +02:00 [INF] Completed certificate request and automated bindings update (IIS)
2021-05-30 15:50:04.546 +02:00 [INF] Request completed
2021-05-30 15:50:04.548 +02:00 [INF] Performing Post-Request (Deployment) Tasks…
2021-05-30 15:50:04.549 +02:00 [INF] Task [[Post-Request Script]] :: Task is enabled and primary request was successful.
2021-05-30 15:50:04.549 +02:00 [INF] Executing command via PowerShell
2021-05-30 15:50:05.201 +02:00 [ERR] Unerwarteter Fehler. Ein Watson-Abbild wird generiert: Die Assembly im gemischten Modus wurde während Version v2.0.50727 der Laufzeit erstellt und kann nicht während der 4.0-Laufzeit ohne zusätzliche Konfigurationsinformationen geladen werden…
Powershell Task Completed.
Error: Import-ExchangeCertificate: Der Wert darf nicht NULL sein.
Parametername: serverSettings
In C:\Program Files\CertifyTheWeb\Scripts\Common\MSExchangeEnableServices2010.ps1:16 Zeichen:1

The only thing I changed in the script was the Add-PSSnapIn exchange to -name “Microsoft.Exchange.Managment.Powershell.E2010” which caused a dump.

If I run the script manually with the file path instead of $result.ManagedItem.CerificatePath it works fine.
So I assume it’s got to do with this. “serverSettings” is also not contained in the script directly so I assume its called from the $result.ManagedItem.CerificatePath

I don’t think it’s the PS script it self or the PS version, it looks like the PS is using .Net runtime 4.x and the application was compiled for 2.x.
So either the Certify the web part needs to be compiled to run with .Net 4.x OR the before the script the .Net Version needs to be specified (set COMPLUS_version=v2.0…)?

If only a single certificate is needed, a workaround woud be to query the Asset directory for the latest created certificate. But thats not the nicest solution …

Any other ideas?

https://docs.microsoft.com/en-us/archive/blogs/aseemb/mixed-mode-assembly-is-built-against-version-v2-0-50727-of-the-runtime-and-cannot-be-loaded-in-the-4-0-runtime-without-additional-configuration-information

Name Value


PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 6.3.9600.19170
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2

Hi, our minimum supported version of PowerShell is 5.1 and our recommended minimum OS is Windows Server 2012 R2. You may possibly be able to get stuff to work on older PowerShell/OS versions with workarounds. Our PowerShell script runner specifically uses powershell 5 assemblies.

If you do change some of the scripts under \Scripts\Common note that these are old legacy scripts provided for compatibility with old installs of the app and they will be overwritten whenever the app updates, so don’t edit those and use a copy instead. The script name is unfamiliar so I think perhaps it’s either old or it’s a script you adapted yourself? “serverSettings” isn’t a part of our MSExchangeEnableServices.ps1 script in that folder:

param($result)

# enable powershell snap-in for Exchange 2010 upwards
Add-PSSnapIn Microsoft.Exchange.Management.PowerShell.E2010

# tell Exchange which services to use this certificate for, force accept certificate to avoid command line prompt
Enable-ExchangeCertificate -Thumbprint $result.ManagedItem.CertificateThumbprintHash -Services POP,IMAP,SMTP,IIS -Force

Note also that we do now have some built in Tasks for some common scenarios and a few of these are actually implemented as powershell. Here is the code for our basic Deploy to Exchange task:

param($result, $services, [switch] $cleanupPreviousCerts = $false, [switch] $addDoNotRequireSslFlag = $false)

# enable powershell snap-in for Exchange 2010 upwards
Add-PSSnapIn Microsoft.Exchange.Management.PowerShell.E2010

Write-Host "Enabling Certificate for Exchange services.."
		


if ($addDoNotUseSslFlag -eq $true)
{
	$args = @{ 
		Thumbprint = $result.ManagedItem.CertificateThumbprintHash; 
		Services = $services; 
		Force = $true;
		ErrorAction = Stop;
	}

	$args["DoNotRequireSsl"]= $true

	# us eoptional args
	Enable-ExchangeCertificate @args
} else {
	# tell Exchange which services to use this certificate for, force accept certificate to avoid command line prompt
	Enable-ExchangeCertificate -Thumbprint $result.ManagedItem.CertificateThumbprintHash -Services $services -Force -ErrorAction Stop
}

Write-Host "Certificate set OK for services."

if ($cleanupPreviousCerts -eq $true)
{
	Write-Host "Cleaning up previous certs in Exchange"
	
	Get-ExchangeCertificate -DomainName $Certificate.Subject.split("=")[1] | Where-Object -FilterScript { $_.Thumbprint -ne $NewCertThumbprint} | Remove-ExchangeCertificate -Confirm:$false
}

You may be able to wrap the powershell script call and call the command line powershell version, so you can modify the execution context further, or you could write the information you need out to a temp folder (e.g. the new certificate thumbprint) and schedule your own task to run a script, read that value and apply the cert. That has the advantage of being easy to run during scheduled maintenance.

As an aside, you may also be aware of recent malware targeting versions of Exchange, so now is a good time to check all recent security updates have been applied. Overall I would urge you to plan your next migration to a newer version of Exchange and Windows etc as it’s not safe to be on old versions if you rely on them for anything important.

I finally found the time to resolve this issue. I did follow your hint to change the script so it does not directly process the result provided as parameter.

Also I changed the task to run as a separate process by simply setting the flag in the application. I assume that basically did resolve the issue with the runtime environment.

PS: I’m well aware that it does make sense to upgrade to newer versions from a security point of view.

Thanks Chris, regarding running in a separate process we actually have an bug with that currently not behaving - it still runs as local system or the Certify service user instead of impersonating properly, so if it is working that would be interesting. I wonder if it does indeed work on older versions of windows…

Actually it did not work when I provided different credentials.
It’s just an assumption as I did not analyze it any further but I assume it does create a separate process (using the service user or local system) which seems to then have a runtime environment that is ok for the old libraries of Exchange 2010.

Thanks, the ‘create new process’ version starts powershell.exe with your script, whereas the standard version runs an in-process powershell runspace, so they will potentially have different behaviors.