Diálogo Seletor de Arquivos / Pastas de um Script em Lote do Windows

Normalmente, pedir ao usuário que forneça um nome de arquivo a um script em lote é um assunto confuso, não exigindo erros ortocharts, citações de caminhos com espaços e assim por diante. Infelizmente, os usuários não são conhecidos pela precisão. Em situações em que a localização do arquivo de input não é conhecida até o tempo de execução, o uso de uma GUI para input de seleção de arquivo reduz a probabilidade de erro do usuário.

Existe uma maneira de invocar um File... Open o seletor de arquivo GUI estilo ou seletor de pasta de um script em lotes do Windows?

Se o usuário do script tiver o PowerShell ou o .NET instalado, isso é possível. Veja a resposta abaixo.

Também estou interessado em ver que outras soluções podem oferecer a qualquer outra pessoa.

   

Navegador de arquivos

Atualização de 2016.3.20:

Como o PowerShell é um componente nativo de praticamente todas as instalações modernas do Windows atualmente, estou declarando que o fallback C # não é mais necessário. Se você ainda precisar dele para compatibilidade com o Vista ou XP, mudei para uma nova resposta . Começando com essa edição, estou reescrevendo o script como um híbrido Batch + PowerShell e incorporando a capacidade de executar várias seleções. É muito mais fácil ler e ajustar conforme necessário.

 < # : 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 } 

Isso resulta em um diálogo de seleção de arquivos.

selecionador de arquivos

O resultado de uma seleção de saídas You chose C:\Users\me\Desktop\tmp.txt para o console. Se você quiser forçar a seleção de arquivo único, basta alterar a propriedade $f.Multiselect para $false .

(Comando PowerShell impiedosamente leeched do Blog Just Tinkering .) Consulte a documentação da class OpenFileDialog para outras propriedades que você pode definir, como Title e InitialDirectory .


Navegador de pastas

Atualização 2015.08.10:

Como já existe um método COM para chamar um seletor de pastas , é muito fácil criar um One-liner do PowerShell que possa abrir o seletor de pastas e gerar o caminho.

 :: 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 

No método BrowseForFolder() , o quarto argumento especifica a raiz da hierarquia. Veja ShellSpecialFolderConstants para obter uma lista de valores válidos.

Isso resulta em uma checkbox de diálogo de seleção de pastas.

insira a descrição da imagem aqui

O resultado de uma seleção de saídas You chose C:\Users\me\Desktop para o console.

Consulte a documentação da class FolderBrowserDialog para outras propriedades que você pode definir, como RootFolder . Minhas soluções .NET System.Windows.Forms PowerShell e C # originais podem ser encontradas na revisão 4 desta resposta, se necessário, mas esse método COM é muito mais fácil de ler e manter.

Host de scripts do Windows


Seleção de Arquivo

O Windows XP tinha um misterioso object WSH UserAccounts.CommonDialog que permitia que o VBScript e o JScript iniciassem o prompt de seleção de arquivos. Aparentemente, isso foi considerado um risco de segurança e removido no Vista.


Seleção de pasta

No entanto, o método WSH Shell.Application Object BrowseForFolder ainda permitirá a criação de uma checkbox de diálogo de seleção de pasta. Aqui está um exemplo de lote híbrido + JScript. Salve-o com uma extensão .bat .

 @if (@a==@b) @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 : ''); 

caixa de diálogo de seleção de pastas

No método BrowseForFolder() , o quarto argumento especifica a raiz da hierarquia. Veja ShellSpecialFolderConstants para obter uma lista de valores válidos.

Isso deve funcionar do XP para cima e não requer um arquivo híbrido, ele apenas executa o mshta com uma longa linha de comando:

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

Uma seleção de arquivos / pastas pode ser feita com o Batch puro, como mostrado abaixo. É claro que a sensação e a aparência não são tão agradáveis ​​quanto uma GUI, mas funciona muito bem e, na minha opinião, é mais fácil de usar do que a versão da GUI. O método de seleção é baseado no comando CHOICE, portanto, seria necessário baixá-lo nas versões do Windows que não o incluam e modifiquem um pouco seus parâmetros. É claro que o código pode ser facilmente modificado para usar SET / P em vez de CHOICE, mas essa mudança eliminaria o método de seleção muito simples e rápido que requer apenas um pressionamento de tecla para navegar e selecionar.

 @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]= .." :ProcessThisDir set "numNames=1" for /D %%a in (*) do ( set /A numNames+=1 set "name[!numNames!]= %%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 "" 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 

Mais duas maneiras.

1.Usando um script híbrido .bat / hta (deve ser salvo como um bat ) .Pode usar vbscript ou javascript, mas o exemplo é com javascrtipt.Não criar arquivos temporários.Selecionar pasta não é tão fácil e vai exigir um javascript externo bibliotecas, mas a seleção de arquivos é fácil

  == FILE SELECTOR==    

1.1 – sem apresentar formulário proposto por rojo (ver comentários):

  == FILE SELECTOR==     

2. Como você já usa powershell / net você pode criar híbrido jscript.net selfcompiled.Ele não exigirá arquivo cs temp para compilation e vai usar diretamente o compilador jscrript.net built-in.Não há necessidade de powershell também eo código é muito mais legível:

 @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); } 

Solução poligota Batch + PowerShell + C #

Esta é a mesma solução que o híbrido Batch + PowerShell , mas com o material de fallback C # adicionado novamente para compatibilidade com XP e Vista. Múltipla seleção de arquivos foi adicionada a pedido do 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 } 

Para um seletor de pastas para XP ou Vista, use a solução WSH ou a solução HTA do npocmaka .

Outra solução com o comando PowerShell de execução direta no Lote

 rem preparation command set pwshcmd=powershell -noprofile -command "&{[System.Reflection.Assembly]::LoadWithPartialName('System.windows.forms') | Out-Null;$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog; $OpenFileDialog.ShowDialog()|out-null; $OpenFileDialog.FileName}" rem exec commands powershell and get result in FileName variable for /f "delims=" %%I in ('%pwshcmd%') do set "FileName=%%I" echo %FileName%