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 :)
4 Réponses :
au lieu de ...
Rename-Item -Name $file -NewName $MyNewName
essayez ...
Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }
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" }
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." }
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é.
$MyNewName
- pas à l' intérieur d'un bloc de script à liaison différée ( { ... }
) - suffirait. 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
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 .