Skip to content

Instantly share code, notes, and snippets.

@shawngmc
Created July 31, 2026 13:26
Show Gist options
  • Select an option

  • Save shawngmc/67570a810ad7863e880ad9a1946bc85e to your computer and use it in GitHub Desktop.

Select an option

Save shawngmc/67570a810ad7863e880ad9a1946bc85e to your computer and use it in GitHub Desktop.
Offline Workstation Update Procedure

Air-Gapped Windows 11 Patch Runbook

Scope: small fleet, no WSUS/SCCM. One-way sneakernet transfer — only a short text manifest ever leaves the isolated network; all update binaries travel inbound only.

1. Audit (offline machine)

Run Offline-Audit.ps1 as Administrator. It produces AuditReport_<hostname>_<date>.txt — a short, plain-text summary of:

  • OS build number
  • Installed cumulative/quality updates (Get-HotFix)
  • Defender signature/engine/platform versions
  • Installed .NET runtimes/SDKs
  • Installed PowerShell 7.x version

Sneakernet that .txt file to the connected machine. Review it before/after transfer — it's small enough to read in full.

2. Fetch (connected machine)

Compare the report against current versions and pull whatever's missing.

Item Where to get it Cadence
OS cumulative/quality update Microsoft Update Catalog — search the KB for your build (check Windows release health for the current month's KB). Grab any prerequisite Servicing Stack Update (SSU) too if flagged. Monthly, Patch Tuesday
Defender Security Intelligence (signatures) Defender update page — full package (mpam-fe.exe) for the right architecture Daily/every few days — do not wait for the monthly cycle
Windows Security platform update Microsoft Update Catalog — search "Microsoft Defender Antivirus platform update" Monthly, alongside cumulative
.NET runtime/SDK security update .NET 8 downloads or Update Catalog — match exact version from the audit report Monthly
PowerShell 7.x PowerShell GitHub releases — MSI for your architecture As released (irregular)
Malicious Software Removal Tool (MSRT, KB890830) Download Center, x64 / x86 — this link always serves the current month's build, no need to search the Catalog Monthly, 2nd Tuesday

Before moving anything back across the gap, verify it's genuinely from Microsoft:

Get-AuthenticodeSignature <file> | Select-Object Status, SignerCertificate

Status should read Valid. Also scan the transfer media itself for malware — that's the main injection risk in this workflow.

3. Install (offline machine)

Item Install command
Cumulative/SSU update wusa.exe update.msu or DISM /Online /Add-Package /PackagePath:update.msu, then reboot
Defender signatures Run mpam-fe.exe directly (admin rights) — applies immediately, no switches needed
Platform update Same as cumulative update
.NET runtime/SDK dotnet-runtime-8.x.x-win-x64.exe /install /quiet /norestart (or matching MSI)
PowerShell 7.x msiexec /i PowerShell-7.x.x-win-x64.msi /quiet /norestart
MSRT MRT.exe /F:Y /Q (forces a full scan and auto-cleans, no UI). MSRT has no installer — it's a standalone scanner you re-run each month, not something that stays "installed." It writes its own log to %WINDIR%\debug\mrt.log, which the audit script tails.

4. Re-audit

Re-run Offline-Audit.ps1. Confirm the new KB/version numbers show up. This report becomes next cycle's baseline.

5. Drivers (Dell hardware)

Drivers are hardware-specific, so this is a different workflow from the items above — no single package covers the fleet, and there's no offline "scan" without either an internet-connected DCU or a prebuilt catalog.

Why not Dell Command | Update's offline repository mode: DCU supports a fully offline repository workflow, but building one requires Dell TechDirect Portal access and Dell's repo-building tooling, and by most accounts (including Dell partners who've documented it) it's genuinely painful to set up — worth it if you're managing many Dell models at scale, overkill for a handful of machines. Manual, per-model downloads from Dell's public support site are simpler at this scale.

Audit (offline machine): Offline-Audit.ps1 now also captures:

  • Manufacturer/model and Service Tag (Win32_BIOS.SerialNumber) — needed to look up the right driver page
  • BIOS version
  • Every installed driver not authored by Microsoft (inbox/generic drivers update via the normal cumulative update process and don't need separate handling — only third-party/OEM drivers do)

Fetch (connected machine):

  1. Go to dell.com/support and enter the Service Tag from the report — no TechDirect account needed for this, it's the public drivers page.
  2. Filter to categories present in your "Non-Microsoft Drivers" list (chipset, network, storage/RAID, video/graphics, audio).
  3. Compare the listed "current version" against what's in your audit report; download anything newer as its standalone installer (.exe) or driver package (.cab).
  4. Verify: Get-AuthenticodeSignature <file> | Select Status — should read Valid and show Dell as signer.

Install (offline machine):

  • Most Dell driver installers are self-extracting EXEs. Try silent install first: DriverInstaller.exe /s (some use /quiet — check /? on the exe if /s doesn't work).
  • If an installer won't run silently or you'd rather avoid its GUI logic entirely, extract-only (/s /e=<path>) and stage the INF directly: pnputil /add-driver <path>\*.inf /install. This works the same regardless of vendor packaging.
  • Reboot if the driver touches a device in active use (storage, network, chipset).

BIOS/firmware — handle separately, more carefully: Dell BIOS updates are also on the support/Service-Tag page but carry real risk (a power-loss mid-flash can brick the board). Only do these on AC power (laptops) or with confirmed stable power (desktops), and don't bundle them into the same pass as routine driver updates. Track current version via Win32_BIOS.SMBIOSBIOSVersion in the audit report.

Cadence: Drivers don't follow Patch Tuesday — check quarterly, or sooner if a specific CVE affecting your hardware (chipset, NIC firmware) is announced.

6. Office LTSC 2024 Professional Plus

Office LTSC 2024 installs via Click-to-Run (C2R), not the Windows Installer (MSI). This matters a lot for this workflow: C2R has its own update mechanism (Microsoft's Office CDN) that is completely separate from Windows Update, WSUS, and the Microsoft Update Catalog. Nothing above touches it, and there's no KB to hunt for — you version-pin a release channel and pull whatever the CDN currently serves for it.

The tool for this is the Office Deployment Tool (ODT) — a small (~3-4 MB), free, signed utility from Microsoft's Download Center. Get a fresh copy each cycle since ODT itself updates.

Audit (offline machine): Offline-Audit.ps1 now reads HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration for VersionToReport (build) and UpdateChannel (should read PerpetualVL2024 for LTSC ProPlus 2024).

Fetch (connected machine):

  1. Download the latest ODT from Microsoft's Download Center (search "Office Deployment Tool").

  2. Create a config XML pinned to your channel:

    <Configuration>
      <Add SourcePath="C:\OfficeLTSC2024" OfficeClientEdition="64" Channel="PerpetualVL2024">
        <Product ID="ProPlus2024Volume">
          <Language ID="en-us" />
        </Product>
      </Add>
      <Updates Enabled="TRUE" />
    </Configuration>
  3. Run setup.exe /download config.xml. This pulls the full current build for that channel into SourcePath — there's no delta/patch file, so budget for several GB on your transfer media (noticeably bigger than everything else in this runbook).

Install (offline machine):

  1. Copy the ODT setup.exe, the same config XML, and the downloaded source folder over.
  2. Run setup.exe /configure config.xml. If the source build is newer than what's installed, it updates in place; if it's the same, it's a no-op — safe to run every cycle without checking the audit report first, though comparing VersionToReport first saves you moving multi-GB files for nothing.

Verification note: unlike the earlier items, Get-AuthenticodeSignature doesn't cleanly apply to C2R's compressed package format — ODT itself is Microsoft-signed and validates its downloads against the CDN; that's the integrity check here rather than checking the payload files directly.

Cadence: roughly monthly, tracking Patch Tuesday, sometimes with out-of-band releases for critical CVEs.

Notes

  • If the fleet grows past a handful of machines or picks up more Dell models, revisit Dell Command | Update's offline repository mode (or ConfigMgr-integrated driver management) rather than doing this by hand.
  • For OS/AV/.NET/PowerShell/MSRT, if the fleet grows, revisit WSUS Offline Update or a disconnected WSUS pair rather than doing this fully by hand.
<#
.SYNOPSIS
Air-gapped Windows 11 patch audit.
.DESCRIPTION
Run this on the OFFLINE machine. It collects current patch state for:
- OS build + cumulative/quality updates (Get-HotFix)
- Microsoft Defender signature/engine/platform versions
- .NET runtimes and SDKs installed
- PowerShell 7.x version, if installed
Output is a single short, plain-text report — safe to review before
it leaves the isolated network. This is the ONLY file that needs to
come back out; everything else (update packages) travels inbound only.
.NOTES
Run as Administrator for full Defender status.
#>
$ErrorActionPreference = 'SilentlyContinue'
$hostName = $env:COMPUTERNAME
$stamp = Get-Date -Format 'yyyy-MM-dd_HHmm'
$outFile = Join-Path $PSScriptRoot "AuditReport_${hostName}_${stamp}.txt"
function Write-Section {
param([string]$Title)
"" | Out-File $outFile -Append
"==== $Title ====" | Out-File $outFile -Append
}
"Patch Audit Report" | Out-File $outFile
"Host: $hostName" | Out-File $outFile -Append
"Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" | Out-File $outFile -Append
Write-Section "OS Build"
Get-ComputerInfo | Select-Object WindowsProductName, OsBuildNumber, OsVersion |
Format-List | Out-String | Out-File $outFile -Append
Write-Section "Installed Quality/Cumulative Updates (Get-HotFix)"
Get-HotFix | Select-Object HotFixID, Description, InstalledOn |
Sort-Object InstalledOn |
Format-Table -AutoSize | Out-String | Out-File $outFile -Append
Write-Section "Microsoft Defender Status"
Get-MpComputerStatus | Select-Object AMProductVersion, AMEngineVersion, `
AntivirusSignatureVersion, AntispywareSignatureVersion, `
AntivirusSignatureLastUpdated |
Format-List | Out-String | Out-File $outFile -Append
Write-Section ".NET Runtimes Installed"
$dotnetRuntimes = & dotnet --list-runtimes 2>$null
if ($dotnetRuntimes) {
$dotnetRuntimes | Out-File $outFile -Append
} else {
"dotnet CLI not found on PATH" | Out-File $outFile -Append
}
Write-Section ".NET SDKs Installed"
$dotnetSdks = & dotnet --list-sdks 2>$null
if ($dotnetSdks) {
$dotnetSdks | Out-File $outFile -Append
} else {
"dotnet CLI not found on PATH" | Out-File $outFile -Append
}
Write-Section "PowerShell 7.x Installed"
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object { $_.DisplayName -like 'PowerShell*' } |
Select-Object DisplayName, DisplayVersion |
Format-Table -AutoSize | Out-String | Out-File $outFile -Append
Write-Section "Office LTSC 2024 (Click-to-Run) Version"
# Office LTSC/365 uses Click-to-Run, not MSI -- it does not go through
# Get-HotFix or Windows Update at all. Version/channel live in the
# registry instead.
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' -ErrorAction SilentlyContinue |
Select-Object VersionToReport, UpdateChannel, ClientCulture, Platform |
Format-List | Out-String | Out-File $outFile -Append
Write-Section "Machine Identification (for driver/BIOS lookup)"
Get-CimInstance Win32_ComputerSystem | Select-Object Manufacturer, Model |
Format-List | Out-String | Out-File $outFile -Append
Get-CimInstance Win32_BIOS | Select-Object SerialNumber, SMBIOSBIOSVersion, ReleaseDate |
Format-List | Out-String | Out-File $outFile -Append
"Note: SerialNumber above is the Dell Service Tag." | Out-File $outFile -Append
Write-Section "Non-Microsoft Drivers Installed"
# Inbox/Microsoft-authored drivers update via normal cumulative updates.
# This list is what actually needs OEM (Dell) driver packages.
Get-CimInstance Win32_PnPSignedDriver |
Where-Object { $_.Manufacturer -and $_.Manufacturer -notlike '*Microsoft*' } |
Select-Object DeviceName, Manufacturer, DriverVersion, DriverDate |
Sort-Object DeviceName |
Format-Table -AutoSize | Out-String | Out-File $outFile -Append
Write-Section "Malicious Software Removal Tool (MSRT) - Last Run"
# MSRT has no installer and leaves no Get-HotFix/registry version entry.
# Its own log records the version and date it last ran.
$mrtLog = Join-Path $env:WINDIR 'debug\mrt.log'
if (Test-Path $mrtLog) {
Get-Content $mrtLog -Tail 15 | Out-File $outFile -Append
} else {
"No mrt.log found -- MSRT has likely never been run on this machine." | Out-File $outFile -Append
}
Write-Section "End of Report"
Write-Host "Report written to: $outFile" -ForegroundColor Green
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment