Batchskript upgraden?

guterfrager5  27.03.2023, 09:32

muss es Batch sein, oder würde auch Powershell gehen? (:

Lenzer66u 
Fragesteller
 27.03.2023, 09:33

um ehrlich zu sein brauch ich sogar beides xD

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

trivial:

demo.cmd

@echo off
set "VonPfad=%UserProfile%\Desktop\test1\KopiertestServer.txt"
set "NachPfad=%UserProfile%\Desktop\test2"
md "%NachPfad%" 2>nul   &rem Zielordner erzeugen, falls dieser nicht existiert


set "ZeitIntervall=2"
:loop
for %%a in ("%VonPfad%") do (
     rem %%~ta repräsentiert das datum der letzten Änderung!
    if "%%~ta" neq "%lastChange%" (
        copy "%%~fa" "%NachPfad%\"  &rem der abschließende Backslash weist das Ziel als Ordner  aus!
        set "lastChange=%%~ta"  &rem letze Änderung nächsten Vergleich merken...
    ) else (echo mache Nichts...) &rem der elsezweig ist nur zu demozwecken, kann weg
)
timeout %ZeitIntervall% >nul
goto :loop
pause

achte darauf, wie ich die "gänsefüßchen"(Quotes) gesetzt habe. Das ist wichtig!

Zum Kopieren von einzelnen Dateien arbeitet man nicht mit xcopy, sondern mit copy! (der Zielordner muss bei copy existieren und gegebenenfalls zuvor erzeugt werden)

PS: jetzt habe ich Zeit auch noch etwas effizienteres zu schreiben....

Die Batch und auch das Powershell-Script von guterfrager5 sind schrekliche Resorcenfresser, da diese immer und immerwieder die Gegebenheiten der Datei abfragen, was natürlich Unfug ist, folgendes Powershellscript klinkt sich passiv in die Ereignisverarbeitungskette und nur wenn das Ereignis Datei/Ordner "changed" vom System ausgelöst wurde , wird die definierte Action ausgelöst.

Das einzige, was Resourcen (Prozessorzeit) in Anspruch nimmt ist die Ausgabe eines Punktes alle 2 Sekunden. Ohne den Punkt könnte man auch die Schlafzyklen auf 10..100 Millisekunden setzen.

watchfile.ps1

$desktopFolder=[Environment]::GetFolderPath('Desktop')


$SourceFolder="$desktopFolder\test1"  #ordner  der überwacht werden soll
$FileFilter="KopiertestServer.txt"  #datei(en) welche beobachtet werden
$global:DestinationFolder="$desktopFolder\test2"   #wohin kopiert werden soll werden soll muss global deklariert werden, da action ein asnchroner Threat ist, und zur Laufzeit keinen Zugriff auf lokale Variablen  hat!!!!


New-Item $global:DestinationFolder -ItemType "directory" -force #anlegen, wenn er nich existiert...


$watcher=New-Object System.IO.FileSystemWatcher
  #zu beobachtender Ordner 
$watcher.Path=$SourceFolder
  #Dateimaske, welche Dateien beobchtet werden sollen
$watcher.Filter=$FileFilter
  #auch Unterverzeichnisse beobachten?
$watcher.IncludeSubdirectories=$false
$watcher.EnableRaisingEvents=$false 


### was soll getan werden  (scriptblock variable)
$action={
      # Rückgabe Datei, welche  das Ereignis ausgelöst  hat...
    $path = $Event.SourceEventArgs.FullPath
      #welche Veränderung der Auslöser  war
    $changeType = $Event.SourceEventArgs.ChangeType
      #etwas  anzeigen
    Write-Host "$path was $changetype at $(get-date)"
    Copy-Item $path $global:DestinationFolder -verbose
}


    
### registriere  Ereignisse, auf welche wie reagiert werden soll 
  #du  kannst  natürlich für jedes Ereignis auch  eine  eigene Actionvariable definieren
  #...oder einfach nur  das Ereignis  registrieren, auf welches Du reagieren möchtest
Register-ObjectEvent $watcher "Changed" -Action $action|Out-Null
  #Reaktion auf andere Ereignisse für diese Demo deaktiviert
#Register-ObjectEvent $watcher "Created" -Action $action|Out-Null
#Register-ObjectEvent $watcher "Deleted" -Action $action|Out-Null
#Register-ObjectEvent $watcher "Renamed" -Action $action|Out-Null


  #Endlosschleife. Welche das Script geöffnet hält, Reaktionszeit auf  ereignisse 2 sekunden
while ($true) {
    Write-Host '.' -n; #mache einfach einen punkt, damit man sieht, dass das Script noch lebt...
    sleep 2
}

# siehe  auch https://www.msxfaq.de/code/powershell/ps_und_callbackfunktion.htm

die anderen Ereignisse habe ich nur Auskommentiert, da diese für Deine Sache nicht relevant sind, aber durchaus informationswert haben.

Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
Lenzer66u 
Fragesteller
 27.03.2023, 15:15

also wenn ich den teil ausprobiere:

@echo off
set "VonPfad=%UserProfile%\Desktop\test1\KopiertestServer.txt"
set "NachPfad=%UserProfile%\Desktop\test2"
md "%NachPfad%" 2>nul   &rem Zielordner erzeugen, falls dieser nicht existiert


set "ZeitIntervall=2"
:loop
for %%a in ("%VonPfad%") do (
     rem %%~ta repräsentiert das datum der letzten Änderung!
    if "%%~ta" neq "%lastChange%" (
        copy "%%~fa" "%NachPfad%\"  &rem der abschließende Backslash weist das Ziel als Ordner  aus!
        set "lastChange=%%~ta"  &rem letze Änderung nächsten Vergleich merken...
    ) else (echo mache Nichts...) &rem der elsezweig ist nur zu demozwecken, kann weg
)
timeout %ZeitIntervall% >nul
goto :loop
pause

bekomme ich immer ein Systax error

0
Erzesel  27.03.2023, 15:47
@Lenzer66u

Kann ich nicht nachvollziehen, ohne zu wissen wo der Syntax Fehler ausgelöst wird,

kommentiere das @Echo off am anfang aus:

::@echo off

Dann siehst Du Du wo der Syntaxfehler auftrat.

Falls es sich um einen Abbruchfehler handelt, starte cmd und rufe die Batch in der Console auf. Dann bekommt man auch kritische Fehler zu Gesicht.

hast du vielleicht was an den klammern verändert? oder das unnütze Zeug nicht gründlich weggeputzt?

demo.cmd

@echo off
set "VonPfad=%UserProfile%\Desktop\test1\KopiertestServer.txt"
set "NachPfad=%UserProfile%\Desktop\test2"
md "%NachPfad%" 2>nul

set "ZeitIntervall=2"
:loop
for %%a in ("%VonPfad%") do (
    if "%%~ta" neq "%lastChange%" (
        copy "%%~fa" "%NachPfad%\"
        set "lastChange=%%~ta"
    )
)
timeout %ZeitIntervall% >nul
goto :loop
pause

der häufigste Grund für Syntaxfehler sind zuwenige/zuviele Klammern und nicht abgeschlossene "Quotes".

0
Lenzer66u 
Fragesteller
 28.03.2023, 07:01
@Erzesel

ok funktioniert jetzt. Aber erkannt wird ja nur eine Änderung wenn sich eine Minute ändert was ja nicht sein sollte. Eigentlich soll ja jede 2. Sekunde geprüft werden. Also ja er prüft jede 2. Sekunde aber erkennen tut er es nur wenn eine Minute dazwischen liegt. Ich hoffe man versteht mich. ^^

0
Erzesel  28.03.2023, 09:24
@Lenzer66u

sorry hatte echt nicht mehr auf dem Schirm, das Batch keine Sekunden im %~t.-Parameter liefert.

Ja dann wirds für Batch eng...

WMIC datafile ... liefert genaue Zeitstempel :

@echo off
set "VonPfad=%UserProfile%\Desktop\test1\KopiertestServer.txt"
set "NachPfad=%UserProfile%\Desktop\test2"
md "%NachPfad%" 2>nul 
set "ZeitIntervall=2"
:loop
 rem WMIC erwartet Pfade im Javaformat . (Backslashes verdoppeln) 
for /f "tokens=2,3 delims=,+" %%a in ('wmic datafile where "Name='%VonPfad:\=\\%'" get Caption^,LastModified /format:csv^|find "%ComputerName%"') do (
    if "%%~b" neq "%lastChange%" (
        echo LastModified: %%b   Caption: %%a
        copy "%%a" "%NachPfad%\"
        set "lastChange=%%b"
    )
)
timeout %ZeitIntervall% >nul
goto :loop
pause

Aber nicht zu früh freuen:

In einigen Windows11 Devs wurde wmic bereits entfernt, ergo funktioniert letztere Lösung nicht mehr immer und überall und ewig.

...bleibt die Verwendung Powershell in der Batch:

...
for /f  %%a in ('powershell "(gi '%VonPfad%').LastWriteTime.ToString('yyyyMMddhhmmss.ffff')"') do (
    if "%%a" neq "%lastChange%" (
        copy "%VonPfad%" "%NachPfad%\"
        set "lastChange=%%a"
    )
)
...

...aber wenn man schon Powershell verwendet, warum dann nicht gleich auf Powershell umsteigen?

Zeit für Dich Batch weitgehend den Rücken zu kehren! 👎🙌

oben habe ich ein sehr effiziente PoshScript gepostet.

1