-
Notifications
You must be signed in to change notification settings - Fork 0
/
BackupPhone.ps1
205 lines (171 loc) · 6.8 KB
/
BackupPhone.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
$ErrorActionPreference = [string]"Stop"
$DestDirForPhotos = [string]"C:\BACKUP\TELEFON_DCIM_NEW"
$Summary = [Hashtable]@{NewFilesCount=0; ExistingFilesCount=0}
$phoneName = "Galaxy J5 Pro" # Phone name as it appears in This PC
function Create-Dir($path) {
if (!(Test-Path -Path $path)) {
Write-Host "Creating: $path"
New-Item -Path $path -ItemType Directory
} else {
Write-Host "Path $path already exists"
}
}
function Get-SubFolder($parentDir, $subPath) {
$result = $parentDir
foreach ($pathSegment in ($subPath -split "\\")) {
$result = $result.GetFolder.Items() | Where-Object { $_.Name -eq $pathSegment } | select -First 1
if ($result -eq $null) {
throw "Not found $subPath folder"
}
}
return $result
}
function Get-PhoneMainDir($phoneName) {
$o = New-Object -com Shell.Application
$rootComputerDirectory = $o.NameSpace(0x11)
$phoneDirectory = $rootComputerDirectory.Items() | Where-Object { $_.Name -eq $phoneName } | select -First 1
if ($phoneDirectory -eq $null) {
throw "Not found '$phoneName' folder in This computer. Connect your phone."
}
return $phoneDirectory
}
function Get-FullPathOfMtpDir($mtpDir) {
$fullDirPath = ""
$directory = $mtpDir.GetFolder
while ($directory -ne $null) {
$fullDirPath = -join($directory.Title, '\', $fullDirPath)
$directory = $directory.ParentFolder
}
return $fullDirPath
}
function Get-ExistingFilesIndex($destDirPath) {
$existingFiles = @{}
if (!(Test-Path -Path $destDirPath)) {
Write-Host "Destination directory does not exist: $destDirPath"
return $existingFiles
}
$shell = New-Object -Com Shell.Application
$destFolder = $shell.NameSpace($destDirPath)
if (-not $destFolder) {
throw "Failed to access destination directory: $destDirPath"
}
function Add-FilesToIndex($folder) {
foreach ($subItem in $folder.Items()) {
if (-not $subItem.IsFolder) {
$existingFiles[$subItem.Name] = $true
}
if ($subItem.IsFolder) {
Add-FilesToIndex $subItem.GetFolder
}
}
}
Add-FilesToIndex $destFolder
return $existingFiles
}
function Check-IfItemExists($existingFilesIndex, $itemName) {
return $existingFilesIndex.ContainsKey($itemName)
}
# New function to buffer the files before copying
function Get-MtpFilesBuffered {
param (
[Parameter(Mandatory=$true)]
[Object]$sourceMtpDir
)
$files = @()
$retryCount = 5
while ($retryCount -gt 0) {
try {
$items = $sourceMtpDir.GetFolder.Items()
if ($items.Count -gt 0) {
$files += $items | Where-Object { -not $_.IsFolder }
if ($files.Count -gt 0) {
break
}
}
} catch {
Write-Host "Error retrieving files, retrying..."
}
Start-Sleep -Seconds 5
$retryCount--
}
if ($files.Count -eq 0) {
throw "Failed to retrieve files after multiple attempts."
}
return $files
}
function Copy-FromPhoneSource-ToBackup($sourceMtpDir, $destDirPath, $existingFilesIndex) {
Create-Dir $destDirPath
$destDirShell = (New-Object -Com Shell.Application).NameSpace($destDirPath)
$directoriesStack = New-Object System.Collections.Stack
$directoriesStack.Push(@($sourceMtpDir, $destDirPath))
while ($directoriesStack.count -gt 0) {
$currentSourceDestPair = $directoriesStack.Pop()
$currentSourceDir = $currentSourceDestPair[0]
$currentDestDir = $currentSourceDestPair[1]
$fullSourceDirPath = Get-FullPathOfMtpDir $currentSourceDir
Write-Host "Processing directory: '$fullSourceDirPath'"
# Use buffered file retrieval
$files = Get-MtpFilesBuffered -sourceMtpDir $currentSourceDir
foreach ($item in $files) {
$itemName = $item.Name
$fullFilePath = Join-Path -Path $currentDestDir -ChildPath $itemName
if (Check-IfItemExists $existingFilesIndex $itemName) {
Write-Host "Element '$itemName' already exists"
$script:Summary.ExistingFilesCount++
} else {
Write-Host ("Copying {0}: {1}" -f $itemName, $fullSourceDirPath)
$destDirShell.CopyHere($item)
$script:Summary.NewFilesCount++
}
}
# Handle folders last to ensure all files are copied before stepping into subdirectories
foreach ($item in $currentSourceDir.GetFolder.Items()) {
if ($item.IsFolder) {
$subDestDir = Join-Path $currentDestDir $item.GetFolder.Title
Create-Dir $subDestDir
$directoriesStack.Push(@($item, $subDestDir))
}
}
}
Write-Host "Completed copying files from '$destDirPath'. New files: $($script:Summary.NewFilesCount), Existing files: $($script:Summary.ExistingFilesCount)"
}
$phoneRootDir = Get-PhoneMainDir $phoneName
# Create the index of existing files
$existingFilesIndex = Get-ExistingFilesIndex $DestDirForPhotos
# Ensure the index is always initialized
if ($null -eq $existingFilesIndex) {
$existingFilesIndex = @{}
}
# Check if index creation was successful
if ($existingFilesIndex.Count -eq 0) {
Write-Host "No files indexed. Either the directory is empty or indexing failed."
} else {
Write-Host "Index created with $($existingFilesIndex.Count) files."
}
# Start the copy process using the index
Copy-FromPhoneSource-ToBackup (Get-SubFolder $phoneRootDir "Phone\DCIM\Camera") $DestDirForPhotos $existingFilesIndex
# Get the files which should be moved, without folders
$files = Get-ChildItem $DestDirForPhotos | Where-Object { -not $_.PSIsContainer }
# List Files which will be moved
$files
# Target Folder where files should be moved to. The script will automatically create a folder for the year and month.
$targetPath = $DestDirForPhotos
foreach ($file in $files) {
# Get year and Month of the file
# I used LastWriteTime since these are synced files and the creation day will be the date when it was synced
$year = $file.LastWriteTime.Year.ToString()
$month = $file.LastWriteTime.Month.ToString()
# Output FileName, year and month
$file.Name
$year
$month
# Set Directory Path
$Directory = $targetPath + "\" + $year + "\" + $month
# Create directory if it doesn't exist
if (!(Test-Path $Directory)) {
New-Item $directory -type directory
}
# Move File to new location
$file | Move-Item -Destination $Directory
}
write-host ($Summary | out-string)