{"id":1026,"date":"2026-11-04T02:38:53","date_gmt":"2026-11-04T02:38:53","guid":{"rendered":"https:\/\/windows-vps.org\/blog\/?p=1026"},"modified":"2026-11-04T02:38:53","modified_gmt":"2026-11-04T02:38:53","slug":"wsus-offline-patching-wsusutil-airgap","status":"publish","type":"post","link":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/","title":{"rendered":"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">An air-gapped VPS has no route to Microsoft Update, and WSUS cannot synchronize its catalog without one. The workable answer is to carry the update metadata and binaries across the gap on removable media using <code>wsusutil export<\/code> on a connected upstream server and <code>wsusutil import<\/code> on the isolated downstream. The mechanics are simple; the disk space math is what trips people.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The export package is not just the .cab payloads. It contains the WSUS database content minus the log files, expanded to a folder on disk before being packed, so peak usage during export is roughly twice the final package size plus the SQL database itself. On a VPS with a 100 GB data disk and a 60 GB WSUS content store, that peak easily exceeds the volume.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Plan the sizing before you run the command, not after. A useful starting number: content store \u00d7 2 + database size + 20 GB working headroom. For a <a href=\"https:\/\/windows-vps.org\/\">Windows VPS used as an offline update point<\/a>, that usually means attaching a temporary second volume for the export stage and detaching it once the media is written.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing the upstream server<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Decline nothing casually. Every declined update is excluded from the export, so the isolated side will never receive it. On the connected upstream, approve updates for the exact products and classifications the air-gapped estate needs, let synchronization finish, and confirm that content has actually downloaded \u2014 approved but not downloaded updates appear in the catalog but fail at install with error 0x80244019.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># On the connected upstream\n&amp; \"$env:ProgramFiles\\Update Services\\Tools\\WsusUtil.exe\" export D:\\export\\wsus-2026-11.cab D:\\export\\wsus-2026-11.log\nGet-ChildItem D:\\export | Select Name,@{n='GB';e={[math]::Round($_.Length\/1GB,2)}}\n\n# On the isolated downstream\n&amp; \"$env:ProgramFiles\\Update Services\\Tools\\WsusUtil.exe\" import E:\\media\\wsus-2026-11.cab E:\\media\\wsus-2026-11.log<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Stage<\/th><th>Disk needed (GB)<\/th><th>Duration at 150 MB\/s<\/th><\/tr><\/thead><tbody><tr><td>Content store (mirrored)<\/td><td>60<\/td><td>baseline<\/td><\/tr><tr><td>Temp expand during export<\/td><td>60<\/td><td>7 min<\/td><\/tr><tr><td>Output .cab<\/td><td>55<\/td><td>6 min<\/td><\/tr><tr><td>Log file<\/td><td>1\u20132<\/td><td>&lt; 1 min<\/td><\/tr><tr><td>Total working set<\/td><td>~180<\/td><td>15\u201325 min<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The log file is worth attention. WsusUtil writes one line per update exported, and on a catalog of 60,000 updates it grows past a gigabyte. It is also the only record of which updates made it into the package, so archive it with the media rather than deleting it to save space.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What the export does not include<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The package carries the update metadata, the binary payloads, and the approval state at export time. It does not carry computer group membership, target group assignments in a form the downstream will honor unconditionally, or the WSUS server&#8217;s own configuration \u2014 port, SSL settings, content path, and product list all have to match on the receiving side or the import will complete but clients will not see the updates.<\/p>\n\n<p>It also does not carry the synchronization schedule or the server certificate. If the downstream uses SSL with a self-signed certificate, deploy the certificate to clients separately; an imported catalog over HTTPS with an untrusted certificate produces client-side errors that look like missing updates.<\/p>\n<!-- \/wp:post-content -->\n\n<!-- wp:heading {\"level\":2} -->\n<h2 class=\"wp-block-heading\">The import on the isolated side<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Import is a database merge, not a replacement. Updates already present are updated; new ones are added; nothing is deleted. That is useful for incremental monthly packages but means an old package applied after a new one will not roll anything back. Sequence imports by date and keep the media labeled with the export date and the upstream sync timestamp.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>The import runs as a single database transaction, so a 60 GB package can hold the WSUS database locked for 40\u201390 minutes on modest hardware. Schedule it outside the approval window, stop the WSUS service during the operation if your version permits, and take a database backup first with <code>wsusutil.exe backupAll<\/code> \u2014 a failed import mid-way is rare but recovery without a backup is a rebuild.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"level\":2} -->\n<h2 class=\"wp-block-heading\">Content path and hash verification<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>The common failure after a successful import is content that exists in the catalog but not on disk. WsusUtil reports success based on the database, and the binaries land under the configured local content folder \u2014 <code>C:\\WSUS\\WsusContent<\/code> by default. Confirm the content folder has the expected file count and total size before letting clients scan.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Hash mismatch is the other one: media copied over USB with a generic copy tool can lose a block silently. Always compare SHA-256 of the .cab before import, and on the downstream run a client-side <code>wuauclt \/resetauthorization \/detectnow<\/code> on one test machine to confirm it reports updates rather than error 0x80244022 or a pending install that fails on hash validation.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:table -->\n<figure class=\"wp-block-table\"><table><thead><tr><th>Check<\/th><th>Pass criterion<\/th><th>Tool<\/th><\/tr><\/thead><tbody><tr><td>Package integrity<\/td><td>SHA-256 matches source<\/td><td>Get-FileHash<\/td><\/tr><tr><td>Catalog count<\/td><td>Within 1% of upstream approved<\/td><td>WSUS console counts<\/td><\/tr><tr><td>Content folder<\/td><td>Size equals upstream content store \u00b13%<\/td><td>Explorer \/ du<\/td><\/tr><tr><td>Client scan<\/td><td>Test host sees the latest CU<\/td><td>wuauclt \/detectnow<\/td><\/tr><\/tbody><\/table><\/figure>\n<!-- \/wp:table -->\n\n<!-- wp:heading {\"level\":2} -->\n<h2 class=\"wp-block-heading\">Keeping packages small<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Full content store exports become unmanageable after a year. Use incremental exports: run the export monthly with only newly approved updates still in the &#8220;not yet exported&#8221; state, which WsusUtil tracks on the upstream server. A monthly incremental for a typical 200-server estate is 2\u20136 GB; the initial full package is 50\u201380 GB. Keep the full package on the shelf as a rebuild artifact.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Decline superseded updates before each export. Microsoft supersedes cumulative updates on a fixed cadence, and declining the old one removes its binaries from the content store and shrinks the next incremental. Run the cleanup wizard with &#8220;unused updates and update revisions&#8221; monthly, but never with &#8220;unneeded update files&#8221; on a server you export from \u2014 it deletes payloads an unexported update still needs.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"level\":2} -->\n<h2 class=\"wp-block-heading\">Pilot approval and rollback<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Approve each imported package to a pilot group of three to five machines for 48 hours before promoting it. An air-gapped estate cannot pull a replacement update on demand, so a bad patch is fixed by importing a superseding package on the next media run \u2014 typically a week later. The pilot window is what prevents a fleet-wide outage with a one-week recovery tail.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Keep the previous two approved cumulative updates unapproved rather than declined, so a rollback via <code>wusa \/uninstall \/kb:&lt;number&gt;<\/code> works if a pilot finds a regression. Declining removes the payload from content and makes the uninstall fail with 0x800f0906.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"level\":2} -->\n<h2 class=\"wp-block-heading\">A repeatable monthly routine<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:list -->\n<ul><li>Day 1: upstream syncs, approve for the air-gapped product set, confirm downloads complete.<\/li>\n<li>Day 2: decline superseded, run export to a temp volume with 2\u00d7 headroom.<\/li>\n<li>Day 2: hash the .cab, write to two media, label with date and sync timestamp.<\/li>\n<li>Day 3: verify media on a scratch machine, then import on the downstream.<\/li>\n<li>Day 3: compare content folder size, scan one test client, approve for pilot.<\/li>\n<li>Day 4: promote to production groups; archive the log and hash list.<\/li><\/ul>\n<!-- \/wp:list -->\n\n<!-- wp:paragraph -->\n<p>Two people should be able to run this without tribal knowledge; write the disk-size table into the runbook so nobody starts an export with 70 GB free. The transport is the fragile part of an <a href=\"https:\/\/windows-vps.org\/\">offline Windows VPS patching workflow<\/a>, not the commands, and the hash list is the only thing standing between a corrupt copy and a patch Tuesday that silently installs nothing.<\/p>\n<!-- \/wp:paragraph -->\n","protected":false},"excerpt":{"rendered":"<p>An air-gapped VPS has no route to Microsoft Update, and WSUS cannot synchronize its catalog without one. The workable answer is to carry the update metadata and binaries across the gap on removable media using wsusutil export on a connected upstream server and wsusutil import on the isolated downstream. The mechanics are simple; the disk &#8230; <a title=\"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil\" class=\"read-more\" href=\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/\" aria-label=\"Read more about Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[5],"tags":[],"class_list":["post-1026","post","type-post","status-publish","format-standard","hentry","category-tutorials-guides"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil - Windows VPS Blog<\/title>\n<meta name=\"description\" content=\"An air-gapped VPS has no route to Microsoft Update, and WSUS cannot synchronize its catalog without one. The workable answer is to carry the update\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil\" \/>\n<meta property=\"og:description\" content=\"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil\" \/>\n<meta property=\"og:url\" content=\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/\" \/>\n<meta property=\"og:site_name\" content=\"Windows VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-04T02:38:53+00:00\" \/>\n<meta name=\"author\" content=\"windows-vps\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@myxiechengxuan\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"windows-vps\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/\",\"url\":\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/\",\"name\":\"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil - Windows VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\"},\"datePublished\":\"2026-11-04T02:38:53+00:00\",\"author\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\"},\"description\":\"An air-gapped VPS has no route to Microsoft Update, and WSUS cannot synchronize its catalog without one. The workable answer is to carry the update\",\"breadcrumb\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/windows-vps.org\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\",\"url\":\"https:\/\/windows-vps.org\/blog\/\",\"name\":\"Windows VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/windows-vps.org\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\",\"name\":\"windows-vps\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"caption\":\"windows-vps\"},\"sameAs\":[\"https:\/\/windows-vps.org\/blog\",\"https:\/\/x.com\/myxiechengxuan\"],\"url\":\"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil - Windows VPS Blog","description":"An air-gapped VPS has no route to Microsoft Update, and WSUS cannot synchronize its catalog without one. The workable answer is to carry the update","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/","og_locale":"en_US","og_type":"article","og_title":"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil","og_description":"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil","og_url":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/","og_site_name":"Windows VPS Blog","article_published_time":"2026-11-04T02:38:53+00:00","author":"windows-vps","twitter_card":"summary_large_image","twitter_creator":"@myxiechengxuan","twitter_misc":{"Written by":"windows-vps","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/","url":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/","name":"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil - Windows VPS Blog","isPartOf":{"@id":"https:\/\/windows-vps.org\/blog\/#website"},"datePublished":"2026-11-04T02:38:53+00:00","author":{"@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58"},"description":"An air-gapped VPS has no route to Microsoft Update, and WSUS cannot synchronize its catalog without one. The workable answer is to carry the update","breadcrumb":{"@id":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/windows-vps.org\/blog\/wsus-offline-patching-wsusutil-airgap\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/windows-vps.org\/blog\/"},{"@type":"ListItem","position":2,"name":"Offline Windows Patching on an Air-Gapped VPS: Exporting and Importing with wsusutil"}]},{"@type":"WebSite","@id":"https:\/\/windows-vps.org\/blog\/#website","url":"https:\/\/windows-vps.org\/blog\/","name":"Windows VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/windows-vps.org\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58","name":"windows-vps","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","caption":"windows-vps"},"sameAs":["https:\/\/windows-vps.org\/blog","https:\/\/x.com\/myxiechengxuan"],"url":"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/"}]}},"_links":{"self":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/1026","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/comments?post=1026"}],"version-history":[{"count":1,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/1026\/revisions"}],"predecessor-version":[{"id":1029,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/1026\/revisions\/1029"}],"wp:attachment":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/media?parent=1026"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/categories?post=1026"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/tags?post=1026"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}