mqlmann
Goto Top

Hilfe bei Shell Script zum verschieben von Ordnern

Hallo,

ich versuche gerade ein Script zu bauen, das folgendes können soll:

1. Einen bestimmten Pfad nach Ordnern mit einem bestimmten Namen durchsuchen (in diesem Fall "Avid1_TEMP")
das klappt auch schon ganz gut mit folgendem Code:
Get-ChildItem $QuellPfad -Recurse | Where { $_.PSIsContainer } | Where { $_ -match "Avid1_TEMP" } | Select-Object FullName  

2. innerhalb der gefunden Ordner zwei Ordner tiefer gehen (es sind in jedem Fall immer genau zwei Ordner) und die dort vorhandenen Ordner nach
Datum umbenennen und nummerieren. Das umbenennen bekomme ich auch hin:
$Datum = Get-Date -format "yyyyMMdd"   
$Nr = 1 
Get-ChildItem $QuellPfadTiefer | ForEach-Object {$_ | Rename-Item -NewName ("$Datum{0}" -f $Nr++)}  
Aber ich habe noch keinen blassen Schimmer wie ich die Variable
$QuellPfadTiefer

also die unter Punkt 1 gefundenen Treffer + zwei Ordner tiefer definieren kann.

3. Erschwerend kommt hinzu, dass am Ende die umbenannten Ordner innerhalb des Überordners der Pfade aus Punkt 1 in andere Ordner verschoben werden sollen. Hier habe ich noch nicht einmal Ansätze.

Im Prinzip soll das Ganze so aussehen

1. Pfad1\Avid1_TEMP\OrdnerA\OrdnerB\(hier gibts dann z.B. drei Ordner mit unbekanntem Namen)
wird umbenannt zu
2. Pfad1\Avid1_TEMP\OrdnerA\OrdnerB\(201407101 + 201407102 + 201407103)
und verschoben nach
3. Pfad1\ZielOrdnerA\ZielOrdnerB\(201407101 + 201407102 + 201407103)

Ich hoffe es blickt hier jemand durch das Chaos in meinem Kopf und hat noch einen Tipp wie ich das realisieren kann!

Vielen Dank

Content-Key: 243286

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

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

Member: colinardo
colinardo Jul 11, 2014 updated at 08:44:20 (UTC)
Goto Top
Moin mqlman,
also bis zu Punkt 2 konnte ich deiner Beschreibung folgen, das sähe dann so aus:
$quellpfad = "C:\temp\quelle"  
$quellpfadtiefer = "\OrdnerA\OrdnerB"  
$folders = dir $quellpfad -Recurse | ?{$_.PSIsContainer -and $_.Name -like "Avid1_TEMP"}  
foreach ($folder in $folders){
    $cnt=0
    dir "$($folder.FullName)$quellpfadtiefer" | ?{$_.PSIsContainer} | %{Rename-Item $_.FullName -NewName ((get-date -Format "yyyyMMdd")+$cnt++)}  
}
aber Punkt 3 (das Verschieben), ist mir nicht klar wie sich hier die Pfade genau zusammensetzen sollen. Bitte beschreibe das mal etwas verständlicher.

Grüße Uwe
Member: mqlmann
mqlmann Jul 11, 2014 at 15:25:11 (UTC)
Goto Top
Hallo Uwe,

es ist mir regelrecht unangenehm, dass immer Du es bist, der mir auf die Sprünge helfen muss ;)

Die umbenannten Ordner, die mit deinem Code jetzt unter
C:\temp\quelle\OrdnerA\OrdnerB\(umbenannte Ordner: 201407101 + 201407102 + 201407103)
liegen, muss ich verschieben nach
C:\temp\quelle\
und dort in andere Unterordner rein. Also am Ende sollte das so in der Art aussehen:
C:\temp\quelle\OrdnerA1\OrdnerB1\(umbenannte Ordner: 201407101 + 201407102 + 201407103)

Wenn ich Deinen Code richtig verstehe sollte das doch so funktionieren:
$quellpfad = "C:\temp\quelle"  
$quellpfadtiefer = "\OrdnerA\OrdnerB"  
$quellpfadtieferNEU = "\OrdnerA1\OrdnerB1"  
$folders = dir $quellpfad -Recurse | ?{$_.PSIsContainer -and $_.Name -like "Avid1_TEMP"}  
foreach ($folder in $folders){
    $cnt=0
    dir "$($folder.FullName)$quellpfadtiefer" | ?{$_.PSIsContainer} | %{Rename-Item $_.FullName -NewName ((get-date -Format "yyyyMMdd")+$cnt++)} | Move-Item "$($folder.FullName)$quellpfadtiefer" "$($folder.FullName)$quellpfadtiefer" "$($folder.FullName)$quellpfadtieferNEU"  
}
?

Viele Grüße
Member: colinardo
colinardo Jul 11, 2014 updated at 19:53:18 (UTC)
Goto Top
Zitat von @mqlmann:
es ist mir regelrecht unangenehm, dass immer Du es bist, der mir auf die Sprünge helfen muss ;)
kein Thema, irgendeiner muss es ja machen face-wink
Wenn ich Deinen Code richtig verstehe sollte das doch so funktionieren:
Nicht ganz, wenn du alle umbenannten Ordner in diese Ordnerfolge packen willst, Hier würde es ja sonst zu Dulikaten kommen, also muss der Counter außerhalb der Schleife initialisiert werden und der Move-Befehl war auch nicht ganz korrekt.
Member: mqlmann
mqlmann Jul 11, 2014 at 19:38:49 (UTC)
Goto Top
Hallo Uwe,

vielen Dank für deine Geduld!
Ich versuche das Ganze nochmal nachvollziehbarer zu erklären.

1. Es gibt den Hauptordner, der auf Unterordner mit Namen "Avid1_TEMP" durchsucht werden soll. Hier nenne ich ihn mal wie in Deinem Code:

C:\temp

2. In diesem Ordner gibt es zwei Unterordner:

C:\temp\Avid MediaFiles
C:\temp\Avid1_TEMP

3. Innerhalb des Ordners "Avid MediaFiles" sieht es wie folgt aus:

C:\temp\Avid MediaFiles\MXF

4. Innerhalb des Ordners "Avid1_TEMP" sieht es wie folgt aus:

C:\temp\Avid1_TEMP\Avid MediaFiles\MXF

5. In dem Ordner "MXF" liegen die Ordner, die mit dem Script nach Datum nummeriert umbenannt wurden:

C:\temp\Avid1_TEMP\Avid MediaFiles\MXF\201407101
C:\temp\Avid1_TEMP\Avid MediaFiles\MXF\201407102
C:\temp\Avid1_TEMP\Avid MediaFiles\MXF\201407103

6. Diese Ordner sollen nach der Umbenennung in folgenden Ordner verschoben werden:

C:\temp\Avid MediaFiles\MXF

7. Sodass das Ganze dann so aussieht:

C:\temp\Avid1_TEMP\Avid MediaFiles\MXF\ -- leer --
C:\temp\Avid MediaFiles\MXF\201407101
C:\temp\Avid MediaFiles\MXF\201407102
C:\temp\Avid MediaFiles\MXF\201407103

Ich hoffe das war zielführend ;)


Vielen Dank
Member: colinardo
Solution colinardo Jul 11, 2014 updated at 20:58:16 (UTC)
Goto Top
$quellpfad = "C:\temp"  
$quellpfadtiefer = "\Avid MediaFiles\MXF"  
$folders = dir $quellpfad -Recurse | ?{$_.PSIsContainer -and $_.Name -like "Avid1_TEMP"}  
foreach ($folder in $folders){
    $cnt=0
    dir "$($folder.FullName)$quellpfadtiefer" | ?{$_.PSIsContainer} | %{Rename-Item $_.FullName -NewName ((get-date -Format "yyyyMMdd")+$cnt++) -passthru } | Move-Item -Destination "$($folder.parent.FullName)$quellpfadtiefer"  
}
Member: mqlmann
mqlmann Jul 11, 2014 at 20:32:27 (UTC)
Goto Top
Das funtioniert gut!
Leider, leider habe ich ein wichtiges Detail übersehen:

1. Im Quellordner

C:\temp

2. gibt es noch einen Unterordne, deren Namen nicht vorhersehbar sind:

C:\temp\UnbekannterOrdner1
C:\temp\UnbekannterOrdner2

3. Und erst da drin gibt es die Struktur

C:\temp\UnbekannterOrdner1\Avid MediaFiles
C:\temp\UnbekannterOrdner1\Avid1_TEMP
C:\temp\UnbekannterOrdner2\Avid MediaFiles
C:\temp\UnbekannterOrdner2\Avid1_TEMP

---

7. Das heisst am Ende muss das so aussehen:

C:\temp\UnbekannterOrdner1\Avid1_TEMP\Avid MediaFiles\MXF\ -- leer --
C:\temp\UnbekannterOrdner2\Avid1_TEMP\Avid MediaFiles\MXF\ -- leer --
C:\temp\UnbekannterOrdner1\Avid MediaFiles\MXF\201407101
C:\temp\UnbekannterOrdner1\Avid MediaFiles\MXF\201407102
C:\temp\UnbekannterOrdner1\Avid MediaFiles\MXF\201407103
C:\temp\UnbekannterOrdner2\Avid MediaFiles\MXF\201407101
C:\temp\UnbekannterOrdner2\Avid MediaFiles\MXF\201407102
C:\temp\UnbekannterOrdner2\Avid MediaFiles\MXF\201407103

Gibt es einen Weg den Namen diese Ordners bei der Suche mit
dir $quellpfad -Recurse | ?{$_.PSIsContainer -and $_.Name -like "Avid1_TEMP"}  
in eine Variable zu bringen?

Sorry, aber das hatte ich echt nicht bedacht - Asche auf mein Haupt!
Member: colinardo
colinardo Jul 11, 2014 updated at 20:53:11 (UTC)
Goto Top
ist oben angepasst...

du siehst ... fürs nächste mal direkt detaillierte Angaben machen. Beim Skripten kommt es eben auf kleinste Details an.

standby for the next change face-wink

good night.
Member: mqlmann
mqlmann Jul 11, 2014 at 20:58:04 (UTC)
Goto Top
Respekt Uwe!
Wenn ich Dir ein Bier mailen könnte würde ich es glatt machen ;)

Vielen Dank!!
Member: mqlmann
mqlmann Jul 23, 2014 at 19:22:39 (UTC)
Goto Top
Hallo Uwe,

das Script läuft super. Dummerweise habe ich hier @home nie darüber nachgedacht, dass der Speicher, den das Script durchsuchen soll, relativ groß ist (30TB um genau zu sein). Dementsprechen lange dauert die Ausführung, ich habe zwischen 20s und 30s gemessen.
Was mich natürlich auf zwei Fragen bringt: Kann das Get-ChildItem Cmdlt irgendwie beschleunigen?
Und noch eine grundsätzliche Frage: Wie kann ich eine Form aufrufen während das Script läuft? Das Einfachste wäre hier natürlich dem User die Info zu geben, dass das Script gerade umbenennt und verschiebt.

Viele Grüße
Member: colinardo
colinardo Jul 23, 2014 updated at 19:43:18 (UTC)
Goto Top
Hi,
Zitat von @mqlmann:
das Script läuft super. Dummerweise habe ich hier @home nie darüber nachgedacht, dass der Speicher, den das Script
durchsuchen soll, relativ groß ist (30TB um genau zu sein). Dementsprechen lange dauert die Ausführung, ich habe
zwischen 20s und 30s gemessen.
Was mich natürlich auf zwei Fragen bringt: Kann das Get-ChildItem Cmdlt irgendwie beschleunigen?
Wenn du Powershell mit mindestens Version 3.0 hast eventuell ja. Deine aktuelle Powershellversion kannst du dir mit folgendem Befehl anzeigen lassen:
$psversiontable.PSVersion.toString()
Wenn du noch 2.0 hast, upgraden...
Und noch eine grundsätzliche Frage: Wie kann ich eine Form aufrufen während das Script läuft? Das Einfachste
wäre hier natürlich dem User die Info zu geben, dass das Script gerade umbenennt und verschiebt.

das Script hier läuft ab PS3.0 und müsste es vermutlich beschleunigen und zeigt eine Info an während das Script läuft:
$myjob = [Powershell]::Create().AddScript({
    $quellpfad = "C:\temp"  
    $quellpfadtiefer = "\Avid MediaFiles\MXF"  
    $folders = dir $quellpfad -Filter "Avid1_TEMP" -Recurse -Directory  
    foreach ($folder in $folders){
        $cnt=0
        dir "$($folder.FullName)$quellpfadtiefer" -Directory | %{Rename-Item $_.FullName -NewName ((get-date -Format "yyyyMMdd")+$cnt++) -passthru } | Move-Item -Destination "$($folder.parent.FullName)$quellpfadtiefer"  
    }
})
$myjob.BeginInvoke()| out-null

while($myjob.InvocationStateInfo.State -eq "Running"){  
    Write-Progress -Activity "Ordnerverarbeitung" -Status "Bitte warten Umbenennung läuft ..."  
}
write-host "Vorgang abgeschlossen!"  
Grüße Uwe
Member: mqlmann
mqlmann Jul 23, 2014 at 20:09:45 (UTC)
Goto Top
Hallo Uwe,

wie immer: vielen Dank für Deine Schnelle Antwort!
Ich arbeite mit Powershell3.

Kann ich denn statt
Write-Progress -Activity "Ordnerverarbeitung" -Status "Bitte warten Umbenennung läuft ..."  
das auch in in einer System.Windows.Forms.Form mit selbigem Text anzeigen lassen?
Wenn ich an dieser Stelle einfach eine Form ohne Buttons einsetze, wird das Script erst beendet sobald ich die Form schließe.
Member: colinardo
colinardo Jul 23, 2014 at 21:43:29 (UTC)
Goto Top
Member: mqlmann
mqlmann Jul 24, 2014 at 18:25:30 (UTC)
Goto Top
Hallo Uwe,

in diesem Fall brauche ich keine Progressbar. Es würde mir völlig reichen ein Fenster mit "Es wird umbenannt..." oder so anzeigen zulassen, während das Script läuft.
Member: colinardo
colinardo Jul 24, 2014 at 18:48:12 (UTC)
Goto Top
function GenerateForm {
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null  
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null  
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$label1 = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects


$handler_form1_Shown= 
{
    #------------ Arbeitscode ---------------
    
    $quellpfad = "C:\temp"  
    $quellpfadtiefer = "\Avid MediaFiles\MXF"  
    $folders = dir $quellpfad -Recurse | ?{$_.PSIsContainer -and $_.Name -like "Avid1_TEMP"}  
    foreach ($folder in $folders){
        $cnt=0
        dir "$($folder.FullName)$quellpfadtiefer" | ?{$_.PSIsContainer} | %{Rename-Item $_.FullName -NewName ((get-date -Format "yyyyMMdd")+$cnt++) -passthru } | Move-Item -Destination "$($folder.parent.FullName)$quellpfadtiefer"  
    }


    # ------------------------------------
    
    #Form schließen wenn fertig
    $form1.Close()

}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 65
$System_Drawing_Size.Width = 325
$form1.ClientSize = $System_Drawing_Size
$form1.ControlBox = $False
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.FormBorderStyle = 3
$form1.Name = "form1"  
$form1.Text = "Status"  
$form1.StartPosition = 1
$form1.add_Shown($handler_form1_Shown)

$label1.DataBindings.DefaultDataSourceUpdateMode = 0
$label1.Font = New-Object System.Drawing.Font("Arial",12,1,3,0)  

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 9
$label1.Location = $System_Drawing_Point
$label1.Name = "label1"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 41
$System_Drawing_Size.Width = 301
$label1.Size = $System_Drawing_Size
$label1.TabIndex = 0
$label1.Text = "Umbenennung läuft... Bitte warten."  
$label1.TextAlign = 32

$form1.Controls.Add($label1)

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm