Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A folder browser dialog with an address bar in native PowerShell
$AssemblyFullName = 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
$Assembly = [System.Reflection.Assembly]::Load($AssemblyFullName)
$OpenFileDialog = [System.Windows.Forms.OpenFileDialog]::new()
$OpenFileDialog.AddExtension = $false
$OpenFileDialog.CheckFileExists = $false
$OpenFileDialog.DereferenceLinks = $true
$OpenFileDialog.Filter = "Folders|`n"
$OpenFileDialog.Multiselect = $false
$OpenFileDialog.Title = "Select folder"
$OpenFileDialogType = $OpenFileDialog.GetType()
$FileDialogInterfaceType = $Assembly.GetType('System.Windows.Forms.FileDialogNative+IFileDialog')
$IFileDialog = $OpenFileDialogType.GetMethod('CreateVistaDialog',@('NonPublic','Public','Static','Instance')).Invoke($OpenFileDialog,$null)
$null = $OpenFileDialogType.GetMethod('OnBeforeVistaDialog',@('NonPublic','Public','Static','Instance')).Invoke($OpenFileDialog,$IFileDialog)
[uint32]$PickFoldersOption = $Assembly.GetType('System.Windows.Forms.FileDialogNative+FOS').GetField('FOS_PICKFOLDERS').GetValue($null)
$FolderOptions = $OpenFileDialogType.GetMethod('get_Options',@('NonPublic','Public','Static','Instance')).Invoke($OpenFileDialog,$null) -bor $PickFoldersOption
$null = $FileDialogInterfaceType.GetMethod('SetOptions',@('NonPublic','Public','Static','Instance')).Invoke($IFileDialog,$FolderOptions)
$VistaDialogEvent = [System.Activator]::CreateInstance($AssemblyFullName,'System.Windows.Forms.FileDialog+VistaDialogEvents',$false,0,$null,$OpenFileDialog,$null,$null).Unwrap()
[uint32]$AdviceCookie = 0
$AdvisoryParameters = @($VistaDialogEvent,$AdviceCookie)
$AdviseResult = $FileDialogInterfaceType.GetMethod('Advise',@('NonPublic','Public','Static','Instance')).Invoke($IFileDialog,$AdvisoryParameters)
$AdviceCookie = $AdvisoryParameters[1]
$Result = $FileDialogInterfaceType.GetMethod('Show',@('NonPublic','Public','Static','Instance')).Invoke($IFileDialog,[System.IntPtr]::Zero)
$null = $FileDialogInterfaceType.GetMethod('Unadvise',@('NonPublic','Public','Static','Instance')).Invoke($IFileDialog,$AdviceCookie)
if ($Result -eq [System.Windows.Forms.DialogResult]::OK) {
$FileDialogInterfaceType.GetMethod('GetResult',@('NonPublic','Public','Static','Instance')).Invoke($IFileDialog,$null)
}
Write-Output $OpenFileDialog.FileName
@theM94

This comment has been minimized.

Copy link

@theM94 theM94 commented Feb 3, 2020

Add " | Out-Null" on Lines 13, 16, 23
-> Otherwise the Output, when returned through function returns an array with count of 4.

@IMJLA

This comment has been minimized.

Copy link
Owner Author

@IMJLA IMJLA commented Feb 5, 2020

You are absolutely right, thank you so much! Sorry for sending garbage downstream when you were expecting a folder path :)

All fixed now, with the caveat that I prefer $null = because Out-Null is quite a bit slower. The difference is insignificant in this case but it's habitually what I use. I'm told that Out-Null performs better and takes the lead in PS 6.0+ but obviously this script is pretty Windows-specific since it uses Windows Forms.

@theM94

This comment has been minimized.

Copy link

@theM94 theM94 commented Feb 5, 2020

You are absolutely right, thank you so much! Sorry for sending garbage downstream when you were expecting a folder path :)

All fixed now, with the caveat that I prefer $null = because Out-Null is quite a bit slower. The difference is insignificant in this case but it's habitually what I use. I'm told that Out-Null performs better and takes the lead in PS 6.0+ but obviously this script is pretty Windows-specific since it uses Windows Forms.

All good! Your Folderbrowser is exactly what I wanted and needed. At the time, the easiest fix was just to ' -join "" ' on the resulting variable that catches the output and then it would work.

But I ended up wanting to find the culprits, when I had the time to test it out.

Thanks for your efforts!

@Jasonthurston

This comment has been minimized.

Copy link

@Jasonthurston Jasonthurston commented Apr 12, 2020

It's opening behind my window, how to set "Topmost"?
I suspect this is happening b/c I have topmost set in my form that this is getting called from via a click event. I had to set the containing form to topmost b/c it was opening behind ISE.

@IMJLA

This comment has been minimized.

Copy link
Owner Author

@IMJLA IMJLA commented Apr 13, 2020

@Jasonthurston Initially my research led me to complicated workarounds like this: https://stackoverflow.com/questions/4666580/how-can-i-set-topmost-at-the-savefiledialog-using-c

I found the solution to be MUCH simpler. After your other window is loaded (you have achieved the desired behavior), just set TopMost to false so it can behave normally again. Then the folder browser dialog opens in front the way it should.

@Lakyner

This comment has been minimized.

Copy link

@Lakyner Lakyner commented Aug 29, 2020

Awesome! Thanks for sharing :) 👍

@FireQuacker

This comment has been minimized.

Copy link

@FireQuacker FireQuacker commented Sep 14, 2020

I am very new to powershell so I apologize in advanced. I have been looking all over for something like this and it has worked wonders for me, just one question, is it possible to get the folder browser to open a specific path. I am creating a batch program that uses this powershell script for obvious reasons. Is there a way that batch could change where this script opens? Preferably a UNC path? Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.