wake-up-neo.com

Datei-/Ordnerauswahldialog aus einem Windows-Stapelskript

Normalerweise ist die Aufforderung an den Benutzer, einen Dateinamen für ein Stapelskript anzugeben, eine unordentliche Angelegenheit, die keine Rechtschreibfehler, Anführungszeichen um Pfade mit Leerzeichen usw. erfordert. Leider sind die Benutzer nicht für ihre Genauigkeit bekannt. In Situationen, in denen der Speicherort der Eingabedatei erst zur Laufzeit bekannt ist, verringert die Verwendung einer GUI für die Dateiauswahleingabe die Wahrscheinlichkeit eines Benutzerfehlers.

Gibt es eine Möglichkeit, eine File... Open-Stil-GUI-Dateiauswahl oder eine Ordnerauswahl aus einem Windows-Batch-Skript aufzurufen?

Wenn auf dem Skriptbenutzer PowerShell oder .NET installiert ist, ist dies möglich. Siehe die Antwort unten.

Ich bin auch daran interessiert, welche anderen Lösungen andere anbieten können.

30
rojo

Dateibrowser

Update 2016.3.20:

Da PowerShell heutzutage in fast allen modernen Windows-Installationen eine native Komponente ist, erkläre ich den C # -Fallback als nicht mehr erforderlich. Wenn Sie es noch für die Kompatibilität mit Vista oder XP benötigen, habe ich in eine neue Antwort verschoben . Beginnend mit dieser Bearbeitung schreibe ich das Skript als Batch + PowerShell-Hybrid um und füge die Möglichkeit ein, mehrere Auswahlen durchzuführen. Es ist wesentlich einfacher zu lesen und bei Bedarf zu optimieren.

<# : chooser.bat
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
:: https://stackoverflow.com/a/15885133/1683264

@echo off
setlocal

for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
    echo You chose %%~I
)
goto :EOF

: end Batch portion / begin PowerShell hybrid chimera #>

Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }

Dies führt zu einem Dateiauswahldialog.

file chooser

Das Ergebnis einer Auswahl gibt You chose C:\Users\me\Desktop\tmp.txt an die Konsole aus. Wenn Sie eine Einzeldatei auswählen möchten, ändern Sie einfach die $f.Multiselect-Eigenschaft in $false.

(Der PowerShell-Befehl wurde gnadenlos aus der Just Tinkering Blog entfernt.) In der Dokumentation zu OpenFileDialog-Klasse finden Sie weitere Eigenschaften, die Sie festlegen können, wie Title und InitialDirectory.


Ordnerbrowser

Update 2015.08.10:

Da es bereits eine COM-Methode für Aufruf einer Ordnerauswahl gibt, ist es ziemlich einfach, einen PowerShell-Einzeiler zu erstellen, der die Ordnerauswahl öffnen und den Pfad ausgeben kann.

:: fchooser.bat
:: launches a folder chooser and outputs choice to the console
:: https://stackoverflow.com/a/15885133/1683264

@echo off
setlocal

set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please choose a folder.',0,0).self.path""

for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"

setlocal enabledelayedexpansion
echo You chose !folder!
endlocal

In der BrowseForFolder()-Methode gibt das vierte Argument den Stamm der Hierarchie an. Eine Liste der gültigen Werte finden Sie unter ShellSpecialFolderConstants .

Dies führt zu einem Ordnerauswahldialog.

enter image description here

Das Ergebnis einer Auswahl gibt You chose C:\Users\me\Desktop an die Konsole aus.

In der Dokumentation zu FolderBrowserDialog finden Sie weitere Eigenschaften, die Sie festlegen können, z. B. RootFolder. Meine ursprünglichen .NET System.Windows.Forms PowerShell- und C # -Lösungen finden Sie bei Bedarf in Version 4 dieser Antwort. Diese COM-Methode ist jedoch viel einfacher zu lesen und zu verwalten.

39
rojo

Dies sollte ab XP funktionieren und erfordert keine hibrid-Datei. Es wird nur mshta mit einer langen Befehlszeile ausgeführt:

@echo off
set dialog="about:<input type=file id=FILE><script>FILE.click();new ActiveXObject
set dialog=%dialog%('Scripting.FileSystemObject').GetStandardStream(1).WriteLine(FILE.value);
set dialog=%dialog%close();resizeTo(0,0);</script>"

for /f "tokens=* delims=" %%p in ('mshta.exe %dialog%') do set "file=%%p"
echo selected  file is : "%file%"
pause
10
Antoni Gual Via

Windows Script Host


Dateiauswahl

Windows XP hatte ein mysteriöses UserAccounts.CommonDialog WSH-Objekt das VBScript zugelassen hat und JScript, um die Dateiauswahlaufforderung zu starten. Anscheinend war das wurde als Sicherheitsrisiko eingestuft und wurde in Vista entfernt.


Ordnerauswahl

Die WSH Shell.Application-Objektmethode BrowseForFolder ermöglicht jedoch weiterhin die Erstellung eines Ordnerauswahldialogs. Hier ist ein Hybrid-Batch + JScript-Beispiel. Speichern Sie es mit einer Erweiterung .bat.

@if (@[email protected]) @end /*

:: fchooser2.bat
:: batch portion

@echo off
setlocal

for /f "delims=" %%I in ('cscript /nologo /e:jscript "%~f0"') do (
    echo You chose %%I
)

goto :EOF

:: JScript portion */

var shl = new ActiveXObject("Shell.Application");
var folder = shl.BrowseForFolder(0, "Please choose a folder.", 0, 0x00);
WSH.Echo(folder ? folder.self.path : '');

folder selection dialog

In der BrowseForFolder()-Methode gibt das vierte Argument den Stamm der Hierarchie an. Eine Liste der gültigen Werte finden Sie unter ShellSpecialFolderConstants .

8
rojo

Eine Datei-/Ordnerauswahl kann mit reinem Stapel durchgeführt werden (siehe unten). Natürlich ist das Gefühl und Aussehen nicht so angenehm wie eine GUI, aber es funktioniert sehr gut und meiner Meinung nach ist es einfacher zu bedienen als die GUI-Version. Die Auswahlmethode basiert auf dem Befehl CHOICE. Sie müssen sie daher in den Windows-Versionen herunterladen, in denen sie nicht enthalten ist, und die Parameter leicht ändern. Natürlich kann der Code leicht geändert werden, um SET/P anstelle von CHOICE zu verwenden. Diese Änderung würde jedoch die sehr einfache und schnelle Auswahlmethode überflüssig machen, bei der zum Navigieren und Auswählen nur ein Tastendruck erforderlich ist.

@echo off
setlocal

rem Select a file or folder browsing a directory tree
rem Antonio Perez Ayala

rem Usage examples of SelectFileOrFolder subroutine:

call :SelectFileOrFolder file=
echo/
echo Selected file from *.* = "%file%"
pause

call :SelectFileOrFolder file=*.bat
echo/
echo Selected Batch file = "%file%"
pause

call :SelectFileOrFolder folder=/F
echo/
echo Selected folder = "%folder%"
pause

goto :EOF


:SelectFileOrFolder resultVar [ "list of wildcards" | /F ]

setlocal EnableDelayedExpansion

rem Process parameters
set "files=*.*"
if "%~2" neq "" (
   if /I "%~2" equ "/F" (set "files=") else set "files=%~2"
)

rem Set the number of lines per page, max 34
set "pageSize=30"
set "char=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

rem Load current directory contents
set "name[1]=<DIR>  .."
:ProcessThisDir
set "numNames=1"
for /D %%a in (*) do (
   set /A numNames+=1
   set "name[!numNames!]=<DIR>  %%a"
)
for %%a in (%files%) do (
   set /A numNames+=1
   set "name[!numNames!]=       %%a"
)
set /A numPages=(numNames-1)/pageSize+1

rem Show directory contents, one page at a time
set start=1
:ShowPage
set /A page=(start-1)/pageSize+1, end=start+pageSize-1
if %end% gtr %numNames% set end=%numNames%
cls
echo Page %page%/%numPages% of %CD%
echo/
if %start% equ 1 (set base=0) else set "base=1"
set /A lastOpt=pageSize+base, j=base
for /L %%i in (%start%,1,%end%) do (
   for %%j in (!j!) do echo     !char:~%%j,1! -  !name[%%i]!
   set /A j+=1
)
echo/

rem Assemble the get option message
if %start% equ 1 (set "mssg=: ") else (set "mssg= (0=Previous page")
if %end% lss %numNames% (
   if "%mssg%" equ ": " (set "mssg= (") else set "mssg=%mssg%, "
   set "mssg=!mssg!Z=Next page"
)
if "%mssg%" neq ": " set "mssg=%mssg%): "

:GetOption
choice /C "%char%" /N /M "Select desired item%mssg%"
if %errorlevel% equ 1 (
   rem "0": Previous page or Parent directory
   if %start% gtr 1 (
      set /A start-=pageSize
      goto ShowPage
   ) else (
      cd ..
      goto ProcessThisDir
   )
)
if %errorlevel% equ 36 (
   rem "Z": Next page, if any
   if %end% lss %numNames% (
      set /A start+=pageSize
      goto ShowPage
   ) else (
      goto GetOption
   )
)
if %errorlevel% gtr %lastOpt% goto GetOption
set /A option=start+%errorlevel%-1-base
if %option% gtr %numNames% goto GetOption
if defined files (
   if "!name[%option%]:~0,5!" neq "<DIR>" goto endSelect
) else (
   choice /C OS /M "Open or Select '!name[%option%]:~7!' folder"
   if errorlevel 2 goto endSelect
)
cd "!name[%option%]:~7!"
goto ProcessThisDir

:endSelect
rem Return selected file/folder
for %%a in ("!name[%option%]:~7!") do set "result=%%~Fa"
endlocal & set "%~1=%result%
exit /B
4
Aacini

Zwei weitere Möglichkeiten.

1.Verwenden Sie ein hybrides .bat/hta-Skript (muss als bat-Skript gespeichert werden.) Es kann Vbscript oder Javascript verwenden, aber das Beispiel ist mit javascrtipt. Es werden keine temporären Dateien erstellt. Die Auswahl des Ordners ist nicht so einfach und erfordert ein externes Javascript Bibliotheken, aber die Auswahl der Datei ist einfach

<!-- : starting html comment

:: FileSelector.bat
@echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
    set "file=%%~fp"
)
echo/
if not "%file%" == "" (
    echo selected  file is : %file%
)
echo/
exit /b
-->
<Title>== FILE SELECTOR==</Title>
<body>
    <script language='javascript'>
    function pipeFile() {

         var file=document.getElementById('file').value;
         var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
         close(fso.Write(file));

    }
    </script>
<input type='file' name='file' size='30'>
</input><hr><button onclick='pipeFile()'>Submit</button>
</body>

1.1 - ohne von rojo vorgeschlagenes Formular (siehe Kommentare):

<!-- : starting html comment

:: FileSelector.bat
@echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
    set "file=%%~fp"
)
echo/
if not "%file%" == "" (
    echo selected  file is : "%file%"
)
echo/
exit /b
-->
<Title>== FILE SELECTOR==</Title>
<body>
    <script language='javascript'>
    function pipeFile() {

         var file=document.getElementById('file').value;
         var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
         close(fso.Write(file));

    }
    </script>
<input id='file' type='file' name='file' size='30' onchange='pipeFile()' >
</input>
<hr>
<button onclick='pipeFile()'>Submit</button>
<script>document.getElementById('file').click();</script>
</body>

2.Wenn Sie bereits powershell/net verwenden, können Sie selbst kompilierte jscript.net -Hybride erstellen. Zum Kompilieren ist keine temporäre cs-Datei erforderlich. Der eingebaute Compiler jscrript.net wird direkt verwendet. Es ist auch keine Powershell-Funktion erforderlich, und der Code ist vorhanden weit lesbarer:

@if (@X)==(@Y) @end /* JScript comment
@echo off

:: FolderSelectorJS.bat
setlocal

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

for /f "tokens=* delims=" %%p in ('"%~n0.exe"') do (
    set "folder=%%p"
)
if not "%folder%" == "" ( 
    echo selected folder  is %folder%
)

endlocal & exit /b %errorlevel%

*/

import System;
import System.Windows.Forms;

var  f=new FolderBrowserDialog();
f.SelectedPath=System.Environment.CurrentDirectory;
f.Description="Please choose a folder.";
f.ShowNewFolderButton=true;
if( f.ShowDialog() == DialogResult.OK ){
    Console.Write(f.SelectedPath);
}
2
npocmaka

Lösung für Batch + PowerShell + C #

Dies ist die gleiche Lösung wie der Batch + PowerShell-Hybrid , jedoch wurde der C # -Fallback-Stuff für die Kompatibilität mit XP und Vista hinzugefügt. Mehrfachauswahl von Dateien wurde unter xNightmare67xs Anfrage hinzugefügt.

<# : chooser_XP_Vista.bat
:: // launches a File... Open sort of file chooser and outputs choice(s) to the console
:: // https://stackoverflow.com/a/36156326/1683264

@echo off
setlocal enabledelayedexpansion

rem // Does powershell.exe exist within %PATH%?

for %%I in ("powershell.exe") do if "%%~$PATH:I" neq "" (
    set chooser=powershell -noprofile "iex (${%~f0} | out-string)"
) else (

    rem // If not, compose and link C# application to open file browser dialog

    set "chooser=%temp%\chooser.exe"

    >"%temp%\c.cs" (
        echo using System;
        echo using System.Windows.Forms;
        echo class dummy {
        echo    public static void Main^(^) {
        echo        OpenFileDialog f = new OpenFileDialog^(^);
        echo        f.InitialDirectory = Environment.CurrentDirectory;
        echo        f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
        echo        f.ShowHelp = true;
        echo        f.Multiselect = true;
        echo        f.ShowDialog^(^);
        echo        foreach ^(String filename in f.FileNames^) {
        echo            Console.WriteLine^(filename^);
        echo        }
        echo    }
        echo }
    )
    for /f "delims=" %%I in ('dir /b /s "%windir%\Microsoft.net\*csc.exe"') do (
        if not exist "!chooser!" "%%I" /nologo /out:"!chooser!" "%temp%\c.cs" 2>NUL
    )
    del "%temp%\c.cs"
    if not exist "!chooser!" (
        echo Error: Please install .NET 2.0 or newer, or install PowerShell.
        goto :EOF
    )
)

rem // Do something with the chosen file(s)
for /f "delims=" %%I in ('%chooser%') do (
    echo You chose %%~I
)

rem // comment this out to keep chooser.exe in %temp% for faster subsequent runs
del "%temp%\chooser.exe" >NUL 2>NUL

goto :EOF
:: // end Batch portion / begin PowerShell hybrid chimera #>

Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }

Verwenden Sie für eine Ordnerauswahl für XP oder Vista entweder die WSH-Lösung oder npocmakas HTA-Lösung .

1
rojo

Andere Lösung mit direktem Start des PowerShell-Befehls in Batch

rem preparation command
set pwshcmd=powershell -noprofile -command "&{[System.Reflection.Assembly]::LoadWithPartialName('System.windows.forms') | Out-Null;$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog; $OpenFileDialog.ShowDialog()|out-null; $OpenFileDialog.FileName}"

rem exec commands powershell and get result in FileName variable
for /f "delims=" %%I in ('%pwshcmd%') do set "FileName=%%I"

echo %FileName%
1
Esperento57

Ich habe meine eigene tragbare Lösung geschrieben: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Utilities/Sources/_gui/wxFileDialog/

Sie können die ausführbare Datei von hier herunterladen: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Utilities/Binaries/wxFileDialog.exe

Das Dienstprogramm ist von wxWidgets 3.1.x abhängig, sodass Sie es für andere Betriebssysteme erstellen können.

0
Andry