# Windows Server and IIS

> A Windows Task Scheduler task fetches the fresh certificate once a day, links it to the key in the Windows store and binds it to the IIS site.

URL: https://zrazu.com/en/docs/ssl-auto-windows-iis/

Use this for a site on IIS (Windows Server 2016 and newer) if the certificate is already installed on the server, meaning the private key is in the Windows certificate store. This is the case when the CSR was created in IIS ("Create Certificate Request") or a PFX was imported at some point.

How it works: a PowerShell script fetches the new certificate from the link, puts it into the computer store and links it to the key already there (`certutil -repairstore`). If the server has no key for the new certificate, the script changes nothing. Then it binds the new certificate to all of the site's HTTPS bindings in IIS.

## What you need

- The certificate link from your account: `https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN`.
- Sign-in to the server with administrator rights.
- The site name in IIS (as in **IIS Manager → Sites**), for example `Default Web Site`.

## Step 1. First installation (if the certificate is not installed yet)

If the CSR was created in IIS: **IIS Manager → server → Server Certificates → Complete Certificate Request** → the `cert.pem` file from `https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN/cert.pem`. If you have the key as a file, build a PFX in your account (certificate card → "Files" → PFX) and import it: **Server Certificates → Import**. Then **Sites → site → Bindings → https → SSL certificate**.

## Step 2. The script

Open **PowerShell as administrator** and create the file:

```powershell
New-Item -ItemType Directory -Force -Path "$env:ProgramFiles\ZRAZU" | Out-Null
notepad "$env:ProgramFiles\ZRAZU\zrazu-ssl.ps1"
```

Paste the text below into Notepad, put your IIS site name in the `$Site` line, and save.

```powershell file=zrazu-iis-update.ps1
# ZRAZU: updates the SSL certificate in IIS using the personal link. Run by Task Scheduler once a day.
$ErrorActionPreference = "Stop"
$Url = "https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN"
$Site = "Default Web Site"
$Dir = Join-Path $env:ProgramFiles "ZRAZU"
$CertFile = Join-Path $Dir "cert.cer"
$ChainFile = Join-Path $Dir "chain.cer"
Invoke-WebRequest -Uri "$Url/cert.pem" -OutFile $CertFile -UseBasicParsing
Invoke-WebRequest -Uri "$Url/chain.pem" -OutFile $ChainFile -UseBasicParsing
$New = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertFile)
# Already imported — do not import again, but check the binding: yesterday the import may have worked and the binding not.
$Have = Test-Path "Cert:\LocalMachine\My\$($New.Thumbprint)"
if (-not $Have) {
  Import-Certificate -FilePath $ChainFile -CertStoreLocation Cert:\LocalMachine\CA | Out-Null
  Import-Certificate -FilePath $CertFile -CertStoreLocation Cert:\LocalMachine\My | Out-Null
  certutil -repairstore my $New.Thumbprint | Out-Null
}
$Mine = Get-Item "Cert:\LocalMachine\My\$($New.Thumbprint)"
if (-not $Mine.HasPrivateKey) {
  if (-not $Have) { Remove-Item $Mine.PSPath }
  throw "ZRAZU: this server has no key for this certificate — certificate not replaced"
}
Import-Module WebAdministration
foreach ($Binding in Get-WebBinding -Name $Site -Protocol https) {
  if ($Binding.certificateHash -ne $New.Thumbprint) { $Binding.AddSslCertificate($New.Thumbprint, "My") }
}
$Until = $New.NotAfter.ToString('yyyy-MM-dd')
if ($Have) { "ZRAZU: certificate unchanged, valid until $Until" } else { "ZRAZU: new certificate installed, valid until $Until" }
```

Run it once by hand:

```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:ProgramFiles\ZRAZU\zrazu-ssl.ps1"
```

## Step 3. Schedule

```powershell
schtasks /Create /F /SC DAILY /ST 04:17 /RU SYSTEM /TN "ZRAZU SSL" /TR "powershell -NoProfile -ExecutionPolicy Bypass -File \"C:\Program Files\ZRAZU\zrazu-ssl.ps1\""
```

The task will appear in **Task Scheduler → Task Scheduler Library → ZRAZU SSL** and will run every day at 04:17 as the system.

## Check

1. A manual run prints "new certificate installed" or "certificate unchanged".
2. **IIS Manager → Sites → site → Bindings → https** — the certificate with the new date is selected.
3. Site: [https://zrazu.com/tools/ssl/example.com/](https://zrazu.com/tools/ssl/example.com/).
4. The result of the daily runs: **Task Scheduler → ZRAZU SSL → History** (the **Last Run Result** column: `0x0` means success).

## If it did not work

- "this server has no key for this certificate" — the certificate was issued for a key that this server does not have (reissued with a new key, or the CSR was created elsewhere). Import a PFX with the new key (step 1).
- `running scripts is disabled` — run it exactly as in steps 2–3: with `-ExecutionPolicy Bypass`.
- `(404) Not Found` — the link is disabled or replaced: create a new one in the certificate card and replace `$Url`.
- A site on IIS 8 / Windows Server 2012 — update the server: this Windows version no longer receives security updates.
