2
votes

renommer plusieurs dossiers (fonctionne avec des erreurs!)

Je suis nouveau sur PowerShell et j'ai écrit le script suivant, en utilisant ISE , en essayant de renommer un tas de dossiers dans le même répertoire, qui ont strictement le format de date 20201130 en 2020-11-30 (simplement en ajoutant des tirets) le script un peu fonctionne, mais j'ai 3 problèmes avec cela.

1- quand il s'est exécuté, il a jeté un tas d'erreurs liées à Rename-Item l'erreur:

$FileNameArr_All = (Get-ChildItem).Name
$i = 0

foreach($file in $FileNameArr_All){
    
    if ( ($file -match "^\d+$") -and ($file.Length -eq 8) ){
    
        [string] $MyNewName = $file.Substring( 0 , 4 )+"-"+$file.Substring( 4 , 2 )+"-"+$file.Substring( 6 , 2 )
        
        #the actual renamining of the item, where the error is:
        Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }

        $message = "the item " + $file + " has been renamed : " + $MyNewName
        Write-Output $message
        $i ++

        Write-Output $file.Length
    }
}
if ($i -eq 0){
    Write-Output "No mathcing items found."
}
else{
    $message2 = "total of items affected: " + $i
    Write-Output $message2
}

2- quand je l'ai testé avec un dossier nommé (234567890) il fonctionnait encore bien que la longueur de ce dossier ne soit pas égale à 8!

3- lorsque le changement de nom ci - dessus est arrivé le nom résultant était « 1234-56- 7890 » , qui est étrange puisque $MyNewName doit se terminer par 2 personnages! $file.Substring( 6 , 2 )

le script:

Rename-Item : Source and destination path must be different.
At line:13 char:25
+ ... ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (D:\Google Drive...Term 2\testings:String 
   ) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.Renam 
   eItemCommand

Je sais que c'est beaucoup mais c'est mon premier message, et mon premier script, j'apprécie d'aider sur l'un des points.
Merci beaucoup :)


1 commentaires

Permettez-moi de vous donner le conseil standard aux nouveaux arrivants: si vous acceptez une réponse, vous aiderez les futurs lecteurs en leur montrant ce qui a résolu votre problème. Pour accepter une réponse, cliquez sur le grand symbole ✓ sous le grand nombre à gauche de la réponse (vous obtiendrez 2 points de réputation). Si vous avez au moins 15 points de réputation, vous pouvez également voter pour d'autres réponses utiles (éventuellement aussi celle acceptée). Si votre problème n'est pas encore résolu, fournissez des commentaires ou, si vous avez trouvé la solution vous-même, répondez vous- même .


4 Réponses :


1
votes

au lieu de ...

Rename-Item -Name $file -NewName $MyNewName

essayez ...

Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }


0 commentaires

1
votes

Vous pouvez demander à regex -match dans la clause Where-Object de vérifier que le nom du dossier contient exactement 8 chiffres et de ne renommer que ceux-ci:

Get-ChildItem -Path 'D:\Test' -Directory | 
    Where-Object { $_.Name -match '^\d{8}$' } | 
    Rename-Item -NewName {$_.Name -replace '(\d{4})(\d{2})(\d{2})', '$1-$2-$3'} -WhatIf

Ici, le commutateur -WhatIf garantit que vous ne voyez que ce qui se passerait. Rien n'est encore renommé. Si vous êtes satisfait de cette sortie, supprimez le commutateur -WhatIf de la cmdlet Rename-Item.

En outre, regex -replace rend la création du nouveau format de nom beaucoup plus facile que d'utiliser Substring () plusieurs fois, en capturant les chiffres dans 3 `` backreferences '' différentes et en les affichant avec des tirets entre les deux.

Si vous ne vous souciez pas des messages Write-Host à tout moment, le code peut être raccourci à

$i = 0
Get-ChildItem -Path 'D:\Test' -Directory | 
    Where-Object { $_.Name -match '^\d{8}$' } | 
    ForEach-Object {
        $newName = $_.Name -replace '(\d{4})(\d{2})(\d{2})', '$1-$2-$3'
        Write-Host "Renaming folder $($_.FullName) to: $newName"
        $_ | Rename-Item -NewName $newName -WhatIf
        $i++
    }

if ($i) {
    Write-Host "Total of items affected: $i"
}
else {
    Write-Host "No matching folder names found"
}


0 commentaires

0
votes

Ce script fonctionne un peu plus fiable, car il utilise les objets de réexécution de "Get-ChildItem" et pas seulement les noms de fichier / dossier.

$i = 0
Get-ChildItem -Directory "C:\UserData\Test" | ForEach-Object {
    if (($_.Name) -match "^\d{8}$") {
        [System.String]$NewFolderName = ($_.Name).Insert(6, "-").Insert(4, "-")
        Rename-Item -Path ($_.FullName) -NewName $NewFolderName
        Write-Output ("the item {0} ({1}) has been renamed : {2}" -f  ($_.Name), (($_.Name).Length), $NewFolderName)
        $i++
    }
}

if ($i) {
    Write-Output ("total of items affected: {0}" -f $i)
} else{
    Write-Output "No matching items found."
}


0 commentaires

2
votes

Il y a de bonnes informations dans les réponses existantes, mais permettez-moi de les résumer conceptuellement et d'offrir une solution plus rationalisée:

  • Vous bouclez sur tous les noms de répertoires, individuellement , mais vous essayez de renommer tous les éléments de chaque itération de boucle, en utilisant simplement Get-ChildItem - pas d'arguments - comme entrée pour Rename-Item :

    • Get-ChildItem | Rename-Item ... envoie tous les fichiers et sous-répertoires à Rename-Item ; vous essayez effectivement de tous les renommer avec leurs noms existants (voir la puce suivante), ce qui est une opération silencieuse pour les fichiers , mais qui déclenche Source and destination path must be different erreur Source and destination path must be different pour les répertoires .
  • $MyNewName est le nouveau nom de fichier complet, donc il n'y a aucune raison d'utiliser -replace sur le nom du répertoire d' origine: depuis $MyNewName n'est pas une sous - chaîne des noms existants, $_.Name -replace $file, $MyNewName Est efficace a no-op - le $_.Name existant $_.Name est passé.

Cependant, vous pouvez rationaliser votre solution pour utiliser un pipeline unique , comprenant un appel Get-ChildItem qui utilise une expression générique pour faire correspondre les répertoires d'intérêt, et Rename-Item avec un bloc de script de liaison de retard pour insérer les caractères - . dans les noms des éléments correspondants via l' opérateur -replace basé sur les regex:

$files = Get-ChildItem -Directory -Path ('[0-9]' * 8)

$files | Rename-Item -NewName { $_.Name -replace '(.{4})(.{2})(.{2})', '$1-$2-$3'  } -Verbose

Write-Verbose -Verbose $(if ($files) { "$($files.Count) directories renamed." } else { 'No matching directories found.' })

Ce qui précède effectue le changement de nom souhaité et, en raison de l'utilisation du paramètre commun -Verbose , imprime ce qui suit (sauts de ligne pour plus de lisibilité):

VERBOSE: Performing the operation "Rename Directory" on target "Item: ...\12345678 
         Destination: ...\1234-56-78".       
VERBOSE: Performing the operation "Rename Directory" on target "Item: ...\87654321
         Destination: ...\8765-43-21".

Remarque:

  • Si vous souhaitez prévisualiser l'opération de changement de nom, utilisez le paramètre commun -WhatIf avec Rename-Item .

  • Si vous avez besoin de savoir si des fichiers correspondent et ont donc été renommés, capturez d'abord l'appel Get-ChildItem dans une variable:

    # Create two sample directories
    $null = New-Item -Force -Type Directory '12345678', '87654321'
    
    Get-ChildItem -Directory -Path ('[0-9]' * 8) |
      Rename-Item -NewName { $_.Name -replace '(.{4})(.{2})(.{2})', '$1-$2-$3'  } -Verbose
    


0 commentaires