Last active
January 14, 2024 05:43
-
-
Save IMJLA/1d570aa2bb5c30215c222e7a5e5078fd to your computer and use it in GitHub Desktop.
A folder browser dialog with an address bar in native PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$AssemblyFullName = 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' | |
$Assembly = [System.Reflection.Assembly]::Load($AssemblyFullName) | |
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog | |
$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 |
Thanks for posting! Found a few issues:
- $Result is 0 when I press OK, so
if ($Result -eq [System.Windows.Forms.DialogResult]::OK)
never equals true, so line 25 never runs - $AdviseResult is set but never used in line 20
- It fails at line 13 in PowerShell 7 as
$OpenFileDialogType.GetMethod('OnBeforeVistaDialog',@('NonPublic','Public','Static','Instance'))
returns null, which generates an error when trying to call .Invoke() on it.
Due to the PS7 issue I am using the Show-FolderDialog cmdlet from the PSShowFunctions module instead for now, which looks identical when presented.
@DanGough thank you!
Interesting, I can't reproduce $Result being 0 on my Windows 10 machine but I suspect we have an environment difference; I certainly didn't do thorough testing. (also why PS7 doesn't work, thank you for posting a modern alternative)
I did need to invoke the Advise method, although I'm pretty sure I could have dumped $AdviseResult to $null instead since it is unused, and that would make PSScriptAnalyzer happy.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@FVZGmbH for now this is all I've got on that https://gist.github.com/IMJLA/1d570aa2bb5c30215c222e7a5e5078fd?permalink_comment_id=3251927#gistcomment-3251927
But if you find a better solution let us know! It might be possible to solve this if your other dialogs are behaving properly.