How can you resolve Windows Update 413 Request Entity Too Large errors caused by orphaned virtual devices?
Issue Description
Windows patch Update can fail with 413 Request Entity Too Large on RDP- or VDI-heavy servers when orphaned virtual devices accumulate under TERMINPUT_BUS\UMB.
Important Note
This article is provided for reference only. The issue described is caused by the Windows operating system and is outside the scope of UiPath product support. We recommend contacting Microsoft Support for assistance. The steps and script below are provided "as is", are not a Microsoft-endorsed solution, and UiPath does not take ownership of or support them. They modify the Windows registry and remove device entries, which can disrupt active sessions if applied incorrectly. Review all steps with your IT team and test in a non-production environment before proceeding. If your IT team does not approve these steps, contact Microsoft Support.
Resolution
- Preferred path: run the Virtual Devices Cleanup Script before patching
- Create a working folder on the affected server, for example
C:\Temp\VirtualDevicesCleanup. - Download and install the Windows Driver Kit (WDK). DevCon is included with the WDK.
- Copy
devcon.exefrom the WDK tools folder into the same working folder as the script. On a 64-bit server, the path is typically similar toC:\Program Files (x86)\Windows Kits\10\Tools\<version>\x64\devcon.exe. - Create a new PowerShell script file such as
VirtualDevicesCleanup.ps1, paste in the script below, and save it in that same folder. - Open PowerShell as Administrator, change to the working folder, and optionally start with
.\VirtualDevicesCleanup.ps1 -ReportOnlyor.\VirtualDevicesCleanup.ps1 -WhatIf. - When you are ready to clean up stale devices, run the script without switches in the same maintenance window immediately before Windows Update.
- This is the safest remediation path because it targets older orphaned devices instead of deleting every virtual device entry at once.
- PowerShell script:
param( [switch]$ReportOnly, # Totals only, no removal [switch]$WhatIf # Preview removals without deleting )Banner
Write-Host "##########################################################"
Write-Host "# Virtual Devices Cleanup Script #"
Write-Host "# ==================================================== #"
Write-Host "# Purpose: Identify accumulated virtual keyboard/mouse #"
Write-Host "# devices under TERMINPUT_BUS\UMB and (optionally) #"
Write-Host "# remove older non-active instances before patching. #"
Write-Host "##########################################################"
Write-Host ""Registry path
$registryPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\TERMINPUT_BUS\UMB"
Get all devices
$devices = Get-ChildItem -Path $registryPath -ErrorAction SilentlyContinue
if (-not $devices) {
Write-Host "No devices found under $registryPath"
return
}Get active session IDs
$activeSessions = @(
quser 2>$null | ForEach-Object {
if ($_ -match '^\s*>?\s*(\S+)\s+(\S+)\s+(\d+)\s+Active\b') {
[int]$matches[3]
}
}
)Write-Host "Active Sessions Detected: $($activeSessions -join ', ')"
Write-Host ""Separate devices into keyboards and mice
$keyboards = @()
$mice = @()foreach ($device in $devices) {
$deviceProps = Get-ItemProperty -Path $device.PSPath -ErrorAction SilentlyContinue
$hardwareIds = @($deviceProps.HardwareID)if ($hardwareIds -match "TS_INPT\\TS_KBD") { $keyboards += $device } elseif ($hardwareIds -match "TS_INPT\\TS_MOU") { $mice += $device }}
Count active sessions
$activeCount = $activeSessions.Count
Sort by most recently written (newest = likely active)
$keyboardsSorted = $keyboards | Sort-Object LastWriteTime -Descending
$miceSorted = $mice | Sort-Object LastWriteTime -DescendingSplit active vs old devices
$activeKeyboards = $keyboardsSorted | Select-Object -First $activeCount
$oldKeyboards = $keyboardsSorted | Select-Object -Skip $activeCount$activeMice = $miceSorted | Select-Object -First $activeCount
$oldMice = $miceSorted | Select-Object -Skip $activeCountCounts
$keyboardCount = $activeKeyboards.Count
$mouseCount = $activeMice.Count
$oldKeyboardCount = $oldKeyboards.Count
$oldMouseCount = $oldMice.Count
$totalOld = $oldKeyboardCount + $oldMouseCountOutput totals
Write-Host "--------------------------------------------------------"
Write-Host "Total virtual devices identified:"
Write-Host "--------------------------------------------------------"
Write-Host "Total number of virtual keyboards in active sessions: $keyboardCount"
Write-Host "Total number of virtual mice in active sessions: $mouseCount"
Write-Host "Total number of old virtual keyboards (not in active sessions): $oldKeyboardCount"
Write-Host "Total number of old virtual mice (not in active sessions): $oldMouseCount"
Write-Host "--------------------------------------------------------"
Write-Host "Note: The most recently written devices are assumed active."
Write-Host " Older devices are candidates for removal."
Write-Host ""if ($ReportOnly) {
Write-Host "Report-only mode enabled. No devices were removed." -ForegroundColor Cyan
return
}if ($totalOld -eq 0) {
Write-Host "No old devices found to remove."
return
}Resolve devcon path:
1) Prefer devcon.exe in the same folder as this script
2) Fallback to PATH
$scriptDir = if ($PSCommandPath) { Split-Path -Parent $PSCommandPath } else { (Get-Location).Path }
$localDevcon = Join-Path $scriptDir "devcon.exe"if (Test-Path $localDevcon) {
$devconPath = $localDevcon
}
else {
$devconCmd = Get-Command devcon.exe -ErrorAction SilentlyContinue
if (-not $devconCmd) {
Write-Host "ERROR: devcon.exe not found in script folder or PATH." -ForegroundColor Red
Write-Host "Install WDK and copy devcon.exe beside this script, or add it to PATH." -ForegroundColor Yellow
return
}
$devconPath = $devconCmd.Source
}Confirm removal
$confirmation = Read-Host "Do you want to remove all old virtual keyboard and mouse devices using DevCon? (Y/N)"
if ($confirmation -notmatch '[1]$') {
Write-Host "Operation cancelled."
return
}Write-Host ""
Write-Host "Starting DevCon removal…" -ForegroundColor Yellow
Write-Host "Using DevCon: $devconPath"
Write-Host ""$deleted = 0
$failed = 0function Remove-WithDevCon {
param(
[Parameter(Mandatory = $true)]
$Device,
[Parameter(Mandatory = $true)]
[string]$DevconPath
)# Build device instance ID $instanceId = "TERMINPUT_BUS\UMB\$($Device.PSChildName)" if ($WhatIf) { Write-Host "[WhatIf] Would remove: $instanceId" -ForegroundColor Cyan return $true } $output = & $DevconPath remove "$instanceId" 2>&1 $exitCode = $LASTEXITCODE if ($exitCode -eq 0) { Write-Host "Removed (devcon): $instanceId" -ForegroundColor Green return $true } else { Write-Host "Failed: $instanceId" -ForegroundColor Red if ($output) { Write-Host " DevCon output: $($output -join ' ')" -ForegroundColor DarkRed } return $false }}
Remove old keyboards first, then mice
foreach ($device in $oldKeyboards) {
if (Remove-WithDevCon -Device $device -DevconPath $devconPath) { $deleted++ } else { $failed++ }
}
foreach ($device in $oldMice) {
if (Remove-WithDevCon -Device $device -DevconPath $devconPath) { $deleted++ } else { $failed++ }
}Write-Host ""
Write-Host "--------------------------------------------------------"
Write-Host "Cleanup complete"
Write-Host "Deleted: $deleted"
Write-Host "Failed: $failed"
Write-Host "--------------------------------------------------------"if ($failed -eq 0) {
Write-Host "DevCon removal completed successfully." -ForegroundColor Green
}
else {
Write-Host "Some devices could not be removed. A reboot may help before retrying." -ForegroundColor Yellow
}
- Create a working folder on the affected server, for example
- If needed, increase the WUS server payload-size limit
- If the environment routes Windows Update through WUS with request-size limits, review and increase the allowed server payload size so the update path can tolerate larger requests.
- This does not remove the stale devices, but it can reduce the chance of 413 failures while the environment is being cleaned up.
- Last resort: remove all virtual devices directly from the registry
- Use this only in a maintenance window and only if the targeted cleanup path is not available or does not resolve the issue.
- The command removes all entries under
TERMINPUT_BUS\UMB, so a reboot or session reinitialization may be required afterward. - PowerShell command:
Remove-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\TERMINPUT_BUS\UMB\*" -Recurse -Force
Additional Information
- This issue is most often seen in environments with frequent RDP or VDI session churn.
- If only a subset of servers is affected, compare session volume and stale device counts between working and failing hosts.
- Running the cleanup step as part of the patch workflow can help prevent recurrence.
Yy ↩︎