So the Microsoft.Web.Administration API is very easy to use to create HTTP and HTTPS bindings for sites:
using (ServerManager manager = new
I feel like it's important to highlight Devator's comment in this answer. There appears to be a bug that prevents the certificate changes from taking place and I would never have solved it without seeing this comment.
If you set the binding information to itself, this causes IIS to bind the certificate. A quick example is shown below:
binding.BindingInformation = binding.BindingInformation;
Adding to Taylor Bird's comment but using powershell:
...
Write-Verbose ("Remove old certificate [ {0} ]... " -f $SiteHttpsBinding.GetAttributeValue("certificateHash"))
$BindingMethod=$SiteHttpsBindings.Methods["RemoveSslCertificate"]
$BindingMethodInstance=$BindingMethod.CreateInstance()
$BindingMethodInstance.Execute()
Write-Verbose ("Add new certificate [ {0} ]..." -f $AfterThumbprint)
$BindingMethod=$SiteHttpsBindings.Methods["AddSslCertificate"]
$BindingMethodInstance=$BindingMethod.CreateInstance()
$BindingMethodInstance.Input.SetAttributeValue("certificateHash", $AfterThumbprint)
$BindingMethodInstance.Input.SetAttributeValue("certificateStoreName", "My")
$BindingMethodInstance.Execute()
...
The above code snippet is useful for updating certificates without needing to remove the whole binding. I've used it for adding and updating ssl bindings on local and remote machines.
Thanks Mr. Bird for supplying the WinAPI reference.
If you landed here and are wanting to use PowerShell to accomplish this, I put a fairly complete answer here. The simplest answer, if you know the hash of the certificate that you want to use is to do this:
cd IIS:\SslBindings
get-item Cert:\LocalMachine\My\XFX2DX02779XFD1F6F4X8435A5X26ED2X8DEFX95 | New-Item 0.0.0.0!443
As Helephant's answer is the best if you need the certificate hashes (i.e. multiple IPs on a single machine with various SSL certs), you'll need to know how to get the certificates/hashes. The few lines below demonstrate how to find the information out, as the MSDN documentation is so poor for this subject.
You can't remotely update an SSL binding using ServerManager.OpenRemote() - there appears to be a bug with this. Appcmd won't help you either.
If you want to convert a byte string back into a byte array (if you know the hash), here's how.
static void Main(string[] args)
{
var store2 = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine);
Console.WriteLine("TrustedPublisher:");
PrintCerts(store2);
Console.WriteLine();
Console.WriteLine("MY:");
store2 = new X509Store(StoreName.My, StoreLocation.LocalMachine);
PrintCerts(store2);
Console.WriteLine();
Console.WriteLine("CertificateAuthority:");
store2 = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);
PrintCerts(store2);
Console.WriteLine();
}
static string PrintHash(byte[] cert)
{
StringBuilder builder = new StringBuilder();
foreach (byte b in cert)
{
builder.AppendFormat("{0:x2}", b);
}
return builder.ToString();
}
static void PrintCerts(X509Store store)
{
store.Open(OpenFlags.OpenExistingOnly);
foreach (var cert in store.Certificates)
{
Console.Write("{0} - {1}", cert.FriendlyName, PrintHash(cert.GetCertHash()));
Console.WriteLine();
}
}
Example output:
MY:
www.awesomesite.com - cc2b5fc8216a949b58aadc21089c12b2c090f6bd
There is a method overload for adding Bindings that will add the certificate to HTTP.sys correctly, see: http://msdn.microsoft.com/en-us/library/bb355650(v=VS.90).aspx
Optionally you can actually set the binding settings:
binding.CertificateHash and binding.CertificateStoreName and when commiting it will register correctly with HTTP.sys: http://msdn.microsoft.com/en-us/library/microsoft.web.administration.binding_properties(v=VS.90).aspx
The Bindings.Add() method has an overload for passing in the SSL certificate. If you already have a SSL certificate, you can select it from the SSL certificate store like this:
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly);
var certificate = store.Certificates.Find(X509FindType.FindByThumbprint, the thumbprint for the key", true);
var site = _mgr.Sites[name];
site.Bindings.Add("*:4043:", certificate[0].GetCertHash(), "MY");
Once you have run the code, you can check that it has worked by running this from the command line:
netsh http show sslcert