Powershell: Ordner mit Filechooser auswählen

Sempervivum

Erfahrenes Mitglied
In einem größerem Skript brauche ich einen Dialog, um ein Verzeichnis auszuwählen. Mit dem Folderchooser war das kein großes Problem. Ich mag jedoch diesen Dialog nicht und würde lieber den Filechooser verwenden. Dafür habe ich bei Github ein Skript gefunden:
A folder browser dialog with an address bar in native PowerShell
Für sich allein funktioniert dieses einwandfrei. Ich hatte jedoch Probleme, es mit meinem bisherigen Skript zusammenzubringen. Mit viel Bastelei habe ich dann dieses zum Laufen gebracht:
Code:
# Filechooser vorbereiten, dies ist von Github uebernommen
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$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)
$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
$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]
# Ende von Github uebernommen

# So habe ich es bisher gemacht:
$objForm = New-Object System.Windows.Forms.Form
[System.Windows.Forms.Application]::EnableVisualStyles()
$objForm.Size = New-Object System.Drawing.Size(800, 500)
$folderChooseBtn = New-Object System.Windows.Forms.Button
$folderChooseBtn.Location = New-Object System.Drawing.Size($x, $y)
$folderChooseBtn.Size = New-Object System.Drawing.Size(100, 20)
$folderChooseBtn.Text = "Ordner wählen"
$folderChooseBtn.Name = "Ordnerwahl"
$folderChooseBtn.Add_Click( {
        # Oeffnen des Filechoosers, von Github uebernommen
        $Result = $FileDialogInterfaceType.GetMethod('Show', @('NonPublic', 'Public', 'Static', 'Instance')).Invoke($IFileDialog, [System.IntPtr]::Zero)
        $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-Host $OpenFileDialog.FileName
        # Ende von Github uebenommen
    })
$objForm.Controls.Add($folderChooseBtn)
[void] $objForm.ShowDialog()
Read-Host -Prompt "Press Enter to exit"
Ich habe das dumpfe Gefühl, dass die Art und Weise, wie ich beides vermengt habe, nicht so optimal ist und bitte um Durchsicht und Verbesserungsvorschläge.
 
Zuletzt bearbeitet:
OK, hier ein anderer Versuch: Ich hatte versucht, den originalen Filechooser in das Muster, das ich bisher verwendet hatte, einzubauen. Das war soweit kein Problem, aber ich habe nicht heraus gefunden, wie man ihn dazu bringt, beim Klick auf "Öffnen" nicht in das Verzeichnis hineinzugehen, sondern das Ergebnis bzw. die Eigenschaft "FileName" auf das Verzeichnis zu setzen und sich zu schließen.
Der Code von Github schafft das irgend wie, aber ich kann nicht heraus lesen, wie ich es auf mein Muster übertragen kann.

Code:
# Formular vorbereiten, funktioniert soweit
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
[System.Windows.Forms.Application]::EnableVisualStyles()
$objForm.Size = New-Object System.Drawing.Size(800, 500)

# OpenFileDialog vorbereiten
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
$FileBrowser.InitialDirectory = 'd:\temp\_Fotos\_Olympus'
$FileBrowser.Filter = "Folders|`n"
# Bis hierher funktioniert es: Der Dialog zeigt nur die Ordner an.
# Was nicht funktioniert: Klick auf "Oeffnen" öffnet das betr. Verzeichnis.
# Was ich brauche ist, dass statt dessen die Eigenschaft "FileName"
# auf das ausgewaehlte Verzeichnis gesetzt wird und der Dialog geschlossen,
# so wie bei dem Code von Github.

# Button, um den Dialog zu oeffnen, funktioniert
$folderChooseBtn = New-Object System.Windows.Forms.Button
$folderChooseBtn.Location = New-Object System.Drawing.Size(20, 20)
$folderChooseBtn.Size = New-Object System.Drawing.Size(100, 20)
$folderChooseBtn.Text = "Ordner wählen"
$folderChooseBtn.Name = "Ordnerwahl"
$folderChooseBtn.Add_Click( {
        # Filebrowser oeffnen, funktioniert
        $FileBrowser.ShowDialog()
        Write-Host 'path' $FileBrowser.FileName
    })
$objForm.Controls.Add($folderChooseBtn)

[void] $objForm.ShowDialog()

Read-Host -Prompt "Press Enter to exit"
 
Nein, leider die danach, die eben nicht mehr sichtbar ist. Okay, ich wiederhole sie kurz aus dem Gedächtnis:

Den folgenden Code, der in deinem von GitHub übernommenen Code drinsteckt, aber nicht in deinem, ist wohl ausschlaggebend dafür, dass dein Code nur Dateien auswählen lässt:
Code:
$OpenFileDialogType = $OpenFileDialog.GetType()
$FileDialogInterfaceType = $Assembly.GetType('System.Windows.Forms.FileDialogNative+IFileDialog')
$IFileDialog = $OpenFileDialogType.GetMethod('CreateVistaDialog', @('NonPublic', 'Public', 'Static', 'Instance')).Invoke($OpenFileDialog, $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
$FileDialogInterfaceType.GetMethod('SetOptions', @('NonPublic', 'Public', 'Static', 'Instance')).Invoke($IFileDialog, $FolderOptions)

Du siehst, wie $PickFoldersOption das Flag `FOS_PICKFOLDERS` repräsentiert, danach die Default-Optionen des Dialogs via `get_Options` gequeried werden und mit `FOS_PICKFOLDERS` gemerged (geor'ed) werden.
 
Zurück