none
Dateinamen aendern mit der Powershell

    Frage

  • Hallo liebe Gemeinde,

    ich beschäftige mich gerade intensiv mit der Powershell, komme aber gerade nicht weiter..

    Zum Beispiel möchte ich gerne in einem Verzeichnis Dateinamen wie folgt ändern:

    von:     <prefix>_in-bearbeitung.<suffix>

    in:        <prefix>_Projekt_in-bearbeitung.<suffix>

    <prefix> und <suffix> sind platzhalter für beliebige Zeichenketten, die sich von Datei zu Datei unterscheiden...

    Alle Dateien des Verzeichnisses (inkl. Unterverzeichnisse) mit Ausnahme von *.txt sollen umbenannt werden

    Bekommt man das so einfach mit der Powershell hin, oder ist einen Umweg (z.B. .bat) geschickter?

     

    Montag, 12. März 2018 20:29

Antworten

  • Auch auf die Gefahr hin unhöflich oder altklug oder mäkelig zu erscheinen, aber Dein Code verwirrt mich jedesmal mehr ... Wenn ich mich nicht verguckt habe, benutzt Du die Variable $i bevor Du sie deklarierst.

    Hier, probier mal den Schnipsel:

    $StartPath = 'Pfad zum Startverzeichnis'
    $NewProjectName = Read-Host -Prompt 'Bitte den neuen Projektnamen eingeben'
    $NewProjectName
    Get-ChildItem -Path $StartPath -Recurse -Force -Exclude *.txt | 
        ForEach-Object {
            Rename-Item -Path $_.FullName -NewName $($_.Name -replace '_in\-bearbeitung',"_$($NewProjectName)_in-bearbeitung") -Verbose
        }
    
    möglichst ohne Änderungen ... wenn der funktioniert (bei mir tut er das), kannst Du den Rest drumherum bauen.

    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Mittwoch, 14. März 2018 18:38

Alle Antworten

  • Hallo Andreas,

    also erstmal Willkommen im deutschen Powershell Forum. 

    Deine Aufgabe kann man definitiv mit der Powershell lösen und die Powershell ist auch immer die bessere, einfachere und mächtigere Lösung für Scripting-Aufgaben im Vergleich zur alten, obsoleten cmd.

    Wie Du bestimmt in den Forenregeln und den hilfreichen Hinweisen am Anfang des Forums gelesen hast, schreiben wir keinen gebrauchsfertigen Code auf Anfrage. Solltest Du also noch keine  Erfahrungen mit Powershell haben, lautet die dringende Empfehlung, Dir als erstes die Grundlagen der Powershell anzueignen. Das geht auch kostenlos zum Beispiel mit einem sehr empfehlenswerten Video-Kurs der Microsoft Virtual Academy - Getting started with Windows Powershell. Oder Du besorgst Dir ein gutes Einsteiger-Buch.

    Wenn Du bereits selbstgeschriebenen Code hast und dabei Hilfe brauchst, kannst Du den hier gerne posten und wir werden nach Kräften versuchen Dir zu helfen (Code bitte als solchen formatieren!  :-)  )

    Na dann viel Spaß und viel Erfolg!

    Edit: ... fast hätte ich's vergessen . solltest Du schon ein wenig Erfahrung mit Scripting in Powereshell haben und brauchst nur einen Schubs in die richtige Richtung - für Deine Aufgabe könntest Du mit den cmdlets Get-ChildItem, Foreach-Object und Rename-Item anfangen und das Ganze mit etwas Regulären Ausdrücken garnieren. ;-)


    Best regards,

    (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH_666 Montag, 12. März 2018 22:36
    Montag, 12. März 2018 22:30
  • Vielen Dank =)

    Mein Code sieht so aus:

    gci *.* -recurse -force -exclude *.txt| rename-item -NewName {$_.Name -replace '_in-bearbeitung','_projektname_in-bearbeitung'}

    Das klappt auch ganz gut, aber dann dachte ich mir, Nutzerfreundlicher wäre doch ein Nutzerdialog..

    Da man so den Code bearbeiten, und händisch den Projektnamen eintragen muss.. Zu umständlich!

    Also versuchte ich mich daran:

    ##########################################################################
    #Script zum ändern der Dateinamen
    #Alle Dateien des Verzeichnisses (inkl. Unterverzeichnisse) mit Ausnahme von *.txt werden umbenannt
    #
    ##########################################################################
    
    # Show input box popup and return the value entered by the user.
    function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
    {
    Add-Type -AssemblyName Microsoft.VisualBasic
    return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText)
    }
    
    # Show an Open Folder Dialog and return the directory selected by the user.
    function Read-FolderBrowserDialog([string]$Message, 
    [string]$InitialDirectory, [switch]$NoNewFolderButton)
    {
    $browseForFolderOptions = 0
    if ($NoNewFolderButton) { $browseForFolderOptions += 512 }
    
    $app = New-Object -ComObject Shell.Application
    $folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory)
    if ($folder) { $selectedDirectory = $folder.Self.Path } else { $selectedDirectory = '' }
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null
    return $selectedDirectory
    }
    
    ##########################################################################
    #Start Code
    ##########################################################################
    
    $i = 1
    
    $directoryPath = Read-FolderBrowserDialog -Message "Bitte waehle ein Verzeichnis" -NoNewFolderButton -InitialDirectory 'Computer\'
    if (![string]::IsNullOrEmpty($directoryPath)) { Write-Host "You selected the directory: $directoryPath" }
    else { "Kein Verzeichnis ausgewaehlt" }
    
    $newguy = Read-InputBoxDialog -Message "Bitte Projektnamen eingeben?" -WindowTitle "_<Projektname>_in-work" -DefaultText "<Projektname>"
    if ($newguy -eq $null) { Write-Host "Abbruch" }
    else { Write-Host "Gewaehlter Projektname lautet $newguy" }
    
    If(!$newguy){
    $isnull++
    }
    else{
    Get-ChildItem -Path $($directoryPath)*.* -Recurse -Force -Exclude *.txt | 
    ForEach-Object {
    $newname = "${newguy}_{0}.*" -f $i
    $i++ 
    Rename-Item -NewName { $_.name -replace '_in-bearbeitung', '_$newname_in-bearbeitung'}
    }
    }
    
    
    ##########################################################################
    #Closing
    ##########################################################################
    if ($Host.Name -eq "ConsoleHost")
    { 
    Write-Host "Press any key to continue..."
    $Host.UI.RawUI.FlushInputBuffer()   # Make sure buffered input doesn't "press a key" and skip the ReadKey().
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
    }

    Tya, und hier hänge ich seit heute Mittag..

    Ich bekomme eine Fehlermeldung die so aussieht:

    Rename-Item : Der Parameter "NewName" kann nicht ausgewertet werden, da dessen Argument als Skriptblock angegeben wurde
     und keine Eingabe vorhanden ist. Ein Skriptblock kann nicht ohne Eingabe ausgewertet werden.
    Bei C:\Users\Andreas\Desktop\nutzerdialog.ps1:50 Zeichen:21
    + Rename-Item -NewName <<<<  { $_.name -replace '_in-work', '_$newname_in-work'}
        + CategoryInfo          : MetadataError: (:) [Rename-Item], ParameterBindingException
        + FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.RenameItemCommand

    Scheinbar schmeckt ihm die Zeile nicht:

    Rename-Item -NewName { $_.name -replace '_in-bearbeitung', '_$newname_in-bearbeitung'}

    Habt ihr mir dazu ein Tipp wie ich das lösen könnte?


    • Bearbeitet Andreas_AL Dienstag, 13. März 2018 17:33
    Dienstag, 13. März 2018 17:07
  • Warum verwendest du die geschweiften Klammern? Die verwendet man nicht bei Argumenten. 

    Deinen Fehler kannst du umgehen, indem du mit normalen Klammern arbeitest: 

    Rename-Item -NewName $($_.name -replace '_in-bearbeitung', '_$newname_in-bearbeitung')

    Den Rest des Skripts habe ich jetzt nicht angeschaut, das können die Profis hier machen ;-)

    Kleiner Exkurs: 

    Das $ vor der Klammer ist optional, manchmal aber notwendig wenn Anführungszeichen gesetzt werden. Die Powershell möchte dann Sachen auflösen, die zur Variable gehören. Beispiel in deiner Foreach-Schleife: 

    "$($_.Name) ist nicht $_.Name"

    Ist nicht ganz einfach, aber du wirst es noch verstehen. 


    • Bearbeitet Fahiko Dienstag, 13. März 2018 20:27
    Dienstag, 13. März 2018 20:26
  • Danke für deinen Exkurs =)

    Nun bekomme ich in der Powershell folgende Ausgabe:

    Ausgewaehltes Verzeichnis: C:\Users\Andreas\Desktop\shell
    Gewaehlter Projektname lautet Test22
    
    Cmdlet Rename-Item an der Befehlspipelineposition 1
    Geben Sie Werte für die folgenden Parameter an:
    Path:

    Damit kann ich jetzt mal garnichts anfangen?!?Ich nehme an dass es nur noch an der Syntax liegt.

    $newName wird nicht ausgegeben, weil es in Hochkommata steht...Aber wie mache ich es Syntaktisch richtig?

    Jemand ein Tipp?

    Mittwoch, 14. März 2018 13:08
  • > Nun bekomme ich in der Powershell folgende Ausgabe:

    Welcher aktuelle Code produziert denn diese Ausgabe? :-)

    Mittwoch, 14. März 2018 13:24
  • > Rename-Item -NewName { $_.name -replace '_in-bearbeitung', '_$newname_in-bearbeitung'}

    Wenn Du Variablen in Hochkomma verwendest, mußt Du " statt ' nehmen, sonst bleibt $newname... Besser ist diese Form:

    ( '_{0}_in-bearbeitung' -f $newname )

    Das ist immer unzweideutig.

    Mittwoch, 14. März 2018 13:27
  • Ahh ok, das ist natürlich eleganter!

    Trotzdem bekomme ich mit folgendem Code die oben genannte Fehlermeldung..

    ##########################################################################
    #Script zum ändern der Dateinamen
    #Alle Dateien des Verzeichnisses (inkl. Unterverzeichnisse) mit Ausnahme von *.txt werden umbenannt
    #
    ##########################################################################
    
    # Show input box popup and return the value entered by the user.
    function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
    {
    Add-Type -AssemblyName Microsoft.VisualBasic
    return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText)
    }
    
    # Show an Open Folder Dialog and return the directory selected by the user.
    function Read-FolderBrowserDialog([string]$Message, 
    [string]$InitialDirectory, [switch]$NoNewFolderButton)
    {
    $browseForFolderOptions = 0
    if ($NoNewFolderButton) { $browseForFolderOptions += 512 }
    
    $app = New-Object -ComObject Shell.Application
    $folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory)
    if ($folder) { $selectedDirectory = $folder.Self.Path } else { $selectedDirectory = '' }
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null
    return $selectedDirectory
    }
    
    ##########################################################################
    #Start Code
    ##########################################################################
    
    $i = 1
    
    $directoryPath = Read-FolderBrowserDialog -Message "Bitte waehle ein Verzeichnis" -NoNewFolderButton -InitialDirectory 'Computer\'
    if (![string]::IsNullOrEmpty($directoryPath)) { Write-Host "Ausgewaehltes Verzeichnis: $directoryPath" }
    else { "Kein Verzeichnis ausgewaehlt" }
    
    $newguy = Read-InputBoxDialog -Message "Bitte Projektnamen eingeben" -WindowTitle "_<Projektname>_in-work" -DefaultText "<Projektname>"
    if ($newguy -eq $null) { Write-Host "Abbruch" }
    else { Write-Host "Gewaehlter Projektname lautet $newguy" }
    
    If(!$newguy){
    $isnull++
    }
    else{
    Get-ChildItem -Path $($directoryPath)*.* -Recurse -Force -Exclude *.txt | 
    ForEach-Object {
    $newname = "${newguy}_{0}.*" -f $i
    $i++ 
    Rename-Item -NewName ( '_{0}_in-bearbeitung' -f $newname )
    }
    }
    
    
    ##########################################################################
    #Closing
    ##########################################################################
    if ($Host.Name -eq "ConsoleHost")
    { 
    Write-Host "Press any key to continue..."
    $Host.UI.RawUI.FlushInputBuffer()   # Make sure buffered input doesn't "press a key" and skip the ReadKey().
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
    }
    

    Mittwoch, 14. März 2018 13:37
  • > Rename-Item -NewName ( '_{0}_in-bearbeitung' -f $newname )

    Ja was soll Rename-Item denn auch umbenennen? Entweder Du lieferst ihm Input über die Pipe oder Du mußt das Zielobjekt angeben...

    Mittwoch, 14. März 2018 14:48
  • Vielleicht mal ein oder zwei Tipps für's Debuggen.

    Um einen Fehler "einzukreisen" würde ich alles, was nicht direkt mit dem beanstandeten Fehler zusammenhängt weglassen, wie z.B.  Eye-Candy wie grafische Auswahl-Dialoge oder so etwas. 

    Das umbenennen einer Datei mit der direkten Eingabe der Parameter-Werte wird ja hoffentlich klappen. Dann kann man also versuchen, die Variablen, die man als Parameter-Werte übergeben möchte, vor dem eigentlichen cmdlet "zusammenbauen" und vor der Ausführung einmal ausgeben. Da machen sich dann entweder Haltepunkte gut, oder die zeilenweise Ausführung des Codes. Meistens hat man den Fehler dann schon gefunden.

    Je nach cmdlet könnte man dann noch Common Parameters wie -Verbose oder -PassThru versuchen.

    Dann noch 'n Tipp hier für's Forum, oder eigentlich auch generell für Scripte: Code zu kommentieren ist eine gute Idee. Aber die Powershell ist in weiten Teilen quasi "selbst-dokumentierend".  Jeder der Powershell kann, weiß z.B. was ein "Read-Host" macht. Da bräuchte man nicht dazuschreiben "Abfragen von Eingaben" ... oder so. Komplette Zeilen mit "Gartenzaun" sind auch nicht hilfreich und verschwenden eher nur den in der Höhe meistens knappen Platz. Genau wie unnötig viele Leerzeilen.  ;-) Ein einheitliches Bild beim Einrücken und sinnvoll gesetzte Zeilenumbrüche helfen beim Lesen und Verstehen aber so gut wie immer.


    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Mittwoch, 14. März 2018 15:00
  • Danke für die Tipps!

    Sobald das Skript läuft, werde ich sie beherzigen =)

    Zum Debuggen: Den Fehler kann ich ja schon lokalisieren.. Den Einzeiler, der eigentlich genau das macht was ich möchte habe ich ja schon:

    gci *.* -recurse -force -exclude *.txt| rename-item -NewName {$_.Name -replace '_in-bearbeitung','_projektname_in-bearbeitung'}

    Die Userabfrage funktioniert auch schon, bzw alles was vor der cmdlet gci geschrieben ist läuft.

    Ich bekomme nur die Variable, bzw. den String den der User eingibt nicht richtig übergeben..

    Genauer: Alle Fehlermeldungen richten sich nach der Zeile mit dem cmdlet Rename-Item.

    Der Projektname wird vom User eingegeben und in der Variable $newguy gespeichert. Aber ich kriege einfach die Ausgabe, bzw. das ändern der Dateien (_Projektname_in-bearbeitung.*) nicht hin. Ich hänge hier schon seit 3 Tagen und es frustriert...

    Mittwoch, 14. März 2018 16:16
  • Du sagst, dass der neue Projektname in der Variable $newguy gespeichert wird, aber Du benutzt diese Variable beim Umbenennen gar nicht!?
    Get-ChildItem -Filter *.* -Recurse -Force -Exclude *.txt | 
        Rename-Item -NewName ($_.Name -replace '_in-bearbeitung',"_$($newguy)_in-bearbeitung")
    

    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Mittwoch, 14. März 2018 16:41
  • Du bist schon ein Schritt voraus..

    $newname = "${newguy}_{0}.*" -f $i

    ..damit dies auch auf alle anderen Dateien angewendet werden kann!

    D.h. $newguy wird zu $newname, was auch schließlich ausgegeben werden soll.

    Mittwoch, 14. März 2018 16:51
  • Auch auf die Gefahr hin unhöflich oder altklug oder mäkelig zu erscheinen, aber Dein Code verwirrt mich jedesmal mehr ... Wenn ich mich nicht verguckt habe, benutzt Du die Variable $i bevor Du sie deklarierst.

    Hier, probier mal den Schnipsel:

    $StartPath = 'Pfad zum Startverzeichnis'
    $NewProjectName = Read-Host -Prompt 'Bitte den neuen Projektnamen eingeben'
    $NewProjectName
    Get-ChildItem -Path $StartPath -Recurse -Force -Exclude *.txt | 
        ForEach-Object {
            Rename-Item -Path $_.FullName -NewName $($_.Name -replace '_in\-bearbeitung',"_$($NewProjectName)_in-bearbeitung") -Verbose
        }
    
    möglichst ohne Änderungen ... wenn der funktioniert (bei mir tut er das), kannst Du den Rest drumherum bauen.

    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Mittwoch, 14. März 2018 18:38
  • Falls du dich noch etwas tiefer mit der Materie beschäftigen willst findest du unter [1] einen Microsoft Virtual Academy Kurs, der sich mit Grundlagen der PowerShell auseinandersetzt.

    [1] https://mva.microsoft.com/de-de/training-courses/einfhrung-in-powershell-18319?l=UeWuwtk5E_6111100275

    LG
    Rick

    Mittwoch, 14. März 2018 22:47
  • Danke für den Denkanstoß, ich habe es nun so gelöst:

    function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText) { Add-Type -AssemblyName Microsoft.VisualBasic return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText) } function Read-FolderBrowserDialog([string]$Message, [string]$InitialDirectory, [switch]$NoNewFolderButton) { $browseForFolderOptions = 0 if ($NoNewFolderButton) { $browseForFolderOptions += 512 } $app = New-Object -ComObject Shell.Application $folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory) if ($folder) { $selectedDirectory = $folder.Self.Path } else { $selectedDirectory = '' } [System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null return $selectedDirectory }

    #Start Code $directoryPath = Read-FolderBrowserDialog -Message "Bitte waehle ein Verzeichnis" -NoNewFolderButton -InitialDirectory 'Computer\' if (![string]::IsNullOrEmpty($directoryPath)) { Write-Host "Ausgewaehltes Verzeichnis: $directoryPath" } else { "Kein Verzeichnis ausgewaehlt" } $startpath = Read-InputBoxDialog -Message "Bitte Projektnamen eingeben" -WindowTitle "_<Projektname>_in-work" -DefaultText "<Projektname>" if ($startpath -eq $null) { Write-Host "Abbruch" } else { Write-Host "Gewaehlter Projektname lautet $startpath" } Get-ChildItem -Path $directoryPath -Recurse -Force -Exclude *.txt | ForEach-Object { Rename-Item -Path $_.FullName -NewName $($_.Name -replace '_in\-work',"_$($startpath)_in-work") -Verbose }

    #Closing if ($Host.Name -eq "ConsoleHost") { Write-Host "Press any key to continue..." $Host.UI.RawUI.FlushInputBuffer() $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null }


    Eine neue Version, in der der erste Dialog wegfällt folgt hoffentlich nach dem Wochenende ;)

    Der erste Dialog soll wegfallen. Die Verknüpfung soll eigenständig herausfinden in welchem Verzeichnis es sich befindet. Somit ist es nicht mehr nötig, das richtige Verzeichnis über den ersten Dialog auszuwählen..

    Als Defaultwert im zweiten Dialog soll der Ordnername (und nur dieser) angezeigt werden..

    Das funktioniert schon ganz gut, allerdings wird bisher als Defaultwert der koplette Pfad angezeigt... Das muss ich noch mit RegEx korrigieren..

    Aber jetzt ist erstmal Wochenende ;)

    p.s Danke Rick, evtl setzte ich mich doch noch am Sonntag hin und arbeite den Kurs durch :)


    • Bearbeitet Andreas_AL Freitag, 16. März 2018 11:43
    Freitag, 16. März 2018 11:41
  • Bitte markiere noch die Antworten!

     


    Blog: http://bytecookie.wordpress.com

    Kostenloser Powershell Code Manager v5: Link
    (u.a. Codesnippets verwalten + komplexe Scripte graphisch darstellen)

    Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
    Warum das Ganze? Hier gibts die Antwort.

    Samstag, 17. März 2018 13:43
    Moderator