# Powershell: Ordner mit Filechooser auswählen



## Sempervivum (13. Oktober 2019)

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:

```
# 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.


----------



## Sempervivum (15. Oktober 2019)

Keine Powershell-Experten hier? Ich versuche es mal dort:
Powershell: Ordner mit Filechooser auswählen


----------



## ComFreek (15. Oktober 2019)

Dass keiner antwortet, liegt vielleicht daran, dass dein Skript eine "wall of code" ist. Dinge in Funktionen auszulagern mit API-Docs und ein paar Newlines würden deinem Skript ganz gut tun 

Außerdem: give credit where credit is due, ich würde auf A folder browser dialog with an address bar in native PowerShell verlinken.


----------



## Sempervivum (15. Oktober 2019)

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.


```
# 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"
```


----------



## ComFreek (17. Oktober 2019)

@Sempervivum Hattest du meine Nachricht gelesen, die durch den Hardwareausfall des Forums leider verloren gegangen ist?


----------



## Sempervivum (18. Oktober 2019)

Du meinst die #3 vom Dienstag? Ja, die habe ich gelesen.


----------



## ComFreek (19. Oktober 2019)

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:

```
$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.


----------

