Upgrading Duo Authentication for Windows Logon - 夜莺博客

Upgrading Duo Authentication for Windows Logon

原文:Upgrading Duo Authentication for Windows Logon — theDXT (Daniel Keer)

Update

The script below still works. However, the MSI installer for Duo Win Logon does not include the new Microsoft Visual C++ 2022 Redistributable dependency. For a safer upgrade, I created a new PowerShell script that uses the EXE installer for Duo Win Logon, which includes the dependency. My new post Install or Upgrade Duo Authentication for Windows Logon contains all the details about the new script.

Duo Authentication for Windows Logon and RDP is great tool that I like to use to add MFA to Windows systems specifically servers, as it could help prevent lateral movement in the network.

When you only have a few systems running Duo Authentication for Windows Logon and RDP upgrading it is short and painless. When you have many systems it can be a bit of a painful process as the only method seems to be to do it manually.

Naturally to solve this I wrote a PowerShell script to do the work.

Why Automate the Duo WinLogon Upgrade

Duo Authentication for Windows Logon installs a credential provider plus an RDP-only protection layer on the host. The credential provider sits in front of the Windows logon UI, so once it is installed the machine will not let anyone in without either a Duo push or a bypass code. That is the whole point of the tool, but it also means an upgrade that leaves the credential provider half-registered can lock you out of a server — including the console session you were relying on.

The installer is also updated regularly: new Duo API endpoints, TLS changes, and new dependencies mean that a fleet left alone for a year will usually be several versions behind. Nothing about the upgrade is complicated on a single machine, and that is exactly the problem. The manual path is click, next, next, finish on every host, which does not scale to fifty servers and invites drift between them.

Automating the upgrade buys three concrete things: every host ends up on the same version, the process is repeatable and logged instead of remembered, and the person doing it does not have to RDP into fifty servers to do five minutes of clicking each. The three things to get right are pinned dependencies, a predictable installer silent-switch, and a reboot policy you have actually decided on rather than let the installer decide for you.

Prerequisites and Version Rules

Before the script runs, the host needs to satisfy a few conditions. None of them are exotic, but each one has bitten somebody:

  • Winlogon is actually installed. The script looks for the product by its registry display name and exits quietly if it is not found. This makes it safe to push to a broad group of machines where only some of them run Duo.
  • Installed version is 4.1.0 or newer. Older builds need manual intervention because the installer changed too much underneath. The Duo upgrade help article documents what the old versions require; the practical answer is to touch those hosts by hand.
  • A current dependency set. Recent builds expect the Microsoft Visual C++ 2022 Redistributable. If it is missing the MSI can fail late, after it has already unregistered the old credential provider, which is the worst possible time to fail.
  • Local administrator rights and outbound HTTPS. The script downloads the installer from Duo, so a host behind a strict proxy needs the download step adapted or the package staged locally.
  • A download directory. The script checks for C:\temp and creates it if it does not exist, so the working path is predictable whether or not the image ships with it.

PowerShell Script

The PowerShell script will check if Duo Authentication for Windows Logon is installed. If no Duo Authentication for Windows Logon install is found it will just exit.

If the script detects that your Duo Authentication for Windows Logon version is older than 4.1.0 the script will exit. Versions older than 4.1.0 may need manual steps to upgrade. You can read more about what you need to do in this Duo help article.

If the script detects that the installed version of Duo Authentication for Windows Logon is less than 4.2.2 (the current version of Duo Authentication for Windows Logon at the time of writing) it will consider Duo Authentication for Windows Logon as old. (If you edit the variable $newduo you can change which version it checks for)

The script also checks if C:\temp exist and if it doesn’t it will create it.

The script will download a zip file from Duo that contains the MSI installer.

The script will then run the MSI install which will upgrade the installed version of Duo Authentication for Windows Logon. If the upgrade requires a reboot it won’t reboot the system.

I’ve posted the PowerShell script on my GitHub. https://github.com/thedxt/Duo

What the Script Actually Does, Step by Step

It is worth reading the logic once before you trust it on a production server, because every branch is a decision you may want to change. The flow is:

  1. Query the registry uninstall keys for the Duo WinLogon product and read its DisplayVersion.
  2. If the product is absent, log that fact and exit 0. Absent is not an error; the machine simply is not a Duo host.
  3. Compare the installed version against two thresholds: the 4.1.0 floor below which the upgrade is not safe to automate, and the $newduo target above which no work is needed.
  4. Create C:\temp if missing and download the current installer archive into it.
  5. Expand the archive and locate the MSI.
  6. Invoke the MSI with a silent command line and REBOOT=ReallySuppress so a pending-reboot requirement does not take the server down mid-change-window.
  7. Re-read the installed version and report the before/after pair, so the automation log answers "did the upgrade actually happen?" without anyone logging in.

A reference implementation of exactly those steps looks like this. Treat it as a starting point you adapt to your environment rather than a black box, and test it against a lab host first:

#Requires -RunAsAdministrator
$log      = "C:\temp\duo-winlogon-upgrade.log"
$newduo   = [version]"4.2.2"   # target version
$minduo   = [version]"4.1.0"   # below this we refuse to automate
$workdir  = "C:\temp"
$uri      = "https://dl.duosecurity.com/DuoWinLogon-latest.zip"

function Write-Log($msg) {
    $line = "{0}  {1}" -f (Get-Date -Format s), $msg
    Add-Content -Path $log -Value $line
    Write-Host $line
}

if (-not (Test-Path $workdir)) { New-Item -ItemType Directory -Path $workdir | Out-Null }

# 1. find the installed product
$keys = @(
  'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
  'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
$app = Get-ItemProperty $keys -ErrorAction SilentlyContinue |
       Where-Object { $_.DisplayName -like 'Duo Authentication for Windows Logon*' } |
       Select-Object -First 1

if (-not $app) { Write-Log "Duo WinLogon not installed; nothing to do."; exit 0 }

$installed = [version]$app.DisplayVersion
Write-Log "Installed version: $installed"

# 2. version gates
if ($installed -lt $minduo) {
    Write-Log "Version $installed is older than $minduo - manual upgrade required."; exit 1
}
if ($installed -ge $newduo) {
    Write-Log "Version $installed already meets target $newduo; skipping."; exit 0
}

# 3. download and expand
$zip = Join-Path $workdir "DuoWinLogon.zip"
Invoke-WebRequest -Uri $uri -OutFile $zip -UseBasicParsing
Expand-Archive -Path $zip -DestinationPath $workdir -Force
$msi = Get-ChildItem $workdir -Filter *.msi | Select-Object -First 1
Write-Log "Installing $($msi.FullName)"

# 4. silent upgrade, never reboot
$args = @('/i', "`"$($msi.FullName)`"", '/qn', '/norestart', 'REBOOT=ReallySuppress', "/l*v `"$workdir\msi.log`"")
$p = Start-Process msiexec.exe -ArgumentList $args -Wait -PassThru
Write-Log "msiexec exit code: $($p.ExitCode)"

# 5. report the result
$after = (Get-ItemProperty $keys -ErrorAction SilentlyContinue |
          Where-Object { $_.DisplayName -like 'Duo Authentication for Windows Logon*' } |
          Select-Object -First 1).DisplayVersion
Write-Log "Version after upgrade: $after"
if ($p.ExitCode -eq 3010) { Write-Log "Reboot required to complete the upgrade." }

Two details in that script matter more than the rest. The MSI log switch (/l*v) is the only reliable way to find out why a silent install failed on one host out of fifty, and the exit-code check for 3010 is how you find out a reboot is pending without letting the installer take it for you. Note that $app.DisplayVersion can be buried in the product's own subkey on some builds; a script that reports an empty version string should fall back to reading the versioned subkey rather than assuming the upgrade is unnecessary.

The Microsoft Visual C++ 2022 Redistributable Problem

This is the single biggest gotcha with the MSI path, and it is why the newer script in the follow-up post switched to the EXE installer. The Duo MSI does not carry the Microsoft Visual C++ 2022 Redistributable as a bundled dependency, so on a freshly imaged or heavily trimmed server the upgrade can uninstall the old version, fail to register the new component, and leave the host in a state where the credential provider is gone but no replacement is in place.

The symptoms are unpleasant and easy to misread: logon falls back to plain Windows authentication with no Duo prompt (a security regression rather than a lockout), or, if the RDP protection component half-installed, Remote Desktop refuses connections while the console still works. On an RDP-only administration model the second symptom looks exactly like a network or firewall problem.

Two mitigations are worth applying regardless of which installer you use. First, install the VC++ 2022 x64 redistributable as an explicit prerequisite step before running the Duo upgrade, and make that step idempotent so a second run is a no-op. Second, prefer the EXE installer on any host that has been hardened or slimmed down, because it carries its own prerequisites; the EXE offers no documented no-reboot flag, so you decide the reboot window rather than the installer deciding for you. Duo publishes checksums for both packages, and the current download links are on the Duo checksums page — verify the hash before you push a binary to fifty servers.

Running the Upgrade at Scale

Once the script works on one host, the question becomes how it reaches the rest. All the usual deployment channels work as long as they run the script in a context with local admin rights and network access:

  • Scheduled task or GPO startup script. Simple and dependency-free; a computer-targeted scheduled task that runs once and writes status to a file share is enough for a small fleet.
  • Configuration Manager or Intune. Package the installer as a locally staged payload rather than letting every endpoint download it, then use the exit codes as your compliance signal (3010 in particular needs to be a soft, non-failing code).
  • PDQ Deploy, Ansible or a fleet tool of choice. These give you the retry and reporting behaviour that a bare script lacks.
  • A staged rollout. Upgrade a pilot ring first, leave it for a week so users actually log off and back on, then widen. Duo upgrades are usually uneventful, but a bad credential provider only shows up when somebody tries to log in.

Whatever channel you choose, decide the reboot policy up front. The script deliberately never reboots; the consequence is that a host may sit with a pending reboot until the next maintenance window, and during that time the old and new binaries can coexist. Track it: record hosts that returned 3010 and bounce them on a schedule rather than hoping.

Verifying the Upgrade

Do not treat a zero exit code as proof. Verify on each host with three cheap checks:

# Version actually reported by Windows
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* |
  Where-Object DisplayName -like 'Duo Authentication for Windows Logon*' |
  Select-Object DisplayName, DisplayVersion, InstallDate

# Components the Duo agent depends on
Get-Service DuoAuthService, DuoCredProvSvc -ErrorAction SilentlyContinue
Get-Process duod* -ErrorAction SilentlyContinue

Then do the one test no script can do for you: log off and log back on to a pilot host and confirm the Duo prompt appears, and open a fresh RDP session to confirm the RDP protection is still active. A version number that advanced while the credential provider stopped working is a silent MFA outage, not a successful upgrade.

Extra Info

You can upgrade Duo Authentication for Windows Logon with the EXE method but there doesn’t appear to be a no reboot flag. In my testing sometimes when upgrading Duo Authentication for Windows Logon it needed a reboot.

You can find the links for the most recent MSI or EXE from Duo here.

See also the follow-up on this site, Install or Upgrade Duo Authentication for Windows Logon, and Duo Authentication Proxy Upgrade for the server-side proxy that handles the actual Duo API calls. If you are rolling out MFA alongside other remote-access changes, Windows Admin Center SSO and mass editing ADSI values cover the adjacent pieces of the same identity problem.