Это основано на моих ограниченных знаниях об объекте Shell.Application, который недостаточно хорошо документирован. Если кто-то знает лучше, пожалуйста, не стесняйтесь исправить.
COM-объект Shell.Application является копией оболочки Windows Explorer, которая выполняет файловые операции асинхронно. Новый поток создается для каждого действия «копировать», а экземпляр $shell
управляет этими потоками и получает события - завершено / не выполнено / требуется ввод данных пользователем / и т.д.
Когда скрипт завершается, $shell
очищается и не может получать события. Созданные им потоки копирования будут прерываться ненормально, как если бы вы выключили компьютер во время копирования файлов с одного диска на другой.
Обратите внимание, что CopyHere не вызывает завершенное событие . Это затрудняет определение ошибки или ожидание завершения в скрипте. В идеале вы должны использовать Powershell, встроенный в Copy-Item, а не Shell, но это может быть невозможно на устройствах MTP.
Быстрое решение, вероятно, состоит в том, чтобы добавить System.Console.ReadKey()
, например, связанный ответ, или увеличить продолжительность ожидания, если вы хотите запускать без присмотра.
Редактировать: Вместо ожидания вы можете подтвердить существование каждого из файлов в пути назначения: $destinationFolder.GetFolder.Items()
содержит список файлов в месте назначения. С этот поток WMI также вариант, но примеры редки.
Редактировать 2: Вот простой скрипт, который копирует с жесткого диска на телефон и подтверждает, что он выполнен:
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)"
}