Я пытаюсь разработать довольно простой так называемый SendLet. Он состоит из сценария PowerShell, который запускается с помощью ярлыка «Отправить» из контекстного меню проводника Windows. Вызванные для произвольных файлов или папок, они передаются сценарию в качестве аргументов. Мой подход заключается в следующем:
SendLet.ps1
param (
[Parameter(ValueFromRemainingArguments=$true)]
$FilePath
)
Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
Write-Host $_
}
Pause
Произвольные файлы
PowerShell 7.3.2
PS C:\Users\user\Desktop\Arbitrary Files> Get-ChildItem
Directory: C:\Users\user\Desktop\Arbitrary Files
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 29.01.2023 16:44 276246528 Baz qux.AVI
-a--- 29.01.2023 16:44 3787047 Foo bar.JPG
PS C:\Users\user\Desktop\Arbitrary Files>
Настраивать
C:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1
shell:sendto
(например, как C:\Users\user\AppData\Roaming\Microsoft\Windows\SendTo\SendLet.lnk
) с целью C:\Users\user\AppData\Local\Microsoft\WindowsApps\pwsh.exe C:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1
.Бегать
Выполнение описанного выше подхода на моем компьютере с Windows 11 22H2 приводит к следующему выводу:
C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:
Значение: найдены два файла с абсолютным путем для обработки...
Однако использование того же подхода на моем компьютере с Windows 10 Pro 22H2 приводит к следующей ошибке:
Get-ChildItem: D:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1:6
Line |
6 | Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:\Users\user\Documents\PowerShell\Scripts\Files\' because it does not exist.
Get-ChildItem: D:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1:6
Line |
6 | Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:\Users\user\Documents\PowerShell\Scripts\Files\' because it does not exist.
Press Enter to continue...:
Путь, на который жалуются в сообщении об ошибке, совершенно неверен и не существует. Вот почему его нет! Так что само сообщение об ошибке правильное. Но почему скрипт ищет неверный аргумент пути? Я предполагаю, что цитирование аргумента не работает должным образом.
/UPDATE: Единственное отличие, которое я вижу, заключается в том, что тестовые данные помещаются на диск C: моей рабочей машины. На моей неисправной машине тестовые данные помещаются на диск D: вместо этого. Но почему это должно иметь значение?
/UPDATE 2: Теперь я проверил размещение тестовых данных на диске C: моей неисправной машины. Странно все работает!? Итак, мой SendLet работает с файлами или папками на диске C:, но не с диском D: :-(
/ОБНОВЛЕНИЕ 3: я протестировал оба сценария, предложенные @zett42 в качестве решения. Результат немного странный.
Запустите папку «Произвольные файлы» (упомянутую выше) на моем рабочем компьютере с Windows 11, второй скрипт напечатает:
Processing file: C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
Processing file: C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:
Второй скрипт, запущенный на двух содержащихся файлах, печатает:
Processing file: C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
Processing file: C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:
Пока все хорошо... И теперь то же самое на моей проблемной машине с Windows 10 Pro.
Второй скрипт запускает печать папки:
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files
Press Enter to continue...:
Запустите непосредственно два содержащихся файла, которые он печатает:
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files\Baz
Processing file: qux.AVI
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files\Foo
Processing file: bar.JPG
Press Enter to continue...:
Что это? Что происходит с моей машиной с Windows 10 Pro?
Похоже, моя машина с Windows 11 запускает сценарий PowerShell для папки с аргументами как "C:\Users\user\Desktop\Arbitrary Files"
. См. один аргумент в кавычках, содержащий пробелы.
Однако мой компьютер с Windows 10 Pro, похоже, запускает скрипт в папке с аргументами как C:\Users\user\Desktop\Arbitrary Files
, в результате чего два аргумента разделены пробелом.
Такое же поведение, по-видимому, применимо к сценарию, запускаемому непосредственно в двух тестовых файлах в папке в качестве аргументов в кавычках:
"C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI" "C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG"
=> Два аргумента в кавычках
... или аргументы без кавычек:
C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
=> 6 аргументов без кавычек
Это не может быть нормальным поведением. Или это?
Может быть, я что-то упускаю? Какие-либо предложения?
/ОБНОВЛЕНИЕ 4: Я обнаружил проблему -__-, которая оказалась очень и очень раздражающей... Я еще раз проверил ссылки SendTo на обеих своих машинах. Единственным отличием был абсолютный путь к интерпретатору pwsh.exe
, потому что PowerShell был установлен по-другому.
На хорошей машине путь к pwsh.exe
указывает на C:\Program Files\PowerShell\7\pwsh.exe
. Все идет нормально.
На проблемной машине путь, указывающий на pwsh.exe
, вместо этого был C:\Users\user\AppData\Local\Microsoft\WindowsApps\pwsh.exe
. Ну и что, подумал я. Это просто другой путь. Но когда я открыл папку в проводнике, у меня возникли подозрения, потому что файл pwsh.exe
имеет размер 0 байт :-O Затем я открыл ту же папку в терминале PowerShell и набрал ls
, чтобы показать то, чего я не ожидал. Все EXE-файлы там просто ссылки на что-то еще, но я не знаю, куда? Что означают стрелки ->
?
PowerShell 7.3.2
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps> ls
Directory: C:\Users\user\AppData\Local\Microsoft\WindowsApps
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10.01.2023 18:44 Backup
d---- 25.01.2023 10:57 Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
d---- 20.12.2022 11:50 Microsoft.MicrosoftEdge_8wekyb3d8bbwe
d---- 28.01.2023 23:08 Microsoft.PowerShell_8wekyb3d8bbwe
d---- 26.01.2023 17:18 Microsoft.SkypeApp_kzf8qxf38zg5c
d---- 28.01.2023 14:19 Microsoft.WindowsTerminal_8wekyb3d8bbwe
d---- 10.02.2023 10:50 Microsoft.XboxGamingOverlay_8wekyb3d8bbwe
d---- 03.02.2023 15:55 SpotifyAB.SpotifyMusic_zpdnekdrzrea0
la--- 10.02.2023 10:50 0 GameBarElevatedFT_Alias.exe ->
la--- 20.12.2022 11:50 0 MicrosoftEdge.exe ->
la--- 28.01.2023 23:08 0 pwsh.exe ->
la--- 25.01.2023 10:57 0 python.exe ->
la--- 25.01.2023 10:57 0 python3.exe ->
la--- 26.01.2023 17:18 0 Skype.exe ->
la--- 03.02.2023 15:55 0 Spotify.exe ->
la--- 25.01.2023 10:57 0 WindowsPackageManagerServer.exe ->
la--- 25.01.2023 10:57 0 winget.exe ->
la--- 28.01.2023 14:19 0 wt.exe ->
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps>
В заключение я заключаю, что проблема здесь в том, что ВСЕ аргументы, переданные в интерпретатор-ссылку, не передаются правильно (кавычки теряются) интерпретатору PowerShell!
Настройка моего SendLet, указывающего на сам интерпретатор, а не на ссылку, решила мою проблему.
Спасибо всем
Является ли общий диск D под той же учетной записью и с тем же уровнем привилегий?
@Max Да, вы правильно проверили. Поскольку вы тестировали с помощью powershell.exe (PS v5.x), а я тестировал с помощью pwsh.exe (PS v7.x), я снова попробовал его с powershell.exe, но все результаты были одинаковыми на моей неисправной машине. Таким образом, поведение кажется последовательным.
@ js2010 Мой диск D: — это физический вращающийся жесткий диск.
Re update #4: Отличная находка! Возможно ли, что PowerShell установлен через Microsoft Store на проблемную машину?
@mrkskwsnck Я думаю, проблема здесь в том, что режим la
указывает на следующие битовые поля: l - Reparse point, symlink, ...
и a - archive
, поэтому la будет означать, что эти «файлы» на самом деле являются архивами символических ссылок или архивами точек повторной обработки, которые совершенно бесполезны для пользователя. Похоже, что обновление до Win11 не помогло некоторым файлам, и теперь они указывают на новые местоположения или что-то в этом роде.
Это действительно сложная вещь, которую вы нашли. Возможно, вы можете написать свое обновление 4 в качестве ответа, принять его и закрыть ветку? таким образом другие люди могут найти решение быстрее. И, возможно, измените заголовок, чтобы указать на реальную проблему со ссылками для отправки.
@zett42 zett42 Я больше не могу сказать, был ли PowerShell установлен из Магазина Microsoft или через winget
. Определенно не для загрузки старого доброго установщика EXE.
Я не думаю, что вы должны передавать пути к файлам с помощью -recurse
переключаться на Get-ChildItem
. По крайней мере, я получаю странное поведение в том, что каталог, содержащий файл, перечисляется, даже если я передаю только один файл через меню SendTo
. Кроме того, скрипт корректно получает все пути, независимо от пробелов и расположения на дисках.
Итак, чтобы убедиться, что Get-ChildItem
ведет себя так, как ожидалось, сначала переберите пути, полученные в качестве аргументов, и проверьте, какой из них на самом деле является каталогом. Кроме того, не забудьте вызвать Get-ChildItem
с параметром -File
, если вы хотите только перебирать файлы.
param (
[Parameter(ValueFromRemainingArguments=$true)]
$FilePath
)
foreach( $path in $FilePath ) {
if ( (Test-Path $path -PathType Container) ) {
"Is directory: $path"
Get-ChildItem -Recurse -File -Path $path | ForEach-Object {
$_
}
}
else {
"Is file: $path"
}
}
Pause
Обратите внимание, что я удалил Write-Host
, потому что он не нужен. Неназначенные выражения рассматриваются PowerShell как неявные выходные данные.
Хотя для лучшей структуры я бы обернул код перечисления файлов в функцию.
param (
[Parameter(ValueFromRemainingArguments=$true)]
$FilePath
)
# A function that outputs only file paths, regardless if file
# paths or directory paths are passed. Directories are processed recursively.
Function EnumerateFilesRecursive( [string[]] $FileOrDirectoryPaths ) {
foreach( $path in $FileOrDirectoryPaths ) {
if ( (Test-Path $path -PathType Container) ) {
Get-ChildItem -Recurse -File -Path $path | ForEach-Object Fullname
}
else {
$path
}
}
}
# Call the function and process its output (file paths)
EnumerateFilesRecursive $FilePath | ForEach-Object {
"Processing file: $_"
}
pause
Спасибо за ваши тестовые сценарии. Я написал обновление 3 в своем первоначальном вопросе со странным результатом.
@mrkskwsnck Это действительно очень странно. Создали ли вы таким же образом ярлык SendTo на проблемной машине? Для дальнейшей диагностики проблемы, можете ли вы скопировать командную строку, полученную pwsh.exe, с помощью диспетчера задач?
Еще раз спасибо @zett42 Я решил свою проблему. Пожалуйста, прочитайте мое обновление номер 4 для деталей.
Здесь я отвечаю на свой вопрос, основанный на /UPDATE 4 (см. выше) подобного.
Обратите внимание на то, на какой EXE-файл интерпретатора PowerShell указывает ваш ярлык «Отправить» (находится внутри shell:SendTo
). Является ли это подлинным EXE-файлом (например, pwsh.exe
для версии 7) или символической ссылкой на него? Оказывается, отправка файловых аргументов в символическую ссылку вообще не обрабатывает пути, содержащие пробелы!
Символическую ссылку можно узнать по ее размеру 0 байт в проводнике Windows или по стрелке вправо ->
, напечатанной командой ls
в терминале PowerShell.
PowerShell 7.3.2
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps> ls
Directory: C:\Users\user\AppData\Local\Microsoft\WindowsApps
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10.01.2023 18:44 Backup
d---- 25.01.2023 10:57 Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
d---- 20.12.2022 11:50 Microsoft.MicrosoftEdge_8wekyb3d8bbwe
d---- 28.01.2023 23:08 Microsoft.PowerShell_8wekyb3d8bbwe
d---- 26.01.2023 17:18 Microsoft.SkypeApp_kzf8qxf38zg5c
d---- 28.01.2023 14:19 Microsoft.WindowsTerminal_8wekyb3d8bbwe
d---- 10.02.2023 10:50 Microsoft.XboxGamingOverlay_8wekyb3d8bbwe
d---- 03.02.2023 15:55 SpotifyAB.SpotifyMusic_zpdnekdrzrea0
la--- 10.02.2023 10:50 0 GameBarElevatedFT_Alias.exe ->
la--- 20.12.2022 11:50 0 MicrosoftEdge.exe ->
la--- 28.01.2023 23:08 0 pwsh.exe ->
la--- 25.01.2023 10:57 0 python.exe ->
la--- 25.01.2023 10:57 0 python3.exe ->
la--- 26.01.2023 17:18 0 Skype.exe ->
la--- 03.02.2023 15:55 0 Spotify.exe ->
la--- 25.01.2023 10:57 0 WindowsPackageManagerServer.exe ->
la--- 25.01.2023 10:57 0 winget.exe ->
la--- 28.01.2023 14:19 0 wt.exe ->
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps>
Я просто заново создал и запустил его. Теперь, пожалуйста, дайте мне знать, правильно ли я понял: Script находится на моем диске C, и я только что проверил его с каталогом на моем диске D. Это то, что вы тестировали, не так ли? На моей машине все работало без проблем. Однако я изменил расположение своего PowerShell в ссылке:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe