如何使用PowerShell将项目可靠地复制到mtp设备? [英] How to reliably copy items with PowerShell to an mtp device?

查看:225
本文介绍了如何使用PowerShell将项目可靠地复制到mtp设备?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够将Windows PC中的项目(文件,文件夹)复制到MTP设备.我想使用PowerShell来实现脚本目的.

I want to be able to copy items (files, folders) from a Windows PC to an MTP device. I want to do it with PowerShell for scripting purposes.

我发现了此线程: shell32 copyhere无法正常工作既不是.Net也不是Powershell脚本,但是那里的答案无助于理解解决方案(由提出该问题的同一人给出).下面是一个最小的代码示例:

I found this thread: shell32 copyhere not working neither in .Net nor powershell script but the answer there does not help understanding the solution (and was given by the same person who asked that question). Below there is a minimal code example:

param ($itemName)

$shell = New-Object -com Shell.Application

$sourceFolder = $shell.Namespace($(Get-Location).toString()).self
$item = $sourceFolder.GetFolder.Items() | where { $_.Name -eq $itemName }

$mtpDevice = $shell.NameSpace(0x11).items() | where { $_.name -eq 'DUMMY_MODEL' }
$destination = $mtpDevice.GetFolder.items() | where { $_.Name -eq 'Card' }
$destinationFolder=$shell.Namespace($destination).self

$destinationFolder.GetFolder.CopyHere($item)

$shell.open($destinationFolder)
Start-Sleep -s 1

我假定Windows计算机上存在要复制的项目($ itemName).我假设mtp设备在Windows资源管理器中被视为"DUMMY_MODEL",并且其中包含一个空的顶级文件夹"Card".

I assume that the item to be copied ($itemName) exists on the Windows machine. I assume that the mtp device is seen as "DUMMY_MODEL" in Windows Explorer and that it contains an empty, top-level folder "Card".

我希望这行

$destinationFolder.GetFolder.CopyHere($item)

应该做的工作.但事实并非如此.为了使其正常工作,我需要以编程方式打开目标文件夹窗口并使用sleep.为什么?上面提到的线程说是为了完成复制线程.为什么不打开窗户就无法完成?可以在不以编程方式打开窗口的情况下完成此操作吗?即使我确实打开窗户并入睡,复制也无法100%可靠地进行.为什么?

should do the job. But it is not the case. In order for it to work I need to programmatically open the destination folder window and use sleep. Why? The above mentioned thread says that it is in order for the copying thread to finish. Why can't it finish without opening the window? Can this be done without programmatically opening the window? And even if I do open the window and do the sleep, copying does not work 100% reliably. Why?

推荐答案

这是基于我对Shell.Application对象的有限了解,而该知识没有充分的文档说明.如果有人知道的更好,请随时进行纠正.

This is based on my limited knowledge of the Shell.Application object that isn't well documented. If anyone knows better, please feel free to correct.

Shell.Application COM对象是Windows Explorer Shell的副本,它异步执行文件操作.为每个复制"操作创建一个新线程,并且$shell实例管理这些线程并接收事件-完成/失败/需要用户输入等. 脚本终止后,$shell被清除,无法接收事件.它创建的复制线程将异常终止,就像您在将文件从一个驱动器复制到另一个驱动器时关闭了计算机一样.

The Shell.Application COM object is a copy of the Windows Explorer shell, which performs file operations asynchronously. A new thread is created for each 'copy' action, and the $shell instance manages those threads and receives the events - completed/failed/needs user input/etc. When the script terminates, $shell is cleaned up and can't receive events. The copy threads it created will terminate abnormally, like if you had turned off your computer while copying files from one drive to another.

请注意 CopyHere不会引发已完成的事件.这使得难以捕获故障或等待脚本完成.理想情况下,您将使用内置在Copy-Item中的Powershell而不是Shell,但对于MTP设备可能无法实现.

Note that CopyHere doesn't raise a completed event. That makes it difficult to capture failure or wait for completion in a script. Ideally you would use Powershell built in Copy-Item instead of the Shell, but it may not be possible with MTP devices.

快速解决方案可能是像链接的答案一样添加System.Console.ReadKey(),或者如果您想在无人看管的情况下运行,请延长睡眠时间.

The quick fix is probably to add System.Console.ReadKey() like the linked answer, or extend the sleep duration if you want to run unattended.

无需等待,您可以确认目标路径中每个文件的存在:$destinationFolder.GetFolder.Items()包含目标中文件的列表.来自此线程 WMI也是一种选择,但示例很少.

Instead of waiting, you can confirm the existence of each of the files in the destination path: $destinationFolder.GetFolder.Items() contains the list of files in the destination. From this thread WMI is also an option, but the examples are sparse.

这是一个简单的脚本,可以将其从硬盘复制到手机并确认已完成:

Edit 2: Here's a simple script that copies from hard drive to phone and confirms that it completed:

param([string]$phoneName = 'Nexus 5X', #beyond compare path: 'mtp://Nexus 5X'
    [string]$sourcePath = 'C:\Temp\',
    [string]$targetPath = '\Card\DCIM\',
    [string]$filter='(.jpg)|(.mp4)$'
)

$Shell = New-Object -ComObject Shell.Application
$PhoneObject = $shell.NameSpace(17).self.GetFolder.items() | where { $_.name -eq $phoneName } #gets the phone special folder

$SourceFolder = $Shell.NameSpace($sourcePath).self.GetFolder()
$DestFolder = $Shell.NameSpace((Join-path $PhoneObject.Path $targetPath)).self.GetFolder()

foreach($Item in $SourceFolder.Items() | ?{$_.Name -match $filter}){
    $DestFolder.CopyHere($Item)
    Do {
        $CopiedFile = $null 
        $CopiedFile = $DestFolder.Items() | ?{$_.Name -eq $Item.Name}
    }While( ($CopiedFile -eq $null) -and ($null -eq (Sleep -Milliseconds 100)) )#skip sleeping if it's already copied
    Write-Host "Copied $($item.Name)"
}

这篇关于如何使用PowerShell将项目可靠地复制到mtp设备?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆