Created
October 10, 2025 08:25
-
-
Save HenkPoley/4aedc30e5c8506450a66988bb560df5e to your computer and use it in GitHub Desktop.
Easus Disk Copy missing uninstaller PowerShell script; based on a Process Monitor trace of version the 6.7.1 installer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| EaseUS Disk Copy Cleanup Script | |
| Generated: 2025-10-10T07:55:30 | |
| What it does: | |
| - Enumerates and (optionally) removes EaseUS Disk Copy files/folders, registry keys/values, shortcuts. | |
| - Handles multiple versions by matching directories like "EaseUSDiskCopy6.*" under ProgramData. | |
| - Locates related services/tasks/processes whose executable paths point into those folders. | |
| Safety: | |
| - Shows a scrollable list (Out-GridView if available) of planned deletions first. | |
| - Prompts for confirmation before deleting. | |
| - Can export the list to a timestamped file for manual deletion. | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param( | |
| [switch]$ListOnly, | |
| [string]$ExportListPath | |
| ) | |
| function Test-Admin { | |
| $currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent() | |
| $principal = New-Object System.Security.Principal.WindowsPrincipal($currentIdentity) | |
| return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) | |
| } | |
| if (-not (Test-Admin)) { | |
| Write-Warning "Please run this script in an elevated PowerShell (Run as administrator)." | |
| return | |
| } | |
| # --- Patterns and targets (derived from your install logs) --- | |
| $BaseDirPatterns = @('C:\ProgramData\EaseUSDiskCopy*') | |
| # Shortcuts | |
| $Shortcuts = @('C:\Users\Public\Desktop\EaseUS Disk Copy.lnk') | |
| # Registry keys | |
| $RegKeysHKCU = @( | |
| 'HKCU:\Software\Classes\AppID\edc.exe', | |
| 'HKCU:\Software\EASEUS\EaseUS Disk Copy', | |
| 'HKCU:\Software\EaseUS', | |
| 'HKCU:\Software\EaseUS\EaseUS Disk Copy' | |
| ) | |
| $RegKeysHKLM = @( | |
| 'HKCR:\AppID\edc.exe', | |
| 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\edc.exe', | |
| 'HKLM:\SOFTWARE\WOW6432Node\EaseUS', | |
| 'HKLM:\SOFTWARE\WOW6432Node\EaseUS\EaseUS Disk Copy' | |
| ) | |
| $AppCompatLayersKey = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers' | |
| # --- Discover current system matches --- | |
| $planned = @() | |
| # Expand directories (including all versioned EaseUSDiskCopy*) | |
| foreach ($pattern in $BaseDirPatterns) { | |
| Get-ChildItem -Path $pattern -Directory -ErrorAction SilentlyContinue | ForEach-Object { | |
| $planned += [pscustomobject]@{ Type = 'Directory'; Path = $_.FullName } | |
| # Include subtree files too | |
| Get-ChildItem -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue | ForEach-Object { | |
| if (-not $_.PSIsContainer) { | |
| $planned += [pscustomobject]@{ Type = 'File'; Path = $_.FullName } | |
| } | |
| else { | |
| $planned += [pscustomobject]@{ Type = 'Directory'; Path = $_.FullName } | |
| } | |
| } | |
| } | |
| } | |
| # Include shortcuts if they exist | |
| foreach ($lnk in $Shortcuts) { | |
| if (Test-Path $lnk) { $planned += [pscustomobject]@{ Type = 'Shortcut'; Path = $lnk } } | |
| } | |
| # Registry keys (existence check) | |
| foreach ($rk in $RegKeysHKCU + $RegKeysHKLM) { | |
| try { | |
| if (Test-Path -LiteralPath $rk) { $planned += [pscustomobject]@{ Type = 'RegistryKey'; Path = $rk } } | |
| } | |
| catch { } | |
| } | |
| # AppCompatFlags\Layers values pointing to EaseUSDiskCopy paths | |
| if (Test-Path -LiteralPath $AppCompatLayersKey) { | |
| try { | |
| # $layersKey = Get-Item -LiteralPath $AppCompatLayersKey | |
| # $vals = (Get-ItemProperty -LiteralPath $layersKey.PSPath) | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name | |
| $rk = Get-Item -LiteralPath $AppCompatLayersKey | |
| $vals = $rk.GetValueNames() | |
| foreach ($name in $vals) { | |
| if ($name -match '(?i)\\EaseUSDiskCopy') { | |
| $planned += [pscustomobject]@{ Type = 'RegistryValue'; Path = ($AppCompatLayersKey + ' (ValueName) ' + $name) } | |
| } | |
| } | |
| } | |
| catch { } | |
| } | |
| # Services whose binary path points inside EaseUSDiskCopy | |
| try { | |
| $svcCandidates = Get-CimInstance Win32_Service -ErrorAction SilentlyContinue | Where-Object { | |
| ($_.PathName -match '(?i)\\EaseUSDiskCopy') -or ($_.Name -match '(?i)EaseUS|DiskCopy|edc') | |
| } | |
| foreach ($svc in $svcCandidates) { | |
| $planned += [pscustomobject]@{ Type = 'Service'; Path = $svc.Name; Detail = $svc.PathName } | |
| } | |
| } | |
| catch { } | |
| # Scheduled tasks that reference EaseUSDiskCopy paths | |
| try { | |
| if (Get-Command Get-ScheduledTask -ErrorAction SilentlyContinue) { | |
| $tasks = Get-ScheduledTask | Where-Object { | |
| $_.TaskPath -match '(?i)EaseUS' -or $_.TaskName -match '(?i)EaseUS|DiskCopy' -or (($_.Actions | Out-String) -match '(?i)EaseUSDiskCopy') | |
| } | |
| foreach ($t in $tasks) { | |
| $planned += [pscustomobject]@{ Type = 'ScheduledTask'; Path = $t.TaskName; Detail = $t.TaskPath } | |
| } | |
| } | |
| } | |
| catch { } | |
| # De-duplicate planned items | |
| $planned = $planned | Sort-Object Type, Path -Unique | |
| # --- Present planned actions --- | |
| if ($planned.Count -eq 0) { | |
| Write-Host "No EaseUS Disk Copy related items found to remove based on current patterns." | |
| return | |
| } | |
| # Optional export of list | |
| function Export-PlannedList([string]$OutPath) { | |
| $dir = Split-Path -Parent $OutPath | |
| if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null } | |
| $planned | ConvertTo-Json -Depth 4 | Out-File -FilePath $OutPath -Encoding UTF8 | |
| Write-Host "Saved planned list to $OutPath" | |
| } | |
| $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' | |
| if (-not $ExportListPath) { $ExportListPath = Join-Path -Path (Get-Location) -ChildPath ("EaseUS-DiskCopy-PlannedRemovals-$timestamp.json") } | |
| try { | |
| if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { | |
| $null = $planned | Out-GridView -Title "Planned removals (review and close to continue)" | |
| } | |
| else { | |
| Write-Host "Planned removals:" | |
| $planned | Format-Table -AutoSize | Out-Host | |
| } | |
| } | |
| catch { } | |
| Write-Host "" | |
| Write-Host "Options: [Y] Proceed with deletion [N] Cancel [S] Save list only to file" | |
| if ($ListOnly) { $resp = 'S' } else { $resp = Read-Host "Choose Y/N/S" } | |
| if ($resp -match '^[sS]$') { | |
| Export-PlannedList -OutPath $ExportListPath | |
| return | |
| } | |
| elseif ($resp -notmatch '^[yY]$') { | |
| Write-Host "Cancelled." | |
| return | |
| } | |
| # --- Stop related processes --- | |
| # Any process whose module path is within EaseUSDiskCopy base directories | |
| $baseDirs = @() | |
| foreach ($pattern in $BaseDirPatterns) { | |
| Get-ChildItem -Path $pattern -Directory -ErrorAction SilentlyContinue | ForEach-Object { $baseDirs += $_.FullName } | |
| } | |
| $baseDirs = $baseDirs | Sort-Object -Unique | |
| if ($baseDirs.Count -gt 0) { | |
| Get-Process | ForEach-Object { | |
| try { | |
| $p = $_ | |
| $path = $p.Path | |
| if ($path) { | |
| foreach ($bd in $baseDirs) { | |
| if ($path -like ($bd + '*')) { | |
| Write-Host "Stopping process $($p.Name) ($($p.Id))" | |
| Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue | |
| break | |
| } | |
| } | |
| } | |
| } | |
| catch { } | |
| } | |
| } | |
| # --- Remove scheduled tasks --- | |
| try { | |
| if (Get-Command Unregister-ScheduledTask -ErrorAction SilentlyContinue) { | |
| $planned | Where-Object Type -eq 'ScheduledTask' | ForEach-Object { | |
| $tn = $_.Path | |
| try { Unregister-ScheduledTask -TaskName $tn -Confirm:$false -ErrorAction SilentlyContinue } catch { } | |
| } | |
| } | |
| } | |
| catch { } | |
| # --- Stop & delete services --- | |
| $planned | Where-Object Type -eq 'Service' | ForEach-Object { | |
| $svcName = $_.Path | |
| try { Stop-Service -Name $svcName -Force -ErrorAction SilentlyContinue } catch { } | |
| try { sc.exe delete $svcName | Out-Null } catch { } | |
| } | |
| # --- Remove registry values in AppCompatFlags\Layers --- | |
| if (Test-Path -LiteralPath $AppCompatLayersKey) { | |
| try { | |
| # $reg = Get-Item -LiteralPath $AppCompatLayersKey | |
| # $props = (Get-ItemProperty -LiteralPath $reg.PSPath) | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name | |
| $rk = Get-Item -LiteralPath $AppCompatLayersKey | |
| $props = $rk.GetValueNames() | |
| foreach ($name in $props) { | |
| if ($name -match '(?i)\\EaseUSDiskCopy') { | |
| try { Remove-ItemProperty -LiteralPath $AppCompatLayersKey -Name $name -ErrorAction SilentlyContinue } catch { } | |
| } | |
| } | |
| } | |
| catch { } | |
| } | |
| # --- Remove registry keys --- | |
| function Remove-KeyIfExists([string]$keyPath) { | |
| try { | |
| if (Test-Path -LiteralPath $keyPath) { | |
| Remove-Item -LiteralPath $keyPath -Recurse -Force -ErrorAction SilentlyContinue | |
| } | |
| } | |
| catch { } | |
| } | |
| # Remove product-specific subkeys first, then vendor roots if empty | |
| foreach ($rk in ($RegKeysHKCU + $RegKeysHKLM)) { | |
| Remove-KeyIfExists -keyPath $rk | |
| } | |
| # Attempt to remove empty vendor keys | |
| foreach ($vendorKey in @('HKCU:\Software\EaseUS', 'HKCU:\Software\EASEUS', 'HKLM:\SOFTWARE\WOW6432Node\EaseUS')) { | |
| try { | |
| if (Test-Path $vendorKey) { | |
| $sub = Get-ChildItem -LiteralPath $vendorKey -ErrorAction SilentlyContinue | |
| if ($null -eq $sub -or $sub.Count -eq 0) { | |
| Remove-Item -LiteralPath $vendorKey -Force -ErrorAction SilentlyContinue | |
| } | |
| } | |
| } | |
| catch { } | |
| } | |
| # --- Remove files & directories --- | |
| # Remove shortcuts | |
| foreach ($lnk in $Shortcuts) { | |
| try { if (Test-Path $lnk) { Remove-Item -LiteralPath $lnk -Force -ErrorAction SilentlyContinue } } catch { } | |
| } | |
| # Remove versioned root directories | |
| foreach ($pattern in $BaseDirPatterns) { | |
| Get-ChildItem -Path $pattern -Directory -ErrorAction SilentlyContinue | ForEach-Object { | |
| try { Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } catch { } | |
| } | |
| } | |
| Write-Host "Removal completed." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment