I was building a script for my manager the other day and inside the script, he wanted us to triple check the naming of a file path. He went as far as to have us copy the file path from the browser. Paste it, Then click rename on the file itself and copy that and paste it. It was extremely time-consuming and micromanagement. I finally got tired of it as it was about 5 file paths. Using the 80/20 rule, I made a function for this within the script that opened the file dialog box and allowed the user to select the file and have it programmatically push the names into the Variable.

The Script

function Get-SHDOpenFileDialog {
    [cmdletbinding()]
    param (
        [string]$InitialDirectory = "$Env:USERPROFILE",
        [string]$Title = "Please Select A file",
        [string]$Filter = "All files (*.*)| *.*",
        [switch]$MultiSelect
    )
    Add-Type -AssemblyName System.Windows.Forms
    $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog 
    $FileBrowser.InitialDirectory = "$InitialDirectory"
    $FileBrowser.Filter = "$Filter"
    $FileBrowser.Title = "$Title"
    if ($MultiSelect) {
        $FileBrowser.Multiselect = $true
    } else {
        $FileBrowser.Multiselect = $false
    }

    $FileBrowser.ShowDialog((New-Object System.Windows.Forms.Form -Property @{TopMost = $true })) | Out-Null
    $FileBrowser.Filenames
    $FileBrowser.dispose()
}

The Breakdown

Let us break down this script and explain it a little better. Our parameters are as the following:

  • InitialDirectory [string]- This is the directory we will open the Open Dialog in. By default we use the user’s profile.
  • Title [string]- This will be the title on the Open Dialog box. We have this because when you execute the function mutiple times in a single script, this can give some direction.
  • Filter [string]- This is the filter that you will sort by. We have it defaulting to all files with all extensions. If you want to guide the user even more, you can change the filter to something like “XML Files (*.xml)| *.xml” for xml files.
  • Multiselect [switch]- This determines if you want to limit the system to a single file select, which is default or allow mulitple select. This way if you want to select 5 files at once, you can. This is more for the advanced user. If you want to guide the user, then don’t flip this switch.

Now we have our parameters, it’s time to build our assembly. We do this by adding the add-type command. We are loading the Forms assembly.

Add-Type -AssemblyName System.Windows.Forms

Now we have loaded the assembly, we need to create the dialog box. To do this we will create a new-object. System > Windows > Forms > OpenFileDialog. From there we build out the properties.

$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog 

Now the object is created, we need to add the properties. The first three properties we are filling are from our parameters. The InitialDirectory, Filter, and Title.

$FileBrowser.InitialDirectory = $InitialDirectory
$FileBrowser.Filter = $Filter
$FileBrowser.Title = "$Title"

Then we ask if the MultiSelect flag is checked. If it is we set the property to true, if not, we set it to false.

if ($MultiSelect) {
    $FileBrowser.Multiselect = $true
} else {
    $FileBrowser.Multiselect = $false
}

Next, we need to show the dialog box. One thing I ran into was the dialog box would open behind my VS code. In VB.net we set forms to TopMost. I tried a few variations of this with the open file dialog box, but this dialog box doesn’t have the TopMost property. So, what we do is open a form inside the form to force the form to the front. The System > Windows > Forms > Form has the TopMost property. So, inside the showdialog method, we plop the new-object into it.

$FileBrowser.ShowDialog((New-Object System.Windows.Forms.Form -Property @{TopMost = $true }))

However, there is catch! This command outputs the button you click. So if you click cancel, you get a cancel as output, if you click a file and click ok, you get an OK and the file name as the next part of the array it produces. The way to resolve this is pipping the command into an out-null.

$FileBrowser.ShowDialog((New-Object System.Windows.Forms.Form -Property @{TopMost = $true })) | Out-Null

Now we have selected the file/files, we need to display them. The data is stored in the filenames property. So we use the $FileBrowser.Filenames to display that information.

$FileBrowser.Filenames

Finally, we need to dispose of the open file dialog. This way we don’t have hundreds of invisible forms clogging up our system.

$FileBrowser.dispose()

I hope that makes since. Here are some Examples

Examples

PS C:\> Get-SHDOpenFileDialog -Title "Select the required files" -MultiSelect -InitialDirectory c:\temp  

The Output:

C:\temp\tempshow.csv
C:\temp\Moo.txt

Example with Filter

PS C:\> Get-SHDOpenFileDialog -Title "Select the CSV file" -MultiSelect -InitialDirectory c:\temp -Filter "CSV Files (*.csv)| *.csv"

The Output:

C:\temp\tempshow.csv
C:\temp\ACC_Active.csv