param( [Parameter(Mandatory)] [string]$PhoneName, [Parameter(Mandatory)] [string]$DestinationFolder ) # Timestamped log file in root of destination $timestamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss' $hashLog = Join-Path $DestinationFolder "FileSizeMismatchLog_$timestamp.txt" New-Item -ItemType File -Path $hashLog -Force | Out-Null # Target folder names $targetFolders = @("DCIM", "Camera", "Pictures", "Screenshots", "Recordings") # Shell access $shell = New-Object -ComObject Shell.Application $desktop = $shell.Namespace(0) # 0 {Windows 11} # 0x11 {Windows 10} $mtp = $desktop.Items() | Where-Object { $_.Name -eq $PhoneName } if (-not $mtp) { Write-Error "Could not find device '$PhoneName'." exit 1 } # Get storage roots: Internal + SD card etc. $volumes = $mtp.GetFolder.Items() | Where-Object { $_.IsFolder } if (-not $volumes) { Write-Error "No accessible storage volumes found on device." exit 1 } function Test-FileSizeIntegrity { param ( [object]$ShellItem, [string]$DestinationFilePath, [string]$RelativePath ) if (-not (Test-Path $DestinationFilePath)) { Add-Content $hashLog "`r`n❌ Missing file:`r`nDEST: $DestinationFilePath`r`nSRC Item: $RelativePath`r`n" return } $mtpSize = [int64]$ShellItem.Size $localSize = (Get-Item $DestinationFilePath).Length $sizeDiff = [math]::Abs($mtpSize - $localSize) if ($sizeDiff -le 4096) { # allow up to 4KB padding tolerance Write-Host ("✅ Size matched: $RelativePath → $mtpSize bytes (MTP) / $localSize bytes (Local)") } else { $logEntry = @" ❌ Size mismatch: PATH: $RelativePath MTP: $mtpSize bytes LOCAL: $localSize bytes FILE: $DestinationFilePath "@ Add-Content $hashLog $logEntry Write-Warning "⚠ Size mismatch for $RelativePath → $mtpSize bytes (MTP) / $localSize bytes (Local)" } } function Copy-MatchingFolders { param($folder, $currentDepth, $maxDepth, $outPath) foreach ($item in $folder.Items()) { if (-not $item.IsFolder) { continue } $name = $item.Name $targetPath = Join-Path $outPath $name if ($targetFolders -contains $name) { Write-Host "📁 Copying entire folder '$name' to '$targetPath'" if (-not (Test-Path $targetPath)) { New-Item -ItemType Directory -Path $targetPath | Out-Null } $sourceItems = $item.GetFolder.Items() foreach ($subitem in $sourceItems) { $shell.Namespace($targetPath).CopyHere($subitem, 16) Start-Sleep -Milliseconds 100 } # After all files are copied — run integrity checks once try { $shellItems = $item.GetFolder.Items() | Where-Object { -not $_.IsFolder } foreach ($child in $shellItems) { $destFilePath = Join-Path $targetPath $child.Name $relativePath = $child.Name Test-FileSizeIntegrity -ShellItem $child -DestinationFilePath $destFilePath -RelativePath $relativePath } } catch { Write-Warning "⚠ Could not perform post-copy integrity check for '$name'" } continue } if ($currentDepth -lt $maxDepth) { try { Copy-MatchingFolders -folder $item.GetFolder -currentDepth ($currentDepth + 1) -maxDepth $maxDepth -outPath $outPath } catch { Write-Warning "⚠ Could not access subfolder '$name'" } } } } # Walk all volumes (e.g. Internal, SD card) foreach ($volume in $volumes) { $volumeName = $volume.Name $volumeFolder = $volume.GetFolder $volumeOutput = Join-Path $DestinationFolder $volumeName Write-Host "`n🔎 Scanning '$volumeName'..." if (-not (Test-Path $volumeOutput)) { New-Item -ItemType Directory -Path $volumeOutput | Out-Null } Copy-MatchingFolders -folder $volumeFolder -currentDepth 1 -maxDepth 2 -outPath $volumeOutput } if ((Get-Content $hashLog).Length -eq 0) { Remove-Item $hashLog -Force Write-Host "`n✅ No file size mismatches detected. Log file removed." } else { Write-Host "`n⚠ File size mismatches recorded in: $hashLog" } Write-Host "`n✅ All matching folders copied from all available device storage to '$DestinationFolder'"