ERCC (http://eriedel.info)

Dialogs for Folder and File Selections


In this article, I present ways to use Windows scripts to display a dialog for selecting folders or files. In addition to the application in VBScript, coding in HTML/HTA and PowerShell is demonstrated. The scripts presented are included in a zip file for this article.

Preliminary Remark

Before I discuss the display of a selection dialog, I would like to briefly point out the possibility of "outsourcing" this selection, so to speak. If you prepare a script so that it is started from Windows Explorer and takes over its file or folder selection, you can avoid having your own dialog display.
Of course, this assumes that the script's task is file-related from the outset and can be defined as an Explorer option. (The FolderCopy scripts are an example of this.) However, the script then has no control over the selection in advance, so it cannot, for instance, specify a folder or a file type.

A downside of this method is that it's left to the user to move or copy the selection to the script file, starting it hereby. This may be perceived as impractical or not very intuitive. 1   The Explorer context menu usually doesn't offer an easy to use option —unless you put in some preparatory work in setting up a "Send to" option (see the article Extending the Explorer context menu).
Therefore, it is usually best (or unavoidable) to make the selection through the script itself.

Dialog for a Folder Selection

The folder selection is usually intended to determine a single folder, which then serves as a working directory, for example to save data there. There is a shell dialog for this task that scripts can use in a simple way: BrowseForFolder.

The API function has a number of parameters and also allows the selection of various objects such as printers or shortcuts. If you limit the application to directories in the file system, the options are manageable. The most important are:

The start folder can be specified by a string or a special numerical value. As a rule, you will either want to preset a specific directory (e.g. "C:\Workdir"), or set the selection to the drive level (ssfDRIVES), although, depending on the Windows version, some special folders may also be included.
In the simplest case, the value for the option flags (iOptions) can be the combination of BIF_RETURNONLYFSDIRS (1) + BIF_NONEWFOLDERBUTTON (512).

vRootFolder = 17    ' ssfDRIVES
sTitle = ""
iOptions = 513
Set obj = CreateObject("Shell.Application")
Set obj = obj.BrowseForFolder(0, sTitle, iOptions, vRootFolder)

After the selection is made, the function returns a folder, not as a string but as a folder object. This shell folder is not identical to the object of the same name in the scripting component FileSystemObject (FSO). If the dialog is canceled, we do not get an object, otherwise the path can then be determined via a small detour.

If obj Is Nothing Then WScript.Quit     '  or error handling
Set obj = obj.Self
folder = obj.Path
WScript.Echo folder

The code shown is contained in the browseforfolder.vbs script. (A similar script with some explanatory comments —folderselection.vbs— can also be found in the VTool examples, which you can download as a separate zip file.)

File Selection Dialog

Apparently it was possible in the past to select files using the BrowseForFolder dialog. However, later and current versions of Windows no longer support this option. Unfortunately, Windows does not contain any other dialog for this purpose that would be suitable for WSH scripts. The standard file selection dialogs are accessible for WSH scripts only with additional COM support. (I'll come back to this later, but I want to cover the other options first.)

HTA

A common solution to a scripted file selection is to run MSHTA, which is part of the Windows system programs.

sMSHTA = "mshta.exe ""about:<input type=file id=FILE>" & _
         "<script>FILE.click();new ActiveXObject('Scripting.FileSystemObject')" & _
         ".GetStandardStream(1).WriteLine(FILE.value);close();</script>"""
Set obj = CreateObject("WScript.Shell")
Set obj = obj.Exec(sMSHTA)
sFile = obj.StdOut.ReadLine()
Set obj = Nothing
WScript.Echo sFile

The parameter represents a minimal HTA (HTML Application) that opens a file selection dialog and outputs the selected file name to the console via the FSO. The WSH object WshShellExec allows reading this output (mshta-filesel.vbs).

Using MSHTA had and still has the advantage of working on practically all versions of Windows. A disadvantage of the solution shown is the limited file selection and the given window title. Unfortunately, no directory can be specified. The underlying shell dialog therefore regularly uses the folder of a previous selection.

The HTA technology also offers a way of creating complex windows with various GUI elements and supports the combination with script code. (I demonstrated displaying such a multi-option window in the article on Multiple Selection.) So, in addition to the file selection, the entire application could also be handled via an HTA. However, if the selected file name is to be passed to a script, one must consider that the standard console I/O streams are not available to the HTA file. A different approach would have to be chosen here, such as transfer using call parameters. This is demonstrated by the files hta-dlg-1.hta and hta-dlg-2.vbs: The HTA can be started directly and displays the selection dialog. The file name is then passed to the script file.

PowerShell (PS)

PowerShell, a very powerful command interpreter, was introduced in 2006 and became a standard part of Windows ever since. There are now several versions that differ in terms of functionality. The specific version depends on the Windows version, but also on optional updates. This may have the disadvantage that the availability of certain functions is not guaranteed on all systems. The solution shown here should not be affected by this.

PowerShell can use objects from the .NET Framework. Displaying a file selection dialog is implemented in System.Windows.Forms.OpenFileDialog. The corresponding instructions can be put together in a small PowerShell script (filedlg.ps1).

To make it easier to distinguish from WSH/VBS, PS code is highlighted in color below.

In general, Windows security settings prevent the execution of PS scripts. However, the setting can be changed so that local PS scripts can be executed. To do this, start PowerShell in an administrator console and enter the command

set-executionpolicy remotesigned

The current setting can be checked using the command

get-executionpolicy

Alternatively, the security restriction can be reduced or abrogated for an individual script file by a call parameter, for instance (see ps-filedlg.cmd):

powershell -executionpolicy bypass .\filedlg.ps1

A reference to the .NET dialog class must be explicitly defined in the script. In the following code, this is done by the statement in the first line. The object is then created and two of its properties are specified:

Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
$FileBrowser.InitialDirectory = [Environment]::CurrentDirectory
$FileBrowser.Title = 'Select a File'
$val = $FileBrowser.ShowDialog()

The PowerShell script can also be called by a WSH script (see ps-filedlg.vbs). And if the actual application that handles a file selection needs to be done by the WSH script, this can be accomplished via console I/O. For this purpose, the name of the selected file is output to the console. If the dialog is canceled, this is a blank line. This output can be read and checked in the WSH script.

write-host $FileBrowser.FileName

The ShowDialog method returns "OK" or "Cancel" as text. You can end the script accordingly with an exit code:

if ($val -eq 'OK') {exit 0}
else {exit 1}

This allows a command file to evaluate the exit code using %errorlevel% (see the example ps-filedlg.cmd). In a WSH script, the value can be determined using the ExitCode property.

The sample WSH script (ps-filedlg.vbs) runs the PowerShell script via WshScriptExec. For the older PowerShell version 2.0 (by default present in Windows 7 and Windows Server 2008 R2), the program must be explicitly started as an STA application, which is done using the "-Sta" parameter. Later versions may do this on their own, not being bothered about this parameter.

sCmd = "powershell -Sta -WindowStyle Hidden .\filedlg.ps1"
Set oExec = CreateObject("wscript.shell")
Set oExec = oExec.Exec(sCmd)

Starting PowerShell opens a PS console window, which is unwanted in this situation. However, its visibility can be prevented with the "-WindowStyle Hidden" parameter. (Attention: This would also cause a previously opened console window to disappear. So, if the execution is carried out via a command file or a console script, this parameter should not be used or altered to "-WindowStyle Minimized".)
The file name output in the window can be read in with a WshScriptExec method:

sLine = oExec.StdOut.ReadLine
Set oExec = Nothing
WScript.Echo "Output:" & vbNewLine & sLine

The PowerShell process continues to run beyond the closing of the dialog window and the end of the PS script as long as the WshScriptExec object exists. It therefore makes sense to dissolve this reference as soon as possible.

The dialog also allows selecting multiple files. This is demonstrated in the examples filedlg2.ps1 and ps-filedlg2.vbs.

COM Add-Ins

WSH/VBS (like PS) can access objects from existing COM modules and use their functionality. Microsoft had developed such a module in the past that supports the use of standard dialogs, including file selection ("MSComDlg.CommonDialog", comdlg32.ocx). This component was formerly installed with Visual Basic 6.0 and various programs, possibly also with some MS Office products. It is most likely not present on current systems, but Microsoft continues to make it available for download, subject to terms of use and system conditions. 2  

If installing a COM add-in is not an obstacle, I can also suggest two complementary solutions based on components I have developed.

One of these is the very easy to use VTool, which offers a number of GUI dialogs including file selection. VTool.FileSelection uses the standard Windows API dialog to open or save files. In the simplest case of selecting a single file, the following instructions are sufficient:

Set obj = CreateObject("VTool.FileSelection")
If obj.Dialog(0) Then
    MsgBox obj.Directory & obj.FileName, , "File:"
End If
Set obj = Nothing

The object is described with examples in the VTool documentation.

A different approach ist provided with DynaLib (DynaLib.Caller). DynaLib allows scripts to call DLL functions. This way you can use the Windows API. To open a file selection dialog, the API functions GetFileNameFromBrowse (Shell32.dll) and GetOpenFileName (Comdlg32.dll) are availlable.

The GetFileNameFromBrowse function is fairly easy to use, but it can only select a single file. The following example (browseforfile.vbs) shows a possible application.

Set obj = WScript.CreateObject("WScript.Shell")
pdir = obj.CurrentDirectory
cc = 512
pfile = String(cc, 0)
Set obj = CreateObject("DynaLib.Caller")
args = Array(Null, pfile, Array(cc), pdir, Null, Null, "File Selection")
n = obj.CallFunc("Shell32.dll", "GetFileNameFromBrowse", args)
If n Then
    msg = args(1)
Else
    msg = "Function cancelled or an error occurred."
End If
MsgBox msg
Set obj = Nothing

The GetOpenFileName function offers some more extensive options, but also takes a large structure as a parameter. (Unfortunately, VBScript does not support the structure data type. It must therefore be represented using a string. DynaLib contains functions that help with this.)
A sample application is included with the getopenfile.vbs and getopenfile2.vbs scripts.

Download, Usage

The script files mentioned in this article are contained in  fselection.zip. You can unzip them to any folder and use them however you like.
Please note that these files are provided without any guarantee or liability. Use at your own risk!

Links

The following list refers to Microsoft websites with further information on the script techniques and functions covered.

WSH & VBS
Windows Script Host overview
Windows Script Host
VBScript
Script Runtime

HTA
Introduction to HTML Applications (HTAs)

PowerShell, .NET Filedialog
OpenFileDialog Class
PowerShell Documentation
PowerShell Intro
PowerShell - Getting Started
PowerShell command-line parameters

API Functions
Shell.BrowseForFolder method
GetFileNameFromBrowse (Shell)
GetOpenFileName (Comdlg)
OPENFILENAME Structure


Remarks:

1 Starting a script (or any executable) with argument transfer is possible using copy & paste. To do this, the file selection is to be copied and then "pasted" on the marked script file. Dragging the selection with the mouse onto the script file (drag & drop) does the same thing, but is basically only practical if both are in the same directory.

2 Microsoft points out on the download page that the use of the two controls offered depends on a valid license and that the installation requires the presence of a previous version.
A contribution from the "Microsoft Community" describes a possible procedure for installing the individual component (comdlg32.ocx).



http://eriedel.info/en/info/fselection.html


ERCC (http://eriedel.info)  2023   © Erhard Riedel Computer Consulting (ERCC)


link to info overview