<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ET Ducky Blog]]></title><description><![CDATA[ET Ducky Blog]]></description><link>https://etducky.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 31 Oct 2026 16:59:39 GMT</lastBuildDate><atom:link href="https://etducky.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[0x8A15000F Data Required by the Source Is Missing in winget]]></title><description><![CDATA[This post first appeared on the ET Ducky blog. I build ET Ducky, an RMM that reads ETW on Windows and eBPF on Linux. 0x8A15000F is the winget return code…]]></description><link>https://etducky.hashnode.dev/0x8a15000f-data-required-by-the-source-is-missing-in-winget</link><guid isPermaLink="true">https://etducky.hashnode.dev/0x8a15000f-data-required-by-the-source-is-missing-in-winget</guid><category><![CDATA[Windows]]></category><category><![CDATA[winget]]></category><category><![CDATA[Powershell]]></category><category><![CDATA[sysadmin]]></category><dc:creator><![CDATA[Christopher Smith]]></dc:creator><pubDate>Fri, 30 Oct 2026 13:40:51 GMT</pubDate><content:encoded><![CDATA[<p>This post first appeared on the ET Ducky blog. I build ET Ducky, an RMM that reads ETW on Windows and eBPF on Linux.</p>
<p>0x8A15000F is the winget return code APPINSTALLER_CLI_ERROR_SOURCE_DATA_MISSING, with the description "Data required by the source is missing". It shows as the error of a failed winget command, and a script or deployment tool that runs winget reads it as the exit code -1978335217, the decimal form of the same value.</p>
<h2>What it means</h2>
<p>Data that a winget source needs is missing. The default winget source is stored as the package Microsoft.Winget.Source_8wekyb3d8bbwe. WinGet ships in App Installer as a packaged app, and packaged apps depend on being registered for the user who runs them. When the error appears for some users and not for others, it's likely that the source package isn't registered for those profiles. Packages can't be registered for NT AUTHORITY\SYSTEM, so the winget command line isn't supported in the system context at all.</p>
<h2>How to find the cause</h2>
<p>Check which account the failing command runs as. A script set to run as SYSTEM, such as a scheduled task or a deployment script in the system context, can't use winget.exe.</p>
<p>As an affected user, list the sources, then update them with verbose logging.</p>
<pre><code class="language-powershell">winget source list
winget source update --verbose-logs --open-logs
</code></pre>
<p>The log files are in <code>%LOCALAPPDATA%\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir</code>, and <code>winget --info</code> prints the same folder.</p>
<p>Then find the app deployment error for the source package in that user's session.</p>
<pre><code class="language-powershell">Get-WinEvent -FilterHashtable @{
    LogName = 'Microsoft-Windows-AppXDeploymentServer/Operational'
    StartTime = (Get-Date).AddMinutes(-15)
} | Where-Object { $_.Message -like '*Winget.Source*' } |
    Select-Object TimeCreated, Id, LevelDisplayName, Message
</code></pre>
<p>In Event Viewer the same log is under Applications and Services Logs &gt; Microsoft &gt; Windows &gt; AppXDeployment-Server &gt; Microsoft-Windows-AppXDeploymentServer/Operational. <code>Get-AppxLog</code> shows the logs of the most recent deployment operation. Run both checks as a working user too and compare the two results.</p>
<h2>Fixes</h2>
<p>When the source package isn't registered for the user, register it by its family name as that user, then update the sources.</p>
<pre><code class="language-powershell">Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.Winget.Source_8wekyb3d8bbwe
winget source update
</code></pre>
<p>When the source configuration is damaged, reset the sources from an elevated prompt. The reset removes every source except the defaults msstore, winget, and winget-font, so add any custom sources again afterward.</p>
<pre><code class="language-powershell">winget source reset --force
winget source update
</code></pre>
<p>When the winget client itself is broken, install the Microsoft.WinGet.Client module from the PowerShell Gallery and repair the client. Run the repair with -AllUsers from an elevated prompt to repair it for every user account on the machine.</p>
<pre><code class="language-powershell">Install-Module -Name Microsoft.WinGet.Client
Repair-WinGetPackageManager -AllUsers
</code></pre>
<p>When the command has to run as SYSTEM, use the Microsoft.WinGet.Client cmdlets such as Update-WinGetPackage in place of winget.exe. The module works in the system context for applications installed machine wide.</p>
<h2>Related errors</h2>
<ul>
<li>0x8A15000B, APPINSTALLER_CLI_ERROR_SOURCES_INVALID, "The configured source information is corrupt".</li>
<li>0x8A15000A, APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED, "The index is corrupt".</li>
<li>0x8A15003F, APPINSTALLER_CLI_ERROR_SOURCE_DATA_INTEGRITY_FAILURE, "The source data is corrupted or tampered".</li>
</ul>
<h2>Where ET Ducky shows it</h2>
<p>I build ET Ducky, and its patch management updates Windows apps through winget and Windows Update and Linux packages through apt, dnf, zypper, snap, and flatpak. You'd tag a few machines as your first ring and schedule app updates to that tag before the rest. A patch is marked successful only when services come back up with no crash loops, and a regression in a ring pauses the deployment.</p>
<p>Patch management docs: <a href="https://etducky.com/documentation/patch-management">https://etducky.com/documentation/patch-management</a></p>
<h2>Sources</h2>
<p>Windows Package Manager Client repository, Return codes and Repair-WinGetPackageManager; Microsoft Learn, Debugging and troubleshooting issues with the WinGet tool, The WinGet source command, Troubleshooting packaging, deployment, and query of Windows apps, Add-AppxPackage, Get-AppxLog, and Get-WinEvent; PowerShell Gallery, Microsoft.WinGet.Client. All read 2026-10-28.</p>
]]></content:encoded></item><item><title><![CDATA[Event ID 20 WindowsUpdateClient Installation Failure and How to Find the Cause]]></title><description><![CDATA[This post first appeared on the ET Ducky blog. I build ET Ducky, an RMM that reads ETW on Windows and eBPF on Linux. Event ID 20 from…]]></description><link>https://etducky.hashnode.dev/event-id-20-windowsupdateclient-installation-failure-and-how-to-find-the-cause</link><guid isPermaLink="true">https://etducky.hashnode.dev/event-id-20-windowsupdateclient-installation-failure-and-how-to-find-the-cause</guid><category><![CDATA[Windows]]></category><category><![CDATA[windows update]]></category><category><![CDATA[Powershell]]></category><category><![CDATA[sysadmin]]></category><dc:creator><![CDATA[Christopher Smith]]></dc:creator><pubDate>Sat, 24 Oct 2026 00:55:41 GMT</pubDate><content:encoded><![CDATA[<p>This post first appeared on the ET Ducky blog. I build ET Ducky, an RMM that reads ETW on Windows and eBPF on Linux.</p>
<p>Event ID 20 from Microsoft-Windows-WindowsUpdateClient is the event Windows writes when an update fails to install. It is an Error in the System log, under the task category Windows Update Agent. The message reads "Installation Failure: Windows failed to install the following update with error" followed by the error code and the update's name with its KB number. Microsoft's own example of the event is "Installation Failure: Windows failed to install the following update with error 0x80070002: Security Update for Windows (KB4586793)."</p>
<p>The matching success event is event 19 from the same source, which reads "Installation Successful: Windows successfully installed the following update" followed by the update's name.</p>
<h2>What it means</h2>
<p>Windows Update downloaded the update and the install step failed. The event names the update and the error code, but not the component that failed. The detail is in the servicing log, CBS.log, which records every package install and the error that stopped it.</p>
<h2>How to find the cause</h2>
<p>List the recent install results on the affected machine from an elevated PowerShell prompt. Events 19 and 20 together show which updates succeeded, which failed, and whether the same update fails on every attempt.</p>
<pre><code class="language-powershell">Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    ProviderName = 'Microsoft-Windows-WindowsUpdateClient'
    Id = 19, 20
} -MaxEvents 30 | Select-Object TimeCreated, Id, Message | Format-List
</code></pre>
<p>Note the error code and the KB number from the newest event 20, then look up the code in the table of common corruption errors in Microsoft's article Fix Windows Update corruptions and installation failures. Codes such as 0x800f0831 (CBS_E_STORE_CORRUPTION) and 0x80073712 (ERROR_SXS_COMPONENT_STORE_CORRUPT) point at the component store.</p>
<p>Search CBS.log for the same error code to find the component that failed. The log is at C:\Windows\Logs\CBS\CBS.log, and older entries roll over into CBSpersist files in the same folder. Replace the code below with the one from your event.</p>
<pre><code class="language-powershell">Select-String -Path C:\Windows\Logs\CBS\CBS.log -Pattern '0x80070002' -SimpleMatch | Select-Object -First 10
</code></pre>
<p>Read the first match by time. The lines around it point to the package or installer that failed.</p>
<p>For the Windows Update client's own trace, build the Windows Update log. Windows Update writes .etl trace files, and this command merges them into one readable WindowsUpdate.log on the current user's desktop.</p>
<pre><code class="language-powershell">Get-WindowsUpdateLog
</code></pre>
<p>When several machines fail the same update, run the event query on three or four of them. The same error code and KB number on every machine points at something those machines share more than at one damaged machine.</p>
<h2>Fixes</h2>
<p>When the error code is one of the component store errors in Microsoft's table, repair the component store, then check the system files, then retry the update.</p>
<pre><code>DISM.exe /Online /Cleanup-Image /RestoreHealth
sfc /scannow
</code></pre>
<p>When the machine can't reach Windows Update, or DISM reports 0x800F081F (CBS_E_SOURCE_MISSING), point the repair at a source running the same Windows version.</p>
<pre><code>DISM.exe /Online /Cleanup-Image /RestoreHealth /Source:\\&lt;servername&gt;\c$\windows /LimitAccess
</code></pre>
<p>When the error code is 0x8024002E (WU_E_WU_DISABLED), turn the Windows Update client service back on, then retry the update.</p>
<p>When the update installs, asks for a restart, and then rolls back, find the failing component in CBS.log as above and fix that component. Microsoft's article on 0x80070002 includes a cumulative update on Windows Server that rolled back after a restart, where CBS.log pointed at a driver.</p>
<p>When the error code is 0x800f0922, follow the steps on its own reference page: <a href="https://etducky.com/blog/windows-update-error-0x800f0922-cbs-e-installers-failed">https://etducky.com/blog/windows-update-error-0x800f0922-cbs-e-installers-failed</a></p>
<h2>Related events and errors</h2>
<ul>
<li>Event 19 from WindowsUpdateClient, the successful install of an update.</li>
<li>0x800F0922 CBS_E_INSTALLERS_FAILED, an update that fails while its installers run and then rolls back.</li>
<li>0x80070002, documented by Microsoft in Troubleshoot Windows Update error 0x80070002.</li>
</ul>
<h2>Where ET Ducky shows it</h2>
<p>I build ET Ducky, and its patch management talks to the Windows Update Agent directly and installs updates by KB number. You'd tag a few machines as your first ring and schedule updates to that tag before the rest. A patch is marked successful only when the kernel events show services back up with no crash loops. The deployment moves to the next ring only after the machines in the current ring pass that check, and a regression in a ring pauses the deployment. You can also open a Live Session shell from the browser without the need for a VPN and run the commands above on each machine.</p>
<p>Patch management docs: <a href="https://etducky.com/documentation/patch-management">https://etducky.com/documentation/patch-management</a></p>
<h2>Sources</h2>
<p>Microsoft Learn, Troubleshoot Windows Update error 0x80070002; Event ID 20, WUA Update Installation; Troubleshoot unexpected reboots using system event logs; Fix Windows Update corruptions and installation failures; Get-WinEvent; Select-String; Get-WindowsUpdateLog. All read 2026-10-21.</p>
]]></content:encoded></item><item><title><![CDATA[Finding Why a Linux Service Stopped After an Update]]></title><description><![CDATA[This post first appeared on the ET Ducky blog. I build ET Ducky, an RMM that reads ETW on Windows and eBPF on Linux. A service on an Ubuntu or Debian…]]></description><link>https://etducky.hashnode.dev/finding-why-a-linux-service-stopped-after-an-update</link><guid isPermaLink="true">https://etducky.hashnode.dev/finding-why-a-linux-service-stopped-after-an-update</guid><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[debian]]></category><category><![CDATA[systemd]]></category><dc:creator><![CDATA[Christopher Smith]]></dc:creator><pubDate>Wed, 14 Oct 2026 15:31:41 GMT</pubDate><content:encoded><![CDATA[<p>This post first appeared on the ET Ducky blog. I build ET Ducky, an RMM that reads ETW on Windows and eBPF on Linux.</p>
<p>A service on an Ubuntu or Debian server shows as inactive the morning after a round of updates, and its own log has no error in it. Restarting it fixes the symptom, but the next update can stop it again. This post covers how to tell a crash from a stop request, how to find what asked systemd to stop the service, and how to check every service after an update so the next one is caught in minutes.</p>
<h2>Find out whether it crashed or was stopped</h2>
<p>I'd start with the unit's status. Replace haproxy.service with your own unit in every command below.</p>
<pre><code>systemctl status haproxy.service --no-pager
</code></pre>
<p>A unit that shows inactive (dead) was stopped cleanly. A unit that crashed or failed to start shows failed with a result such as exit-code or signal. When the log lines under the status show "Stopping haproxy.service" and a process that exited with code 143, that process received SIGTERM (128 plus signal 15). systemd sends SIGTERM when something asks it to stop the unit.</p>
<p>Read the unit's own journal for the day to get the exact second of the stop.</p>
<pre><code>journalctl -u haproxy.service --since today -o short-iso --no-pager | tail -n 20
</code></pre>
<p>A restart that fails leaves a different trail. The journal shows "Stopping", then "Starting", then an error from the service's own start command, such as a configuration test that failed. That points at the service's configuration or at something it depends on being unavailable at that second.</p>
<h2>Check what apt ran at that minute</h2>
<p>Every apt and unattended-upgrades run writes a block to /var/log/apt/history.log with a Start-Date, the command line, the packages it changed, and an End-Date. Older months are rotated into compressed files, so search them with zgrep.</p>
<pre><code>zgrep -h -A4 "Start-Date: 2026-10-10" /var/log/apt/history.log*
</code></pre>
<p>When the Commandline line shows /usr/bin/unattended-upgrade, the automatic updates ran it. Compare its Start-Date and End-Date with the time of the stop. Then check whether the service's own package was in that run.</p>
<pre><code>zgrep -h " upgrade haproxy" /var/log/dpkg.log*
</code></pre>
<p>A package upgrade usually restarts its own service from the package scripts. The unattended-upgrades runs also write the full dpkg output, including any service restarts, to /var/log/unattended-upgrades/unattended-upgrades-dpkg.log. Search that file for the unit name.</p>
<pre><code>sudo grep -n "haproxy" /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
</code></pre>
<p>Run <code>systemctl list-timers apt-daily-upgrade.timer</code> to see when the automatic upgrade last ran and when it runs next. The timer runs at a set time with a random delay, so the stop time can move from day to day.</p>
<h2>Check needrestart on Ubuntu 24.04 and later</h2>
<p>A library upgrade can restart a service whose own package didn't change. On Ubuntu 24.04 needrestart restarts the affected services directly after apt finishes, in unattended-upgrades runs too. Ubuntu documented the change in <a href="https://discourse.ubuntu.com/t/needrestart-changes-in-ubuntu-24-04-service-restarts/44671">needrestart changes in Ubuntu 24.04</a>. A glibc update, for example, restarts most long-running services in one systemctl restart call. That call is in unattended-upgrades-dpkg.log with the full list of units it restarted.</p>
<p>A service that starts before something it needs at that second, such as name resolution, fails its start and stays down. When a service has to stay out of those restarts, add it to <code>$nrconf{override_rc}</code> in a file under /etc/needrestart/conf.d/ and restart it yourself in a maintenance window.</p>
<pre><code>$nrconf{override_rc}{qr(^haproxy\.service$)} = 0;
</code></pre>
<h2>Read everything logged in the minute before the stop</h2>
<p>When apt didn't run at that time, read every unit's journal lines from the minute before the stop. The -o cat output leaves out the hostname, which is useful if you post it on a forum.</p>
<pre><code>sudo journalctl --since "2026-10-10 10:04:30" --until "2026-10-10 10:05:38" -o cat
</code></pre>
<p>A stop that someone ran by hand with sudo shows up as a sudo line with the command it ran. Search for it directly.</p>
<pre><code>sudo journalctl -t sudo --since "2026-10-10 10:00" --until "2026-10-10 10:10" -o cat | grep systemctl
</code></pre>
<p>Check the timers that fired in that minute with <code>systemctl list-timers --all</code>, and check crontab and /etc/cron.d for a script that stops services before a backup or a certificate renewal. A configuration management run from Ansible or Puppet also shows up as its own lines in the journal for that minute.</p>
<h2>Prevent the next one</h2>
<p>Adding Restart=on-failure to the unit doesn't help with this. systemd doesn't restart a service when its death is the result of a stop or restart that systemd performed. The fix depends on what asked for the stop.</p>
<p>When the stop came from unattended-upgrades, exclude that package with Unattended-Upgrade::Package-Blacklist in /etc/apt/apt.conf.d/50unattended-upgrades and upgrade it by hand. When it came from needrestart, use override_rc as above. When it came from a script or a person, fix the script or the runbook.</p>
<p>Also check every service after each update. Save the list of running services before the update and compare it after.</p>
<pre><code>systemctl list-units --type=service --state=running --no-legend | awk '{print $1}' | sort &gt; /tmp/running-before.txt
sudo apt upgrade
systemctl list-units --type=service --state=running --no-legend | awk '{print $1}' | sort | comm -23 /tmp/running-before.txt -
</code></pre>
<p>Any unit the last command prints was running before the update and isn't running now. Run <code>systemctl --failed</code> as well to list units that failed to start.</p>
<h2>Where ET Ducky shows it</h2>
<p>I build ET Ducky, and its Linux agent reads process exec and exit events from eBPF tracepoints. The systemctl, needrestart, or package script process that ran in the minute before the stop is in that event record, along with the service's own processes exiting.</p>
<p>For patching, ET Ducky runs apt updates in rollout rings. You'd tag a few servers as your first ring and schedule updates to that tag before the rest. A patch is marked successful only when the kernel event stream shows services back up with no crash loops. If the first ring regresses, the deployment pauses before the next ring. You can also open a Live Session shell from the browser without the need for a VPN and run the journalctl and zgrep commands above on the host.</p>
<p>One Windows or Linux server on the Free query tier with your own AI key costs $5 a month. Pricing is at <a href="https://etducky.com/pricing">https://etducky.com/pricing</a>.</p>
<p>Drafted with AI, reviewed by me.</p>
]]></content:encoded></item></channel></rss>