Batch: Aktionen in allen Unterordnern eines Ordners ausführen

Der Leser Matthias Buchner fragte mich vor einiger Zeit, wie man mit Batch bestimmte Aktionen in allen Benutzerprofilen eines PCs ausführen kann. Die Lösung lieferte er später selbst und ich möchte euch das natürlich nicht vorenthalten. Mehr zu seiner Lösung in Schritt 4, vorher erstmal etwas Code-Kennenlernen und Basics.

Allgemein gesehen geht es darum Batch Aktionen in allen Unterordnern eines Ordners auszuführen. Dies lässt sich dann später auf das C:\Users\ Verzeichnis anwenden um den erwähnten Effekt zu erzielen.

Schritt 1: Unterordner eines Ordners ausgeben

Fangen wir klein an:

REM Achtung, Doppelbackslash Bug, siehe unten
setlocal
set rootdir=%cd%
set localusersdir=%systemdrive%\Users
for /d %%i in (%localusersdir%\*) do (
  echo %%i
)
pause
endlocal

Das Script gibt alle Unterordner eines Ordners aus. (linker Screenshot)
Erste mögliche Problemstelle: damit der Code funktioniert muss am Ende des Pfades \* stehen. Wenn die Pfadvariable jetzt bereits ein \ am Ende zu stehen hat (Laufwerksangabe z.B. per „C:\“), werden Pfade mit doppelten Backslashes ausgegeben. (rechter Screenshot) Das kann natürlich zu weiteren Problemen führen.
batch-execute-actions-in-each-subdir-simple batch-execute-actions-in-each-subdir-doublebackslash

Um das Problem zu beheben und unabhängig davon zu sein, wie der Pfad am Ende aussieht, habe ich folgenden Workaround gebastelt:

setlocal ENABLEDELAYEDEXPANSION
set rootdir=%cd%
set localusersdir=%systemdrive%\Users
for /d %%i in (%localusersdir%\*) do (
  set dir=%%i
  echo !dir:\\=\!
)
pause
endlocal

Bei der Verarbeitung auftretende Doppelbackslashes werden durch einfache Backslashes ersetzt.
batch-execute-actions-in-each-subdir-doublebackslash-fix

Schritt 2: Aktionen auf Elemente in Unterordnern ausführen

Damit lassen sich jetzt also Aktionen auf die direkten Unterordner eines Ordners ausführen. Das hilft jetzt aber selten.
Wichtiger ist es auf einen bestimmten Ordner oder eine Datei in jedem Unterordner Aktionen auszuführen.
Dazu wäre folgender Code eine Grundlage:

setlocal ENABLEDELAYEDEXPANSION
set localusersdir=%systemdrive%\Users
for /d %%i in (%localusersdir%\*) do (
  set dir=%%i
  del /q /f "!dir:\\=\!\Desktop\passwords.txt"
)
pause
endlocal

Der Code schaut in allen Benutzerprofilen auf dem Desktop nach einer passwords.txt und löscht diese, falls vorhanden. Funktioniert dank Workaround auch bei Doppelbackslashes.
batch-execute-actions-in-each-subdir-delete-edit-file-doublebackslash batch-execute-actions-in-each-subdir-delete-edit-file

Das Beispiel lässt sich jetzt beliebig ausbauen.

Schritt 3: mehrfache Verschachtelung

Dieser Fall kommt vielleicht seltener vor, war aber tatsächlich die Anfrage des Lesers: Bestimmte Aktionen in allen Benutzerprofilen ausführen; diese Aktion war eine Manipulation der Firefox Einstellungen, die wiederum in allen Firefox Profilen stattfinden soll.
Also [foreach] User -> [foreach] Firefox Browser Profile -> [do smth]
Dazu muss der oben gezeigte Code verschachtelt werden:

@echo off
setlocal ENABLEDELAYEDEXPANSION
set localusersdir=%systemdrive%\Users\
for /d %%i in (%localusersdir%\*) do (
  set dir=%%i
  echo User Profile: !dir!
  for /d %%j in ("!dir:\\=\!\AppData\Roaming\Mozilla\Firefox\Profiles\*") do (
    set deepdir=%%j
    echo Browser Profile: !deepdir!
    if "!deepdir:~-8!"==".default" (
      echo profile valid
      findstr /i /c:devtools.toolbox.selectedTool !deepdir!\prefs.js
      if not errorlevel 1 (
        echo prefs.js valid, rename it
        ren "!deepdir!\prefs.js" "prefs_backup.js"
      )
    )
  )
  echo.
)
pause
endlocal

Erläuterung: Jeder Firefox Profilordner aller lokalen Benutzer wird überprüft, ob er mit „.default“ endet. Wenn das der Fall ist wird in dem Ordner in der Datei prefs.js nachgesehen, ob die Zeichenkette „devtools.toolbox.selectedTool“ enthalten ist. Wenn ja wird die Datei in prefs_backup.js umbenannt, wodurch die Einstellungen des Firefox Profils zurückgesetzt werden (also seid vorsichtig mit dem Beispiel).

batch-execute-actions-in-each-subdir-nested-commands-complex
Der Screenshot zeigt die 4 unterschiedlichen Reaktionen:
User 1: Profil gefunden jedoch existiert keine prefs.js in dem Ordner (ungewöhnlich, hätte ich es nicht provoziert)
User 2: Profil gefunden, prefs.js gefunden, jedoch enthält sie den gesuchten String nicht
User 3: kein Firefox Profilordner gefunden
User 4: Profil gefunden, prefs.js gefunden, String gefunden (beim 2. Profil), Datei wird umbenannt

Das Beispiel soll nur zeigen, dass sich für eine Menge von Unterordnern, welche wiederum Unterordner eines Root Ordners sind, komplexe Überprüfungen und Befehle ausführen lassen. Jedoch hat auch das seine Grenzen. Beispielsweise können innerhalb der for Blöcke eine goto Sprungmarken benutzt werden. Es gibt sicher noch weitere Dinge, die in diesem Konstrukt nicht so funktionieren, wie sie es in Batch normalerweise tun, bisher ist mir nur das mit dem goto aufgefallen.

Schritt 4: Code komprimieren und optimieren

Ohne Überprüfungen, mögliche Fehler-Korrekturen, Variablen usw ist das Programm zwar weniger flexibel aber dafür sehr viel kürzer. Ich poste hier das konkrete Beispiel, dass mir Matthias Buchner per Mail geschickt hat:

FOR /D %%i IN (%systemdrive%\Users\*) Do FOR /D %%j IN (%%i\AppData\Roaming\Mozilla\Firefox\Profiles\*) Do (
 ren "%%j\prefs.js" "prefs_backup.js"
 findstr /v /i /c:Test "%%j\prefs_backup.js" >> "%%j\prefs.js"
 del /q/f "%%j\prefs_backup.js" 2>nul 1>nul
)

Alle Firefox Profile aller Nutzer werden nach der prefs.js durchsucht. Über einen typischen Batch Workaround werden aus der prefs.js einfach nur alle Zeilen, die den String „Test“ enthalten, gelöscht.

Mehr Firefox Profile Manipulation mit Batch hier: Batch: Textzeile aus einer Datei herauslöschen/filtern (ist aber das gleiche wie in Schritt 4: bestimmte Zeilen entfernen)

39 Kommentare

  1. Erst mal Danke für diese Tipps. Damit habe ich schon mal einen Großteil meines Problems gelöst.

     

    Nur die Ausgabe gefällt mir noch nicht. Vielleicht kann mir da Jemand noch helfen.

     

    Um folgendes geht es:

     

    Ich habe auf C: einen Ordner namens Test angelegt. In diesem Ordner befinden sich mehrere Unterordner mit jeweils mehreren MP3 Dateien da drin.

     

    Ich möchte nun das die Dateien in den jeweiligen Unterordnern zusammengefügt  in einer Datei gespeichert werden.

    Bis hier hin funktioniert das auch.

     

    Allerdings wird hier die neue Datei immer test.mp3 genannt. Hier würde ich gern das der Namen der neuen MP3 Datei dem des Unterordners entspricht in dem die Dateien drin sind. Also, sind die Dateien im Unterordner ABCD soll die neue Datei ABCD.mp3 heißen.

     

    Außerdem wäre es noch schön wenn die neue Datei dann direkt im Test Ordner (C:\Test) gespeichert werden würde.

    1. PS: Mein abgeänderter Code bis jetzt

      setlocal ENABLEDELAYEDEXPANSION
      set rootdir=%cd%
      set localusersdir=%systemdrive%\Test
      for /d %%i in (%localusersdir%\*) do (
        set dir=%%i
        copy /b „!dir:\\=\!\*.mp3“ „!dir:\\=\!\test.mp3“
      )
      pause
      endlocal

      1. Hallo Michael B,

        hast du deinen Code erstellen können ? Ich habe jetzt auch das Problem das ich gerne Mp3´s in Ordner mit den Copy /b befehlt zusammen fassen möchte.

        Mfg
        Mike

  2. Hi Michael,

    entschuldige die späte Antwort – besteht das Problem noch?
    Ich kann es leider nicht recht nachvollziehen. Ausgangslage mit den Ordner und MP3s ist klar, aber was willst du damit nochmal machen?

    Ich möchte nun das die Dateien in den jeweiligen Unterordnern zusammengefügt  in einer Datei gespeichert werden.

    Was meinst du mit Dateien zusammenfügen? Wie fügst du MP3s zusammen?
    Ich denke die Benennung und das Ablegen einer Kopie im Oberordner sollte dann nicht mehr das Problem sein, sobald ich die eigentliche Aufgabe verstanden habe 😉

    LG

  3. Hallo,

    erst einmal vielen Dank für die Erklärung. Ich habe ein ähnliches Problem, wo ich leider nicht weiterkomme, da mir immer angezeigt wird, dass die Datei nicht gefunden werden kann.

    Ich habe folgende Ordnerstruktur:

    Ordnerebene 1
    – Ordnerebene 2
    — Ordnerebene 3
    — PDF-Dateien

    Ich möchte nun einen Befehl erzeugen, der ordnerübergreifend nach bestimmten Ordnernamen suchen soll und diese dann umbenennt. Die Ordner befinden sich hauptsächlich in Ordnerebene 3. Da ich aber sehr viele Ordner habe, möchte ich das nicht für jeden Ordner in Ebene 3 einzeln machen, sonder am besten auf Grundlage von Ordnerebene 1.

    Gibt es dafür eine Lösung?

    Vielen Dank schon einmal für die Hilfe.

    VG
    Sebastian

    1. Hallo Sebastian,
      ich bin da gerade nicht mehr ganz so drin aber ich würde mir das mal ansehen. Du willst also Ordner mit einem bestimmten Namen umbenennen – nur Ordner der Ebene 3 oder auch alle anderen Ebenen drüber und drunter durchsuchen? Und Dateien werden ignoriert? Das sollte aber schon machbar sein. Kann aber sein, dass ich erst am Wochenende oder nächste Woche dazu komme.
      LG

      1. Hallo Hannes,

        erst einmal vielen Dank, dass du dich der Sache überhaupt annimmst.
        Ja genau, es sollen nur die Ordner der Ebene 3 umbenannt werden, alles andere ist irrelevant. Die Dateien sollen natürlich in den Ordnern, die umbenannt werden enthalten bleiben. Das Problem ist nur, dass in Ordnerebene 2 verschiedene Ordnernamen vorhanden sind.

        Vielen Dank und viele Grüße
        Sebastian

  4. Hallo,
    ich suche eine Batch Datei die folgendes erledigen soll:
    aus einen Ordner (Users) befinden sich mehrere Ordner, diese sind mit einer Datei bestückt, mit der Endung dll.
    wie kann man die ganzen Ordner deren Inhalt (dll) auslesen ?

    1. Danke für Ihre Rückantwort.
      Ich habe einen Ordner mit den namen „Users“ darin befinden sich weitere Ordner mit der Bezeichnung von Namen „Horst, Susi usw.“ in der Datei Susi ist nur eine Datei mit den Namen Susi.dll .
      Ich möchte den Ordner Users in einen Rutsch auslesen. Ist das so möglich ?
      Danke im voraus. Claudia P.

  5. Hallo Hannes,
    habe wieder einmal ein Problem. Möchte in einer Batch Datei zwei Variable gemeinsam abfragen und dann per goto weiter schicken.
    if %month-num%==11 %and% %day%==25 goto spiegel
    Es geht nicht mit zwei Var. mit einer geht es. Es heißt hier : ist der Monat =11 und der Tag =25 dann goto
    LG
    Claudia P.

    1. Hey Claudia, du wirst hier noch zum Stammleser, freut mich! 😉
      Was du brauchst ist eigentlich recht easy, da es nur eine einfache Verkettung von if-Abfragen ist.
      An sich ist ein if-Befehl ja immer so aufgebaut:
      if [Bedingung] [Befehle]
      z.B.:
      if "%test%"=="etwas" del /f file.txt
      oder
      if exist %path% cd /d %path%
      Heißt: Der nächste Befehl, der bei positiver Prüfung ausgeführt werden soll, steht ohne irgendwelche Trennung direkt hinter der Bedingung. Genauso ist es eben auch möglich, als „Befehl“ hinter die Bedingung direkt noch ein if mit einer Bedingung zu schreiben. Das ist legitim und sorgt für eine zweite Prüfung nach der ersten und beide müssen positiv ausfallen, damit der Befehl danach ausgeführt wird.
      if [Bedingung] if [Bedingung] [Befehl]
      wirkt dann wie if Bedingung 1 UND Bedingung 2, z.B. :
      IF exist %path% IF NOT "%path%"=="%windir%" RD /s /q %path%
      Noch etwas : If … Else… Else If… in Batch – mit Verschachtelung
      Sehr hilfreich beim Fummeln mit Batch und vor allem beim Rausfummeln von Informationen aus komplexeren Ausgaben ist übrigens die Seite dostips.com, die haben auch bisschen was zum Thema Zeit.
      Damit solltest du dein Thema abhaken können.

      1. Guten Morgen Herr Schurig,
        alles hat geklappt, so wie Sie es beschrieben habe. herzlichen Dank, es läuft alles stabil.
        Aber für dieses Jahr ist Schluss mit Batch, ausspannen.
        Ihre Claudia P.

  6. Hallo,

    ich wollte den Code nutzen um eine Batch auszuführen, die mp3-Dateien zusammen fügt. Ich habe ~60 Ordner, in jedem Ordner befinden sich mehrere Mp3-Dateien und die Batch zum zusammenfügen:
    Mrg.bat
    copy /b „*.mp3“ „0.mp3“ (Alle Mp3s werden zu deiner „0.mp3“ zusammengefügt)
    del /S *e* (Alle Daten mit einer „E“ im Namen werden gelöscht, dabei bleibt i.d.R. nur die =.mp3 übrig)
    del /s Mrg.bat (Auch die Batch-Datei wird gelöscht)

    Wenn ich nun versuche alle Batch-Daten über eine weitere Batch zu starten, öffnet sich nur ein neuen cmd-Fenster und wartet auf eine Eingabe…

    set local ENABLEDELAYEDEXPANSION
    set localusersdir=%cd%
    for /d %%i in (%localusersdir%\*) do (
    set dir=%%i
    start „!dir:\\=\!\Mrg.bat“
    )
    pause
    endlocal

    Was mache ich falsch?

    1. Hallo Rafael,
      soweit klingt das alles plausibel. Ohne das jetzt getestet zu haben, würde ich am ehesten die Zeile start „!dir:\\=\!\Mrg.bat“ untersuchen, die sieht doch sehr kryptisch aus für einen einfachen Startbefehl. Du ersetzt dort doppelte Backslashes durch einfache und setzt hinten „\Mgr.bat“ ran. Lass dir mal den String ausgeben, der durch „!dir:\\=\!\Mrg.bat“ erzeugt wird und prüfe, ob der daraus resultierende Pfad passt. Außerdem kannst du mal start "" "[pfad]" probieren, also leere doppelte Anführungszeichen vor dem Pfad, manchmal braucht start das.
      Sag Bescheid, wie es lief.

      1. Hallo,
        der String zeigt mir, dass es offensichtlich Probleme mit den Leerzeichen in den Ordner- und Dateinamen gibt. Als Pfad wird mir nur „Laufwerk:\Ordner\Unterordner\Der“ statt „Laufwerk:\Ordner\Unterordner\Der erste Ordner\“ ausgegeben.
        Habe da etwas rumgespielt und bekomme für %dir% auch den korrekten Pfad angezeigt. Ohne eine „\“ am Ende, also müsste es korrekt sein wenn ich „\Mrg.bat“ anhänge.
        Jetzt öffnen sich aber ~60 neue cmd-Fenster und warten auf eine Eingabe…

  7. Hi,
    ich hatte die Mail raus geschickt, kam aber zwei Mal zurück, wahrscheinlich wurden die *.bat als „schädlich“ eingestuft. Kam die dritte bei dir an?
    Vielen Dank für die Mühe und einen guten Rutsch!

      1. Antwort ist raus.
        Hinweis für Leser: Auch in seiner Lösung kommt wieder die Schleife zum Einsatz, die ausschließlich Ordner und keine Dateien durchläuft und Aktionen in jedem Unterordner ausführt:

        setlocal enableDelayedExpansion
        for /d /r "%cd%" %%i in (*) do (
        set dir=%%i
        copy /b "!dir!\*.mp3" "!dir!\0.mp3"
        del "!dir!\*__*"
        )

        Die Schleife durchläuft alle Unterordner des Arbeitsverzeichnisses (%cd%, das Verzeichnis in dem die ausgeführte Batch-Datei liegt) und für jeden Ordner, der gerade durchlaufen wird und in einer dir-Variable zwischengespeichert wird (Aufrufe mit Ausrufezeichen wegen enableDelayedExpansion), werden zwei Befehle mit Bezug auf diesen aktuellen Pfad eines Unterordners ausgeführt.

        1. Ich mach es mal ganz knapp:
          Das funktioniert so, vielen Dank. Es hatte keinen speziellen Grund warum ich vorher mehrere Batches genutzt hatte. Ich fing bloß mit einer an, dachte dann: „Der nächste Schritt lässt sich evtl auch automatisieren.“ Kam aber nicht auf den Trichter die vorhandene Batch zu erweitern.

    1. Hallo Claudia,
      ich sehe hier ein Syntax und ein Logikfehler:
      1.) Syntax: Zwischen dem zweiten Set und dem nächsten Befehle „goto“ fehlt die && Verknüpfung. Damit landet vermutlich „15:23 goto spiegel“ in der SU Variable.
      2.) Die Handhabung des set Befehls ist (vermutlich) nicht korrekt. Der Grund ist, dass set alle folgenden Zeichen in eine Variable speichert, bis der nächste Befehl aufgerufen wird. Wichtig ist hierbei: Auch alle Leerzeichen werden in die Variable übernommen. Der nächste Befehl wird entweder mit „&&“ oder durch eine neue Zeile eingeleitet.
      Demnach setzt „SA=07:27 &&“ den Variableninhalt nicht etwa auf „07:27“ sondern eben auf „07:27 „. Das kannst du durch eine Ausgabe mit umschlossenen Symbolen auch erkennen:
      how batch set works

      Einfache Lösung: Entweder Variablendefinitionen immer in separaten Zeilen, nur das set in einer Zeile, dann endet das Set mit dem letzten Zeichen. Oder das „&&“ bzw. andere folgende Befehle ranziehen, wenn es nach dem set weitergeht: „if %day%==01 set SA=07:27&& set SU=15:23&&goto spiegel“

    1. Du kannst einfach über den „start“ Befehl einen installierten Browser mit der URL als Paramter starten, das sollte mit fast allen Browsern gleich funktionieren: „start chrome.exe http://www.test.de„, dann öffnet sich die Seite.
      Anschließen könnte man beispielsweise mit „taskkill /im chrome.exe /f“ den Browserprozess wieder schließen.

      1. Hallo Herr Schurig,
        leider funktioniert das nicht. Ich denke das Batch -Programm ist ein Zeilenorientierter Ablauf,
        nach den Aufruf :
        cd Mia\super_website\n_menue
        start „“ „index.html“
        kehrt das Programm (html) nicht zurück. Es handelt sich hierbei um Offline Scripte.
        Es scheint keine Lösung hierzu zu geben, von Hand und separat kein Problem.
        LG
        Claudia P.

        1. Hallo Claudia,
          dein „start“ Befehl hat keinen Browser/Programm als Parameter bekommen. Der Aufbau für den Aufruf einer Webseite ist: „start [Browser] [URL]“. Du hast beim Browser aber nur leere Anführungszeichen benutzt – ich glaube dann versucht Batch, die HTML/URL mit dem Standardbrowser zu öffnen. Sicherer wäre die konkrete Angabe des Browsers, also chrome.exe oder iexplore.exe oder so. Dann sollte das auch gehen.
          Ich denke da musst du nochmal etwas rumprobieren, das geht bei mir sehr gut soweit und ich habe das Öffnen von HTML-Berichten oder Webseiten schon dutzende Male in Skripts verwendet.
          LG

  8. Hallo herr Schurig,
    benötige wieder einmal Ihren Rat.
    Wenn eine Batchdatei im Hintergrund eine Abfrage für ein anderes Laufwerk macht, dieses nicht vorhanden ist, möchte ich gern die Abfrage „kein Laufwerk“ überspringen. Im Schacht steckt eine SD Karte.
    Danke im voraus

    1. Ich fürchte ich kann nicht folgen. Was für eine „Abfrage „kein Laufwerk“ überspringen“?
      Generell kann die Verfügbarkeit von Dateien/Ordnern/Laufwerken/Wechseldatenträgern gleichermaßen mit „if exist [LW:/] [Befehle]“ überprüft werden. Wenn also die Speicherkarte immer in G:/ geladen wird, wäre ein „if exist G:/ goto LwGefunden“ ausreichend.
      LG

        1. Reden wir hier von innerhalb eines Batch Skriptes? „kein Laufwerk.
          weiter-wiederholen“ klingt nach UI Ausgaben des Explorers. Ich dachte wir skripten hier?
          „If exist [X:/]“ macht einfach erstmal gar nichts, wenn das Laufwerk X:/ nicht gefunden wird. Dann läuft das Skript weiter.
          Ich brauche mehr konkretere Infos worum es hier geht, was gemacht werden soll, wo das Problem ist, was das Skript ausgibt und was es ausgeben soll, sonst kann ich nicht helfen.

  9. Hallo Hannes,
    habe wieder einmal ein Frage. Ich möchte bei der Abfrage vom Laufwerk set root=%~dp0% den Buchstaben und den Doppepunkt ausblenden. Geht das ?
    statt F:\Mia nur Mia
    LG
    Claudia

  10. Hallo allerseits. Ich habe Kommentare von Leuten gesehen, die ihr Darlehen bereits von CHRISTY WALTON FINANCE erhalten haben, und dann habe ich beschlossen, mich gemäß ihren Empfehlungen zu bewerben. Vor wenigen Stunden habe ich auf meinem persönlichen Bankkonto einen Gesamtbetrag von 30.000 Euro bestätigt, den ich beantragt habe. Dies ist wirklich eine großartige Nachricht und ich rate jedem, der ein echtes Darlehen benötigt, um sich per E-Mail (christywalton355@gmail.com) zu bewerben. Ich bin jetzt froh, dass ich das Darlehen erhalten habe, das ich angefordert habe

Schreibe einen Kommentar