AI工具:读取手机系统文件工具

AI模型:Deepseek

开发:AI+人工

测试环境:鸿蒙4.2+windows11

准备:手机数据线连接电脑+USB连接方式为传输文件+手机被系统识别

保存:记事本编码ansi+所有类型+名称.ps1

运行:右键使用Powershell运行

代码:

点击查看代码
# 定义递归函数,列出 MTP 文件夹中的所有项(文件夹和文件)
function Get-MTPItemsRecursive {
    param(
        $FolderObject,          # Shell.Folder 对象
        $RelativePath = ""      # 当前相对路径(用于显示)
    )
     
    $items = $FolderObject.Items()
    foreach ($item in $items) {
        $currentPath = if ($RelativePath) { "$RelativePath\$($item.Name)" } else { $item.Name }
         
        if ($item.IsFolder) {
            # 如果是文件夹,先显示文件夹本身(可选),然后递归进入
            #Write-Host "  [DIR] $currentPath"
            $subFolder = $item.GetFolder()
            if ($subFolder) {
                Get-MTPItemsRecursive -FolderObject $subFolder -RelativePath $currentPath
            }
        } else {
            # 如果是文件,直接显示相对路径和类型
            #Write-Host "  $currentPath [$($item.Type)]"
            Write-Host "$currentPath"
        }
    }
}
 
# 复制MTP文件到本地的完整示例
$shell = New-Object -ComObject Shell.Application -ErrorAction Stop
if ($null -eq $shell) {
    Write-Error "无法创建 Shell.Application 对象,请检查系统组件。"
    exit 1
}
 
# 定位到"此电脑"
$myComputer = $shell.NameSpace(0x11)
if ($null -eq $myComputer -or -not $myComputer.Items()) {
    Write-Error "无法获取“此电脑”文件夹。"
    exit 1
}
 
$myComputer.Items() | foreach -process {$_} | format-list -property Name,Type
$tp = Read-Host -Prompt "请查找你的设备并输入你设备的Type字段"
 
# 找到便携设备
$portableDevices = $myComputer.Items() | Where-Object { $_.Type -eq "$tp" }
 
if (-not $portableDevices) {
    Write-Host "未找到任何 MTP 设备,请连接手机并解锁。"
    exit
}
 
$portableDevices | ForEach-Object -process { $_ } | format-list -property Name,Type
$nm = Read-Host -Prompt "请查找你的设备并输入你设备的Name字段"
 
# 假设手机名包含 "xxx",可根据实际情况修改
$device = $portableDevices | Where-Object { $_.Name -like "*$nm*" }
if (-not $device) {
    Write-Host "未找到匹配的设备,当前设备有:"
    $portableDevices | ForEach-Object -process { $_ } | format-list -property Name,Type
    exit
}
 
Write-Host "找到设备: $($device.Name)"
 
# 进入设备内部
$deviceFolder = $device.GetFolder()
$storageAreas = $deviceFolder.Items()
 
# 找到内部存储(通常名为"内部共享存储空间")
$storageAreas | foreach-object -process {$_} | format-list -property Name,Type
$nme = Read-Host -Prompt "请查找你的设备并输入你设备的Name字段"
 
$internalStorage = $storageAreas | Where-Object { $_.Name -eq "$nme" }
if (-not $internalStorage) {
    Write-Host "未找到内部存储区域,可用的区域有:"
    $storageAreas | foreach-object -process {$_} | format-list -property Name,Type
    exit
}
 
# 获取内部存储根目录的 Folder 对象
$storageFolder = $internalStorage.GetFolder()
Write-Host "内部存储所有文件(递归):"
Get-MTPItemsRecursive -FolderObject $storageFolder

介绍:

点击查看代码
下面详细解释 `checkMobile.ps1` 脚本的每个部分及其作用、潜在问题与改进建议。

---

## 一、脚本总体目标

该脚本利用 Windows 的 `Shell.Application` COM 对象,通过 MTP 协议访问连接的手机(或其他便携设备),并递归列出手机内部存储中的所有文件路径(不包含文件夹名,仅输出文件的相对路径)。  
主要流程:  
1. 定义递归遍历 MTP 文件夹的函数。  
2. 获取“此电脑”下的所有项目,让用户手动识别便携设备的 `Type` 和 `Name`。  
3. 定位到手机设备,再进入内部存储区域。  
4. 调用递归函数输出所有文件路径。

---

## 二、代码逐段详解

### 1. 递归函数 `Get-MTPItemsRecursive`

```powershell
function Get-MTPItemsRecursive {
    param(
        $FolderObject,          # Shell.Folder 对象
        $RelativePath = ""      # 当前相对路径(用于显示)
    )
    
    $items = $FolderObject.Items()
    foreach ($item in $items) {
        $currentPath = if ($RelativePath) { "$RelativePath\$($item.Name)" } else { $item.Name }
        
        if ($item.IsFolder) {
            # 如果是文件夹,先显示文件夹本身(可选),然后递归进入
            #Write-Host "  [DIR] $currentPath"
            $subFolder = $item.GetFolder()
            if ($subFolder) {
                Get-MTPItemsRecursive -FolderObject $subFolder -RelativePath $currentPath
            }
        } else {
            # 如果是文件,直接显示相对路径和类型
            #Write-Host "  $currentPath [$($item.Type)]"
            Write-Host "$currentPath"
        }
    }
}

解释:

  • 参数:
    • $FolderObject:一个 Shell.Folder 对象,代表 MTP 设备中的一个文件夹(如根目录或子目录)。
    • $RelativePath:当前文件夹相对于内部存储根目录的路径,用于构建文件的完整相对路径。
  • 核心逻辑:
    1. 调用 $FolderObject.Items() 获取文件夹内所有子项(文件和子文件夹)。
    2. 遍历每个子项:
      • 构建当前项的完整相对路径 $currentPath(例如 DCIM/Camera/photo.jpg)。
      • 如果 $item.IsFolder 为 $true,说明是子文件夹:
        • 注释掉的 Write-Host 原本用于输出文件夹名,现被忽略。
        • 调用 $item.GetFolder() 获取子文件夹的 Folder 对象,然后递归调用自身。
      • 如果是文件(else 分支),直接输出 $currentPath。
  • 输出:每行一个文件相对路径(不包含根目录名称,例如 Pictures/1.jpg,而不是 内部共享存储空间/Pictures/1.jpg)。
  • 缺点:
    • 没有对 $FolderObject 做空值检查,如果传入 $null 会报错。
    • 递归可能非常深(手机存储可能有数十万文件),导致 PowerShell 执行缓慢或栈溢出(不过一般 MTP 文件夹深度有限)。
    • 未处理访问被拒绝的文件夹(GetFolder() 可能返回 $null,但代码只是跳过)。

2. 创建 Shell.Application 对象

$shell = New-Object -ComObject Shell.Application -ErrorAction Stop
if ($null -eq $shell) {
    Write-Error "无法创建 Shell.Application 对象,请检查系统组件。"
    exit 1
}

解释:

  • 使用 New-Object -ComObject Shell.Application 创建 Windows Shell 的 COM 对象,这是访问 MTP 设备的核心入口。
  • -ErrorAction Stop 确保创建失败时脚本终止。
  • 随后检查 $shell 是否为 $null,若为 null 则报错退出。

3. 定位到“此电脑”文件夹

$myComputer = $shell.NameSpace(0x11)
if ($null -eq $myComputer -or -not $myComputer.Items()) {
    Write-Error "无法获取“此电脑”文件夹。"
    exit 1
}

解释:

  • $shell.NameSpace(0x11):参数 0x11 是 Windows 常量 ssfDRIVES,代表“我的电脑/此电脑”虚拟文件夹。
  • 检查 $myComputer 和其 Items() 方法是否可用,防止后续遍历失败。

4. 列出所有项目并让用户输入设备的 Type

$myComputer.Items() | foreach -process {$_} | format-list -property Name,Type
$tp = Read-Host -Prompt "请查找你的设备并输入你设备的Type字段"

解释:

  • $myComputer.Items() 返回“此电脑”下所有项目(包括本地磁盘、网络位置、便携设备等)。
  • foreach -process {$_} 将每个项目向下传递(等价于 ForEach-Object { $_ }),然后 format-list -property Name,Type 以列表形式显示每个项目的名称和类型。
  • 用户需从输出中找到自己的手机设备(通常 Type 为“便携设备”或“Portable Device”),并手动输入该 Type 字段的值(例如中文的“便携设备”)。
  • 问题:
    • 用户需要知道确切 Type 字符串,且不同语言系统可能不同。
    • 直接让用户复制粘贴易出错(可能包含不可见字符)。
    • 更好的做法是自动筛选 Type -eq "便携设备",但脚本选择交互式输入,增加了手动操作负担。

5. 根据用户输入的 Type 筛选便携设备

$portableDevices = $myComputer.Items() | Where-Object { $_.Type -eq "$tp" }

if (-not $portableDevices) {
    Write-Host "未找到任何 MTP 设备,请连接手机并解锁。"
    exit
}

解释:

  • 使用用户输入的 $tp 字符串筛选出所有 Type 匹配的项目(理论上应该只有便携设备)。
  • 若没有匹配项,提示并退出。
  • 问题:
    • 如果用户输错一个字符(如“便抉设备”),就会匹配失败。
    • 未考虑多个便携设备的情况(会保留所有匹配项,后续仍可能出错)。

6. 再次列出设备并让用户输入设备的 Name

$portableDevices | ForEach-Object -process { $_ } | format-list -property Name,Type
$nm = Read-Host -Prompt "请查找你的设备并输入你设备的Name字段"

解释:

  • 显示所有匹配到的便携设备的 Name 和 Type(通常 Name 是设备型号,如“Redmi Note 10”)。
  • 用户需根据显示的 Name 再次输入设备名称(支持部分匹配,因为后续使用 -like "*$nm*")。

7. 根据用户输入的 Name 筛选特定设备

$device = $portableDevices | Where-Object { $_.Name -like "*$nm*" }
if (-not $device) {
    Write-Host "未找到匹配的设备,当前设备有:"
    $portableDevices | ForEach-Object -process { $_ } | format-list -property Name,Type
    exit
}
Write-Host "找到设备: $($device.Name)"

解释:

  • 使用 -like "*$nm*" 实现模糊匹配,只要设备名包含用户输入的字符串即可。
  • 若匹配失败,重新显示可用设备列表并退出。
  • 注意:如果 $portableDevices 包含多个设备且用户输入的字符串匹配到多个,$device 将包含第一个匹配项(取决于 Where-Object 返回的集合)。若希望精确匹配,应使用 -eq 或要求用户输入完整名称。

8. 进入设备内部并列出存储区域

$deviceFolder = $device.GetFolder()
$storageAreas = $deviceFolder.Items()

$storageAreas | foreach-object -process {$_} | format-list -property Name,Type
$nme = Read-Host -Prompt "请查找你的设备并输入你设备的Name字段"

解释:

  • $device.GetFolder() 获取设备根目录的 Folder 对象。
  • $storageAreas 是设备下的存储区域(例如“内部共享存储空间”、“SD 卡”等)。
  • 再次列出这些存储区域的 Name 和 Type,让用户选择内部存储对应的 Name。
  • 潜在问题:
    • 若设备只有内部存储,$storageAreas 可能只有一个项目。
    • 不同手机可能名称不同(“内部存储”、“Phone”、“Internal Storage”),用户需要知道准确名称。

9. 根据用户输入的 Name 选择内部存储区域

$internalStorage = $storageAreas | Where-Object { $_.Name -eq "$nme" }
if (-not $internalStorage) {
    Write-Host "未找到内部存储区域,可用的区域有:"
    $storageAreas | foreach-object -process {$_} | format-list -property Name,Type
    exit
}

解释:

  • 使用精确匹配(-eq)查找用户输入的存储区名称。
  • 若未找到,显示可用区域并退出。
  • 缺点:用户必须完全正确输入名称(包括大小写、空格)。如果名称是“内部共享存储空间”,输成“内部共享存储”就会失败。

10. 获取内部存储根目录并递归列出所有文件

$storageFolder = $internalStorage.GetFolder()
Write-Host "内部存储所有文件(递归):"
Get-MTPItemsRecursive -FolderObject $storageFolder

解释:

  • $internalStorage.GetFolder() 获得内部存储的根 Folder 对象。
  • 调用递归函数,输出所有文件的相对路径(每行一个)。
  • 最终输出:手机内部存储中的所有文件路径(相对于存储根目录)。

三、脚本的总体评价

优点

  • 无需安装 ADB 或开启 USB 调试,纯 Windows 原生 MTP 支持。
  • 提供了交互式选择过程,适应不同手机的不同设备名称和存储区名称。

缺点与改进建议

  1. 过度依赖人工输入

    • 用户需要手动输入 Type、Name 两次,极易出错。
    • 改进:脚本应自动识别 Type -eq "便携设备",并让用户从列表中选择编号,而不是手动输入字符串。
  2. 无错误处理

    • 未检查 $device.GetFolder() 是否返回 $null(手机未解锁或断开时可能失败)。
    • 递归函数未处理无效的 $FolderObject。
    • 改进:增加 if ($null -eq $deviceFolder) { exit } 等检查。
  3. 性能问题

    • 递归遍历整个手机存储可能非常慢(MTP 协议本身低效)。
    • 改进:增加进度提示或允许用户指定子目录(如仅扫描 DCIM)。
  4. 输出格式

    • 仅输出文件路径,没有区分不同文件夹,输出量大时难以阅读。
    • 改进:允许输出到文件(> filelist.txt)或同时显示文件夹路径。
  5. 递归深度风险

    • PowerShell 默认递归深度无限制,但 MTP 文件夹层级一般较浅(< 50),风险较低。

四、使用示例

假设手机已通过 USB 连接并选择“传输文件”模式,运行脚本:

  1. 显示“此电脑”下所有项目(本地磁盘 C:、D:、便携设备等)。
  2. 用户输入便携设备的 Type(例如“便携设备”)。
  3. 显示所有便携设备列表(如“Redmi Note 10”、“SD 卡”)。
  4. 用户输入设备 Name(例如“Redmi”)。
  5. 显示设备内的存储区域(“内部共享存储空间”、“SD 卡”)。
  6. 用户输入内部存储的 Name(例如“内部共享存储空间”)。
  7. 脚本开始递归输出所有文件路径,如:
    DCIM/Camera/IMG_001.jpg
    DCIM/Camera/IMG_002.jpg
    Download/app.apk
    ...
    

五、总结

该脚本是一个交互式的 MTP 文件列表工具,通过 COM 接口访问手机存储。虽然可以实现基本功能,但交互方式原始、易错,且缺乏健壮的错误处理。更适合作为学习 PowerShell COM 对象和 MTP 协议的参考示例,实际生产环境中建议改用 ADB 或成熟的第三方工具。

</details>
posted @ 2026-10-28 13:32  humors221  阅读(4)  评论(0)    收藏  举报