hainsane
Goto Top

Powershell Dateien archivieren und im LogSpeichern

Hallo zusammen,

bei uns werden auf einem Fileserver automatisch Ergebnisse der Produktion in verschiedenen Files abgelegt. Die entsprechenden Verzeichnisse platzen langsam aus allen nähten und ich habe versucht mit robocopy alle Dateien die älter als 30 Tage sind wegzusichern in ein Archivordner. Allerdings archiviert mir der Robocopy Job auch Ordner die nicht genutzt werden, was bei Maschinenreparaturen durchaus mal vorkommt. Gab jetzt schon mehrfach Probleme. Jetzt wollte ich es eleganter über die Powershell lösen und habe mir folgendes Script zusammen gesucht

$path = "C:\Temp"  
$date = get-date -format "yyyy-MM-dd-HH-mm"  
$file = ("Log_" + $date + ".log")  
$logfile = $path + "\" + $file  


$sourceRoot = 'C:\Users\XX\Downloads'  
$targetRoot = 'C:\Users\XX\Desktop\Test'  
gci $sourceRoot -Recurse | ?{!$_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1)} | %{
        # Name des neuen Ordners erstellen indem der Quell-Root durch den Zielroot ersetzt wird
        $newDir = $_.DirectoryName.Replace($sourceRoot,$targetRoot)
        # Zielordnerstruktur erstellen
        new-item -ItemType Directory -Path $newDir -Force
        # File an seinen neuen Ort verschieben
        move-item $_.FullName -Destination "$newDir\$($_.Name)" -Force  
}

Jetzt habe ich das Problem das ganze in ein Log zu bekommen. Mit Out-file bekomme ich immer Fehlermeldungen wenn ich $logfile angebe, genauso wenn ich mit > $logfile arbeite.

Ich komme gerade nicht weiter, ich möchte nur eine Datei haben, wo ich nachvollziehen kann, wann er welche Dateien verschoben hat.

Content-Key: 583215

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

Printed on: April 19, 2024 at 17:04 o'clock

Member: emeriks
emeriks Jun 30, 2020 at 11:52:17 (UTC)
Goto Top
Hi,
existiert C:\Temp denn überhaupt und hat der ausführende Benutzer dort Schreibrechte?

E.
Member: TK1987
TK1987 Jun 30, 2020 updated at 13:15:51 (UTC)
Goto Top
Moin,

move-item hat bei erfolgreicher Ausführung keine Ausgabe, diese musst du dir also selbst basteln.
Z.B.:
$logfile="C:\Temp\Log_$((get-date).ToString('yyyy-MM-dd-HH-mm')).log"  

$sourceRoot = 'C:\Users\XX\Downloads'  
$targetRoot = 'C:\Users\XX\Desktop\Test'  
gci $sourceRoot -Recurse | ?{!$_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1)} | %{
        # Name des neuen Ordners erstellen indem der Quell-Root durch den Zielroot ersetzt wird
        $newDir = $_.DirectoryName.Replace($sourceRoot,$targetRoot)
        # Zielordnerstruktur erstellen
        new-item -ItemType Directory -Path $newDir -Force
        # File an seinen neuen Ort verschieben
        move-item $_.FullName -Destination "$newDir\$($_.Name)" -Force -EA SilentlyContinue  
        # Prüfen, ob das Verschieben erfolgreich war
	if ($?) {(get-date).ToString('dd.MM.yyyy HH:mm')+" - '$_' verschoben nach '$newdir'"                  | Out-File -Append $logfile }  
	else    {(get-date).ToString('dd.MM.yyyy HH:mm')+" - Fehler beim Verschieben von '$_' nach '$newdir'" | Out-File -Append $logfile }  
}

Gruß Thomas


PS: Bitte zukünftig auf die richtige Forenkategorie (in diesem Fall "Batch & Shell") achten.
Member: SlainteMhath
SlainteMhath Jun 30, 2020 updated at 13:34:55 (UTC)
Goto Top
Moin,

und die Fehlermeldung die erzeugt wird sollen wir nun erraten?! :D

Nebenbei:
Zeile 9: Das "Get-Date.AddDays(-1)" solltest nicht in der Schleife machen, sonst wird das pro File und Ordner einmal ausgeführt
Zeile 10+11: können ersatzlos gestrichen werden (was versuchst du da zu tun??)

lg,
Slainte
Member: emeriks
emeriks Jun 30, 2020 updated at 13:40:34 (UTC)
Goto Top
Zitat von @SlainteMhath:
Zeile 10+11: können ersatzlos gestrichen werden (was versuchst du da zu tun??)
Den Zielordner bestimmen. Das ist schon OK so, wenn man jede Datei einzeln verschiebt.
Wobei man das auch gleich mit .FullName machen könnte.
Member: SlainteMhath
SlainteMhath Jun 30, 2020 at 13:46:45 (UTC)
Goto Top
Hm, naja, nachdem nur Einträge verarbeitet werden, die KEINE Verzeichnisse sind, führt ein
$newDir = $_.DirectoryName.Replace($sourceRoot,$targetRoot)
Doch immer dazu das $newDir = $targetroot ist, oder nicht?
Und dann wird $_.FullName nach "$newDir\$($_.Name)" verschoben. Würde als Destination auch $targetroot + $_.Name ausreichen

Recht verworrener Code :D
Member: emeriks
emeriks Jun 30, 2020 at 13:58:32 (UTC)
Goto Top
Zitat von @SlainteMhath:
Hm, naja, nachdem nur Einträge verarbeitet werden, die KEINE Verzeichnisse sind, führt ein
Doch immer dazu das $newDir = $targetroot ist, oder nicht?
Nein. Da er mit "-recurse" arbeitet wird $_.DirectoryName bei untergeordneten Verzeichnissen immer verschieden sein.
Member: SlainteMhath
SlainteMhath Jun 30, 2020 at 14:10:17 (UTC)
Goto Top
Ah, das recurse hatte ich überlesen - Ja dann hast du natürlich recht .)
Member: erikro
Solution erikro Jun 30, 2020 at 19:01:40 (UTC)
Goto Top
Moin,

gruselig formatiert und wenig perfomant und unflexibel das Ganze.

PARAM(

    $logpath = "C:\Temp\",  
    $file_prefix = "log_",  
    $sourceRoot = 'C:\Users\XX\Downloads',  
    $targetRoot = 'C:\Users\XX\Desktop\Test'  

)

$logfile = $logpath + $file_prefix + $(get-date -format "yyyy-MM-dd-HH-mm") + ".log"  

if(-not (test-path $targetRoot)) {

    out-file -InputObject "Abbruch! $targetRoot existiert nicht!" -FilePath $logfile -Append -Encoding utf8  
    Write-error "Das Skript wurde abgebrochen. Der Zielpfad existiert nicht."  
    exit 1

}

$files = get-childitem $sourceRoot -Recurse | ?{!$_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1)} 

foreach ($file in $files) {
        
        # Name des neuen Ordners erstellen indem der Quell-Root durch den Zielroot ersetzt wird
        $newDir = $file.DirectoryName
        $newDir = $newDir.Replace("$sourceRoot","$targetRoot")  
        
        # Zielordnerstruktur erstellen

        if(-not (test-path $newDir)) {

            new-item -ItemType Directory -Path $newDir
        
        }
 
        # File an seinen neuen Ort verschieben
        try {
        
            move-item $file.FullName -Destination "$newDir\$($file.Name)" -Force  
            Out-File -InputObject "$file.fullname wurde nach $newDir verschoben." -FilePath $logfile -Append -Encoding utf8  
            

        }
        catch {

            Out-File -InputObject "FEHLER! $file.fullname wurde NICHT nach $newDir verschoben." -FilePath $logfile -Append -Encoding utf8  

        }
 
}

Das macht, was Du willst.

hth

Erik
Member: HAinsane
HAinsane Jul 01, 2020 at 07:34:41 (UTC)
Goto Top
Hi Thomas,

vielen Dank für die Antwort. Ich dachte eigentlich dass ich es richtig erstellt hatte, mein Fehler.

Welche Möglichkeiten gibt es dann mit einer Ausgabe zu arbeiten oder wie bastelt man sich eine Ausgabe?
Member: HAinsane
HAinsane Jul 01, 2020 at 07:35:41 (UTC)
Goto Top
Vielen Dank!!

Ich werde es gleich mal testen und Rückmeldung geben!
Member: TK1987
TK1987 Jul 01, 2020 at 10:14:26 (UTC)
Goto Top
Zitat von @HAinsane:
Welche Möglichkeiten gibt es dann mit einer Ausgabe zu arbeiten oder wie bastelt man sich eine Ausgabe?
Ich hab doch oben ein Beispiel mit einer Ausgabe gepostet.
Mitglied: 144705
144705 Jul 01, 2020 updated at 10:27:33 (UTC)
Goto Top
Zitat von @TK1987:

Zitat von @HAinsane:
Welche Möglichkeiten gibt es dann mit einer Ausgabe zu arbeiten oder wie bastelt man sich eine Ausgabe?
Ich hab doch oben ein Beispiel mit einer Ausgabe gepostet.
Ein weiteres Beispiel wie man sowas strukturiert z.B. in eine CSV schreibt, hier nur mal ein Ausschnitt um @erikro 's try catch Variante aufzugreifen

$log = @()

# .........

try {
        move-item $file.FullName -Destination "$newDir\$($file.Name)" -Force -EA Stop  
        $log += [pscustomobject]@{Date=(get-date);File=$file.Fullname; Status="OK"}  
}catch {
        $log += [pscustomobject]@{Date=(get-date);File=$file.Fullname; Status=$_.Exception.Message}
}

# .....
# und am Ende dann ausgeben
$log | export-csv $logfile -NoType -Delimiter ";" -Encoding UTF8  
So landet dann auch etwas mehr Info zum Fehler im Log und die Weiterverarbeitung ist leichter.

Oder man loggt sämtliche Infos der Konsole, mit Start-Transcript mit.


Möglichkeiten gibt es ja viele.

https://www.msxfaq.de/code/powershell/pserrhandling.htm
https://www.windowspro.de/script/fehlerbehandlung-powershell-erroraction ...
Member: erikro
erikro Jul 01, 2020 at 10:28:49 (UTC)
Goto Top
Moin,

Zitat von @144705:
> $log = @()
> 
> # .........
> 
> try {
>         move-item $file.FullName -Destination "$newDir\$($file.Name)" -Force -EA Stop  
>         $log += [pscustomobject]@{Date=(get-date);File=$file.Fullname; Status="OK"}  
> }catch {
>         $log += [pscustomobject]@{Date=(get-date);File=$file.Fullname; Status=$_.Exception.Message}
> }
> 
> # .....
> # und am Ende dann ausgeben
> $log | export-csv $logfile -NoType -Delimiter ";" -Encoding UTF8  
> 
So landet dann auch etwas mehr Info zum Fehler im Log und die Weiterverarbeitung ist leichter.

Jo. Da hast Du recht. Ich würde es aber nach jedem Schleifendurchlauf ins Log schreiben. Sonst besteht die Gefahr, dass man kein Log hat, falls das Skript unerwartet abbricht.

Liebe Grüße

Erik
Member: HAinsane
HAinsane Jul 01, 2020 at 11:16:07 (UTC)
Goto Top
Ich hab jetzt so umgesetzt. Funktioniert fast wunderbar. Allerdings kann er mir auf einen Pfad wegen fehlender Berechtigungen nicht zugreifen.
Powershell gibt mir folgende Ausgabe

move-item : Access to the path is denied.
At line:39 char:13
+             move-item $file.FullName -Destination "$newDir\$($file.Na ...  
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (C:\Users\XX\...sion\_setup.dll:FileInfo) [Move-Item], UnauthorizedAccessException
    + FullyQualifiedErrorId : MoveFileInfoItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.MoveItemCommand
Im Log steht aber in der selben Datei
"C:\Users\XX\Downloads\NVIDIA\3DVision\_setup.dll";"OK"  
Mitglied: 144705
Solution 144705 Jul 01, 2020 updated at 12:08:50 (UTC)
Goto Top
Dann hast du den Parameter -EA Stop oder ausgeschrieben -ErrorAction Stop beim Move-Item Command nicht eingesetzt.