File / folder chooser dialog from a Windows batch script

72,187

Solution 1

File Browser

Update 2016.3.20:

Since PowerShell is a native component of pretty much all modern Windows installations nowadays, I'm declaring the C# fallback as no longer necessary. If you still need it for Vista or XP compatibility, I moved it to a new answer. Starting with this edit, I'm rewriting the script as a Batch + PowerShell hybrid and incorporating the ability to perform multi-select. It's profoundly easier to read and to tweak as needed.

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

This results in a file chooser dialog.

file chooser

The result of a selection outputs You chose C:\Users\me\Desktop\tmp.txt to the console. If you want to force single file selection, just change the $f.Multiselect property to $false.

(PowerShell command mercilessly leeched from the Just Tinkering Blog.) See the OpenFileDialog Class documentation for other properties you can set, such as Title and InitialDirectory.


Folder Browser

Update 2015.08.10:

Since there is already a COM method for invoking a folder chooser, it's pretty easy to build a PowerShell one-liner that can open the folder chooser and output the path.

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

In the BrowseForFolder() method, the fourth argument specifies the root of the hierarchy. See ShellSpecialFolderConstants for a list of valid values.

This results in a folder chooser dialog.

enter image description here

The result of a selection outputs You chose C:\Users\me\Desktop to the console.

See the FolderBrowserDialog class documentation for other properties you can set, such as RootFolder. My original .NET System.Windows.Forms PowerShell and C# solutions can be found in revision 4 of this answer if needed, but this COM method is much easier to read and maintain.

Solution 2

This should work from XP upwards and does'nt require an hibrid file, it just runs mshta with a long command line:

@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

Solution 3

Windows Script Host


File Selection

Windows XP had a mysterious UserAccounts.CommonDialog WSH object which allowed VBScript and JScript to launch the file selection prompt. Apparently, that was deemed a security risk and removed in Vista.


Folder Selection

However, the WSH Shell.Application object BrowseForFolder method will still allow the creation of a folder selection dialog. Here's a hybrid batch + JScript example. Save it with a .bat extension.

@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 : '');

folder selection dialog

In the BrowseForFolder() method, the fourth argument specifies the root of the hierarchy. See ShellSpecialFolderConstants for a list of valid values.

Solution 4

Other solution with direct run PowerShell command in Batch

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%

Solution 5

A file / folder selection may be done with pure Batch, as shown below. Of course, the feel and look is not as pleasant as a GUI, but it works very well and in my opinion it is easier to use than the GUI version. The selection method is based on CHOICE command, so it would require to download it in the Windows versions that don't include it and slightly modify its parameters. Of course, the code may be easily modified in order to use SET /P instead of CHOICE, but this change would eliminate the very simple and fast selection method that only requires one keypress to navigate and select.

@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
Share:
72,187

Related videos on Youtube

rojo
Author by

rojo

The trickster, the riddler, the keeper of the balance, he of the many faces who finds life in death and who fears no evil; he who walks through doors.

Updated on July 09, 2022

Comments

  • rojo
    rojo almost 2 years

    Typically, asking the user to supply a file name to a batch script is a messy affair, requiring no misspellings, quotes around paths with spaces, and so forth. Unfortunately, users aren't well-known for accuracy. In situations where input file location is not known until runtime, using a GUI for file selection input reduces the likelihood of user error.

    Is there a way to invoke a File... Open style gui file chooser or folder chooser from a Windows batch script?

    If the script user has PowerShell or .NET installed, it is possible. See the answer below.

    I'm also interested to see what other solutions anyone else can offer.

  • rojo
    rojo over 9 years
    Suggestions for your HTA hybrid: add id='file' to the <input> tag, add onchange='pipeFile()' to the <input> tag, and add <script>document.getElementById('file').click();</script> just above </body>.
  • vir us
    vir us almost 9 years
    Thanks a lot for the code! Works just great! One question though. Is there a way to pick multiple files with this method? I've added property f.Multiselect=true and was able to pick multiple files via GUI however it looks like it prints only the first selected file so I can't figure out a way to read all the selected files from the dialog. Do you think it's possible? Or maybe there is another way do pick multiple files with win GUI?
  • vir us
    vir us almost 9 years
    I feel stupid now :) I had to be a little bit more attentive to the code. So just added foreach(String fileName in f.FileNames^) before Console.Write line to iterate through f.FileNames array to print all the necessary values. Thanks for the code! BTW: printing FileNames array values works for single select mode dialog as well and could be accepted as more generic way to deal with the dialog. Thanks again!
  • Admin
    Admin about 8 years
    Really old post but I hope can you show me how you made it pick multiple files. i wish to accomplish the same thing thanks.
  • Admin
    Admin about 8 years
    Thanks highly appreciated working perfectly on windows 7 - 10. the script does not work for windows XP & Vista and I know this is due to it not including powershell. I was wondering if you can alter C# fallback to accomplish your new powershell edit. I tried editing it and it works good multiple select and all but i got stuck at the for loop it echos only 1 file.
  • rojo
    rojo about 8 years
    @xNightmare67x Instead of doing for /f... do set do for /f... do echo. Since mainstream support for Vista was dropped in 2012 and (at this moment) only about 1⅔% of web-browsing machines are Vista, I'm not particularly inclined to restore the C# failover code to this answer. I added it as a new answer for you, though.
  • Admin
    Admin about 8 years
    @rojo I can't thank you enough for your time and how helpful you have been. it's been working great these past days. saved so much time. tonight while I was feeding it more files it outputted with a missing character so I did a dummy file pinpointed it to the exclamation mark !. is there anyway around this?
  • rojo
    rojo about 8 years
    @xNightmare67x Disable delayed expansion before the activating the chooser.
  • Admin
    Admin about 8 years
    That solved the issue.sorry for bothering you so many times. :)
  • Antoni Gual Via
    Antoni Gual Via over 6 years
    Notice it opens a regular Explorer File Slector dialog. The title of the dialog can't be changed with this method.
  • Xlam
    Xlam almost 6 years
    I want to run a command when the user clicks on the cancel button on the folder chooser dialog box. How do I do it?
  • rojo
    rojo almost 6 years
    @Xiam You could replace echo You chose %%~I with something like set "choice=%%~I" and then if not defined choice ( command ) or similar. If you can't figure it out, create a new question post and show what you've tried that doesn't work, and explain the errors you get or how the script behaves differently from what you expect.
  • Mark Deven
    Mark Deven over 5 years
    Hey does anyone know how I can modify this to have the all files option as well as any image type option? (e.g. .jpg, .png, .bmp)?
  • rojo
    rojo over 5 years
    @MarkDeven You can use multiple file mask patterns in a single option by separating the file masks with semicolons. Example: $f.Filter = "Image Files (*.jpg, *.png, *.gif, *.bmp, *.tif)|*.jpg;*.jpeg;*.png;*.gif;*.bmp;*.tif|All Files (*.*)|*.*" See the remarks section of FileDialog.Filter Property for full details.
  • Dorian Grv
    Dorian Grv almost 5 years
    Is it possible to have this with a multiple selection ?
  • Dorian Grv
    Dorian Grv almost 5 years
    Is it possible to have this with multiple selection ?
  • Dorian Grv
    Dorian Grv almost 5 years
    Found it with powershell: stackoverflow.com/questions/52240766/…
  • Dorian Grv
    Dorian Grv almost 5 years
  • Joel Coehoorn
    Joel Coehoorn over 4 years
    What about WinPE?
  • Ders
    Ders over 4 years
    My antivirus thinks this is a trojan :)
  • aerodavo
    aerodavo almost 4 years
    can this be adjusted to allow navigating to external hard drives?
  • CptDayDreamer
    CptDayDreamer over 3 years
    This does not work if a folder has whitespace like Alpha Tauri or something. How to do it then?
  • 9pfs supports Ukraine
    9pfs supports Ukraine about 3 years
    What would a folder selector be?
  • Felicity
    Felicity over 2 years
    Although I suggest to have: 1) exit /B before :sum and 2) have goto :eof at the end of :sum. Or else :sum runs twice
  • Felicity
    Felicity over 2 years
    To change directory, just add cd statement somewhere in the beginning of this file. You can pass an variable to this bat file that contains a path. And then in the beginning of this bat file, add an if else statement like: if "%~1" neq "" cd "%~1"
  • Felicity
    Felicity over 2 years
    or this if "%~1" neq "" if exist "%~1\*" (cd "%~1") to check and make sure that path exists before you cd it