Last active
December 4, 2025 07:07
-
-
Save DickHorner/c4343e30446594fee55dd0d70ff63ad6 to your computer and use it in GitHub Desktop.
Un-Trasher
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
| <# | |
| .SYNOPSIS | |
| Restores all files from the Recycle Bin to their original locations. | |
| .DESCRIPTION | |
| This script enumerates all items in the Windows Recycle Bin and restores them | |
| to their original folder locations and states before deletion. It handles | |
| errors gracefully and provides detailed logging of the restoration process. | |
| .EXAMPLE | |
| .\Restore-RecycleBin.ps1 | |
| Restores all items from the Recycle Bin. | |
| .EXAMPLE | |
| .\Restore-RecycleBin.ps1 -WhatIf | |
| Shows what would be restored without actually performing the restoration. | |
| .NOTES | |
| Version: 1.0 | |
| Author: https://gist.github.com/DickHorner/ | |
| Creation Date: 2025-12-04 | |
| Requirements: | |
| - Windows PowerShell 5.1 or PowerShell 7+ | |
| - Administrator privileges may be required for some file operations | |
| Error Handling: | |
| - Validates Recycle Bin accessibility | |
| - Handles locked files and permission issues | |
| - Reports items that couldn't be restored | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param() | |
| #Requires -Version 5.1 | |
| Set-StrictMode -Version Latest | |
| $ErrorActionPreference = 'Stop' | |
| function Write-Log { | |
| <# | |
| .SYNOPSIS | |
| Writes formatted log messages to the console. | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [string]$Message, | |
| [Parameter(Mandatory = $false)] | |
| [ValidateSet('Info', 'Success', 'Warning', 'Error')] | |
| [string]$Level = 'Info' | |
| ) | |
| $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' | |
| $color = switch ($Level) { | |
| 'Info' { 'Cyan' } | |
| 'Success' { 'Green' } | |
| 'Warning' { 'Yellow' } | |
| 'Error' { 'Red' } | |
| } | |
| Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color | |
| } | |
| function Get-RecycleBinItems { | |
| <# | |
| .SYNOPSIS | |
| Retrieves all items from the Recycle Bin using Shell.Application COM object. | |
| #> | |
| [CmdletBinding()] | |
| [OutputType([System.Collections.ArrayList])] | |
| param() | |
| try { | |
| Write-Log "Accessing Recycle Bin..." -Level Info | |
| # Create Shell.Application COM object | |
| $shell = New-Object -ComObject Shell.Application | |
| # Access Recycle Bin (namespace 10) | |
| $recycleBin = $shell.Namespace(0x0A) | |
| if (-not $recycleBin) { | |
| throw "Unable to access Recycle Bin. This may indicate a system issue." | |
| } | |
| # Get all items in Recycle Bin | |
| $items = $recycleBin.Items() | |
| if ($null -eq $items) { | |
| Write-Log "Recycle Bin is empty." -Level Info | |
| return [System.Collections.ArrayList]@() | |
| } | |
| $itemList = [System.Collections.ArrayList]@() | |
| # Enumerate items and collect details | |
| foreach ($item in $items) { | |
| try { | |
| # Get original path from extended property | |
| $originalPath = $recycleBin.GetDetailsOf($item, 1) | |
| if ([string]::IsNullOrWhiteSpace($originalPath)) { | |
| $originalPath = "Unknown" | |
| } | |
| $itemInfo = [PSCustomObject]@{ | |
| Name = $item.Name | |
| Path = $item.Path | |
| OriginalPath = $originalPath | |
| Size = $item.Size | |
| Type = $item.Type | |
| DateDeleted = $recycleBin.GetDetailsOf($item, 2) | |
| ShellItem = $item | |
| } | |
| [void]$itemList.Add($itemInfo) | |
| } | |
| catch { | |
| Write-Log "Failed to retrieve details for an item: $_" -Level Warning | |
| } | |
| } | |
| Write-Log "Found $($itemList.Count) item(s) in Recycle Bin." -Level Info | |
| return $itemList | |
| } | |
| catch { | |
| Write-Log "Error accessing Recycle Bin: $_" -Level Error | |
| throw | |
| } | |
| finally { | |
| # Clean up COM object | |
| if ($shell) { | |
| [System.Runtime.InteropServices.Marshal]::ReleaseComObject($shell) | Out-Null | |
| } | |
| } | |
| } | |
| function Restore-RecycleBinItem { | |
| <# | |
| .SYNOPSIS | |
| Restores a single item from the Recycle Bin to its original location. | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [PSCustomObject]$Item | |
| ) | |
| try { | |
| $targetPath = $Item.OriginalPath | |
| if ($targetPath -eq "Unknown" -or [string]::IsNullOrWhiteSpace($targetPath)) { | |
| Write-Log "Cannot restore '$($Item.Name)': Original path is unknown." -Level Warning | |
| return $false | |
| } | |
| # Get parent directory | |
| $parentDir = Split-Path -Path $targetPath -Parent | |
| if ($PSCmdlet.ShouldProcess($targetPath, "Restore from Recycle Bin")) { | |
| # Ensure parent directory exists | |
| if (-not (Test-Path -Path $parentDir -PathType Container)) { | |
| Write-Log "Creating parent directory: $parentDir" -Level Info | |
| New-Item -Path $parentDir -ItemType Directory -Force -ErrorAction Stop | Out-Null | |
| } | |
| # Invoke the restore verb | |
| $verbs = $Item.ShellItem.Verbs() | |
| $restoreVerb = $verbs | Where-Object { $_.Name -match 'Restore|Wiederherstellen' } | |
| if ($restoreVerb) { | |
| $restoreVerb.DoIt() | |
| # Wait briefly for the operation to complete | |
| Start-Sleep -Milliseconds 100 | |
| # Verify restoration | |
| if (Test-Path -Path $targetPath) { | |
| Write-Log "Successfully restored: $targetPath" -Level Success | |
| return $true | |
| } | |
| else { | |
| Write-Log "Restore command executed but file not found at: $targetPath" -Level Warning | |
| return $false | |
| } | |
| } | |
| else { | |
| Write-Log "Restore verb not found for: $($Item.Name)" -Level Warning | |
| return $false | |
| } | |
| } | |
| else { | |
| Write-Log "Would restore: $($Item.Name) -> $targetPath" -Level Info | |
| return $true | |
| } | |
| } | |
| catch { | |
| Write-Log "Failed to restore '$($Item.Name)': $_" -Level Error | |
| return $false | |
| } | |
| } | |
| function Restore-AllRecycleBinItems { | |
| <# | |
| .SYNOPSIS | |
| Main function to restore all items from the Recycle Bin. | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param() | |
| Write-Log "=== Recycle Bin Restoration Script ===" -Level Info | |
| Write-Log "Starting restoration process..." -Level Info | |
| try { | |
| # Get all items from Recycle Bin | |
| $items = Get-RecycleBinItems | |
| if ($items.Count -eq 0) { | |
| Write-Log "No items to restore. Exiting." -Level Info | |
| return | |
| } | |
| # Statistics | |
| $successCount = 0 | |
| $failureCount = 0 | |
| # Restore each item | |
| foreach ($item in $items) { | |
| Write-Log "Processing: $($item.Name)" -Level Info | |
| $result = Restore-RecycleBinItem -Item $item | |
| if ($result) { | |
| $successCount++ | |
| } | |
| else { | |
| $failureCount++ | |
| } | |
| } | |
| # Summary | |
| Write-Log "=== Restoration Complete ===" -Level Info | |
| Write-Log "Total items processed: $($items.Count)" -Level Info | |
| Write-Log "Successfully restored: $successCount" -Level Success | |
| if ($failureCount -gt 0) { | |
| Write-Log "Failed to restore: $failureCount" -Level Warning | |
| } | |
| } | |
| catch { | |
| Write-Log "Fatal error during restoration: $_" -Level Error | |
| throw | |
| } | |
| } | |
| # Main execution | |
| try { | |
| Restore-AllRecycleBinItems | |
| exit 0 | |
| } | |
| catch { | |
| Write-Log "Script execution failed: $_" -Level Error | |
| exit 1 | |
| } |
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
| <# | |
| .SYNOPSIS | |
| Restores all files from the Recycle Bin to their original locations. | |
| .DESCRIPTION | |
| This script enumerates all items in the Windows Recycle Bin and restores them | |
| to their original folder locations and states before deletion. It handles | |
| errors gracefully and provides detailed logging of the restoration process. | |
| .EXAMPLE | |
| .\Restore-RecycleBin.ps1 | |
| Restores all items from the Recycle Bin. | |
| .EXAMPLE | |
| .\Restore-RecycleBin.ps1 -WhatIf | |
| Shows what would be restored without actually performing the restoration. | |
| .NOTES | |
| Version: 1.0 | |
| Author: https://gist.github.com/DickHorner/ | |
| Creation Date: 2025-12-04 | |
| Requirements: | |
| - Windows PowerShell 5.1 or PowerShell 7+ | |
| - Administrator privileges may be required for some file operations | |
| Error Handling: | |
| - Validates Recycle Bin accessibility | |
| - Handles locked files and permission issues | |
| - Reports items that couldn't be restored | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param() | |
| #Requires -Version 5.1 | |
| Set-StrictMode -Version Latest | |
| $ErrorActionPreference = 'Stop' | |
| function Write-Log { | |
| <# | |
| .SYNOPSIS | |
| Writes formatted log messages to the console. | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [string]$Message, | |
| [Parameter(Mandatory = $false)] | |
| [ValidateSet('Info', 'Success', 'Warning', 'Error')] | |
| [string]$Level = 'Info' | |
| ) | |
| $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' | |
| $color = switch ($Level) { | |
| 'Info' { 'Cyan' } | |
| 'Success' { 'Green' } | |
| 'Warning' { 'Yellow' } | |
| 'Error' { 'Red' } | |
| } | |
| Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color | |
| } | |
| function Get-RecycleBinItems { | |
| <# | |
| .SYNOPSIS | |
| Retrieves all items from the Recycle Bin using Shell.Application COM object. | |
| #> | |
| [CmdletBinding()] | |
| [OutputType([System.Collections.ArrayList])] | |
| param() | |
| try { | |
| Write-Log "Accessing Recycle Bin..." -Level Info | |
| # Create Shell.Application COM object | |
| $shell = New-Object -ComObject Shell.Application | |
| # Access Recycle Bin (namespace 10) | |
| $recycleBin = $shell.Namespace(0x0A) | |
| if (-not $recycleBin) { | |
| throw "Unable to access Recycle Bin. This may indicate a system issue." | |
| } | |
| # Get all items in Recycle Bin | |
| $items = $recycleBin.Items() | |
| if ($null -eq $items) { | |
| Write-Log "Recycle Bin is empty." -Level Info | |
| return [System.Collections.ArrayList]@() | |
| } | |
| $itemList = [System.Collections.ArrayList]@() | |
| # Enumerate items and collect details | |
| foreach ($item in $items) { | |
| try { | |
| # Get original path from extended property | |
| $originalPath = $recycleBin.GetDetailsOf($item, 1) | |
| if ([string]::IsNullOrWhiteSpace($originalPath)) { | |
| $originalPath = "Unknown" | |
| } | |
| $itemInfo = [PSCustomObject]@{ | |
| Name = $item.Name | |
| Path = $item.Path | |
| OriginalPath = $originalPath | |
| Size = $item.Size | |
| Type = $item.Type | |
| DateDeleted = $recycleBin.GetDetailsOf($item, 2) | |
| ShellItem = $item | |
| } | |
| [void]$itemList.Add($itemInfo) | |
| } | |
| catch { | |
| Write-Log "Failed to retrieve details for an item: $_" -Level Warning | |
| } | |
| } | |
| Write-Log "Found $($itemList.Count) item(s) in Recycle Bin." -Level Info | |
| return $itemList | |
| } | |
| catch { | |
| Write-Log "Error accessing Recycle Bin: $_" -Level Error | |
| throw | |
| } | |
| finally { | |
| # Clean up COM object | |
| if ($shell) { | |
| [System.Runtime.InteropServices.Marshal]::ReleaseComObject($shell) | Out-Null | |
| } | |
| } | |
| } | |
| function Restore-RecycleBinItem { | |
| <# | |
| .SYNOPSIS | |
| Restores a single item from the Recycle Bin to its original location. | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [PSCustomObject]$Item | |
| ) | |
| try { | |
| $targetPath = $Item.OriginalPath | |
| if ($targetPath -eq "Unknown" -or [string]::IsNullOrWhiteSpace($targetPath)) { | |
| Write-Log "Cannot restore '$($Item.Name)': Original path is unknown." -Level Warning | |
| return $false | |
| } | |
| # Get parent directory | |
| $parentDir = Split-Path -Path $targetPath -Parent | |
| if ($PSCmdlet.ShouldProcess($targetPath, "Restore from Recycle Bin")) { | |
| # Ensure parent directory exists | |
| if (-not (Test-Path -Path $parentDir -PathType Container)) { | |
| Write-Log "Creating parent directory: $parentDir" -Level Info | |
| New-Item -Path $parentDir -ItemType Directory -Force -ErrorAction Stop | Out-Null | |
| } | |
| # Invoke the restore verb | |
| $verbs = $Item.ShellItem.Verbs() | |
| $restoreVerb = $verbs | Where-Object { $_.Name -match 'Restore|Wiederherstellen' } | |
| if ($restoreVerb) { | |
| $restoreVerb.DoIt() | |
| # Wait briefly for the operation to complete | |
| Start-Sleep -Milliseconds 100 | |
| # Verify restoration | |
| if (Test-Path -Path $targetPath) { | |
| Write-Log "Successfully restored: $targetPath" -Level Success | |
| return $true | |
| } | |
| else { | |
| Write-Log "Restore command executed but file not found at: $targetPath" -Level Warning | |
| return $false | |
| } | |
| } | |
| else { | |
| Write-Log "Restore verb not found for: $($Item.Name)" -Level Warning | |
| return $false | |
| } | |
| } | |
| else { | |
| Write-Log "Would restore: $($Item.Name) -> $targetPath" -Level Info | |
| return $true | |
| } | |
| } | |
| catch { | |
| Write-Log "Failed to restore '$($Item.Name)': $_" -Level Error | |
| return $false | |
| } | |
| } | |
| function Restore-AllRecycleBinItems { | |
| <# | |
| .SYNOPSIS | |
| Main function to restore all items from the Recycle Bin. | |
| #> | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param() | |
| Write-Log "=== Recycle Bin Restoration Script ===" -Level Info | |
| Write-Log "Starting restoration process..." -Level Info | |
| try { | |
| # Get all items from Recycle Bin | |
| $items = Get-RecycleBinItems | |
| if ($items.Count -eq 0) { | |
| Write-Log "No items to restore. Exiting." -Level Info | |
| return | |
| } | |
| # Statistics | |
| $successCount = 0 | |
| $failureCount = 0 | |
| # Restore each item | |
| foreach ($item in $items) { | |
| Write-Log "Processing: $($item.Name)" -Level Info | |
| $result = Restore-RecycleBinItem -Item $item | |
| if ($result) { | |
| $successCount++ | |
| } | |
| else { | |
| $failureCount++ | |
| } | |
| } | |
| # Summary | |
| Write-Log "=== Restoration Complete ===" -Level Info | |
| Write-Log "Total items processed: $($items.Count)" -Level Info | |
| Write-Log "Successfully restored: $successCount" -Level Success | |
| if ($failureCount -gt 0) { | |
| Write-Log "Failed to restore: $failureCount" -Level Warning | |
| } | |
| } | |
| catch { | |
| Write-Log "Fatal error during restoration: $_" -Level Error | |
| throw | |
| } | |
| } | |
| # Main execution | |
| try { | |
| Restore-AllRecycleBinItems | |
| exit 0 | |
| } | |
| catch { | |
| Write-Log "Script execution failed: $_" -Level Error | |
| exit 1 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment