bluemen
Goto Top

Batch: betimmte Verzeichnisse in Schleife ignorieren

Hallo,

ich suche nach einer Möglichkeit, bestimmte Verzeichnisse in nachfolgender Schleife zu ignorieren.
Z.B. sollen alle Verzeichnisse unberücksichtigt bleiben, sobald in %~dpi, an beliebiger Stelle, "converted" auftaucht.

Und was mir in diesem Beispiel bislang auch nicht gelingt, ist die Übergabe des Inhaltes von %~dpi an AKTUELLER_PFAD.

for /R %PFAD% %%i in (%BEDINGUNG%) do (
echo.
echo PFAD: %PFAD%
echo DURCHSUCHTER PFAD: %%~dpi REM Inhalt von %~dpi wird angezeigt

SET AKTUELLER_SUCHPFAD=%%~dpi REM Inhalt von %~dpi wird nicht an AKTUELLER_SUCHPFAD übergeben
echo AKTUELLER_SUCHPFAD: %AKTUELLER_SUCHPFAD% REM somit keine Anzeige

)

Hat jemand dazu eine Idee?

Vielen Dank

Content-ID: 3009975671

Url: https://administrator.de/contentid/3009975671

Ausgedruckt am: 22.11.2024 um 09:11 Uhr

em-pie
em-pie 07.06.2022 aktualisiert um 17:49:38 Uhr
Goto Top
Moin,

wie fix ist die Batch?

Wäre Powershell denkbar?
Falls ja:
$fsObjects = Get-ChildItem -Path $PSScriptRoot -exclude *converted*

Und mit $fsObjects hättest du dann alle Dateien/ Ordner, die direkt im Verzeichnis des Scripts liegen, mit Ausnahme jener, die ein "converted" im Namen haben.
Willst du auch Unterverzeichnisse berücksichtigen, so solltest du noch ein -Recurse einbauen.

Edit:
Sollen nur Dateien berücksichtigt werden:
$fsObjects = Get-ChildItem -Path $PSScriptRoot -exclude *converted* -Recurse | Where {!$_.PSIsContainer}

Gruß
em-pie

P.S.
Bitte die Code-Tags nutzen
TK1987
TK1987 07.06.2022 um 17:48:02 Uhr
Goto Top
Moin,

bitte zukünftig codetags nutzen.
Zitat von @bluemen:
ich suche nach einer Möglichkeit, bestimmte Verzeichnisse in nachfolgender Schleife zu ignorieren.
Z.B. sollen alle Verzeichnisse unberücksichtigt bleiben, sobald in %~dpi, an beliebiger Stelle, "converted" auftaucht.
for /f "Delims=" %%i in ('dir /s /b /ad ^|findstr /v "converted"') do echo %%i  

Und was mir in diesem Beispiel bislang auch nicht gelingt, ist die Übergabe des Inhaltes von %~dpi an AKTUELLER_PFAD
SET AKTUELLER_SUCHPFAD=%%~dpi REM Inhalt von %~dpi wird nicht an AKTUELLER_SUCHPFAD übergeben
echo AKTUELLER_SUCHPFAD: %AKTUELLER_SUCHPFAD% REM somit keine Anzeige
Wenn du einen Code mit Klammern gruppierst, gilt diese Gruppierung als 1 Befehl. Wenn du eine Variable innerhalb einer Gruppierung aufrufst, gibt diese den Wert zurück, den sie vor der Gruppierung hatte - in deinem Fall also keinen.
Entweder du Aktivierst die Variablenverzögerung und nutzt diese (Variablen dann in Ausrufezeichen statt Prozentzeichen):
@echo off
setlocal EnableDelayedExpansion
for /f "Delims=" %%i in ('dir /s /b /ad ^|findstr /v "converted"') do (  
  set AKTUELLER_SUCHPFAD=%%~i
  echo !AKTUELLER_SUCHPFAD!
)

oder du nutzt stattdessen Funktionen
@echo off
for /f "Delims=" %%i in ('dir /s /b /ad ^|findstr /v "converted"') do call :MeineFunktion "%%i"  
goto :EoF

:MeineFunktion
set AKTUELLER_SUCHPFAD=%~1
echo %AKTUELLER_SUCHPFAD%

Gruß Thomas
bluemen
bluemen 07.06.2022 um 21:19:29 Uhr
Goto Top
Vielen Dank für die schnellen Antworten,

Powershell habe ich (kurz) probiert, allerdings weiß ich dort gar nicht, was zu tun ist.
Die von Thomas aufgeführten Varianten haben beide funktioniert. face-smile

Nun ist es aber so, dass diese rekursive Schleife

for /R %PFAD% %%i in (%BEDINGUNG%) do (

)

erhalten bleiben muss, da innerhalb dieser noch weiterer Code ausgeführt wird.
Ich möchte jedoch alle Verzeichnisse "überspringen", welche an irgendeiner Stelle im Pfadnamen "converted" stehen haben. Kann ich beides kombinieren?

Einen schönen Abend
bluemen
TK1987
TK1987 07.06.2022 um 22:19:55 Uhr
Goto Top
Zitat von @bluemen:
Nun ist es aber so, dass diese rekursive Schleife

for /R %PFAD% %%i in (%BEDINGUNG%) do (

)

erhalten bleiben muss, da innerhalb dieser noch weiterer Code ausgeführt wird.
Ich möchte jedoch alle Verzeichnisse "überspringen", welche an irgendeiner Stelle im Pfadnamen "converted" stehen haben. Kann ich beides kombinieren?
Sicher, die Schleife halt einfach verschachteln. Den /R-Parameter musst du in dem Fall allerdings weglassen, da "dir /s" die Ordner ja schon rekursiv abarbeitet, du also nur noch die Dateien benötigst.

Zudem würde ich trotzdem mit Funktionen arbeiten, statt den Code direkt in der for-Schleife auszuführen.

Beispiel:
@echo off
for /f "Delims=" %%a in ('dir /s /b /ad ^| findstr /v "converted"') do (  
  echo "Aktueller Pfad: %%a"  
  for %%b in ("%%~a\*") do call :MachWas "%%~b"  
)
goto :EoF

:MachWas
REM  Hier folgt nun dein Code.
REM  Variable "%1" enthält die  
REM  einzelnen Dateien

Falls du mehr Unterstützung brauchst, poste deinen Code.

Gruß Thomas
bluemen
bluemen 08.06.2022 um 16:09:35 Uhr
Goto Top
Hallo Thomas,

es hat prima funktioniert, doch leider stehe ich immer wieder vor neuen Problemen, weil ich den Synthax nicht beherrsche.
Na ja, wenn mal alle paar Jahre etwas versucht und dann unter Windows, dann wieder unter Linux unterwegs ist, wird es für einen Laien kompliziert. Eine Lösung, welche OS-unabhängig funktioniert, wäre da ein Traum.

Es gibt ein batch-Script, was einen Teil der Anforderungen sauber abarbeitet (und ich hätte es gern komplett selbst gelöst), jedoch ist der "Code" so zusammengerockt, dass ich ihn nicht posten möchte.

Und eh sich jemand durch meinen sogenannten Code arbeiten muss, würde ich meinen Wunsch formulieren. Evtl. hat jemand eine clevere Lösung.

Es gibt folgende Verzeichnisstruktur, in der Bild-& Video-Dateien liegen:

2000 ------ 2000-01 ------ converted
2001     2000-02           jpg
2002     2000-03           video
2003     ...               Datei000001.ARW
2004     2000-12           Datei0xxxxx.ARW
2005                       ...
2006
...       
Die Video-Dateien liegen in video, jpg-Dateien in jpg und bearbeitete/entwickelte Dateien in converted.
Die (unbearbeiteten) RAW-Bilder liegen direkt im jeweiligen Jahres-Verzeichnis, mit der Erweiterung des Monats (2000-01).

Die Aufgabe ist, den Inhalt des Verzeichnisses jpg, des jeweiligen Monats (2000-01), mit den .ARW-Dateien im Verzeichnis (2000-01) zu vergleichen und die Dateien in ein neu anzulegendes Verzeichnis (200-01_aussortiert) zu verschieben.
Dabei wäre es ideal, wenn die .JPG-Dateien in ein Unterverzeichnis (2000-01_aussortiert --- jpg) und nur die .ARW-Dateien direkt unter 2000-01_aussortiert liegen würden.

Wie gesagt, die Prüfung, ob die .JPG-Datei zur .ARW-Datei vorliegt und wenn nicht, wird die .ARW-Datei verschoben, funktioniert.
Zusätzlich erzeuge ich noch ein Log, welche Dateien verschoben wurden. Das ist jedoch nicht (mehr) zwingend notwendig, sondern diente mehr der Kontrolle.

Jetzt wollte ich es noch erweitern, um die .JPG zu verschieben, wenn keine .ARW-Datei vorhanden ist ... und scheitere.
Und da ich nicht in der Lage bin, mein Wunsch sauber umzusetzten, kann bzw. muss ich evtl. akzeptieren, dass es nicht gelöst wird.

Viele Grüße
bluemen
TK1987
Lösung TK1987 08.06.2022 um 21:44:53 Uhr
Goto Top
Zitat von @bluemen:
Die Aufgabe ist, den Inhalt des Verzeichnisses jpg, des jeweiligen Monats (2000-01), mit den .ARW-Dateien im Verzeichnis (2000-01) zu vergleichen und die Dateien in ein neu anzulegendes Verzeichnis (200-01_aussortiert) zu verschieben.
Dabei wäre es ideal, wenn die .JPG-Dateien in ein Unterverzeichnis (2000-01_aussortiert --- jpg) und nur die .ARW-Dateien direkt unter 2000-01_aussortiert liegen würden.
[...]

Sofern ich dich denn richtig verstanden habe
@echo off
set Quellpfad=C:\Pfad\zum\Quellordner

REM Alle Ordner namens "JPG" im Quellpfad finden, ausgenommen Pfade namens "converted" oder "_aussortiert"  
for /f "Delims=" %%A in ('dir /s /b /ad "%Quellpfad%\JPG" ^| findstr /i /v "converted _aussortiert"') do (  

  REM  Für jede ARW-Datei im übergeordneten Verzeichnis: Wenn keine gleichnamige JPG-Datei vorhanden
  for %%B in ("%%~dpA*.arw") do if not exist "%%~A\%%~nB.jpg" call :keineJPG "%%~B"  

  REM  Für jede JPG-Datei im Ordner: Wenn keine ARW-Datei im übergeordneten Ordner vorhanden
  for %%B in ("%%~A\*.jpg") do if not exist "%%~dpA%%~nB.arw" call :keineARW "%%~dpA" "%%~B"  
  )
  
)
pause
goto :EoF

:keineJPG
  REM  Verzeichnis "_aussortiert" erstellen, falls nicht vorhanden  
  set Zielpfad=%~dp1
  set Zielpfad=%Zielpfad:~0,-1%_aussortiert
  if not exist "%Zielpfad%" (  
    echo Erstelle Verzeichnis: "%Zielpfad%"  
    mkdir "%Zielpfad%"  
  )
  
  REM  ARW-Datei verschieben
  echo Verschiebe Datei: "%~1" => "%Zielpfad%"  
  1>nul move "%~1" "%Zielpfad%\"  
goto :EoF

:keineARW
  REM  Verzeichnis "_aussortiert\jpg" erstellen, falls nicht vorhanden  
  set Zielpfad=%~1
  set Zielpfad=%Zielpfad:~0,-1%_aussortiert\jpg
  if not exist "%Zielpfad%" (  
    echo Erstelle Verzeichnis: "%Zielpfad%"  
    mkdir "%Zielpfad%"  
  )
  
  REM  JPG-Datei verschieben
  echo Verschiebe Datei: "%~2" => "%Zielpfad%"  
  1>nul move "%~2" "%Zielpfad%\"  

Gruß Thomas
bluemen
bluemen 09.06.2022 um 13:48:35 Uhr
Goto Top
Hallo Thomas,

vielen Dank, dass du dir die Arbeit gemacht hast, dich in meinen Wunsch hineinzudenken und auch gleich noch eine Lösung lieferst.

Zum Test habe ich einen Verzeichnis angelegt (C:\Test), mit den Unterverzeichnissen \jpg, \video und \converted und den Quellpfad angepasst.
\jpg und \converted enthalten jeweils .jpg-Dateien.
Im Testverzeichnis (C:\Test) sind keine .arw-Dateien enthalten. Somit müssten alle Dateien aus C:\Test\jpg verschoben werden, was bislang nicht erfolgt.
Ein - echo Hallo - in Zeile 6 wird nicht ausgegeben. Habe ich etwas übersehen?

Beste Grüße
bluemen
TK1987
TK1987 09.06.2022 aktualisiert um 14:10:45 Uhr
Goto Top
Zitat von @bluemen:
Zum Test habe ich einen Verzeichnis angelegt (C:\Test), mit den Unterverzeichnissen \jpg, \video und \converted und den Quellpfad angepasst.
\jpg und \converted enthalten jeweils .jpg-Dateien.
Im Testverzeichnis (C:\Test) sind keine .arw-Dateien enthalten. Somit müssten alle Dateien aus C:\Test\jpg verschoben werden, was bislang nicht erfolgt.
Ein - echo Hallo - in Zeile 6 wird nicht ausgegeben. Habe ich etwas übersehen?
Ja, du hast übersehen, dass du mit deinem Testordner einen anderen Umstand geschaffen hast face-wink.

In deinem Ursprünglichen Fall hattest du im Quellordner erst noch Unterordner wie etwa "2022-02" - und erst darunter dann die entsprechenden JPG Ordner.

In deinem jetzigen Test-Ordner hast du hingegen direkt den "JPG" Ordner liegen. Das führt dazu, das der Befehl
dir /s /b /ad "C:\Test\JPG"  
versucht, den Inhalt (bzw. die Unterordner) des "JPG"-Ordners aufzulisten, statt in dem Quellverzeichnis nach Ordner namens "JPG" zu suchen. Somit produziert der Befehl schlicht keine Ausgabe und die For-Schleife endet.

Lange Rede kurzer Sinn - ändere den Befehl in der For-Schleife (Zeile 5) auf
dir /s /b /ad "%Quellpfad%\JPG*"  
ab, dann funktioniert das Ganze für beide Fälle.

Gruß Thomas
bluemen
bluemen 09.06.2022 um 16:25:25 Uhr
Goto Top
Hallo Thomas,

1000 Dank! Es funktioniert super! face-smile

Was das * nach JPG bewirkt, ist mir allerdings nicht klar und warum "Zugriff verweigert" in der Console erscheint? Evtl. ein Zusammenhang mit dem neu erstellten Verzeichnis _aussortiert?
Und eine letzte Frage: Könnte Zeile 8 einfach erweitert werden, sodass zusätzlich auch *.xmp-Dateien gelöscht werden?

Inzwischen setze ich das Thema schonmal auf gelöst und bedanke mich für deine Geduld.
TK1987
TK1987 09.06.2022 um 17:11:47 Uhr
Goto Top
Zitat von @bluemen:
Was das * nach JPG bewirkt, ist mir allerdings nicht klar
Das ist einfach nur ein ganz normaler wildcard. Es wird also nach allen Ordern gesucht, die mit "JPG" beginnen. Hat allerdings den Nachteil, dass das dann auch auf Ordner zutrifft die z.B. "JPG_alt" zutreffen würde.

und warum "Zugriff verweigert" in der Console erscheint? Evtl. ein Zusammenhang mit dem neu erstellten Verzeichnis _aussortiert?
Nein. Ich habe in den Echo-Befehlen (Zeile 28 & Zeile 42) einen Fehler gemacht.
  echo Verschiebe Datei: "%~1" => "%Zielpfad%"  
"=>" sollte natürlich ein Pfeil auf der Konsole sein. Das ">" muss hier aber natürlich Escaped werden, sonst wird das als Umleitungsoperator erkannt. Richtig muss die Zeile also so aussehen:
  echo Verschiebe Datei: "%~1" =^> "%Zielpfad%"  
Bitte in beiden Zeilen ändern.

Gruß Thomas
bluemen
bluemen 09.06.2022 um 19:54:44 Uhr
Goto Top
dir /s /b /ad "%Quellpfad%\JPG*"  

Das ist einfach nur ein ganz normaler wildcard. Es wird also nach allen Ordern gesucht, die mit "JPG" beginnen. Hat allerdings den Nachteil, dass das dann auch auf Ordner zutrifft die z.B. "JPG_alt" zutreffen würde.

Die Bedeutung des Wildcard kenne ich, verstehe jedoch nicht, weshalb es dafür sorgt, dass nun "eine Ebene höher", also in C:\Test\JPG die Dateien gesucht werden und nicht mehr unter C:\Test\JPG\JPG (was nicht existiert).


echo Verschiebe Datei: "%~1" =^> "%Zielpfad%"  
Ist angepasst und Fehlermeldung verschwunden.

Und eine letzte Frage: Könnte Zeile 8 einfach erweitert werden, sodass zusätzlich auch *.xmp-Dateien gelöscht werden?
Kannst du mir dazu vielleicht noch etwas sagen?

Einen schönen Abend
bluemen
TK1987
TK1987 10.06.2022 aktualisiert um 08:19:49 Uhr
Goto Top
Zitat von @bluemen:
Die Bedeutung des Wildcard kenne ich, verstehe jedoch nicht, weshalb es dafür sorgt, dass nun "eine Ebene höher", also in C:\Test\JPG die Dateien gesucht werden
tut es nicht. Wir stellen mit dem Wildcard nur klar, dass "JPG" eine zu suchende Zeichenkette und kein tatsächlich existierender Pfad ist.
und nicht mehr unter C:\Test\JPG\JPG (was nicht existiert)
der Unterordner unter "C:\Test\JPG" müsste nicht mal "JPG" heissen.
dir /s /ad listet alle Unterverzeichnisse auf. Wenn das letzte Element im angegebenen Pfad nicht existiert, wird nach diesem gesucht, also quasi "Suche nach einem Unterordner namens 'JPG'". Existiert dieses jedoch, so bedeutet der Befehl etwas ganz anderes, nämlich "Liste alle Unterordner des Verzeichnisses 'C:\Test\JPG' auf" - egal wie die dann heissen.

Und eine letzte Frage: Könnte Zeile 8 einfach erweitert werden, sodass zusätzlich auch *.xmp-Dateien gelöscht werden?
Gelöscht oder nach "_aussortiert" verschoben?
Bei letzterem brauchst du nur Zeile zu 8 duplizieren und aus "arw" "xmp" machen.
Bei ersterem machst du das Selbe und ersetzt zusätzlich "call :keineJPG" durch "del /q" ersetzen.

Gruß Thomas
bluemen
bluemen 11.06.2022 um 00:28:01 Uhr
Goto Top
Vielen Dank für die Erklärungen, ich weiß wohl weniger über Wildcards, als gedacht und die .XMP-Dateien werden nun auch, wie gewünscht, verschoben.

Nochmals danke! face-smile
bluemen
bluemen 13.06.2022 um 19:21:47 Uhr
Goto Top
Hallo Thomas,

ich habe noch eine "unglückliche" Konstellation mit den Dateierweiterungen. Es gibt auch .XMP-Dateien, im Format "Dateiname.ARW.xmp". Für diese funktioniert nachfolgende Zeile nicht und die .XMP-Dateien werden nicht verschoben.
Auch die Verwendung von "%%~dpA*.ARW.xmp", statt "%%~dpA*.xmp" ändert nichts. Kann ich das irgendwie anders lösen?

  REM  Für jede XMP-Datei im übergeordneten Verzeichnis: Wenn keine gleichnamige JPG-Datei vorhanden
  for %%B in ("%%~dpA*.xmp") do if not exist "%%~A\%%~nB.jpg" call :keineJPG "%%~B"  
TK1987
TK1987 14.06.2022 um 08:21:02 Uhr
Goto Top
Zitat von @bluemen:
ich habe noch eine "unglückliche" Konstellation mit den Dateierweiterungen. Es gibt auch .XMP-Dateien, im Format "Dateiname.ARW.xmp". Für diese funktioniert nachfolgende Zeile nicht und die .XMP-Dateien werden nicht verschoben.
  REM  Für jede XMP-Datei im übergeordneten Verzeichnis: Wenn keine gleichnamige JPG-Datei vorhanden
  for %%B in ("%%~dpA*.xmp") do if not exist "%%~A\%%~nB.jpg" call :keineJPG "%%~B"  
Versteh ich nicht. Bei mit funktioniert das (mal abgesehen davon, dass die Datei natürlich immer verschoben wird, weil die JPG-Datei vermutlich nicht auch ".ARW.jpg" heisst, was man aber über eine weitere For-Schleife regeln könnte).
Bei meinem Test erzeugt der Befehl wie gewünscht die Ausgabe:
Erstelle Verzeichnis: "C:\Pfad\zum\Quellordner\2022-02_aussortiert"
Verschiebe Datei: "C:\Pfad\zum\Quellordner\2022-02\Dateiname.ARW.xmp" => "C:\Pfad\zum\Quellordner\2022-02_aussortiert"

Gruß Thomas
bluemen
bluemen 14.06.2022 um 14:20:25 Uhr
Goto Top
Hallo Thomas,

ich war gestern nicht mehr so recht bei der Sache. Richtig ist, die .ARW.xmp-Dateien werden ALLE verschoben.
Sobald ich aus Dateiname.ARW.xmp --> Dateiname.xmp mache, funktioniert es.
Ich habe xmp durch * ersetzt, gleiches Ergebnis.
 REM  Für jede XMP-Datei im übergeordneten Verzeichnis: Wenn keine gleichnamige JPG-Datei vorhanden
  for %%B in ("%%~dpA*.*") do if not exist "%%~A\%%~nB.jpg" call :keineJPG "%%~B"  
Die Datei, welche nur .xmp heißt, bleibt erhalten, alle .ARW.xmp werden verschoben, egal ob das entsprechende JPG vorhanden ist oder nicht.
TK1987
TK1987 14.06.2022 aktualisiert um 15:13:53 Uhr
Goto Top
Moin,

Zitat von @bluemen:
ich war gestern nicht mehr so recht bei der Sache. Richtig ist, die .ARW.xmp-Dateien werden ALLE verschoben.
...
Die Datei, welche nur .xmp heißt, bleibt erhalten, alle .ARW.xmp werden verschoben, egal ob das entsprechende JPG vorhanden ist oder nicht.
ahh, na das klingt doch schon plausibler face-smile.

Dann einmal abändern auf:
REM  Für jede XMP-Datei im übergeordneten Verzeichnis: Wenn keine gleichnamige JPG-Datei vorhanden
  for %%B in ("%%~dpA*.xmp") do (  
    for %%C in ("%%~nB") do if not exist "%%~A\%%~nC.jpg" call :keineJPG "%%~B"  
  )
So dürfte es dann für beide Fälle funktionieren.

Gruß Thomas
bluemen
bluemen 17.06.2022 um 13:45:36 Uhr
Goto Top
Hallo Thomas,

konnte es erst jetzt testen.
Nun scheinen alle Eventualitäten berücksichtigt zu sein - zumindest momentan. face-smile

Hab' vielen Dank!
bluemen
bluemen
bluemen 06.03.2023 um 14:10:43 Uhr
Goto Top
Hallo Thomas,

falls du nach so langer Zeit noch Muße hast, einen kleinen Wunsch hätte ich noch.
Aber zuerst, dass Script funktioniert nach wie vor hervorragend und spart jede Menge Zeit! face-smile

Jedoch gibt es den (Sonder)Fall, dass .xmp-Dateien erzeugt werden, welche eine Erweiterung im Namen tragen.
Beispiel:
Version 1: 2016-04-24-__DSC00814___.ARW.xmp
Version 2: 2016-04-24-__DSC00814___01.ARW.xmp
Version 2: 2016-04-24-__DSC00814___03.ARW.xmp

Diese Versionen entstehen durch verschiedene Bearbeitungen, sollen aber natürlich auch erhalten bleiben, wenn die zugehörige Bilddatei vorhanden ist.
Durch die Versionierung ist der .xmp-Dateiname zur Bilddatei (welche es nur einmal gibt) unterschiedlich und diese Datei(Versionen) werden aktuell durch das Script entfernt/verschoben.

Hast du vielleicht noch einen Vorschlag, wie diese Konstellation mit berücksichtigt werden kann?

Gruß
Bodo
TK1987
TK1987 06.03.2023 aktualisiert um 17:07:47 Uhr
Goto Top
Moin Bodo,

Zitat von @bluemen:
Jedoch gibt es den (Sonder)Fall, dass .xmp-Dateien erzeugt werden, welche eine Erweiterung im Namen tragen.
Beispiel:
Version 1: 2016-04-24-__DSC00814___.ARW.xmp
Version 2: 2016-04-24-__DSC00814___01.ARW.xmp
Version 2: 2016-04-24-__DSC00814___03.ARW.xmp
so langsam kommst du mit deinen Sonderfällen an die Grenzen dessen, was mit Batch noch in akzeptabler Laufzeit machbar ist.

Mein Vorschlag wäre daher, das Ganze doch besser auf Powershell umzustellen.

Einfach den Quellpfad oben anpassen und das Skript mit der Endung ".ps1" abspeichern. Dann kannst du über das Kontextmenü (Rechtsklick auf die Datei) "Mit Powershell ausführen" wählen.
$Quellpfad = "C:\Pfad\zum\Quellordner"  

# Wenn Konsolenfenster kleiner als 75 pixel, auf 75 setzen
if ([Console]::WindowWidth -lt 75) {[Console]::WindowWidth = 75}

# Bei Fehlern, Skript abbrechen (Sprung in Catch-Block)
$ErrorActionPreference = 'stop'  
try {
  # Für jeden Ordner Namens JPG, dessen Pfad nicht "converted" oder "_aussortiert" enthält 
  $Files = Foreach ($dir in Get-ChildItem -Recurse -Directory "$Quellpfad\jpg" | ? Fullname -NotMatch "converted|_aussortiert") {  
    # Liste alle JPG-Dateien auf, zu der keine ARW-Datei im übergreifenden Ordner existiert
    Get-ChildItem -File "$($dir.Fullname)\*.jpg" | ? {!(Test-Path ("{0}\{1}.arw" -f $dir.Parent.Fullname,$_.BaseName))}  
    # Liste jede ARW oder XMP Datei, zu der keine JPG-Datei im übergreifenden Ordner existiert
    Get-ChildItem -File "$($dir.Fullname)\*" -Include "*.arw","*.xmp" | ? {!(Test-Path ("{0}\{1}.jpg" -f $dir.Parent.Fullname,($_.BaseName -Replace "\d*(\.ARW)?$")))}  
  }
  
  # Gruppiere Dateien nach Übergreifenden Ordner mit "_aussortiert"-Suffix 
  Foreach ($Group in $Files | Group {$_.Directory.Parent.Fullname+"_aussortiert\JPG"}) {  
    # Wenn Ordner nicht existiert, erstellen
    if (!(Test-Path -PathType Container $Group.Name)) {
      Write-Host -N ('Erstelle Ordner:  {0,-52} ' -f $Group.Name)  
      [void](md -force $Group.Name)
      Write-Host -F Green "[ok]"  
    } else {Write-Host ('Ordner existiert: {0} ' -f $Group.Name)}  
    # Verschiebe Dateien
    Foreach ($File in $Group.Group) {
      Write-Host -N ('   ''-->   {0,-60} ' -f $File.Name)  
      move -Path $File -Destination $Group.Name
      Write-Host -F green "[ok]"  
    }
    ""  
  }
  Foreach ($i in 5..1) {
    Write-Host -f green -N ("`r---   Alles erledigt. Wird beendet in {0,2} Sekunden.  ---" -f $i)  
    sleep 1
  }
} catch {
  # Fehlermeldung ausgeben und anhalten
  Write-Host -F red $_.Exception.Message
  Write-Host -N "---   Beliebige Taste zum Beenden   ---"  
  [void][console]::ReadKey($true)
}

Gruß Thomas
bluemen
bluemen 06.03.2023 um 18:19:43 Uhr
Goto Top
Hi Thomas,

danke für die schnelle Antwort.
Zwar hatte ich auf eine Lösung in Batch gehofft, da ich das halbwegs nachvollziehen kann aber PS wurde ja schon mal vorgeschlagen, von daher sicher die bessere Variante.
Ich habe den Quellpfad angepasst und das Script gestartet, bekomme jedoch folgende Fehlermeldung:

Das Handle ist ungültig.
In S:\Script.ps1:4 Zeichen:5
+ if ([Console]::WindowWidth -lt 75) {[Console]::WindowWidth = 75}
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) , IOException
    + FullyQualifiedErrorId : System.IO.IOException
Bodo
TK1987
TK1987 06.03.2023 um 18:30:05 Uhr
Goto Top
Zitat von @bluemen:
Ich habe den Quellpfad angepasst und das Script gestartet, bekomme jedoch folgende Fehlermeldung:
Hast du das Skript wie oben beschrieben über das Kontextmenü gestartet, oder über die Powershell_ISE ausführen lassen?
Dieser Fehler dürfte nämlich eigentlich nur bei letzterem auftauchen, da die ISE keine Konsole besitzt.
bluemen
bluemen 06.03.2023 um 18:45:10 Uhr
Goto Top
Hast Recht! face-smile
Ich wollte den Fehler in Ruhe ansehen.

Das kommt, wenn ich das Kontextmenü verwende:

Set-ExecutionPolicy : Die Ausführungsrichtlinien wurden von Windows PowerShell erfolgreich aktualisiert, die
Einstellung wird jedoch von einer in einem spezielleren Bereich definierten Richtlinie überschrieben. Aufgrund der
Überschreibung wird die aktuelle geltende Ausführungsrichtlinie "Unrestricted" für die Shell beibehalten. Geben Sie
"Get-ExecutionPolicy -List" ein, um die Ausführungsrichtlinieneinstellungen anzuzeigen. Weitere Informationen erhalten
Sie mit "Get-Help Set-ExecutionPolicy".
In Zeile:1 Zeichen:46

back-to-top... -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'S ...

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : PermissionDenied: (face-smile [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand


Get-ExecutionPolicy -List sagt:

Scope ExecutionPolicy
----- ---------------
MachinePolicy Unrestricted
UserPolicy Undefined
Process Undefined
CurrentUser Undefined
LocalMachine Unrestricted
TK1987
TK1987 06.03.2023 aktualisiert um 19:04:44 Uhr
Goto Top
Eigentlich sollte er über das Kontextmenü die ExecutionPolicy auf ByPass setzen und ein setzen dieser somit nicht nötig sein. Scheint bei dir wohl (noch) nicht der Fall zu sein (ältere Windows Version?)

Dann muss du einmalig zuerst die Ausführung von Powershell-Skripten auf dem Rechner zulassen.

Das geht entweder für alle Benutzer auf dem Computer global (benötigt Administratorrechte) oder nur für den angemeldeten Benutzer (geht ohne Administratorrechte).

Rechtsklick auf das Windows-Startmenü (oder Tastenkombi Win+X), dann...
  • entweder Powershell (Administrator) auswählen bzw. Windows Terminal (Administrator) bei Windows 11 und folgenden Befehl ausführen
Set-ExecutionPolicy RemoteSigned -Force

  • oder Powershell bzw. Windows Terminal ohne Administrator starten und folgendes ausführen
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned -Force

Dadurch dürfen alle Powershell-Skripte, die lokal auf deinem Computer erstellt wurden ausgeführt werden. Skripte, die aus dem Internet heruntergeladen wurden müssen hingegen von einem vertrauenswürdigen Hersteller signiert sein.

Gruß Thomas
bluemen
bluemen 06.03.2023 aktualisiert um 19:17:21 Uhr
Goto Top
Ich benutze Win10.
Noch weigert sich PS weiterhin.

Hier die Ergebisse:

PS C:\WINDOWS\system32> Set-ExecutionPolicy RemoteSigned -Force
Set-ExecutionPolicy : Die Ausführungsrichtlinien wurden von Windows PowerShell erfolgreich aktualisiert, die
Einstellung wird jedoch von einer in einem spezielleren Bereich definierten Richtlinie überschrieben. Aufgrund der
Überschreibung wird die aktuelle geltende Ausführungsrichtlinie "Unrestricted" für die Shell beibehalten. Geben Sie
"Get-ExecutionPolicy -List" ein, um die Ausführungsrichtlinieneinstellungen anzuzeigen. Weitere Informationen erhalten
Sie mit "Get-Help Set-ExecutionPolicy".
In Zeile:1 Zeichen:1

back-to-topSet-ExecutionPolicy RemoteSigned -Force

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : PermissionDenied: (face-smile [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand


PS C:\WINDOWS\system32> Get-ExecutionPolicy -List

Scope ExecutionPolicy
----- ---------------
MachinePolicy Unrestricted
UserPolicy Undefined
Process Undefined
CurrentUser Undefined
LocalMachine RemoteSigned

Im Anschluss im Kontextmenü ausführen bringt folgende Meldung:

PS C:\WINDOWS\system32>
Set-ExecutionPolicy : Die Ausführungsrichtlinien wurden von Windows PowerShell erfolgreich aktualisiert, die
Einstellung wird jedoch von einer in einem spezielleren Bereich definierten Richtlinie überschrieben. Aufgrund der
Überschreibung wird die aktuelle geltende Ausführungsrichtlinie "Unrestricted" für die Shell beibehalten. Geben Sie
"Get-ExecutionPolicy -List" ein, um die Ausführungsrichtlinieneinstellungen anzuzeigen. Weitere Informationen erhalten
Sie mit "Get-Help Set-ExecutionPolicy".
In Zeile:1 Zeichen:46

back-to-top... -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'S ...

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : PermissionDenied: (face-smile [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
--- Alles erledigt. Wird beendet in 4 Sekunden. ---
TK1987
TK1987 06.03.2023 aktualisiert um 19:38:19 Uhr
Goto Top
Zitat von @bluemen:
Set-ExecutionPolicy : Die Ausführungsrichtlinien wurden von Windows PowerShell erfolgreich aktualisiert, die Einstellung wird jedoch von einer in einem spezielleren Bereich definierten Richtlinie überschrieben. Aufgrund der Überschreibung wird die aktuelle geltende Ausführungsrichtlinie "Unrestricted" für die Shell beibehalten.
Ist der Computer Teil einer Domäne?

MachinePolicy Unrestricted
Das ist keine Standardeinstellung, die muss irgendwann mal von jemandem gesetzt worden sein.

Man kann diese natürlich wieder zurücksetzen
Set-ExecutionPolicy -Scope MachinePolicy Undefined -Force
Set-ExecutionPolicy RemoteSigned -Force
Wenn du allerdings in einer Domäne bist und nicht der jeweilige Admin bist, sollte das abgesprochen werden
bluemen
bluemen 06.03.2023 um 19:40:03 Uhr
Goto Top
Nein, keine Domäne.
Nutze sonst, mangels Kenntnissen, PS nicht und habe, zumindest bewusst, nichts verändert.
bluemen
bluemen 06.03.2023 um 19:45:34 Uhr
Goto Top
Über die PS geht es anscheinend nicht.
Soll ich es über die MMC versuchen?


PS C:\WINDOWS\system32> Set-ExecutionPolicy -Scope MachinePolicy Undefined -Force
Set-ExecutionPolicy : Ausführungsrichtlinie kann nicht festgelegt werden. Ausführungsrichtlinien im MachinePolicy-
oder UserPolicy-Bereich müssen über Gruppenrichtlinien festgelegt werden.
In Zeile:1 Zeichen:1

back-to-topSet-ExecutionPolicy -Scope MachinePolicy Undefined -Force

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (face-smile [Set-ExecutionPolicy], InvalidOperationException
+ FullyQualifiedErrorId : CantSetGroupPolicy,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
PS C:\WINDOWS\system32> Set-ExecutionPolicy RemoteSigned -Force
Set-ExecutionPolicy : Die Ausführungsrichtlinien wurden von Windows PowerShell erfolgreich aktualisiert, die
Einstellung wird jedoch von einer in einem spezielleren Bereich definierten Richtlinie überschrieben. Aufgrund der
Überschreibung wird die aktuelle geltende Ausführungsrichtlinie "Unrestricted" für die Shell beibehalten. Geben Sie
"Get-ExecutionPolicy -List" ein, um die Ausführungsrichtlinieneinstellungen anzuzeigen. Weitere Informationen erhalten
Sie mit "Get-Help Set-ExecutionPolicy".
In Zeile:1 Zeichen:1

back-to-topSet-ExecutionPolicy RemoteSigned -Force

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : PermissionDenied: (face-smile [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
TK1987
TK1987 06.03.2023 um 20:01:38 Uhr
Goto Top
Zitat von @bluemen:
Über die PS geht es anscheinend nicht.
Soll ich es über die MMC versuchen?
Über die GPO, ja. Drücke Win+R und gebe
gpedit.msc
ein. Navigiere zu Computerkonfiguration > Administrative Vorlagen > Windows Komponenten > Windows PowerShell und gucke mal, auf was Skriptausführung aktivieren steht.
bluemen
bluemen 06.03.2023 um 20:09:06 Uhr
Goto Top
Das steht, Status: Aktiviert.
TK1987
TK1987 06.03.2023 aktualisiert um 21:20:00 Uhr
Goto Top
Zitat von @bluemen
Das steht, Status: Aktiviert.
Ich habe es gerade mal ausprobiert.

Mein Fehler: Unrestricted heisst natürlich Alle Skripte erlauben und nicht Alle Skripte Verbieten (Restricted). Dennoch ist genau diese GPO-Einstellung dein Problem. Setze sie auf "nicht konfiguriert", danach funktioniert es.

back-to-topHintergrund:
Wie ich oben bereits erwähnt habe, wird bei der Ausführung über das Kontextmenü eigentlich die ExecutionPolicy auf ByPass gesetzt, um Skripte, die so gestartet werden zuzulassen, ohne die Ausführungsrichtlinie extra setzen zu müssen.

Anhand deiner Fehlermeldung von 18:45 sieht man auch, dass er genau das versucht:
Zitat von @bluemen:
In Zeile:1 Zeichen:46
+ ... -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
Jedoch kommt es dann zu einem "Zugriff verweigert", weil die GPO-Einstellung hier Vorrang hat und sich nicht überschreiben lässt.

Gruß Thomas
bluemen
bluemen 06.03.2023 um 21:46:50 Uhr
Goto Top
Habe ich geändert. Fehlermeldung erscheint nicht mehr.

Das "aussortiert"-Verzeichnis erscheint allerdings nicht, wenn ich Dateien im Ursprung lösche.
Bin mir aber nicht sicher, ob das Script etwas getan hat. War quasi sofort fertig.
TK1987
TK1987 06.03.2023 um 22:24:57 Uhr
Goto Top
Zitat von @bluemen:
Das "aussortiert"-Verzeichnis erscheint allerdings nicht, wenn ich Dateien im Ursprung lösche.
aus dem jpg-Ordner?
Bin mir aber nicht sicher, ob das Script etwas getan hat. War quasi sofort fertig.
Alles, was das Skript tut, zeigt es auch an.

Erstellen wir mal eine Test-Umgebung. Führe in Powershell folgende Befehle aus:
"__DSC00814___.ARW.xmp","__DSC00814___01.ARW.xmp","__DSC00815___01.ARW.xmp","__DSC00815___.ARW","__DSC00816___.jpg" |%{ni -force "C:\Test\2023-02\jpg\$_"}  
ni -force "C:\Test\2023-02\__DSC00814___.jpg"  

Dadurch erhälst du folgende Struktur:
C:\Test
  └───2023-02
      │   __DSC00814___.jpg
      │
      └───jpg
            __DSC00814___.ARW.xmp
            __DSC00814___01.ARW.xmp
            __DSC00815___.ARW
            __DSC00815___01.ARW.xmp
            __DSC00816___.jpg

Die Dateien sind hier natürlich nur leere Textdateien, reicht aber für den Test. Ändere den Quellpfad auf "C:\Test" ab und führe das Skript aus. Dort sollte dann folgende Augabe erscheinen:

screenshot
bluemen
bluemen 06.03.2023 um 22:47:59 Uhr
Goto Top
Der Test hat funktioniert.
Ich habe auch den Fehler gefunden, warum das Script erst nichts getan hat.
Um bei deinem Beispiel zu bleiben, ich habe als Pfad C:\Test\2023-02 angegeben und es passierte nichts.
Wenn ich C:\Test verwende, funktioniert die Logik.
TK1987
TK1987 06.03.2023 um 23:01:37 Uhr
Goto Top
Ok, ändere Zeile 10 wie folgt ab, dann funktioniert es in beiden Fällen:
  $Files = Foreach ($dir in Get-ChildItem -Recurse -Directory $Quellpfad -Filter "jpg" | ? Fullname -NotMatch "converted|_aussortiert") {  
bluemen
bluemen 06.03.2023 um 23:15:08 Uhr
Goto Top
Sieht jetzt sehr gut aus.

Ich werde morgen noch mal alle Eventualitäten durchspielen aber schon jetzt meinen allergrößten Respekt und Dank, dass du so viel deiner Zeit für meinen Wunsch geopfert hast!
Schade das ich das selbst nicht so gut kann.

Vielen Dank
Bodo
TK1987
TK1987 06.03.2023 um 23:22:01 Uhr
Goto Top
Zitat von @bluemen:
Schade das ich das selbst nicht so gut kann.
Powershell Leitfaden für Anfänger

Gruß Thomas
bluemen
bluemen 06.03.2023 um 23:27:30 Uhr
Goto Top
Danke für den, dezenten, Hinweis. face-wink Wenngleich ich gern etwas hätte, was auch unter Linux verwendbar ist.
Aber ich versuche es! Ist schon beeindruckend, wie viel schneller es im Vergleich zu Batch arbeitet.

Gruß
Bodo
TK1987
TK1987 06.03.2023 um 23:43:16 Uhr
Goto Top
Zitat von @bluemen:
Wenngleich ich gern etwas hätte, was auch unter Linux verwendbar ist.
Powershell gibt es auch für Linux. Zwar gibt es dort nicht alle Module, aber das worauf es ankommt ist komplett vorhanden.

Das Skript oben wäre zum Beispiel auch unter Linux komplett lauffähig - lediglich die Pfadangaben müssten hier Linuxgemäß abgeändert werden - also Backslashes durch Slashes ersetzt werden.
bluemen
bluemen 06.03.2023 aktualisiert um 23:49:33 Uhr
Goto Top
Das klingt sehr gut!

... und hab' bereits mit dem Lesen der Lektüre zur PS begonnen. face-smile
bluemen
bluemen 07.03.2023 um 09:59:02 Uhr
Goto Top
Moin Thomas,

ich habe noch mal getestet. Dabei ist mir Nachfolgendes aufgefallen:

  • Wenn .ARW-Datei gelöscht wurde, wird die .XMP-Datei nicht entfernt (die .JPG-Datei aber schon).
  • Wenn .JPG-Datei gelöscht wurde, wird weder die .ARW-/ noch .XMP-Datei entfernt.


Nebenbei und (nur) falls es einfach umzusetzen ist.
Im Batch hatte ich mir folgende Möglichkeiten eingebaut, in PS habe ich (noch) keinen Plan:

Auswahl, ob:

1. nur die .JPG-Dateien (und evtl. im gleichen Verzeichnis enthaltene .XMP-Dateien) gelöscht werden sollen, zu denen es keine .ARW-Dateien gibt
2. nur die .ARW-&.XMP-Dateien gelöscht werden sollen, zu denen es keine .JPG-Dateien gibt
3. Punkt 1 & 2 kombiniert (im Grunde die aktuelle Logik)

Dabei soll 3. der Standard sein, wenn nur mit ENTER bestätigt wird.
TK1987
TK1987 07.03.2023, aktualisiert am 10.03.2023 um 07:40:35 Uhr
Goto Top
Zitat von @bluemen:
Nebenbei und (nur) falls es einfach umzusetzen ist.
Im Batch hatte ich mir folgende Möglichkeiten eingebaut, in PS habe ich (noch) keinen Plan:
Was mit Batch geht, ist mit Powershell ein Kinderspiel.

Wie wäre es denn damit:
$Quellordner = "S:\test2\2021-06"  

# Funktion zum aussorieren der Dateien
  Function Aussortieren {
    [CmdletBinding()]Param([Parameter(Mandatory,ValueFromPipeline)][IO.FileInfo[]]$File)
    BEGIN   {$Files = @()}
    PROCESS {$Files += $File}
    END     {
      Foreach ($Group in $Files | Group {$_.DirectoryName -Replace "(?=\\jpg$)|(?<!\\jpg)$","_aussortiert"}) {  
        # Wenn Ordner nicht existiert, erstellen
        if (!(Test-Path -PathType Container $Group.Name)) {
          Write-Host -N ('Erstelle Ordner:  {0,-52} ' -f $Group.Name)  
          [void](md -force $Group.Name)
          Write-Host -F Green "[ok]"  
        } else {Write-Host ('Ordner existiert: {0} ' -f $Group.Name)}  
        # Verschiebe Dateien
        Foreach ($File in $Group.Group) {
          Write-Host -N ('     └-->   {0,-58} ' -f $File.Name)  
          move -Force -Path $File -Destination $Group.Name
          Write-Host -F green "[ok]"  
        }
        ""  
      }
    }
  }

# GUI-Modul laden
  Add-Type -A System.Windows.Forms
  [Windows.Forms.Application]::EnableVisualStyles()

# Modul, um Konsolenfenster zu verstecken / anzuzeigen
  $window = Add-Type -MemberDefinition "[DllImport(""user32.dll"")]`npublic static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);" -name "Win32ShowWindowAsync" -namespace Win32Functions -PassThru  
  $Handle = (PS -Id $PID).MainWindowHandle
  [Void]$window::ShowWindow($Handle, 0)

# Fensterelemente
  $Form = [Windows.Forms.Form]@{Text='Bilder löschen'; StartPosition='CenterScreen'; Size="100,100"; FormBorderStyle='FixedSingle'; AutoSize=$true; Margin='10,10,10,10'; KeyPreview=$true; Font=[Drawing.Font]::New("Microsoft Sans Serif",12,[Drawing.FontStyle]"Bold")}  
  $FlowPanel = [Windows.Forms.FlowLayoutPanel]@{FlowDirection='TopDown'; AutoSize=$true; Dock='Fill'; Padding='10,10,10,10'}  
  $Buttons = @(
    [Windows.Forms.Button]@{Name='JPG'; Text='JPG und XMP';      Size="250,60"; TabIndex=1; Margin='10,10,10,10'}  
    [Windows.Forms.Button]@{Name='ARW'; Text='ARW und XMP';      Size="250,60"; TabIndex=2; Margin='10,10,10,10'}  
    [Windows.Forms.Button]@{Name='All'; Text='JPG, ARW und XMP'; Size="250,60"; TabIndex=0; Margin='10,10,10,10'}  
  )

# Fenster zusammenfügen
  $FlowPanel.Controls.AddRange($Buttons)
  $Form.Controls.Add($FlowPanel)
  
# Eventhandler
  
  # Bei Buttonklick, Fenstertag auf Buttontext setzen und Fenster schließen
    $Buttons.Add_Click({
      $this.TopLevelControl.Tag = $this.Name
      $this.TopLevelControl.Hide()
    })
  
  # Tastatursteuerung aktivieren: Escape="Abbrechen", 1="Option 1", 2="Option 2", 3="Option 3" 
    $Form.Add_KeyDown({
      switch -Regex ($_.KeyCode) {
        "^Escape$" {$this.Hide()}  
        "^(D|Numpad)1$" {$This.Controls.Controls["JPG"].PerformClick();break}  
        "^(D|Numpad)2$" {$This.Controls.Controls["ARW"].PerformClick();break}  
        "^(D|Numpad)3$" {$This.Controls.Controls["ALL"].PerformClick();break}  
      }
    })

  # Beim laden des Fensters
    $Form.Add_Load({
      # Ordnerliste laden
      Add-Member -Inp $this NoteProperty "Dirs"  (Get-ChildItem -Recurse -Directory $Quellordner -Filter "JPG" | ? FullName -NotMatch 'converted|_aussortiert')  
    })

# Ausführung

  # Bei Fehlern, Skript stoppen (Sprung in Catch-Block)
  $ErrorActionPreference = 'stop'  
  try {
    [void]$Form.ShowDialog()
    $Files = @()
    switch -r ($Form.Tag) {
      "ALL|JPG" {  
        Foreach ($dir in $Form.dirs) {
          Foreach ($file in Get-ChildItem -File "$($dir.FullName)\*.jpg" | ?{!(Test-Path "$($dir.Parent.Fullname)\$($_.BaseName).arw")}){  
            $Files += $file
            $Files += Get-ChildItem "$($File.DirectoryName)\$($File.BaseName)*.xm?"  
          }
        }
      }
      "ALL|ARW" {  
        Foreach ($dir in $Form.dirs) {
          Foreach ($File in Get-ChildItem "$($dir.Parent.Fullname)\*.arw"|?{!(Test-Path "$($dir.Fullname)\$($_.BaseName).jpg")}) {  
            $Files += $File
            $Files += Get-ChildItem "$($File.DirectoryName)\$($File.BaseName)*.xm?"  
          }
        }
      }
      "ALL|ARW|JPG" {  
        $Files += Foreach ($dir in $Form.Dirs) {
          Get-ChildItem "$($dir.Parent.Fullname)\*.xm?" |?{!(Test-Path "$($_.DirectoryName)\$($_.BaseName -Replace "(?<=_)\d*(\.arw)?").arw")}  
          Get-ChildItem "$($dir.Fullname)\*.xm?" |?{!(Test-Path "$($_.DirectoryName)\$($_.BaseName -Replace "(?<=_)\d*(\.jpg)?").jpg")}  
        }
        if ($Files) {Aussortieren $Files}
        break
      }
      $Null {Return}
      Default                                       {throw "Falscher Wert im Fenstertag"}  
    }
    [void]$window::ShowWindow($Handle, 1)
    
    Foreach ($i in 5..1) {
      Write-Host -f green -N ("`r---   Alles erledigt. Wird beendet in {0,2} Sekunden.  ---" -f $i)  
      sleep 1
    }
  }
  # Bei Fehlern, Meldung ausgeben und Skript anhalten
  catch {
    [void]$window::ShowWindow($Handle, 1)
    Write-Host -F red $_.Exception.Message
    Write-Host -N "---   Beliebige Taste zum Beenden   ---"  
    [void][console]::ReadKey($true)
  }

Wie gewünscht, 3 ist ausgewählt und kann mit Enter gestartet werden.
Du kannst sowohl über die Pfeiltasten zu den anderen Buttons navigieren, als natürlich auch mit der Maus.
Zudem kannst du auch über die Zahlentasten 1-3 den jeweiligen Button ausführen.
Escape-Button oder Schließen des Fensters beenden das Skript.

Gruß Thomas
bluemen
bluemen 07.03.2023 um 15:45:18 Uhr
Goto Top
Aktuell werden bei 1 oder 3 alle JPGs (ob es auch für evtl. enthaltende .XMPs gilt, habe ich nicht getestet) verschoben, bei 2 und 3 werden die .XMPs und .ARWs nicht bearbeitet.
TK1987
TK1987 07.03.2023 aktualisiert um 16:07:37 Uhr
Goto Top
Zitat von @bluemen:
Aktuell werden bei 1 oder 3 alle JPGs (ob es auch für evtl. enthaltende .XMPs gilt, habe ich nicht getestet) verschoben, bei 2 und 3 werden die .XMPs und .ARWs nicht bearbeitet.
Kleiner Zeichenfehler mit Großer Wirkung. Ergänze in Zeile 59 ein Dollarzeichen am ende der Zeichenkette nach dem replace. Das sollte dann so aussehen:
... -replace "\d*(\.ARW)?$"  
dann dürfte es passen.

Habe es oben auch angepasst.
bluemen
bluemen 07.03.2023 um 16:26:20 Uhr
Goto Top
Habe ich gemacht.
1 funktioniert jetzt, bei
2 und 3 werden die .XMPs und .ARWs nicht bearbeitet.
habe ich keine Veränderung festgestellt.
TK1987
TK1987 07.03.2023 um 16:42:08 Uhr
Goto Top
Zitat von @bluemen:
1 funktioniert jetzt, bei
2 und 3 werden die .XMPs und .ARWs nicht bearbeitet.
habe ich keine Veränderung festgestellt.
Klappt hier im Test problemlos. Oder hast du auch gleichnamige ARW- bzw. XMP-Dateien im übergeordneten Ordner liegen?

Zeige mal Bitte deine Ordnerstruktur:
ls -r -file "C:\Pfad\zum\Quellordner" | select -Expand Fullname  
bluemen
bluemen 07.03.2023 um 16:57:33 Uhr
Goto Top
Das Testverzeichnis:

PS C:\WINDOWS\system32> ls -r -file "S:\test2\2021-06" | select -Expand Fullname
S:\test2\2021-06\2021-06-02-__A7305881____.ARW.xmp
S:\test2\2021-06\2021-06-03-__A7305882____.ARW.xmp
S:\test2\2021-06\2021-06-03-__A7305883____.ARW
S:\test2\2021-06\2021-06-03-__A7305883____.ARW - Kopie.xmp
S:\test2\2021-06\2021-06-03-__A7305883____.ARW.xmp
S:\test2\2021-06\2021-06-03-__A7305883____01.ARW.xmp
S:\test2\2021-06\2021-06-03-__A7305884____.ARW
S:\test2\2021-06\2021-06-03-__A7305884____.ARW.xmp
S:\test2\2021-06\2021-06-03-__A7305886____.ARW
S:\test2\2021-06\2021-06-03-__A7305886____.ARW.xmp
S:\test2\2021-06\2021-06-06-__A7305888____.ARW
S:\test2\2021-06\2021-06-06-__A7305888____.ARW.xmp
S:\test2\2021-06\2021-06-06-__A7305889____.ARW
S:\test2\2021-06\2021-06-06-__A7305889____.ARW.xmp
S:\test2\2021-06\2021-06-06-__A7305890____.ARW
S:\test2\2021-06\2021-06-06-__A7305890____.ARW.xmp
S:\test2\2021-06\2021-06-06-__A7305891____.ARW
S:\test2\2021-06\2021-06-06-__A7305892____.ARW
S:\test2\2021-06\2021-06-06-__A7305892____.ARW.xmp
S:\test2\2021-06\2021-06-12-__A7305895____.ARW
S:\test2\2021-06\2021-06-12-__A7305895____.ARW.xmp
S:\test2\2021-06\2021-06-12-__A7305896____.ARW
S:\test2\2021-06\2021-06-12-__A7305896____.ARW.xmp
S:\test2\2021-06\2021-06-12-__A7305897____.ARW
S:\test2\2021-06\2021-06-12-__A7305897____.ARW.xmp
S:\test2\2021-06\2021-06-12-__A7305898____.ARW
S:\test2\2021-06\2021-06-12-__A7305898____.ARW.xmp
S:\test2\2021-06\2021-06-12-__A7305901____.ARW
S:\test2\2021-06\2021-06-12-__A7305901____.ARW.xmp
S:\test2\2021-06\2021-06-12-__A7305908____.ARW
S:\test2\2021-06\converted\2021-06-14-__A7305951____.jpg
S:\test2\2021-06\jpg\2021-06-02-__A7305881____.JPG
S:\test2\2021-06\jpg\2021-06-03-__A7305882____.JPG
S:\test2\2021-06\jpg\2021-06-03-__A7305883____.JPG
S:\test2\2021-06\jpg\2021-06-03-__A7305884____.JPG
S:\test2\2021-06\jpg\2021-06-03-__A7305886____.JPG
S:\test2\2021-06\jpg\2021-06-06-__A7305888____.JPG
S:\test2\2021-06\jpg\2021-06-06-__A7305889____.JPG
S:\test2\2021-06\jpg\2021-06-06-__A7305890____.JPG
S:\test2\2021-06\jpg\2021-06-06-__A7305891____.JPG
S:\test2\2021-06\jpg\2021-06-06-__A7305892____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305895____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305897____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305898____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305901____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305908____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305910____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305912____.JPG
S:\test2\2021-06\jpg\2021-06-12-__A7305915____.JPG
PS C:\WINDOWS\system32>
TK1987
TK1987 07.03.2023 um 18:49:25 Uhr
Goto Top
Zitat von @bluemen:
Das Testverzeichnis:
Achsooo... ich dachte die ganze Zeit, die ARW- bzw. XMP-Dateien, die verschoben werden sollen liegen auch unter "\jpg", siehe auch meinen Testordner von gestern.

Das kann dann natürlich nicht funktionieren. Ich werde es morgen abändern, hab heute leider keine Zeit mehr.

Gruß Thomas
bluemen
bluemen 07.03.2023 um 18:53:50 Uhr
Goto Top
Sorry, das hatte ich bei deinem Testordner nicht bemerkt.

Gar kein Problem, wenn es morgen wird. Bin ja sehr froh, dass du meine Wünsche erfüllst. face-smile
Bodo
TK1987
TK1987 08.03.2023 aktualisiert um 11:40:18 Uhr
Goto Top
Moin Bodo,

ich habe das Skript oben angepasst.

Bei meinen Tests ist mir allerdings noch eine kleine Unklarheit augefallen:
Wenn zu einer JPG-Datei keine ARW-Datei im Ordner darüber existiert, wird diese ja bisher aussortiert.
Was aber, wenn eine XMP-Datei existiert - soll die JPG dann trotzdem aussortiert werden?

Falls ja, kannst du das Skript so nehmen. Falls nein, ergänze in Zeile 82 am Ende hinter dem ".arw" noch einen Stern:
... ?{!(Test-Path ("$($dir.Parent.Fullname)\$($_.BaseName+"*.arw*")"))}}  

Gruß Thomas
bluemen
bluemen 08.03.2023 um 16:48:09 Uhr
Goto Top
Hallo Thomas,

die gewünschte Logik ist wie folgt:

Auswahl 1:
.JPG und evtl. .XML im Unterordner /JPG löschen, wenn im darüber liegenden Ordner kein .ARW existiert (eine evtl. hier noch vorhandene .XML könnte ebenfalls mit gelöscht werden)
Auswahl 2:
.ARW und .XML löschen, wenn im Unterordner /JPG kein .JPG existiert (eine evtl. hier noch vorhandene .XML könnte ebenfalls mit gelöscht werden)
Auswahl 3:
1 und 2 kombinieren.

Hintergrund: Die .XML enthält die Bearbeitungsinformationen zum zugehörigen Bild. Ist die Bilddatei nicht mehr existent, erübrigt sich auch das .XML-File.

Ich bin noch nicht zum Testen gekommen, melde mich später.

Gruß
Bodo
TK1987
TK1987 08.03.2023 um 17:07:13 Uhr
Goto Top
Zitat von @bluemen:
Auswahl 1:
.JPG und evtl. .XML im Unterordner /JPG löschen, wenn im darüber liegenden Ordner kein .ARW existiert (eine evtl. hier noch vorhandene .XML könnte ebenfalls mit gelöscht werden)
Auswahl 2:
.ARW und .XML löschen, wenn im Unterordner /JPG kein .JPG existiert (eine evtl. hier noch vorhandene .XML könnte ebenfalls mit gelöscht werden)
Auswahl 3:
1 und 2 kombinieren.
du meinst .XMP, oder?

Ich bin noch nicht zum Testen gekommen, melde mich später.
Damit kannst du dann noch warten, wir haben schon wieder aneinander vorbei geredet.

Ich bin davon ausgegangen, dass die XMP wie im Test-Ordner immer in dem übergeordneten Ordner bei den ARW's liegen. Somit funktioniert derzeit nur Auswahl 2. Auswahl 1 muss ich dann noch mal anpassen.

Gruß Thomas
TK1987
TK1987 09.03.2023 aktualisiert um 07:56:23 Uhr
Goto Top
Moin Bodo,

jetzt dürfte alles passen.

Gruß Thomas
bluemen
bluemen 09.03.2023 um 12:14:37 Uhr
Goto Top
Hallo Thomas,

ich traue mich kaum noch zu schreiben aber allein bekomme ich es nicht hin.
Folgendes habe ich festgestellt (und hoffentlich nichts übersehen):
Wenn ich meinen Testordner verwende, wird bei Auswahl von Menüpunkt 1 oder 3 die Datei 2021-06-12-__A7305896____.ARW.xmp gelöscht, obwohl die zugehörige .ARW vorhanden ist. Eine, testweise, im Unterordner /JPG, eingefügte 2021-06-12-__A7305901____.JPG.XMP, wird jedoch nicht gelöscht, wenn die zugehörige .JPG nicht mehr vorhanden ist.


Und ich hätte gern gewusst, wofür das â""--> steht.
1
TK1987
TK1987 09.03.2023 aktualisiert um 13:48:26 Uhr
Goto Top
ich traue mich kaum noch zu schreiben aber allein bekomme ich es nicht hin.
alles gut, kann nicht mehr viel sein face-wink

Folgendes habe ich festgestellt (und hoffentlich nichts übersehen):
Versuche es jetzt noch mal bitte.

Und ich hätte gern gewusst, wofür das â""--> steht.
Das liegt an einer falschen Zeichenkodierung. Wie Oben im Skript zu sehen:
          Write-Host -N ('     └-->   {0,-58} ' -f $File.Name)  
soll hier eigentlich das Zeichen "└" erscheinen. Vermutlich hast du die Datei in UTF-8 ohne BOM gespeichert. Da Powershell die Kodierung in dem Fall nicht identifizieren kann, wird der Systemstandard (sofern nicht anders eingestellt: ANSI-Kodierung) genommen und somit die falsche Zeichentabelle geladen.

Speichere die Datei entweder in Ansi-Kodierung ab, oder als UTF-8 mit BOM - dann wird das Zeichen korrekt dargestellt. Am besten immer letzteres für Powershell-Skripte verwenden.

Gruß Thomas
TK1987
TK1987 09.03.2023 um 13:58:52 Uhr
Goto Top
Habe gerade noch einen kleinen Fehler korrigiert. Bitte noch mal neu nehmen, falls du das zwischenzeitlich schon getan hattest.
bluemen
bluemen 09.03.2023 um 17:15:35 Uhr
Goto Top
Hi Thomas,

ich glaube jetzt passt es! face-smile

Eine Frage noch, die Datei 2021-06-03-__A7305883____.ARW - Kopie.xmp wurde aussortiert, 2021-06-03-__A7305883____01.ARW.xmp. So war auch der Wunsch. Verrätst du mir, an welcher Stelle die Auswertung erfolgt?

Ansonsten bleibt mir noch noch viiiiielen Dank zu sagen, für deine Geduld und Hilfe. Und ich hoffe, es lesen nicht zu viele, ansonsten wirst du sehr beschäftigt sein! face-smile

Gruß
Bodo
bluemen
bluemen 09.03.2023 um 17:55:13 Uhr
Goto Top
Ich habe das Script nun auf ein Jahresarchiv losgelassen.
Menüpunkt 3
Einiges wird bearbeitet, dann steigt es aus, da die Datei angeblich nicht da ist, die es selbst vorher bearbeitet hat ...?
2
3
bluemen
bluemen 09.03.2023 aktualisiert um 18:54:13 Uhr
Goto Top
Ich sehe gerade, die Datei 2022-05-28-__A7304628__XXX__01.ARW.xmp hätte nicht gelöscht werden sollen, da sowohl das .JPG, als auch .ARW vorhanden ist.
Die Datei 2022-05-28-__A7304628__XXX__.ARW.xmp ist weiterhin vorhanden, nur die *01.ARW.xmp wurde verschoben.

Statt dem ___XXX___ stehen da manchmal Anmerkungen, eine alte Angewohnheit, die durch Tags obsolet ist. Vermutlich liegt es an dem zusätzlichen Text. Kann der bleiben?
TK1987
TK1987 10.03.2023 aktualisiert um 09:53:04 Uhr
Goto Top
Zitat von @bluemen:
Einiges wird bearbeitet, dann steigt es aus, da die Datei angeblich nicht da ist, die es selbst vorher bearbeitet hat
Ich habe den Fehler noch gefunden. Gemäß deinem Bild, hast du die Kodierung der Datei aber noch nicht geändert.

Ich sehe gerade, die Datei 2022-05-28-__A7304628__XXX__01.ARW.xmp hätte nicht gelöscht werden sollen, da sowohl das .JPG, als auch .ARW vorhanden ist.
Ist dieses "XXX" in dem Fall auch in dem Dateinamen der JPG- oder ARW-Datei vorhanden? Wenn nein, ist klar, warum er diese verschoben hat.

Statt dem ___XXX___ stehen da manchmal Anmerkungen, eine alte Angewohnheit, die durch Tags obsolet ist. Vermutlich liegt es an dem zusätzlichen Text. Kann der bleiben?
Ich nehme an, diese Anmerkungen stehen dann auch hier nicht in den Dateinamen der ARW- bzw. JPG-Datei?
Das ist grundsätzlich natürlich möglich.

Wie wäre folgendes von der Logik her:
Ich überprüfe bei den XMP-Dateien nur den vorderen Teil bis zur Nummer, also z.B. nur "2022-05-28-__A7304628". Ist eine ARW- bzw. JPG Datei mit diesem Teil vorhanden, ist es dann egal, was ab dem Unterstrich bei den XMP-Dateien dahinter folgt. Spricht da irgendetwas gegen?

Versuchen wir mal einen anderen Ansatz:
Wir lassen das Menü und Verschieben erst mal weg und konzentrieren uns nur auf das Aufspüren der Dateien.
So wird zum einen das Überprüfen erheblich leichter, zum anderen ist der Rest sowieso kein Problem mehr, wenn wir die Dateien erst mal aufgespürt haben.

Fangen wir mal mit den JPG-Dateien, sowie den dazugehörigen XMP's an. Öffne Powershell und führe folgendes aus:
Foreach ($Dir in Get-ChildItem -Path "S:\test2\2021-06" -Filter "JPG") {  
  Foreach ($File in Get-ChildItem $Dir.Fullname -Filter "*.jpg" | ?{!(Test-Path "$($Dir.Parent.Fullname)\$($_.BaseName)*.arw")}) {  
    $File.Fullname
    (Get-ChildItem $Dir.Fullname -Filter (($File.Basename -Replace '(?<=\d)_*?$')+"*.xmp")).Fullname  
  }
}
Den Ordner "S:\test2\2021-06" kannst du auch mal durch dein Jahresarchiv ersetzen. Werden hier alle JPG- und XMP-Dateien zufriedenstellend aufgelistet?
bluemen
bluemen 10.03.2023 um 10:41:16 Uhr
Goto Top
Hallo Thomas,

dass "XXX" ist ein Synonym für Informationen wie z.B. Ort oder Anlass des Fotos und wird, wenn vorhanden, durch ein Script bei allen Dateien (.JPG und .ARW) an die gleiche Stelle geschrieben. Die .XMP-Datei wird erst später durch ein anderes Programm erzeugt und erhält den Namen der .JPG bzw. .ARW.

Dein Vorschlag klingt gut. Das Datum und das A mit der nachfolgenden Ziffer + die Erweiterung (JPG/ARW) sind für die Identifizierung entscheidend.

Das Testscript macht nix, nach Enter ist es "nur da", mehr nicht. Was mache ich falsch?
TK1987
TK1987 10.03.2023 aktualisiert um 11:04:01 Uhr
Goto Top
Zitat von @bluemen:
Dein Vorschlag klingt gut. Das Datum und das A mit der nachfolgenden Ziffer + die Erweiterung (JPG/ARW) sind für die Identifizierung entscheidend.
Also fangen die Dateinamen immer mit Datum und die Nummer immert mit einem A an, gut zu wissen.

Das Testscript macht nix, nach Enter ist es "nur da", mehr nicht. Was mache ich falsch?
Liegt an mir, ich habe beim Suchen der JPG-Ordner den Recurse-Parameter vergessen, somit sucht nur im Quellverzeichnis und nicht in Unterordnern.
Foreach ($Dir in Get-ChildItem -Recurse -Path "S:\test2\2021-06" -Filter "JPG" |? FullName -NotMatch "_aussortiert|converted") {  
  Foreach ($File in Get-ChildItem $Dir.Fullname -Filter "*.jpg" | ?{!(Test-Path "$($Dir.Parent.Fullname)\$($_.BaseName)*.arw")}) {  
    $File.Fullname
    (Get-ChildItem $Dir.Fullname -Filter (($File.Basename -Replace "(?<=^\d{4}-\d{2}-\d{2}-__A\d+)_.*$")+"*.xmp")).Fullname  
  }
}
bluemen
bluemen 10.03.2023 um 11:22:29 Uhr
Goto Top
Ich denke, dass es gut wäre, wenn beim Aufbau des Dateinamens nicht reglementiert wird, sondern nur auf gleiche Dateinamen geprüft wird.
Mit der Ausnahme, dass es mehrere .XMP-Dateien geben kann, welche sich darin unterscheiden, dass der Dateiname um einen Zähler erweitert wird, z.B. 01.ARW.xmp. Das ist zumindest die aktuelle Programmlogik, an der ich nichts ändern kann.

So kann sich der Aufbau des Dateinamens ändern und es müsste im Script nichts angepasst werden.
Was meinst du dazu?
TK1987
TK1987 10.03.2023 um 11:34:39 Uhr
Goto Top
Zitat von @bluemen:
Ich denke, dass es gut wäre, wenn beim Aufbau des Dateinamens nicht reglementiert wird, sondern nur auf gleiche Dateinamen geprüft wird.
Sofern ich dich richtig verstanden habe, hast du doch Dateien wie:
2022-05-28-__A7304628____.ARW
2022-05-28-__A7304628__Irgend-ein-Text__01.ARW.xmp
und die XMP-Datei soll in diesem Fall dann erhalten bleiben.
Der Dateiname hier ist ja nun mal nicht gleich, irgendwo muss man also sagen: "Wenn der Dateiname bis ... gleich ist, dann... "
bluemen
bluemen 10.03.2023 um 11:44:59 Uhr
Goto Top
So habe ich das nicht gemeint.

Dein Beispiel kann so aussehen:
2022-05-28-__A7304628____.ARW
2022-05-28-__A7304628____.ARW.xmp
2022-05-28-__A7304628____01.ARW.xmp
2022-05-28-__A7304628____02.ARW.xmp
2022-05-28-__A7304628____03.ARW.xmp

/JPG
2022-05-28-__A7304628____.JPG
2022-05-28-__A7304628____.JPG
2022-05-28-__A7304628____01.JPG.xmp
2022-05-28-__A7304628____02.JPG.xmp

Der Name, in dem Beispiel 2022-05-28-__A7304628____, ist immer gleich.
Oder es heißen alle 2022-05-28-__A7304628__irgendwas__.
Das gilt für die .ARW, .JPG und .XMP. Letztere können aber, da mehrere möglich, um einen Zähler (01,02,03,...) erweitert sein, also 2022-05-28-__A7304628____01.ARW.xmp.


Diesen Fall darf es nicht geben, da dass Bildbearbeitungsprogramm die sonst die .XMP nicht der .ARW zuordnen könnte.
2022-05-28-__A7304628____.ARW
2022-05-28-__A7304628__Irgend-ein-Text__01.ARW.xmp
bluemen
bluemen 10.03.2023 aktualisiert um 12:11:57 Uhr
Goto Top
Zukünftig könnte sich der Aufbau des Namens ändern.
Z.B. 2022-05-28-__YX4DF04628-- oder so.
Deshalb möglichst nur eine Prüfung auf Gleichheit.
TK1987
TK1987 10.03.2023 um 11:50:49 Uhr
Goto Top
Dann so:
Foreach ($Dir in Get-ChildItem -Recurse -Path "S:\test2\2021-06" -Filter "JPG" |? FullName -NotMatch "_aussortiert|converted") {  
  Foreach ($File in Get-ChildItem $Dir.Fullname -Filter "*.jpg" | ?{!(Test-Path "$($Dir.Parent.Fullname)\$($_.BaseName).arw")}) {  
    $File.Fullname
    (Get-ChildItem $Dir.Fullname -Filter ($File.Basename+"*.xmp")).Fullname  
  }
}
bluemen
bluemen 10.03.2023 um 12:17:40 Uhr
Goto Top
Für die .JPG sollte es so passen.
TK1987
TK1987 10.03.2023 um 12:23:49 Uhr
Goto Top
Dann steht das schon mal. Das selbe nun in grün für die ARW-Dateien:
Foreach ($Dir in Get-ChildItem -Recurse -Path "S:\test2\2021-06" -Filter "JPG" |? FullName -NotMatch "_aussortiert|converted") {  
  Foreach ($File in Get-ChildItem $Dir.Parent.Fullname -Filter "*.arw" | ?{!(Test-Path "$($Dir.Fullname)\$($_.BaseName).jpg")}) {  
    $File.Fullname
    (Get-ChildItem $Dir.Parent.Fullname -Filter ($File.Basename+"*.xmp")).Fullname  
  }
}
bluemen
bluemen 10.03.2023 um 12:45:15 Uhr
Goto Top
Denke, das passt auch.

Würdest du mir erklären, warum in der ersten Zeile auch jetzt -Filter "JPG" steht?
TK1987
TK1987 10.03.2023 um 13:07:49 Uhr
Goto Top
Zitat von @bluemen:
Würdest du mir erklären, warum in der ersten Zeile auch jetzt -Filter "JPG" steht?
Ich lasse zuerst alle "JPG"-Ordner suchen. Von diesen ausgehend gehe ich dann mit ".Parent" einen Ordner höher und schaue da nach den ARW-Dateien.

Du fragst dich nun vielleicht: Warum nicht einfach direkt nach den ARW-Dateien suchen?
Wäre natürlich auch möglich, jedoch willst du ja Pfade, die "converted" oder "_aussortiert" enthalten von der Suche ausschließen.
Hier ist es dann einfach effizienter, zuerst die Ordner aufzulisten, bei denen diese Begriffe nicht im Pfad enthalten sind, anstatt direkt alle Dateien auflisten zu lassen und dann solche ausblenden zu lassen, die in derartigen Pfaden liegen.

Zuguter letzt noch die XMP-Dateien, zu denen keine ARW- bzw. JPG-Datei mehr vorhanden ist:
Foreach ($Dir in Get-ChildItem -Recurse -Path "S:\test2\2021-06" -Filter "JPG" |? FullName -NotMatch "_aussortiert|converted") {  
  (Get-ChildItem $Dir.Parent.FullName -Filter "*.xmp"|?{!(Test-Path "$($_.DirectoryName)\$($_.BaseName -replace '\d*(?=\.arw$)')")}).Fullname  
  (Get-ChildItem $Dir.FullName        -Filter "*.xmp"|?{!(Test-Path "$($_.DirectoryName)\$($_.BaseName -replace '\d*(?=\.jpg$)')")}).Fullname  
}
bluemen
bluemen 10.03.2023 um 13:33:13 Uhr
Goto Top
Danke für die Erklärung!

Auch die .XMP scheinen korrekt gefiltert zu werden. Habe es immer mit dem Testordner durchgespielt.
Das Jahresarchiv enthält mehrere 10.000 Bilder, das war mir zu heftig. face-smile

Wenn ich es richtig sehe, wird genau nach *.ARW.XMP gesucht.
2021-06-03-__A7305883____.ARW - Kopie.xmp wurde z.B. aussortiert, was auch der Logik entspricht.
TK1987
TK1987 10.03.2023 um 14:01:10 Uhr
Goto Top
Zitat von @bluemen:
Wenn ich es richtig sehe, wird genau nach *.ARW.XMP gesucht.
Jein.

Erst mal ein bisschen Hintergundwissen:
Bei den meisten Powershell-Befehlen bekommst du ein Objekt mit Eigenschaften zurück.
Stell es dir einfach wie eine Tabelle vor - diese kann auch mehrdimensional sein, also ein Zellwert kann eine weitere Tabelle sein.

Wenn du zum Beispiel im Dateiexplorer guckst, hast du dort ja auch nicht nur die Dateinamen stehen, sondern noch weitere Eigenschften wie z.B. Dateityp, Änderungsdatum, Dateigröße usw. aufgelistet.

In Powershell kann man dann ganz einfach auf diese Eigenschaften zurückgreifen.
Als Beispiel einfach mal zum ausprobieren:
# Datei in Variable speichern
$File = Get-Item "S:\test2\2021-06\2021-06-02-__A7305881____.ARW.xmp"  

# Änderungsdatum der Datei anzeigen
$File.LastWriteTime

Du kannst dir dann auch Anzeigen lassen, welche Eigenschaften ein Objekt besitzt:
$File | Get-Member
oder das Objekt mit sämtlichen Eigenschaften anzeigen lassen:
$File | Select *

Nun zurück zum Thema.
Ich lasse die XMP-Dateien auflisten und nehme von diesen anschließend nur noch die ".BaseName"-Eigenschaft, das ist der Dateiname ohne die jeweilige Erweiterung.
So wird aus "2021-06-02-__A7305881____01.ARW.xmp" schon mal nur noch "S:\test2\2021-06\2021-06-02-__A7305881____01.ARW".

Dann sage ich über Reguläre Ausdrücke, er soll alle Zahlen, die direkt vor dem ".arw" stehen entfernen.

Das kannst du auch einfach mal in Powershell ausprobieren:
"2021-06-02-__A7305881____01.ARW" -Replace "\d*(?=\.arw$)"  
bekommst du als Ergebnis nur noch "2021-06-02-__A7305881____.ARW" ohne die 01,02, 03... zurück.

Damit habe ich somit den Dateinamen, den ich überprüfen kann.
bluemen
bluemen 10.03.2023 um 14:18:09 Uhr
Goto Top
Sehr interessant! Ich bin begeistert!

$File | Select *

Aber warum ist das CreationTime nach LastWriteTime?

FullName : S:\test2\2021-06\2021-06-02-__A7305881____.ARW.xmp
Extension : .xmp
CreationTime : 07.03.2023 15:32:04
CreationTimeUtc : 07.03.2023 14:32:04
LastAccessTime : 07.03.2023 15:32:04
LastAccessTimeUtc : 07.03.2023 14:32:04
LastWriteTime : 25.12.2022 15:29:22
LastWriteTimeUtc : 25.12.2022 14:29:22
Attributes : Archive
TK1987
TK1987 10.03.2023 um 14:26:59 Uhr
Goto Top
Zitat von @bluemen:
Aber warum ist das CreationTime nach LastWriteTime?
Beim Kopieren von Dateien bleibt das Änderungsdatum gleich, das Erstelldatum der Kopie ist jedoch der Zeitpunkt des Kopiervorgangs.

So dürfte dann jetzt auch alles funktionieren:
$Quellordner = "S:\test2\2021-06"  

# Funktion zum aussorieren der Dateien
  Function Aussortieren {
    [CmdletBinding()]Param([Parameter(Mandatory,ValueFromPipeline)][IO.FileInfo[]]$File)
    BEGIN   {$Files = @()}
    PROCESS {$Files += $File}
    END     {
      Foreach ($Group in $Files | Select -Unique | Group {$_.DirectoryName -Replace "(?=\\jpg$)|(?<!\\jpg)$","_aussortiert"}) {  
        # Wenn Ordner nicht existiert, erstellen
        if (!(Test-Path -PathType Container $Group.Name)) {
          Write-Host -N ('Erstelle Ordner:  {0,-52} ' -f $Group.Name)  
          [void](md -force $Group.Name)
          Write-Host -F Green "[ok]"  
        } else {Write-Host ('Ordner existiert: {0} ' -f $Group.Name)}  
        # Verschiebe Dateien
        Foreach ($File in $Group.Group) {
          Write-Host -N ('     └-->   {0,-58} ' -f $File.Name)  
          move -Force -Path $File.Fullname -Destination $Group.Name
          Write-Host -F green "[ok]"  
        }
        ""  
      }
    }
  }

# GUI-Modul laden
  Add-Type -A System.Windows.Forms
  [Windows.Forms.Application]::EnableVisualStyles()

# Modul, um Konsolenfenster zu verstecken / anzuzeigen
  $window = Add-Type -MemberDefinition "[DllImport(""user32.dll"")]`npublic static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);" -name "Win32ShowWindowAsync" -namespace Win32Functions -PassThru  
  $Handle = (PS -Id $PID).MainWindowHandle
  [Void]$window::ShowWindow($Handle, 0)

# Fensterelemente
  $Form = [Windows.Forms.Form]@{Text='Bilder löschen'; StartPosition='CenterScreen'; Size="100,100"; FormBorderStyle='FixedSingle'; AutoSize=$true; Margin='10,10,10,10'; KeyPreview=$true; Font=[Drawing.Font]::New("Microsoft Sans Serif",12,[Drawing.FontStyle]"Bold")}  
  $FlowPanel = [Windows.Forms.FlowLayoutPanel]@{FlowDirection='TopDown'; AutoSize=$true; Dock='Fill'; Padding='10,10,10,10'}  
  $Buttons = @(
    [Windows.Forms.Button]@{Name='JPG'; Text='JPG und XMP';      Size="250,60"; TabIndex=1; Margin='10,10,10,10'}  
    [Windows.Forms.Button]@{Name='ARW'; Text='ARW und XMP';      Size="250,60"; TabIndex=2; Margin='10,10,10,10'}  
    [Windows.Forms.Button]@{Name='All'; Text='JPG, ARW und XMP'; Size="250,60"; TabIndex=0; Margin='10,10,10,10'}  
  )

# Fenster zusammenfügen
  $FlowPanel.Controls.AddRange($Buttons)
  $Form.Controls.Add($FlowPanel)
  
# Eventhandler
  
  # Bei Buttonklick, Fenstertag auf Buttontext setzen und Fenster schließen
    $Buttons.Add_Click({
      $this.TopLevelControl.Tag = $this.Name
      $this.TopLevelControl.Hide()
    })
  
  # Tastatursteuerung aktivieren: Escape="Abbrechen", 1="Option 1", 2="Option 2", 3="Option 3" 
    $Form.Add_KeyDown({
      switch -Regex ($_.KeyCode) {
        "^Escape$" {$this.Hide()}  
        "^(D|Numpad)1$" {$This.Controls.Controls["JPG"].PerformClick();break}  
        "^(D|Numpad)2$" {$This.Controls.Controls["ARW"].PerformClick();break}  
        "^(D|Numpad)3$" {$This.Controls.Controls["ALL"].PerformClick();break}  
      }
    })

  # Beim laden des Fensters
    $Form.Add_Load({
      # Ordnerliste laden
      Add-Member -Inp $this NoteProperty "Dirs"  (Get-ChildItem -Recurse -Directory $Quellordner -Filter "JPG" | ? FullName -NotMatch 'converted|_aussortiert')  
    })

# Ausführung

  # Bei Fehlern, Skript stoppen (Sprung in Catch-Block)
  $ErrorActionPreference = 'stop'  
  try {
    [void]$Form.ShowDialog()
    $Files = @()
    switch -r ($Form.Tag) {
      "ALL|JPG" {  
        $Files += Foreach ($Dir in $Form.Dirs) {
          Foreach ($File in Get-ChildItem $Dir.Fullname -Filter "*.jpg" | ?{!(Test-Path "$($Dir.Parent.Fullname)\$($_.BaseName).arw")}) {  
            $File
            Get-ChildItem $Dir.Fullname -Filter ($File.Basename+"*.xmp")  
          }
        }
      }
      "ALL|ARW" {  
        $Files += Foreach ($Dir in $Form.Dirs) {
          Foreach ($File in Get-ChildItem $Dir.Parent.Fullname -Filter "*.arw" | ?{!(Test-Path "$($Dir.Fullname)\$($_.BaseName).jpg")}) {  
            $File
            Get-ChildItem $Dir.Parent.Fullname -Filter ($File.Basename+"*.xmp")  
          }
        }
      }
      "ALL|ARW|JPG" {  
        $Files += Foreach ($Dir in $Form.Dirs) {
          Get-ChildItem $Dir.Parent.FullName -Filter "*.xmp"|?{!(Test-Path "$($_.DirectoryName)\$($_.BaseName -replace '\d*(?=\.arw$)')")}  
          Get-ChildItem $Dir.FullName        -Filter "*.xmp"|?{!(Test-Path "$($_.DirectoryName)\$($_.BaseName -replace '\d*(?=\.jpg$)')")}  
        }
        if ($Files) {Aussortieren $Files}
        break
      }
      $Null {Return}
      Default                                       {throw "Falscher Wert im Fenstertag"}  
    }
    [void]$window::ShowWindow($Handle, 1)
    
    Foreach ($i in 5..1) {
      Write-Host -f green -N ("`r---   Alles erledigt. Wird beendet in {0,2} Sekunden.  ---" -f $i)  
      sleep 1
    }
  }
  # Bei Fehlern, Meldung ausgeben und Skript anhalten
  catch {
    [void]$window::ShowWindow($Handle, 1)
    Write-Host -F red $_.Exception.Message
    Write-Host -N "---   Beliebige Taste zum Beenden   ---"  
    [void][console]::ReadKey($true)
  }
bluemen
bluemen 10.03.2023 aktualisiert um 20:10:20 Uhr
Goto Top
Ich habe es wieder auf ein Jahresarchiv losgelassen.
Es sieht alles gut aus, werde aber noch ausführlich prüfen müssen, da einfach sehr viele Dateien.

Eine Kleinigkeit habe ich aber noch face-wink.
Sobald ein Menüpunkt ausgewählt wurde, verschwindet das Fenster. Erst wenn alles fertig ist, taucht kurz die PS-Console auf, die kurz darauf geschlossen wird.
Ein Fortschritts-/Aktivitätsanzeige wäre toll, falls ich es auf mein gesamtes Bilderarchiv loslasse, wird es dauern und es wäre schön, wenn man sehen kann, dass noch etwas getan wird.

Ansonsten ganz toll ... und unglaublich schnell im Vergleich zu Batch.

Viiiielen Dank
Bodo
TK1987
TK1987 11.03.2023 um 09:24:19 Uhr
Goto Top
Du hast natürlich recht, die Sichtbarmachung des Fensters erfolgt eigentlich zu spät.

Du kannst Zeile 108 entweder vor Zeile 80 schieben, dann wird das Fenster gleich nach drücken des Knopfes sichtbar, oder du löschst einfach die Zeilen 31-34 und Zeile 108, dann ist das Konsolenfenster immer sichtbar.

Gruß Thomas
bluemen
bluemen 11.03.2023 um 10:34:29 Uhr
Goto Top
Hi Thomas,

ich habe Zeile 108 vor Zeile 80 geschoben.
Wenn "vieles schon passt", also längere Zeit keine Dateien verschoben werden, bleibt die Frage, ob das Script noch arbeitet, da nichts passiert, auch wenn man davon ausgehen, da dass Fenster noch offen ist.

Aber eine Fortschrittsanzeige o.ä. ist wirklich allerhöchstens die Kür und nicht wirklich notwendig.

Ich bin sehr glücklich mit dem PS-Script, da es mir viel Arbeit abnimmt. Das einzig "Blöde" ist nun, dass es nun einen Grund gibt, mich mit der PS zu beschäftigen. Ich möchte ja zumindest ein bisschen verstehen. face-wink

Danke und ein schönes Wochenende
Bodo