Skip to content

Instantly share code, notes, and snippets.

@DickHorner
Last active December 4, 2025 07:07
Show Gist options
  • Select an option

  • Save DickHorner/c4343e30446594fee55dd0d70ff63ad6 to your computer and use it in GitHub Desktop.

Select an option

Save DickHorner/c4343e30446594fee55dd0d70ff63ad6 to your computer and use it in GitHub Desktop.
Un-Trasher
<#
.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
}
<#
.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