Umlaute per PowerShell finden und ersetzen

The estimated reading time 14 minutes

Den heutigen Post möchte ich einer Legende des deutschen Fernsehens widmen. „Die Maus“ wird dieses Jahr 50 und hat mich bereits durch die Kindheit begleitet, so wie sie es heute bei meiner Tochter tut. Dieses Stück Fernsehgeschichte soll auch auf meinem Blog den ihr gebührenden Platz haben, deshalb habe ich diese Post ausgewählt. Die Sendung vermittelt Wissen spielerisch und auch Erwachsene können immer wieder etwas lernen. Ganz im Sinne meines Blogs.

Also liebe Maus und natürlich alle Charaktere der Sendung:
Herzlichen Glückwunsch zum 50. Geburtstag

Zurück zu den Umlauten:


Für andere Länder sind unsere deutschen Umlaute ungewöhnlich und eigentlich kann keiner so richtig damit umgehen.
Auf Grund meines Namens bin ich in diverse Probleme geraten, da es nach wie vor einige Systeme gibt, die mit Umlauten der deutschen Sprache Probleme haben. Das hat mich veranlasst ein kleines PowerShell Skript zu schreiben, welches diese in Ordnernamen und Dateien findet und auf Wunsch auch eliminieren kann. Anlass war mein Synology NAS, welches zwar Umlaute unterstützt, nicht aber in Kombination mit dem Hochladen von Dateien in OneDrive Business. Siehe Synology Forum

Machen wirs kurz, wie sieht das Ganze aus?
Aufruf nur prüfen: c:\temp\umlautfinder.ps1 -checkpath [PfadZumOrdner] -logpath [PfadZumLogOrdner] -whatif

Aufruf zum Ändern: c:\temp\umlautfinder.ps1 -checkpath [PfadZumOrdner] -logpath [PfadZumLogOrdner] -changeumlauts

<#
    #### requires ps-version 3.0 ####
    <#
    .SYNOPSIS
    searches for umlauts in folder and filenames only for logging or either changing them. 
    Replacement of these characters Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')
    .DESCRIPTION
    script searches for special characters in files and folders ('ä','ö','ü','Ä','Ö','Ü','ß')
    .PARAMETER checkpath
    path where to search for special characters
    .PARAMETER logpath
    path for logfiles
    .PARAMETER whatif
    creates protocoll but no changes (if no switch parameter definied, whatif is used) 
    .PARAMETER changeumlauts
    creates protocoll and changes umlauts
    .INPUTS
    -
    .OUTPUTS
    two logfiles will be created (files and folders)
    .NOTES
    Version:        0.1
    Author:         Alexander Koehler
    Creation Date:  Wednesday, March 31st 2021, 10:07:13 pm
    File: umlautfinder.ps1
    Copyright (c) 2021 blog.it-koehler.com
    HISTORY:
    Date      	          By	Comments
    ----------	          ---	----------------------------------------------------------

    .LINK
    https://blog.it-koehler.com/en/

    .COMPONENT
    Required Modules: 

    .LICENSE
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the Software), to deal
    in the Software without restriction, including without limitation the rights
    to use copy, modify, merge, publish, distribute sublicense and /or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
 
    .EXAMPLE
    .\umlautfinder.ps1 -checkpath \\server\share -logpath C:\temp\ -whatif 
    C:\folder | .\umlautfinder.ps1 -logpath C:\temp\  
    .\umlautfinder.ps1 -checkpath X:\ -logpath C:\log\ -changeumlauts
    .\umlautfinder.ps1 -checkpath X:\,\\server\share2,C:\documents -logpath C:\log\ -changeumlauts
    #

#>
[CmdletBinding()]
param (
  [Parameter(Mandatory = $true, HelpMessage='"w:\","x:\"',ValueFromPipeline,ValueFromPipelineByPropertyName)]
  #test if the folder exists, otherwise throw an error.Test if the user provides a full path to the folder
  [Object[]]
  [ValidateScript({
        #check if destination is a folder
        foreach($obj in $_){
          if(($_ | Test-Path -PathType Leaf)){
            
            throw "The path argument has to be a folder. File paths are not allowed."
          }
          else{
            return $true
          }
        }
        
  })]
  #check if it is a path to folder
  #[System.IO.DirectoryInfo]$checkpath,
  $checkpath,
  #test if the file exists, otherwise throw an error.Test if the user provides a full path to the file
  [Parameter(Mandatory = $true , HelpMessage="c:\logs\")]
  [ValidateScript({
       
        if(($_ | Test-path -PathType Leaf)){
          throw "path has to be a folder, no files allowed!"
        }
       
        return $true
        
  })]
  #check if it is a folder path
  [System.IO.DirectoryInfo]$logpath,
  #parameter for executing and changing special characters (with logging) 
  [Parameter(Mandatory = $false)]
  [switch]$changeumlauts,
  #whatif parameter (only logging) 
  [Parameter(Mandatory = $false)]
  [switch]$whatif=$false
)


#file logging
[string] $csvLogfilePath = "$logpath"
[string] $csvLogfileDate = Get-Date -Format "yyyy-MM-dd-HH-mm-ss"
[string] $csvLogfileNamePrefix = "umlaut-finder-files-"
[string] $csvLogfileName = $("$csvLogfileNamePrefix" + "$csvLogfileDate" + ".csv")
[string] $csvLogfile = $csvLogfilePath + "\" + $csvLogfileName

#folder logging
[string] $csvLogfilePathfolder = "$logpath"
[string] $csvLogfileNamePrefixfolder = "umlaut-finder-folder-"
[string] $csvLogfileName = $("$csvLogfileNamePrefixfolder" + "$csvLogfileDate" + ".csv")
[string] $csvLogfilefolder = $csvLogfilePathfolder + "\" + $csvLogfileName
#adding tableheader
Add-Content -Path "$csvLogfile" -Value "#### files with special characters" -Encoding UTF8
Add-Content -Path "$csvLogfile" -Value "folderpath;filename;duplicates;maxpathlengtherror" -Encoding UTF8
Add-Content -Path "$csvLogfilefolder" -Value "#### Folders with special characters" -Encoding UTF8
Add-Content -Path "$csvLogfilefolder" -Value "folderpath;duplicates;maxpathlengtherror" -Encoding UTF8

foreach($pathstocheck in $checkpath){
  #search patterns
  $pattern = 'ä','ö','ü','Ä','Ö','Ü','ß'
  foreach($folder in $pathstocheck){
    Write-Host "####Searching files with special characters in folder: $folder ..." -ForegroundColor Magenta
    #find all files/folders inside specified path  
    $files=Get-ChildItem  -Path "$Folder" -Recurse -File  | Sort-Object fullname 
    $folders = Get-ChildItem  -Path "$Folder" -Recurse -Directory | Sort-Object fullname
    ####searching for files
    foreach ($file in $files) {
      #check pathlength
      $fullpathlength = ($file).Fullname.Length
      
      
        #filename without file extension
        $umlautfile = $file.BaseName
        $umlauts = $(try {Select-String -InputObject $umlautfile -Pattern $pattern -AllMatches} catch {$null})
        #only rename files with umlauts
        If ($umlauts -ne $Null) {
          $filename1 = ($file).Name
          $path1 = ($file).DirectoryName
          Write-Host "files with special characters: $filename1  in folder: $path1" -ForegroundColor Yellow
                  #rename files with less than 260 pathlength
                  if($fullpathlength -lt 260){
                        Add-Content -Path $csvLogfile -Value "$path1;$filename1" -Encoding UTF8
                          #check if parameter whatif present 
                          if(($whatif.IsPresent) -or ($whatif -eq $false)){
                            #creating new name (replacement) 
                            $NewName=$file.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+$file.Extension
                            #checks if exists already
                            if(Test-Path "$path1\$NewName"){
                              #creating new name with extension --1
                              $NewName=$file.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+"--1"+$file.Extension
                              Write-Host "duplicated file name detected new name $NewName" -ForegroundColor Red
                              Add-Content -Path "$csvLogfile" -Value "$path1;$filename1;DUP--$NewName" -Encoding UTF8
                              $file | Rename-Item -NewName $NewName -WhatIf
                            }
                            else{
                              $file | Rename-Item -NewName $NewName -WhatIf
                            }
                           }
                           #do renaming if present
                          if($changeumlauts.IsPresent){
                            $NewName=$file.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+$file.Extension
                            #checks if already exists
                            if(Test-Path "$path1\$NewName"){
                              Write-Host "duplicated file with name $newname detected, adding --1" -ForegroundColor Red
                              $NewName=$file.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+"--1"+$file.Extension
            
                              $file | Rename-Item -NewName "$NewName"
                              Add-Content -Path "$csvLogfile" -Value "$path1;$filename1;DUP--$NewName" -Encoding UTF8
                            }
                            else{$file | Rename-Item -NewName $NewName}
          
                          }
          
                  }
                  #if path is more than 260 chars
                  else{
            
                    if(($whatif.IsPresent) -or ($whatif -eq $false)){
                      $fullfilepath = ($file).fullname
                      Write-Host "WARNING Special character found but path $fullfilepath more than 260 characterslong,length: $fullpathlength" -ForegroundColor Yellow
                      #change path with .net function for long paths
                      $pathtofile = ($file).Fullname
                      $pathtoolong = "\\?\$pathtofile"
                      $NewName=$file.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+$file.Extension
                      #rename
                      Rename-Item -LiteralPath "$pathtoolong" -NewName $NewName -WhatIf
                      Add-Content -Path $csvLogfile -Value "$path1;$filename1;;WARNING MAX-Path-Length $fullpathlength (Rename done)" -Encoding UTF8
                    }
            
            
                     if($changeumlauts.IsPresent){
            
                       $fullfilepath = ($file).fullname
                       Write-Host "WARNING Special character found but path $fullfilepath more than 260 characterslong,length: $fullpathlength" -ForegroundColor Yellow
                      #change path with .net function for long paths
                       $pathtofile = ($file).Fullname
                       $pathtoolong = "\\?\$pathtofile"
                       $NewName=$file.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+$file.Extension
                      #rename file
                       Rename-Item -LiteralPath "$pathtoolong" -NewName $NewName
                       Add-Content -Path $csvLogfile -Value "$path1;$filename1;;WARNING MAX-Path-Length $fullpathlength (Rename done)" -Encoding UTF8
                     }
          
          
                  }
          
                }
  
        else{
          $dateiohneumlaute = ($file).Name
          Write-Host "File: $dateiohneumlaute has no special characters" -ForegroundColor Green
  
        }
      
    }
    Write-Host "#### Searching for folders with special characters..." -ForegroundColor Magenta
    
    ##searching foldername 
    foreach ($fold in $folders) {
      #checking folder length
      $fullpathlength = ($fold).Fullname.Length
      #getting foldername
      $umlautfolder = $fold.BaseName
      
      #check if folder contains special character
      $umlautfold = $(try {Select-String -InputObject $umlautfolder -Pattern $pattern -AllMatches} catch {$null})
      If ($umlautfold -ne $Null) {
        $ordnername = ($fold).Name
        #get full path
        $ordnerpfad = ($fold).FullName
        Write-Host "Folder with special character found: $ordnername  see path: $ordnerpfad" -ForegroundColor Yellow
                         #check if folderpath is longer than 260 chars
                          if($fullpathlength -lt 260){
                            Add-Content -Path "$csvLogfilefolder" -Value "$ordnerpfad" -Encoding UTF8
                            #parameter whatif is set, no changes made to folder structure (simulation)
                            if(($whatif.IsPresent) -or ($whatif -eq $false)){
                              $NewName=$fold.Name.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')
                              $newpath = (($fold | Select-Object PSparentpath -ExpandProperty PSparentpath) + "\$NewName")
                              #check if the folder already exists
                              if(Test-Path "$newpath"){
                                Write-Host "duplicated folders detected, adding --1" -ForegroundColor Red
                                $NewName=$fold.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')
                                $Newname = "$NewName--1"
                                $fold | Rename-Item -NewName "$NewName" -WhatIf
                                #additional logging
                                Add-Content -Path "$csvLogfilefolder" -Value "$ordnerpfad;DUP--$NewName (Rename done)" -Encoding UTF8
                              }
                              else{
                                $fold | Rename-Item -NewName $NewName -WhatIf
                              }
      
                            }
                            #if parameter is set
                            if($changeumlauts.IsPresent){
                              $NewName=$fold.Name.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')
                              $newpath = (($fold | Select-Object PSparentpath -ExpandProperty PSparentpath) + "\$NewName")
                              #check if the new folder name already exists
                              if(Test-Path "$newpath"){
                                Write-Host "duplicated folders detected, adding --1" -ForegroundColor Red
                                $NewName=$fold.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')
                                $Newname = "$NewName--1"
                                $fold | Rename-Item -NewName "$NewName"
                                #additional logging
                                Add-Content -Path "$csvLogfilefolder" -Value "$ordnerpfad;DUP--$NewName (Rename done)" -Encoding UTF8
          
                              }
                              else{$fold | Rename-Item -NewName $NewName}
          
                            }
      
                          }
                          #if path is longer than 260 chars
                          else{
        
                            #whatif or nothing defined
                            if(($whatif.IsPresent) -or ($whatif -eq $false)){
                                Write-Host "WARNING Special character found but path $ordnerpfad more than 260 characterslong,length: $fullpathlength" -ForegroundColor Yellow
                                #change path with .net function for long paths
                                $pathtoolong = "\\?\$ordnerpfad"
                                $NewName=$fold.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+$file.Extension
                                #rename
                                $pathtoolong | Rename-Item -NewName "$NewName" -WhatIf
                                Add-Content -Path $csvLogfile -Value "$ordnerpfad;WARNING MAX-Path-Length $fullpathlength (Rename done)" -Encoding UTF8
                              }
                      
                               if($changeumlauts.IsPresent){
                                Write-Host "WARNING Special character found but path $ordnerpfad more than 260 characterslong,length: $fullpathlength" -ForegroundColor Yellow
                                #change path with .net function for long paths
                                $pathtoolong = "\\?\$ordnerpfad"
                                $NewName=$fold.BaseName.Replace('ä','ae').Replace('Ä','Ae').Replace('ö','oe').Replace('Ö','Oe').Replace('ü','ue').Replace('Ü','Ue').Replace('ß','ss')+$file.Extension
                                #rename
                                $pathtoolong | Rename-Item -NewName "$NewName"
                                Add-Content -Path $csvLogfile -Value "$ordnerpfad;WARNING MAX-Path-Length $fullpathlength (Rename done)" -Encoding UTF8
                               }
          
                            }
                        }
    
                        else{
                          $ordnerohneumlaute = ($fold).Name
    
                          Write-Host "folder: $ordnerohneumlaute not containing special characters." -ForegroundColor Green
  
                        }
    
    }
  }
}
WESTDEUTSCHER RUNDFUNK KÖLN Frag doch mal die Maus Die Familienshow mit Eckart von Hirschhausen Logo © WDR, honorarfrei – Verwendung gemäß der AGB im engen inhaltlichen, redaktionellen Zusammenhang mit genannter WDR-Sendung und bei Nennung „Bild: WDR“ (S2). WDR Presse und Information/Bildkommunikation, Köln, Tel: 0221/220 -7132 oder -7133, Fax: -777132, bildkommunikation@wdr.de

Was das Skript kann:

  • Skript kann Umlaute in lokalen Ordnern/Dateien und Netzwerkfreigaben finden
  • es kann Umlaute in Ordnern und Dateien nach festen Definitionen ändern (Bsp: Ä=Ae,ö=oe,ß=ss), falls der Parameter gesetzt ist
  • außerdem Umlauten suchen und eine Protokoll CSV ausgeben (ohne Änderungen vorzunehmen)
  • sollte es bereits eine Datei /Ordner mit dem selben Namen geben, wird „–1“ an den Namen angehängt (wird im Log bei der Spalte Duplicate angezeigt)
  • es kann mehrere Pfade nacheinander durchsuchen (muss im Pfad angegeben werden)
  • es erkennt wenn kein Pfad angegeben wird
  • Dateien und Ordner werden in separate CSV Dateien geloggt
  • Dateien und Ordner mit langem Pfad (mehr als 260 Zeichen) werden ebenfalls umbenannt
  • Ordnerpfade können per Pipeline übergeben werden ( „C:\ordner“ | .\umlautfinder.ps1 -logpath c:\log -whatif)

Was es nicht kann:

  • funktioniert nicht auf älteren Systemen (PowerShell 3.0 wird benötigt)
  • kann den Namen der Logdatei nicht angegeben werden
  • es werden immer Ordner UND Dateien geändert (keine Auswahl möglich)
  • keine erweiterte Fehlerbehandlung (nur zu lange Pfade über 260 Zeichen)

Gerne bin ich für Verbesserungsvorschläge / Featurerequests offen. Lasst mir einfach einen Kommentar da oder schreibe mich direkt an. Wenn euch das Skript weitergebracht hat, lasst es mich ebenfalls wissen mit dem Button „Helpful“. Vielen Dank und weiterhin viel Erfolg.

Was this article helpful?
YesNo
5 1 vote
Article Rating
Abonnieren
Benachrichtige mich bei
guest
5 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
A.Karl
A.Karl
3 Jahre zuvor

an sich ein super Script, nur leider bei mir ohne Funktion:

„File: Äste.txt has no special characters“

Marius Henkel
Marius Henkel
Reply to  A.K.
2 Jahre zuvor

Hallo,

leider bei mir immer noch…

folder: Bäderhalle not containing special characters.

Dennoch Danke für die Mühe!!

Marius Henkel
Marius Henkel
Reply to  A.K.
2 Jahre zuvor

funktioniert nun! Merci