Подтвердить что ты не робот

Диалог выбора файлов/папок из пакета Windows script

Как правило, просить пользователя предоставить имя файла пакету script является грязным делом, не требующим орфографических ошибок, кавычек вокруг путей с пробелами и т.д. К сожалению, пользователи не знают точности. В ситуациях, когда местоположение входного файла неизвестно до времени исполнения, использование GUI для ввода файла позволяет уменьшить вероятность ошибки пользователя.

Есть ли способ вызывать выборщик gui файла стиля File... Open или выбор папок из пакета Windows script?

Если у пользователя script установлен PowerShell или .NET, это возможно. См. Ответ ниже.

Мне также интересно узнать, какие другие решения могут предложить другие.

4b9b3361

Ответ 1

Браузер файлов

Обновление 2016.3.20:

Так как PowerShell является родным компонентом почти всех современных установок Windows в настоящее время, я объявляю резерв С# как ненужный. Если вы все еще нуждаетесь в совместимости с Vista или XP, я переместил его в новый ответ. Начиная с этого редактирования, я переписываю script как гибрид Batch + PowerShell и включаю в себя возможность выполнять множественный выбор. Это очень легко читать и настраивать по мере необходимости.

<# : chooser.bat
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
:: https://stackoverflow.com/a/15885133/1683264

@echo off
setlocal

for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
    echo You chose %%~I
)
goto :EOF

: end Batch portion / begin PowerShell hybrid chimera #>

Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }

Это приведет к диалогу выбора файла.

file chooser

Результат выбора выходов You chose C:\Users\me\Desktop\tmp.txt на консоль. Если вы хотите принудительно выделить один файл, просто измените свойство $f.Multiselect на $false.

(команда PowerShell безжалостно вырывается из Just Tinkering Blog.) См. OpenFileDialog Class для других свойств, которые вы можете установить, например Title и InitialDirectory.


Браузер папок

Обновление 2015.08.10:

Поскольку уже существует COM-метод для вызова выбора папок, довольно легко создать однострочный синтаксис PowerShell, который может открыть выбор папки и вывести путь.

:: fchooser.bat
:: launches a folder chooser and outputs choice to the console
:: https://stackoverflow.com/a/15885133/1683264

@echo off
setlocal

set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please choose a folder.',0,0).self.path""

for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"

setlocal enabledelayedexpansion
echo You chose !folder!
endlocal

В методе BrowseForFolder() четвертый аргумент указывает корень иерархии. См. ShellSpecialFolderConstants для списка допустимых значений.

Это приведет к диалогу выбора папки.

enter image description here

Результат выбора выводит You chose C:\Users\me\Desktop на консоль.

Обратитесь к документации FolderBrowserDialog class для других свойств, которые вы можете установить, например RootFolder. Мои исходные решения .NET System.Windows.Forms PowerShell и С# можно найти в версии 4 этого ответа, если это необходимо, но этот COM-метод намного проще читать и поддерживать.

Ответ 2

Windows Script Хост


Выбор файла

В Windows XP появился таинственный объект UserAccounts.CommonDialog WSH который позволил VBScript и JScript запустить приглашение выбора файла. По-видимому, это был считался угрозой безопасности и удален в Vista.


Выбор папки

Однако объект WSH Shell.Application BrowseForFolder по-прежнему позволит создать диалог выбора папки. Здесь приведен пример гибридного пакета + JScript. Сохраните его с расширением .bat.

@if (@[email protected]) @end /*

:: fchooser2.bat
:: batch portion

@echo off
setlocal

for /f "delims=" %%I in ('cscript /nologo /e:jscript "%~f0"') do (
    echo You chose %%I
)

goto :EOF

:: JScript portion */

var shl = new ActiveXObject("Shell.Application");
var folder = shl.BrowseForFolder(0, "Please choose a folder.", 0, 0x00);
WSH.Echo(folder ? folder.self.path : '');

folder selection dialog

В методе BrowseForFolder() четвертый аргумент указывает корень иерархии. См. ShellSpecialFolderConstants для списка допустимых значений.

Ответ 3

Это должно работать от XP вверх и не требует файла hibrid, он просто запускает mshta с длинной командной строкой:

@echo off
set dialog="about:<input type=file id=FILE><script>FILE.click();new ActiveXObject
set dialog=%dialog%('Scripting.FileSystemObject').GetStandardStream(1).WriteLine(FILE.value);
set dialog=%dialog%close();resizeTo(0,0);</script>"

for /f "tokens=* delims=" %%p in ('mshta.exe %dialog%') do set "file=%%p"
echo selected  file is : "%file%"
pause

Ответ 4

Выбор файла/папки может выполняться с помощью чистой партии, как показано ниже. Конечно, ощущение и внешний вид не так приятны, как графический интерфейс, но он работает очень хорошо, и, на мой взгляд, он проще в использовании, чем версия GUI. Метод выбора основан на команде CHOICE, поэтому потребуется загрузить его в версии Windows, которые не включают его, и слегка изменить его параметры. Конечно, код можно легко изменить, чтобы использовать SET/P вместо CHOICE, но это изменение устранит очень простой и быстрый метод выбора, для которого требуется только одно нажатие клавиши для навигации и выбора.

@echo off
setlocal

rem Select a file or folder browsing a directory tree
rem Antonio Perez Ayala

rem Usage examples of SelectFileOrFolder subroutine:

call :SelectFileOrFolder file=
echo/
echo Selected file from *.* = "%file%"
pause

call :SelectFileOrFolder file=*.bat
echo/
echo Selected Batch file = "%file%"
pause

call :SelectFileOrFolder folder=/F
echo/
echo Selected folder = "%folder%"
pause

goto :EOF


:SelectFileOrFolder resultVar [ "list of wildcards" | /F ]

setlocal EnableDelayedExpansion

rem Process parameters
set "files=*.*"
if "%~2" neq "" (
   if /I "%~2" equ "/F" (set "files=") else set "files=%~2"
)

rem Set the number of lines per page, max 34
set "pageSize=30"
set "char=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

rem Load current directory contents
set "name[1]=<DIR>  .."
:ProcessThisDir
set "numNames=1"
for /D %%a in (*) do (
   set /A numNames+=1
   set "name[!numNames!]=<DIR>  %%a"
)
for %%a in (%files%) do (
   set /A numNames+=1
   set "name[!numNames!]=       %%a"
)
set /A numPages=(numNames-1)/pageSize+1

rem Show directory contents, one page at a time
set start=1
:ShowPage
set /A page=(start-1)/pageSize+1, end=start+pageSize-1
if %end% gtr %numNames% set end=%numNames%
cls
echo Page %page%/%numPages% of %CD%
echo/
if %start% equ 1 (set base=0) else set "base=1"
set /A lastOpt=pageSize+base, j=base
for /L %%i in (%start%,1,%end%) do (
   for %%j in (!j!) do echo     !char:~%%j,1! -  !name[%%i]!
   set /A j+=1
)
echo/

rem Assemble the get option message
if %start% equ 1 (set "mssg=: ") else (set "mssg= (0=Previous page")
if %end% lss %numNames% (
   if "%mssg%" equ ": " (set "mssg= (") else set "mssg=%mssg%, "
   set "mssg=!mssg!Z=Next page"
)
if "%mssg%" neq ": " set "mssg=%mssg%): "

:GetOption
choice /C "%char%" /N /M "Select desired item%mssg%"
if %errorlevel% equ 1 (
   rem "0": Previous page or Parent directory
   if %start% gtr 1 (
      set /A start-=pageSize
      goto ShowPage
   ) else (
      cd ..
      goto ProcessThisDir
   )
)
if %errorlevel% equ 36 (
   rem "Z": Next page, if any
   if %end% lss %numNames% (
      set /A start+=pageSize
      goto ShowPage
   ) else (
      goto GetOption
   )
)
if %errorlevel% gtr %lastOpt% goto GetOption
set /A option=start+%errorlevel%-1-base
if %option% gtr %numNames% goto GetOption
if defined files (
   if "!name[%option%]:~0,5!" neq "<DIR>" goto endSelect
) else (
   choice /C OS /M "Open or Select '!name[%option%]:~7!' folder"
   if errorlevel 2 goto endSelect
)
cd "!name[%option%]:~7!"
goto ProcessThisDir

:endSelect
rem Return selected file/folder
for %%a in ("!name[%option%]:~7!") do set "result=%%~Fa"
endlocal & set "%~1=%result%
exit /B

Ответ 5

Еще два способа.

1.Используя гибридный .bat/hta (должен быть сохранен как bat) script. Он может использовать vbscript или javascript, но пример с javascrtipt. Не создает временные файлы. Выбор папки не так легко и потребует внешних библиотек javascript, но выбор файла прост

<!-- : starting html comment

:: FileSelector.bat
@echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
    set "file=%%~fp"
)
echo/
if not "%file%" == "" (
    echo selected  file is : %file%
)
echo/
exit /b
-->
<Title>== FILE SELECTOR==</Title>
<body>
    <script language='javascript'>
    function pipeFile() {

         var file=document.getElementById('file').value;
         var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
         close(fso.Write(file));

    }
    </script>
<input type='file' name='file' size='30'>
</input><hr><button onclick='pipeFile()'>Submit</button>
</body>

1.1 - без формы отправки, предложенной rojo (см. комментарии):

<!-- : starting html comment

:: FileSelector.bat
@echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
    set "file=%%~fp"
)
echo/
if not "%file%" == "" (
    echo selected  file is : "%file%"
)
echo/
exit /b
-->
<Title>== FILE SELECTOR==</Title>
<body>
    <script language='javascript'>
    function pipeFile() {

         var file=document.getElementById('file').value;
         var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
         close(fso.Write(file));

    }
    </script>
<input id='file' type='file' name='file' size='30' onchange='pipeFile()' >
</input>
<hr>
<button onclick='pipeFile()'>Submit</button>
<script>document.getElementById('file').click();</script>
</body>

2. Когда вы уже используете powershell/net, вы можете создать самокомпилированный jscript.net hybrid.It не потребуется файл temp cs для компиляции и будет напрямую использовать встроенный компилятор jscrript.net. Нет необходимости в powershell и код гораздо читабельнее:

@if (@X)==(@Y) @end /* JScript comment
@echo off

:: FolderSelectorJS.bat
setlocal

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

for /f "tokens=* delims=" %%p in ('"%~n0.exe"') do (
    set "folder=%%p"
)
if not "%folder%" == "" ( 
    echo selected folder  is %folder%
)

endlocal & exit /b %errorlevel%

*/

import System;
import System.Windows.Forms;

var  f=new FolderBrowserDialog();
f.SelectedPath=System.Environment.CurrentDirectory;
f.Description="Please choose a folder.";
f.ShowNewFolderButton=true;
if( f.ShowDialog() == DialogResult.OK ){
    Console.Write(f.SelectedPath);
}

Ответ 6

Решение пакетного решения PowerShell + С#

Это то же самое решение, что и Batch + PowerShell hybrid, но с резервным материалом С#, добавленным для совместимости с XP и Vista. В xNightmare67x запрос добавлен несколько файлов.

<# : chooser_XP_Vista.bat
:: // launches a File... Open sort of file chooser and outputs choice(s) to the console
:: // https://stackoverflow.com/a/36156326/1683264

@echo off
setlocal enabledelayedexpansion

rem // Does powershell.exe exist within %PATH%?

for %%I in ("powershell.exe") do if "%%~$PATH:I" neq "" (
    set chooser=powershell -noprofile "iex (${%~f0} | out-string)"
) else (

    rem // If not, compose and link C# application to open file browser dialog

    set "chooser=%temp%\chooser.exe"

    >"%temp%\c.cs" (
        echo using System;
        echo using System.Windows.Forms;
        echo class dummy {
        echo    public static void Main^(^) {
        echo        OpenFileDialog f = new OpenFileDialog^(^);
        echo        f.InitialDirectory = Environment.CurrentDirectory;
        echo        f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
        echo        f.ShowHelp = true;
        echo        f.Multiselect = true;
        echo        f.ShowDialog^(^);
        echo        foreach ^(String filename in f.FileNames^) {
        echo            Console.WriteLine^(filename^);
        echo        }
        echo    }
        echo }
    )
    for /f "delims=" %%I in ('dir /b /s "%windir%\microsoft.net\*csc.exe"') do (
        if not exist "!chooser!" "%%I" /nologo /out:"!chooser!" "%temp%\c.cs" 2>NUL
    )
    del "%temp%\c.cs"
    if not exist "!chooser!" (
        echo Error: Please install .NET 2.0 or newer, or install PowerShell.
        goto :EOF
    )
)

rem // Do something with the chosen file(s)
for /f "delims=" %%I in ('%chooser%') do (
    echo You chose %%~I
)

rem // comment this out to keep chooser.exe in %temp% for faster subsequent runs
del "%temp%\chooser.exe" >NUL 2>NUL

goto :EOF
:: // end Batch portion / begin PowerShell hybrid chimera #>

Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }

Для выбора папок для XP или Vista используйте либо решение WSH, либо npocmaka HTA solution.