Repository navigation
Update-DbaInstance - Allow callers to retain extracted update files for later cleanup #10777
Description
Activity
- addednew commandFeature request that would need a new commandFeature request that would need a new commandtriage requiredNew issue that has not been reviewed by maintainersNew issue that has not been reviewed by maintainers
on Oct 6, 2026 Thanks for the careful write-up and the measurements. Below is some technical input on the interface so a PR can be scoped well. Whether the parameter goes in is Chrissy's decision.
Current code on
developmentThe cleanup logic has not changed since 2.7.22; only the help text has. It runs in the
finallyblock ofInvoke-DbaAdvancedUpdate, once per action, before the pending-reboot check and beforeRestart-Computer. With-Restartit delays the reboot. Without-Restartit delays the return to the caller, exactly as you describe.Related history
#8244 (2022) reported a hang after setup had finished and before the temporary files were gone. I saw the same symptom at a customer on a two-node cluster. We closed that issue without a repro, and your numbers may explain it.
Interface suggestions
- Name:
-KeepExtractedFilesfits the existingKeep*switches. The closest one isStart-DbaAzMigration -KeepBacpac, which works the same way: an intermediate file is removed by default, and its path is reported in an output property. - Forwarding: add the switch to
Invoke-DbaAdvancedUpdate(it is exported) and toUpdate-DbaInstance, and add it to$updateSplat. That also covers two or more computers, becauseInvoke-Parallelruns the same script block. - Path, normal case:
ExtractPathis already on every output object. The default view hides it, and the existing tests inUpdate-DbaInstance.Tests.ps1already assert it. It only needs an entry in the.OUTPUTShelp ofUpdate-DbaInstance, which does not list it today. - Path with
-EnableException: under-EnableException, the innerStop-Functioncalls throw into thecatchblock, which callsStop-Functionagain. Passing-Target $outputto that call puts the object into the error record, so the caller'scatchcan read$_.TargetObject.ExtractPath. This is worth a test for a single computer. With two or more computers,Invoke-Parallelhandles the errors from its runspaces, so I would not promise it there. - The contract I would document instead of relying on either of these: the folder is always
<ExtractPath>\dbatools_KB<KB>_Extract_<32 hex characters>. With-KeepExtractedFiles, pass a dedicated-ExtractPathand, after recovery, remove thedbatools_KB*_Extract_*folders below it. This also covers runs that never return an object, for example a WinRM session lost during the reboot or an orchestrator step that was killed. Without-ExtractPath, each action picks the drive with the most free space. Kept folders use up that space, so a second update in the same run can land on a different drive. - Failures: with the switch, the folder stays on every path. That includes a failed extraction, which leaves a partial folder, and a failed setup. The help text should say so when it states that the caller owns the cleanup.
-WhatIf:Update-DbaInstancecallsShouldProcessbefore it hands any action toInvoke-DbaAdvancedUpdate, so nothing is extracted and nothing can be kept. One test showing that the switch does not change this is enough.
Tests
tests/Invoke-DbaAdvancedUpdate.Tests.ps1mocksInvoke-Programbut not the cleanup, so the realRemove-Itemruns. Let theInvoke-Programmock create the extraction folder below a test-owned-ExtractPath, and the tests can check the file system directly:- by default the folder is gone
- with the switch it still exists and matches
ExtractPathon the output - the same holds for the failing-setup case and for a run with two actions
Heads-up
My PR #10773 (approved, not merged yet) wraps the body of
Invoke-DbaAdvancedUpdatein an outertry/finallyto complete the progress bar, which re-indents the whole function. The two changes do not overlap in substance, but a PR based on today'sdevelopmentwill need a rebase once #10773 is in.A focused PR along these lines sounds good to me.
This text was created by Claude and reviewed by Andreas Jordan.
- Name:
Thanks for the detailed feedback, Andreas! I opened #10784, scoped to your suggestions and to what I had already tested in my environment.
It adds
-KeepExtractedFilesto both commands, passes-Target $outputso the result is reachable under-EnableExceptionfor a single computer, and documents the folder naming contract. Tests cover the default cleanup, retention, a failed setup,-EnableExceptionand-WhatIf.If anything needs changing, please let me know!
- John Wild (jwild91@gmail.com)
Summarize Command's Functionality
Would you consider an opt-in parameter such as -KeepExtractedFiles on Update-DbaInstance, forwarded to Invoke-DbaAdvancedUpdate?
In the code I inspected, extraction cleanup runs synchronously in finally, before the optional restart. Slow deletion can therefore delay reboot and the return to an external patching orchestrator.
My FCI/AG orchestrator owns reboot and SQL/HA recovery checks. Retaining the generated extraction directory would let it complete recovery before removing the temporary media. Existing cleanup would remain the default.
I tested an equivalent local change with dbatools 2.7.23 on Windows PowerShell 5.1. Two SQL2016 FCI canaries successfully cleaned up after recovery. Separately, 24 fresh file-only extraction/deletion trials across eight sandbox hosts took 0.83–5.90 seconds per deletion. Matched uninstall/repatch comparisons are ongoing; the specific security rule or policy responsible remains unresolved.
In our environment, a very commonly used endpoint-security product has caused stalls during inline extraction cleanup, adding roughly 50 minutes to a patch run. Moving cleanup into a separate step after reboot and recovery didn’t reproduce those stalls in our initial trials; cleanup took roughly 6 seconds. We’re gathering more repetitions to check how consistently this holds.
Suggested scope:
Would this fit the project? I’m happy to contribute a focused PR once the interface and failure behavior are agreed.
Is there a command that is similiar or close to what you are looking for?
Yes
Technical Details
No response