Getting MMS attachments from XMLs created by SMS Backup & Restore Android App

SMS Backup & Restore application is one of my favorites one – fast, reliable and simple to use. However, this application has one disadvantage – the MMS attachments are stored as byte64 data, so they are unreadable without any conversion. If you have a lot of MMS messages which you would like to store using classic files, you have to do the conversion manually… since now.

As I was unable to find a tool to make the batch conversion, I created a small PowerShell script which uses the main XML file and saves all attachments (type doesn’t matter) inside the folders named by the contact name – or if there wasn’t contact name, by phone number.

First three variables must be set up at first – $SourceFile for the main XML file, $TempCSV as a path for the temporary CSV file (you could delete it manually after all) and the $FileDest as a final destination for the folders with MMS freshly converted messages.

Script uses ‚X’ as a replacement for ‚?’ – the initial XML files had a problem with encoding, so I decided to replace it this way.

Why I’ve done it via CSV file? Because it was much easier for me to make a direct debugging on the text file. This part could be rewritten but as classics says „do not touch until it stops working”.

SET THE PATHS at first

$SourceFile = „D:\Inne\Backup Mi6\SMSBackupRestore\sms-20201114170517.xml”
$TempCSV = „D:\Inne\Backup Mi6\SMSBackupRestore\TEMP.CSV” # temporary file, could be deleted after all
$FileDest = „D:\Inne\Backup Mi6\SMSBackupRestore\MMS Backup\”

Getting all Nodes by XPATH

$MMSList = Select-XML -Path $SourceFile -XPath „/smses/mms/parts/part” | select-object -ExpandProperty Node

Generating new objects based on the message and export to CSV – to avoid dealing with XPaths

Done by going to the most deepest point – the submessage (attachment) inside the main message

$MMSList | ForEach-Object {
If($_.ParentNode.ParentNode.contact_name -eq „(Unknown)”) { # if the contact is unknown, use the phone number for the folder name
$tmpContact = $_.ParentNode.ParentNode.address
} else {
$tmpContact = $_.ParentNode.ParentNode.contact_name
}
New-Object -Type PSObject -Property @{
Contact = $tmpContact #$_.ParentNode.ParentNode.contact_name # go back two levels to get the contact-name
FileName = $_.name -join ‚;’
FileData = $_.data -join ‚;’
}
} | Export-CSV $TempCSV

Import CSV and finally got the objects

$Temp = Import-CSV $TempCSV -delimiter ‚,’
$Temp | ForEach-Object { #removing ‚?’ char in names
$_.Contact = $_.Contact -replace „[?]”,”X”
}
foreach ($Entry in $Temp) {
$tmp = $FileDest + $Entry.Contact
mkdir $tmp -Force
Set-Location $tmp
$tmp2 = $tmp + „\” +$entry.filename
[IO.File]::WriteAllBytes($tmp2,[Convert]::FromBase64String($Entry.FileData))
}
cd.. # to main folder