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
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
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 3009975671
Url: https://administrator.de/contentid/3009975671
Ausgedruckt am: 22.11.2024 um 09:11 Uhr
78 Kommentare
Neuester Kommentar
Moin,
wie fix ist die Batch?
Wäre Powershell denkbar?
Falls ja:
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
Edit:
Sollen nur Dateien berücksichtigt werden:
Gruß
em-pie
P.S.
Bitte die Code-Tags nutzen
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
Moin,
bitte zukünftig codetags nutzen.
Entweder du Aktivierst die Variablenverzögerung und nutzt diese (Variablen dann in Ausrufezeichen statt Prozentzeichen):
oder du nutzt stattdessen Funktionen
Gruß Thomas
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.
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
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.SET AKTUELLER_SUCHPFAD=%%~dpi REM Inhalt von %~dpi wird nicht an AKTUELLER_SUCHPFAD übergeben
echo AKTUELLER_SUCHPFAD: %AKTUELLER_SUCHPFAD% REM somit keine Anzeige
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
Zitat von @bluemen:
Nun ist es aber so, dass diese rekursive Schleife
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.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?
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
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.
[...]
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
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 .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?
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"
Lange Rede kurzer Sinn - ändere den Befehl in der For-Schleife (Zeile 5) auf
dir /s /b /ad "%Quellpfad%\JPG*"
Gruß Thomas
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.
"=>" 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:
Bitte in beiden Zeilen ändern.
Gruß Thomas
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%"
echo Verschiebe Datei: "%~1" =^> "%Zielpfad%"
Gruß Thomas
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.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)
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
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.
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).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"
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
Moin,
Dann einmal abändern auf:
So dürfte es dann für beide Fälle funktionieren.
Gruß Thomas
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 .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.
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"
)
Gruß Thomas
Moin Bodo,
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.
Gruß Thomas
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.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
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
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?Ich habe den Quellpfad angepasst und das Script gestartet, bekomme jedoch folgende Fehlermeldung:
Dieser Fehler dürfte nämlich eigentlich nur bei letzterem auftauchen, da die ISE keine Konsole besitzt.
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...
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
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
Zitat von @bluemen:
Ist der Computer Teil einer Domäne?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.
MachinePolicy Unrestricted
Man kann diese natürlich wieder zurücksetzen
Set-ExecutionPolicy -Scope MachinePolicy Undefined -Force
Set-ExecutionPolicy RemoteSigned -Force
Über die GPO, ja. Drücke Win+R und gebe
ein. Navigiere zu Computerkonfiguration > Administrative Vorlagen > Windows Komponenten > Windows PowerShell und gucke mal, auf was Skriptausführung aktivieren steht.
gpedit.msc
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.
Anhand deiner Fehlermeldung von 18:45 sieht man auch, dass er genau das versucht:
Gruß Thomas
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.
Hintergrund:
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.In Zeile:1 Zeichen:46
+ ... -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
Gruß Thomas
Zitat von @bluemen:
Das "aussortiert"-Verzeichnis erscheint allerdings nicht, wenn ich Dateien im Ursprung lösche.
aus dem jpg-Ordner?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.
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:
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.
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.
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.Nebenbei und (nur) falls es einfach umzusetzen ist.
Im Batch hatte ich mir folgende Möglichkeiten eingebaut, in PS habe ich (noch) keinen Plan:
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
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: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.
... -replace "\d*(\.ARW)?$"
Habe es oben auch angepasst.
Zitat von @bluemen:
1 funktioniert jetzt, bei
Klappt hier im Test problemlos. Oder hast du auch gleichnamige ARW- bzw. XMP-Dateien im übergeordneten Ordner liegen?1 funktioniert jetzt, bei
2 und 3 werden die .XMPs und .ARWs nicht bearbeitet.
habe ich keine Veränderung festgestellt.Zeige mal Bitte deine Ordnerstruktur:
ls -r -file "C:\Pfad\zum\Quellordner" | select -Expand Fullname
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
Das kann dann natürlich nicht funktionieren. Ich werde es morgen abändern, hab heute leider keine Zeit mehr.
Gruß Thomas
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:
Gruß Thomas
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
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?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.
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
ich traue mich kaum noch zu schreiben aber allein bekomme ich es nicht hin.
alles gut, kann nicht mehr viel sein 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)
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
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.Einiges wird bearbeitet, dann steigt es aus, da die Datei angeblich nicht da ist, die es selbst vorher bearbeitet hat
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
}
}
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.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?
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
}
}
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:Ich denke, dass es gut wäre, wenn beim Aufbau des Dateinamens nicht reglementiert wird, sondern nur auf gleiche Dateinamen geprüft wird.
2022-05-28-__A7304628____.ARW
2022-05-28-__A7304628__Irgend-ein-Text__01.ARW.xmp
Der Dateiname hier ist ja nun mal nicht gleich, irgendwo muss man also sagen: "Wenn der Dateiname bis ... gleich ist, dann... "
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
}
}
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
}
}
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.Würdest du mir erklären, warum in der ersten Zeile auch jetzt -Filter "JPG" steht?
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
}
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:
Du kannst dir dann auch Anzeigen lassen, welche Eigenschaften ein Objekt besitzt:
oder das Objekt mit sämtlichen Eigenschaften anzeigen lassen:
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:
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.
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
$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$)"
Damit habe ich somit den Dateinamen, den ich überprüfen kann.
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:
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)
}
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
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