0

I have no problem adding sequential prefixes to filenames. The following works great on the top directory in question.

$path="E:\path\newtest1"
$count=4000
Get-ChildItem $path -recurse | Where-Object {!$_.PSIsContainer -and $_.Name -NotMatch '^\d{4}\s+'}  | ForEach -Process {Rename-Item $_ -NewName ("$count " + $_.name -f $count++) -whatif}

BUT if there are files in subfolders within the top directory, these are all completely missed. Whatif reports that for any deeper file it "does not exist".

I have tried the following, based on looking at some pages on other recursion problems, but as you can probably guess I have no clue what it is doing. Whatif shows that it does at least pickup and rename all the files. But the following does it too much and makes multiple copies of each file with each number:

$path="E:\path\newtest1"
$count=4000
Get-ChildItem  -recurse | ForEach-Object {  Get-ChildItem $path | Rename-item -NewName    ("$count " + $_.Basename  -f $count++) -whatif}

Really keen to get some guidance on how to get the first of these two snippets to work to find all files in all subdirectories and rename them with sequential number prepended.

1 Answers1

2

Try it like so:

Get-ChildItem $path -recurse -file | Where Name -NotMatch '^\d{4}\s+' | 
    Rename-Item -NewName {"{0} $($_.name)" -f $count++} -whatif

When you supply $_ as an argument (not a pipeline object), that gets assigned to the Path parameter which is of type string. PowerShell tries to convert that FileInfo object to a string but unfortunately the "ToString()" representation of files in nested folders is just the filename and not the full path. You can see this by executing:

Get-ChildItem $path -recurse -file | Where Name -NotMatch '^\d{4}\s+' | ForEach {"$_"}

The solution is either to A) pipe the object into Rename-Item or B) use the FullName property e.g. Rename-Item -LiteralPath $_.FullName ....

Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • Or C) Pipe the object into a ForEach and use $_.MoveTo() – TheMadTechnician May 13 '14 at 15:39
  • Many thanks Keith, I changed to {"{0} $($_.name)" successfully. The part I can't get working is syntax to do A) pipe the objects into Rename-item. if I use `ForEach-object -Process {Rename-Item {"{0} $($_.FullName)" -f $count++} -whatif }` -whatif reports "Cannot evaluate parameter 'Path' because its argument is specified as a script block ". Adding -LiteralPath produces "NamedParameterNotFound". Any advice much appreciated. – user3632867 May 13 '14 at 21:35
  • In scenario A, you don't use `Foreach` you pipe directly into the Rename-Item command as it accepts pipeline input. The trick is that you need to access the pipeline object in the argument for the NewName parameter. That's were you use a scriptblock to make that work. See my first example above. That works for PowerShell V3 and above. – Keith Hill May 13 '14 at 22:44
  • Thanks for getting back so fast and for the clear explanation. Crucially, find I'm on V2 on this machine. Under that A) gets to all files in subdirectories, but the $count is not incremented so all files have the same number prepended. I'll get on another machine and let you know. – user3632867 May 14 '14 at 01:28
  • For V2 use `$global:count++`. – Keith Hill May 14 '14 at 01:52
  • You're a bloody legend Keith. This was head vs wall stuff for me. Using $global:count++ solves all issues at V2. Many thanks again. – user3632867 May 14 '14 at 03:13