Skip to content

Instantly share code, notes, and snippets.

@cveld
Last active February 22, 2023 06:35
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cveld/8fa339306f8504095815 to your computer and use it in GitHub Desktop.
Save cveld/8fa339306f8504095815 to your computer and use it in GitHub Desktop.
PowerShell that crawls your Android usb folder structure

Crawl your Android device attached via usb with PowerShell

The PowerShell script Crawl_Android.ps1 is capable of crawling your Android device when it is attached via usb. Just execute Crawl_Android.ps1 and select the device from the menu.

Limited file details

What I found out is that the Shell Namespace API does not provide a lot of details of the file. It is limited to only a couple of fields that are relevant for the Windows Explorer GUI. Strangely, a byte-oriented filesize field is not part of it. It only contains a summarized version, e.g. 4 kB or 10 MB. After futher investigation, I noticed that Windows Explorer has to make a local temporary copy to get all the details in order to populate the information pane. That's why most operations are so slow!

# http://blogs.technet.com/b/heyscriptingguy/archive/2013/04/26/use-powershell-to-work-with-windows-explorer.aspx
$o = New-Object -com Shell.Application
$folder = $o.NameSpace(0x11)
# https://msdn.microsoft.com/en-us/library/windows/desktop/bb774096(v=vs.85).aspx
# ShellSpecialFolderConstants.ssfDRIVES == 0x11
$items = $folder.Items()
for ($i= 0; $i -lt $items.Count; $i++) {
write-output ([string]$i + ": " + $items.Item($i).Name)
}
$choice = Read-Host "Make your choice"
$android = $items.Item([int]$choice)
$root = $android.GetFolder()
# FolderItem versus FolderItems
$maxdepth = Read-Host "Max depth"
Function Write-Items($item, $depth, $maxdepth) {
if ($depth -ge $maxdepth) {
return;
}
$indent = ""
for ($i = 0; $i -lt $depth; $i++) {
$indent += " ";
}
#write-output ($indent + "Name: " + $item.name)
if ($item.Title) {
$hash = @{
Name = $item.Title
Size = $null #$item.ParentFolder.GetDetailsOf($item, 2)
Modified = $null #$item.ParentFolder.GetDetailsOf($item, 3)
Parent = $item.ParentFolder.Title
Level = $depth
}
$Object = New-Object PSObject -Property $hash
write-output $object
} else {
$hash = @{
Name = $item.Name
Size = $item.Parent.GetDetailsOf($item, 2)
Modified = $item.Parent.GetDetailsOf($item, 3)
Parent = $item.Parent.Title
Level = $depth
}
$Object = New-Object PSObject -Property $hash
Write-Output $object
}
if ($item.Count -gt 0) {
# $item is a folder with its own items
for ($i = 0; $i -lt $item.Count) {
$item2 = $item.item($i)
Write-Items $item2 $depth+1 $maxdepth
}
}
else {
if ($item.Items) {
$items = $item.Items()
if ($items.Count -gt 0) {
foreach ($i in $items) {
if ($i.IsFolder) {
$folder = $i.GetFolder()
Write-Items $folder ($depth+1) $maxdepth
}
else {
Write-Items $i ($depth+1) $maxdepth
}
}
}
}
else {
# .Count == 0 and no Items present
# we don't need to do anything further here
}
}
}
Write-Items $root 0 $maxdepth | Out-GridView
@rmacmorran
Copy link

I think you need to change
$android.GetFolder()
to
$android.GetFolder
It's a property, not a method. (though its name implies otherwise)

@toto1515
Copy link

hello,
really good job.
Please can you help me ?
I am trying to copy files from ssfDRIVES to my computer.
It's a file on 'MY PC\Bebop 2\Media" (a drone) that i want to transfert to my computer
Using $item.path in your script, i found the path of the file is :
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\?\usb#vid_19cf&pid_5038#pi040436aa7j016983#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,7695343616}{00530071-0048-0006-0600-1D007A0794D7}
if i try to use copy-item, a get error because PS can't find "c:\Users\mylogin::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"

Thanks in advance for your help

Here is my code :

clear
Import-Module BitsTransfer


$o = New-Object -com Shell.Application
$folder = $o.NameSpace(0x11)
 write-output ($folder)

$items = $folder.Items()
for ($i= 0; $i -lt $items.Count; $i++) {
    write-output ([string]$i + ": " + $items.Item($i).Name)
	if ($items.Item($i).Name -eq "Bebop 2") {
	$choice = $i
	}
}
$android = $items.Item([int]$choice)
$root = $android.GetFolder
write-output ($root)

$maxdepth = 10
$arraytest = @()

Function showarray($array)
{
Write-Output "----------------------"
	for ($i=0;$i -lt $array.Length;$i++)
	{
		Write-Output "boucle : $i"
		Write-Output "Source=" $array[$i][0]
		Write-Output "Dest=" $array[$i][1]
		Write-Output "--------"
	}
}

Function copyfiles($array)
{
for ($i=0;$i -lt $array.Length;$i++)
	{
	Copy-Item -Path $array[$i][0] -dest $array[$i][1]
	#Copy-File $array[$i][0] $array[$i][1]
}
}

function Copy-File {
    param([string]$from, [string]$to)

    try {
        $job = Start-BitsTransfer -Source $from -Destination $to `
                   -Description "Moving: $from => $to" `
                   -DisplayName "Backup" -Asynchronous

        # Start stopwatch
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
        Write-Progress -Activity "Connecting..."

        while ($job.JobState.ToString() -ne "Transferred") {
            switch ($job.JobState.ToString()) {
                "Connecting" {
                    break
                }
                "Transferring" {
                    $pctcomp = ($job.BytesTransferred / $job.BytesTotal) * 100
                    $elapsed = ($sw.elapsedmilliseconds.ToString()) / 1000

                    if ($elapsed -eq 0) {
                        $xferrate = 0.0
                    } else {
                        $xferrate = (($job.BytesTransferred / $elapsed) / 1mb);
                    }

                    if ($job.BytesTransferred % 1mb -eq 0) {
                        if ($pctcomp -gt 0) {
                            $secsleft = ((($elapsed / $pctcomp) * 100) - $elapsed)
                        } else {
                            $secsleft = 0
                        }

                        Write-Progress -Activity ("Copying file '" + ($PathName.Split("\") | Select -last 1) + "' @ " + "{0:n2}" -f $xferrate + "MB/s") `
                                       -PercentComplete $pctcomp `
                                       -SecondsRemaining $secsleft
                    }
                    break
                }
                "Transferred" {
                    break
                }
                Default {
                    throw $job.JobState.ToString() + " unexpected BITS state."
                }
            }
        }

        $sw.Stop()
        $sw.Reset()
    } finally {
        Complete-BitsTransfer -BitsJob $job
        Write-Progress -Activity "Completed" -Completed
    }
}

Function Write-Items($item, $depth, $maxdepth) {

    if ($depth -ge $maxdepth) {
        return;
    }
    $indent = ""
    for ($i = 0; $i -lt $depth; $i++) {
        $indent += "   ";
    }
    if ($item.Title) {
        $hash = @{
            Name = $item.Title
            Size = $null #$item.ParentFolder.GetDetailsOf($item, 2)
            Modified = $null #$item.ParentFolder.GetDetailsOf($item, 3)
            Parent = $item.ParentFolder.Title
            Level = $depth
			Path = $item.Path
			
        }
        $Object = New-Object PSObject -Property $hash            
        write-output $object
    } else {
        $hash = @{
            Name = $item.Name
            Size = $item.Parent.GetDetailsOf($item, 2)
            Modified = $item.Parent.GetDetailsOf($item, 3)
            Parent = $item.Parent.Title
            Level = $depth
			Path = $item.Path
        }

		$sourcepath = $item.path
		$destpath = "G:\tempo\" + $item.Name
		Write-Output $item.path | clip
		Write-Output "sourcepath=" $sourcepath
		Write-Output "destpath=" $destpath
		$script:arraytest+=,($sourcepath,$destpath)
        #$Object = New-Object PSObject -Property $hash            
        #Write-Output $object
    }
    if ($item.Count -gt 0) {
        # $item is a folder with its own items
        for ($i = 0; $i -lt $item.Count) {
            $item2 = $item.item($i)
            Write-Items $item2 $depth+1 $maxdepth
        }

    }
    else { 
        if ($item.Items) {
            $items = $item.Items()
            if ($items.Count -gt 0) {
                foreach ($i in $items) {
                    if ($i.IsFolder) {
                        $folder = $i.GetFolder
                        Write-Items $folder ($depth+1) $maxdepth
                    }
                    else {                    
                        Write-Items $i ($depth+1) $maxdepth
                    }
                }
            }
        }
        else {
            # .Count == 0 and no Items present
            # we don't need to do anything further here
        }
    }
}

#Write-Items $root 0 $maxdepth | Out-GridView
Write-Items $root 0 $maxdepth

showarray $arraytest
#$arraytest
copyfiles $arraytest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment