I have a large number of pdf's that need renamed in sequential order. These were originally scanned into a single document, then extracted as separate files. When extracted, the name becomes "444026-444050 1", "444026-444050 2", etc. I am trying to rename all the files to match the document number ("444026-444050 1" would become "444026").
I found the following line of code that I can use in Powershell, but it seems that anything over 9 files there is a problem! Once I try it with 10 files, only the first file is saved correctly. The rest become jumbled (file 444027 has the contents of file 444035, then file 444028 has 444027, and 444029 has 444028, etc.)
I imagine there is some sort of problem with a loop, but am having difficulty fixing it.
Can someone help?
thanks
Dir *.pdf | ForEach-Object -begin { $count=26 } -process { rename-item $_ -NewName "4440$count.pdf"; $count++ }
Alright. Let's see if this makes everybody happy. Maybe you should try this with a backup copy of the files.
# make some test files in a new folder
# 1..20 | foreach {
# if (! (test-path "44026-44050 $_.pdf")) {
# echo "44026-44050 $_" > "44026-44050 $_.pdf" }
# }
# rename and pad the first 9 old filenames with a 0 before the last digit for sorting
# is it less than 100 files?
1..9 | foreach {
ren "44026-44050 $_.pdf" "44026-44050 0$_.pdf" -whatif
}
# make dir complete first with parentheses for powershell 5
# pad $count to 2 digits
# take off the -whatif if it looks ok
(dir *.pdf) | foreach { $count = 1 } {
$padded = $count | foreach tostring 00
rename-item $_ -newname 4440$padded.pdf -whatif; $count++ }
The order in which Dir (which is an alias for Get-ChildItem) retrieves the items does not appear to be strictly guaranteed. Furthermore, if it is sorting it's probably sorting them as strings and "444026-444050 10" comes before "444026-444050 2" as strings. It might be worth inserting SortObject into your pipeline and using Split to get at the sequence number you care about:
Dir *.pdf | Sort-Object -Property {[int]$_.Name.Split()[1].Split(".")[0]} | ForEach-Object -begin { $count=26 } -process { rename-item $_ -NewName "4440$count.pdf"; $count++ }
The key part is this new pipeline stage inserted after Dir and before ForEach-Object:
Sort-Object -Property {[int]$_.Name.Split()[1].Split(".")[0]}
This says to sort the output of Dir according to the whatever comes between the first space and the subsequent period, comparing those things as integers (not strings). This ensures that your results will be ordered and that you'll get them in numeric order, not lexicographic order.
Related
I have a bunch of files with integers that range from 30.pdf to 133.pdf as filenames. What I am trying to do is increment each filename, so 30.pdf should become 31.pdf, ..., and 133.pdf should become 134.pdf.
Does anybody know how I can achieve this?
I know I can loop through the directory with foreach ($f in dir) or display and even sort the filenames with get-childitem | sort-object, but this latter method obviously has issues sorting numerically.
No idea why something so simple is so difficult to figure out. Cannot find this anywhere online...
This should work assuming the BaseName of the files contains only digits as you have shown on your question. First you would need to sort the files descending to avoid collision and after that you can pipe them to Rename-Item using the -NewName script block:
Get-ChildItem path/to/files -File | Sort-Object { [int]$_.BaseName } -Descending |
Rename-Item -NewName {
[int]$n = $_.BaseName; '{0}{1}' -f (++$n), $_.Extension
}
We can take some shortcuts to make this easier since your file names are literally just integers. Start by using this statement to get a collection of integers that represents your files ($files is the output of Get-ChildItems from the parent directory):
$integersFromNames = $files | Select -ExpandProperty BaseName | foreach { $_ -as [int] } | sort ‐Descending
Now you have all of the existing files sorted from largest to smallest. You can use Rename-Item in a foreach loop to get you the rest of the way:
foreach ($oldNumber in $integersFromNames) {
$newNumber = $oldNumber + 1
Rename-Item -Path "$oldNumber.pdf" -NewName "$newNumber.pdf"
}
Please excuse any typos. I'm on my phone. Hopefully the concept comes across clearly.
Looking for help writing a script that will remove a specific number of characters from the end of a file name. In my specific dilemma, I have dozens of files with the following format:
1234567 XKJDFDA.pdf
5413874 KJDFSXZ.pdf
... etc. etc.
I need to remove the last 7 alpha characters to leave the 7 digits standing as the file name. Through another posted question I was able to find a script that would remove the first X number of digits from the beginning of the file name but I'm having an incredibly difficult time modifying it to remove from the end:
get-childitem *.pdf | rename-item -newname { [string]($_.name).substring(x) }
Any and all relevant help would be greatly appreciated.
Respectfully,
$RootFolder = '\\server.domain.local\share\folder'
Get-ChildItem -LiteralPath $RootFolder -Filter '*.pdf' |
Where-Object { $_.psIsContainer -eq $false } | # No folders
ForEach-Object {
if ($_.Name -match '^(?<BeginningDigits>\d{7})\s.+\.pdf$' ) {
$local:newName = "$($Matches['BeginningDigits'])$($_.Extension)"
return Rename-Item -LiteralPath $_.FullName -NewName $local:newName -PassThru
}
} |
ForEach-Object {Write-Host "New name: $($_.Name)"}
If file name matches "<FilenameBegin><SevenDigits><Space><Something>.pdf<FilenameEnd>", then rename it to "<SevenDigits>.<KeepExtension>". This uses Regular Expressions with Named Selection groups ( <BeginningDigits> is group name ). Take a note that due to RegExp usage, this is most CPU-taking algorythm, but if you have one-time run or you have little amount of files, there is no sense. Otherwise, if you have many files, I'd recommend adding Where-Object { $_.BaseName.Length -gt 7 } | before if (.. -match ..) to filter out files shorter than 7 symbols before RegExp check to minimize CPU Usage ( string length check is less CPU consumable than RegExp ). Also you can remove \.pdf from RegExp to minimize CPU usage, because you already have this filter in Get-ChildItem
If you strictly need match "<7digits><space><7alpha>.pdf", you should replace RegExp expression with '^(?<BeginningDigits>\d{7})\s[A-Z]{7}\.pdf$'
$RootFolder = '\\server.domain.local\share\folder'
#( Get-ChildItem -LiteralPath $RootFolder -Filter '*.pdf' ) |
Where-Object { $_.psIsContainer -eq $false } | # No folders
Where-Object { $_.BaseName.Length -gt 7 } | # For files where basename (name without extension) have more than 7 symbols)
ForEach-Object {
$local:newName = [string]::Join('', $_.BaseName.ToCharArray()[0..6] )
return Rename-Item -LiteralPath $_.FullName -NewName $local:newName -PassThru
} |
ForEach-Object {Write-Host "New name: $($_.Name)"}
Alternative: Using string split-join: Rename all files, whose name without extension > 7 symbols to first 7 symbols ( not taking in account if digits or not ), keeping extension.
This is idiotic algorythm, because Substring is faster. This just can help learning subarray selection using [x..y]
Please take note that we check string length > 7 before using [x..y] in Where-Object { $_.BaseName.Length -gt 7 }. Otherwise we cat hit error when name is shorter than 7 symbols and we trying to take 7th symbol.
$RootFolder = '\\server.domain.local\share\folder'
#( Get-ChildItem -LiteralPath $RootFolder -Filter '*.pdf' ) |
Where-Object { $_.psIsContainer -eq $false }
Where-Object { $_.BaseName.Length -gt 7 } | # For files where basename (name without extension) have more than 7 symbols)
ForEach-Object {
$local:newName = $x[0].BaseName.Substring(0,7)
return Rename-Item -LiteralPath $_.FullName -NewName $local:newName -PassThru
} |
ForEach-Object {Write-Host "New name: $($_.Name)"}
Alternative: Using substring. Rename all files, whose name without extension > 7 symbols to first 7 symbols ( not taking in account if digits or not ), keeping extension.
.Substring(0,7) # 0 - position of first symbol, 7 - how many symbols to take. Please take note that we check string length > 7 before using substring in Where-Object { $_.BaseName.Length -gt 7 }. Otherwise we cat hit error when name is shorter than 7 symbols
A much simpler alternative to PowerShell is using Command Prompt. If your filenames are along the lines of "00001_01.jpg", "00002_01.jpg", "00003_01.jpg", you can use the following command:
ren ?????_0.jpg ?????.jpg
where the number of ? matches the first part of the filename that you want to keep.
You can read more about this and other Command Prompt methods of batch renaming files in Windows at this useful website.
EDIT: edited to preserve the extension
There's another substring() method that takes 2 args, startIndex and length. https://learn.microsoft.com/en-us/dotnet/api/system.string.substring?view=netframework-4.8
'hithere'.substring
OverloadDefinitions
-------------------
string Substring(int startIndex)
string Substring(int startIndex, int length)
Thus, to delete a total of 8 characters from the right of the basename, including the space:
get-childitem *.pdf | rename-item -newname { $_.basename.substring(0,
$_.basename.length-8) + $_.extension } -whatif
What if: Performing the operation "Rename File" on target
"Item: /Users/js/1234567890.pdf
Destination: /Users/js/12.pdf".
You can write a quick bash function for this.
function fileNameShortener() {
mv "$1" ${1:0:4}
}
This will take the first Argument. which is stored in $1, and create a substring from index 0 to the index 4 characters to the left. This is then used in the move command to move the initial file to the new filename. To Further generalise:
function fileNameShortener2() {
mv "$1" ${1:$2:$3}
}
This can be used, to give starting point, and length of the Substring as second and third function argument.
fileNameShortener fileName.txt 0 -5
This sample would remove the last 5 characters from the Filename.
I have a need for a script that can look at our backup folders (we take full backups of machines) and ensure that we never store more than the two most recent backups for each computer. I am currently working on a powershell loop that should compare each file name to every other file in the backup folder. Each machine has multiple backup files that can be identified by a matching prefix and a unique ID number separated by a delimiting character.
prefix = machine name and unique ID denotes each backup.
I am working on setting up the outer loop and running into a wall. I am storing the list of files to be checked in $array.
I have a nested for loop that I want to have check each file against every other file in the array. I have a query that should rebuild the array and exclude the current reference file each iteration.
for ($i=0; $i -lt 5; $i++) {
$array = Get-ChildItem -Path C:\Users\Aaron.Trujillo\Desktop\test
$array = Get-ChildItem -Path C:\Users\Aaron.Trujillo\Desktop\test -Exclude $array[$i]
for ($j=0; $j -lt 5; $j++){
Write-Host "i: $i j: $j"
Write-Host "Array i: $($array[$i].name) Array j: $($array[$j].name)"
if($array[$i].name -ne $array[$j].name)
{
Write-Host "truthval=false"
$truthval="false"
}
else
{
Write-Host "truthval=true"
$truthval = "true"
}
}
}
I was expecting this loop to compare the first five files in the array against each other (excluding the current reference file) and change the variable for each file, but for some reason the reference file isn't getting excluded.
Something must be wrong with the logic, but I'm struggling to spot it.
I see several flaws with your code.
As $array is presumably populated by a Get-ChildItem (which on ntfs formatted drives returns a sorted output) the nested loops aren't neccessary at all.
When iterating with one for simply compare with the predessor/follower index +/- 1.
As Names include per your description an ID, they are always different. So you've to split the name at the nebulous delimiter and check if the machine name is the same.
your if command doesn't emit anything, it just overwrites the same variable on every iteration.
With #Lee_Dailey's good idea of grouping you can split the names on the fly and check the count per group, sort files per group by LastWriteTime and only keep the newest 2.
So given a hypothetical tree of files
> tree /F
A:.
└───Backup
Alpha_8.bak
Bravo_2.bak
Bravo_5.bak
Bravo_6.bak
Bravo_7.bak
Bravo_9.bak
Charlie_1.bak
Charlie_10.bak
Charlie_3.bak
Charlie_4.bak
this small script:
$BackupDir = 'A:\Backup'
$Delim = '_'
Get-ChildItem -Path $BackupDir -File |
Group-Object {($_.BaseName -split $Delim)[0]}
yields:
Count Name Group
----- ---- -----
1 Alpha {Alpha_8.bak}
5 Bravo {Bravo_2.bak, Bravo_5.bak, Bravo_6.bak, Bravo_7.bak...}
4 Charlie {Charlie_1.bak, Charlie_10.bak, Charlie_3.bak, Charlie_4.bak}
You can then iterate the groups and delete files per group by whatever means,
for example delete all but the 2 newest (defined per LastWriteTime) files per machine:
Get-ChildItem -Path $BackupDir -File |
Group-Object {($_.BaseName -split $Delim)[0]} | ForEach-Object {
$_.Group | Sort LastWriteTime -Desc | Select -skip 2 | Remove-Item -WhatIf
}
If the output looks OK, remove the trailing -WhatIf
I think it's the brackets around the $array[$j.name] i.e. it should be:
if($array[$i].name -ne $array[$j].name)
Edit:
For troubleshooting try manually outputting your information:
for ($i=0; $i -lt 5; $i++) {
for ($j=$i+1; $j -lt 5; $j++){
Write-Host "i: $i j: $j"
Write-Host "Array i: $($array[$i].name) Array j: $($array[$j].name)"
if($array[$i].name -ne $array[$j].name)
{
Write-Host "truthval=false"
$truthval="false"
}
else
{
Write-Host "truthval=true"
$truthval = "true"
}
}
}
I have a source tree, say c:\s, with many sub-folders. One of the sub-folders is called "c:\s\Includes" which can contain one or more .cs files recursively.
I want to make sure that none of the .cs files in the c:\s\Includes... path exist in any other folder under c:\s, recursively.
I wrote the following PowerShell script which works, but I'm not sure if there's an easier way to do it. I've had less than 24 hours experience with PowerShell so I have a feeling there's a better way.
I can assume at least PowerShell 3 being used.
I will accept any answer that improves my script, but I'll wait a few days before accepting the answer. When I say "improve", I mean it makes it shorter, more elegant or with better performance.
Any help from anyone would be greatly appreciated.
The current code:
$excludeFolder = "Includes"
$h = #{}
foreach ($i in ls $pwd.path *.cs -r -file | ? DirectoryName -notlike ("*\" + $excludeFolder + "\*")) { $h[$i.Name]=$i.DirectoryName }
ls ($pwd.path + "\" + $excludeFolder) *.cs -r -file | ? { $h.Contains($_.Name) } | Select #{Name="Duplicate";Expression={$h[$_.Name] + " has file with same name as " + $_.Fullname}}
1
I stared at this for a while, determined to write it without studying the existing answers, but I'd already glanced at the first sentence of Matt's answer mentioning Group-Object. After some different approaches, I get basically the same answer, except his is long-form and robust with regex character escaping and setup variables, mine is terse because you asked for shorter answers and because that's more fun.
$inc = '^c:\\s\\includes'
$cs = (gci -R 'c:\s' -File -I *.cs) | group name
$nopes = $cs |?{($_.Group.FullName -notmatch $inc)-and($_.Group.FullName -match $inc)}
$nopes | % {$_.Name; $_.Group.FullName}
Example output:
someFile.cs
c:\s\includes\wherever\someFile.cs
c:\s\lib\factories\alt\someFile.cs
c:\s\contrib\users\aa\testing\someFile.cs
The concept is:
Get all the .cs files in the whole source tree
Split them into groups of {filename: {files which share this filename}}
For each group, keep only those where the set of files contains any file with a path that matches the include folder and contains any file with a path that does not match the includes folder. This step covers
duplicates (if a file only exists once it cannot pass both tests)
duplicates across the {includes/not-includes} divide, instead of being duplicated within one branch
handles triplicates, n-tuplicates, as well.
Edit: I added the ^ to $inc to say it has to match at the start of the string, so the regex engine can fail faster for paths that don't match. Maybe this counts as premature optimization.
2
After that pretty dense attempt, the shape of a cleaner answer is much much easier:
Get all the files, split them into include, not-include arrays.
Nested for-loop testing every file against every other file.
Longer, but enormously quicker to write (it runs slower, though) and I imagine easier to read for someone who doesn't know what it does.
$sourceTree = 'c:\\s'
$allFiles = Get-ChildItem $sourceTree -Include '*.cs' -File -Recurse
$includeFiles = $allFiles | where FullName -imatch "$($sourceTree)\\includes"
$otherFiles = $allFiles | where FullName -inotmatch "$($sourceTree)\\includes"
foreach ($incFile in $includeFiles) {
foreach ($oFile in $otherFiles) {
if ($incFile.Name -ieq $oFile.Name) {
write "$($incFile.Name) clash"
write "* $($incFile.FullName)"
write "* $($oFile.FullName)"
write "`n"
}
}
}
3
Because code-golf is fun. If the hashtables are faster, what about this even less tested one-liner...
$h=#{};gci c:\s -R -file -Filt *.cs|%{$h[$_.Name]+=#($_.FullName)};$h.Values|?{$_.Count-gt1-and$_-like'c:\s\includes*'}
Edit: explanation of this version: It's doing much the same solution approach as version 1, but the grouping operation happens explicitly in the hashtable. The shape of the hashtable becomes:
$h = {
'fileA.cs': #('c:\cs\wherever\fileA.cs', 'c:\cs\includes\fileA.cs'),
'file2.cs': #('c:\cs\somewhere\file2.cs'),
'file3.cs': #('c:\cs\includes\file3.cs', 'c:\cs\x\file3.cs', 'c:\cs\z\file3.cs')
}
It hits the disk once for all the .cs files, iterates the whole list to build the hashtable. I don't think it can do less work than this for that bit.
It uses +=, so it can add files to the existing array for that filename, otherwise it would overwrite each of the hashtable lists and they would be one item long for only the most recently seen file.
It uses #() - because when it hits a filename for the first time, $h[$_.Name] won't return anything, and the script needs put an array into the hashtable at first, not a string. If it was +=$_.FullName then the first file would go into the hashtable as a string and the += next time would do string concatenation and that's no use to me. This forces the first file in the hashtable to start an array by forcing every file to be a one item array. The least-code way to get this result is with +=#(..) but that churn of creating throwaway arrays for every single file is needless work. Maybe changing it to longer code which does less array creation would help?
Changing the section
%{$h[$_.Name]+=#($_.FullName)}
to something like
%{if (!$h.ContainsKey($_.Name)){$h[$_.Name]=#()};$h[$_.Name]+=$_.FullName}
(I'm guessing, I don't have much intuition for what's most likely to be slow PowerShell code, and haven't tested).
After that, using h.Values isn't going over every file for a second time, it's going over every array in the hashtable - one per unique filename. That's got to happen to check the array size and prune the not-duplicates, but the -and operation short circuits - when the Count -gt 1 fails, the so the bit on the right checking the path name doesn't run.
If the array has two or more files in it, the -and $_ -like ... executes and pattern matches to see if at least one of the duplicates is in the includes path. (Bug: if all the duplicates are in c:\cs\includes and none anywhere else, it will still show them).
--
4
This is edited version 3 with the hashtable initialization tweak, and now it keeps track of seen files in $s, and then only considers those it's seen more than once.
$h=#{};$s=#{};gci 'c:\s' -R -file -Filt *.cs|%{if($h.ContainsKey($_.Name)){$s[$_.Name]=1}else{$h[$_.Name]=#()}$h[$_.Name]+=$_.FullName};$s.Keys|%{if ($h[$_]-like 'c:\s\includes*'){$h[$_]}}
Assuming it works, that's what it does, anyway.
--
Edit branch of topic; I keep thinking there ought to be a way to do this with the things in the System.Data namespace. Anyone know if you can connect System.Data.DataTable().ReadXML() to gci | ConvertTo-Xml without reams of boilerplate?
I'd do more or less the same, except I'd build the hashtable from the contents of the includes folder and then run over everything else to check for duplicates:
$root = 'C:\s'
$includes = "$root\includes"
$includeList = #{}
Get-ChildItem -Path $includes -Filter '*.cs' -Recurse -File |
% { $includeList[$_.Name] = $_.DirectoryName }
Get-ChildItem -Path $root -Filter '*.cs' -Recurse -File |
? { $_.FullName -notlike "$includes\*" -and $includeList.Contains($_.Name) } |
% { "Duplicate of '{0}': {1}" -f $includeList[$_.Name], $_.FullName }
I'm not as impressed with this as I would like but I thought that Group-Object might have a place in this question so I present the following:
$base = 'C:\s'
$unique = "$base\includes"
$extension = "*.cs"
Get-ChildItem -Path $base -Filter $extension -Recurse |
Group-Object $_.Name |
Where-Object{($_.Count -gt 1) -and (($_.Group).FullName -match [regex]::Escape($unique))} |
ForEach-Object {
$filename = $_.Name
($_.Group).FullName -notmatch [regex]::Escape($unique) | ForEach-Object{
"'{0}' has file with same name as '{1}'" -f (Split-Path $_),$filename
}
}
Collect all the files with the extension filter $extension. Group the files based on their names. Then of those groups find every group where there are more than one of that particular file and one of the group members is at least in the directory $unique. Take those groups and print out all the files that are not from the unique directory.
From Comment
For what its worth this is what I used for testing to create a bunch of files. (I know the folder 9 is empty)
$base = "E:\Temp\dev\cs"
Remove-Item "$base\*" -Recurse -Force
0..9 | %{[void](New-Item -ItemType directory "$base\$_")}
1..1000 | %{
$number = Get-Random -Minimum 1 -Maximum 100
$folder = Get-Random -Minimum 0 -Maximum 9
[void](New-Item -Path $base\$folder -ItemType File -Name "$number.txt" -Force)
}
After looking at all the others, I thought I would try a different approach.
$includes = "C:\s\includes"
$root = "C:\s"
# First script
Measure-Command {
[string[]]$filter = ls $includes -Filter *.cs -Recurse | % name
ls $root -include $filter -Recurse -Filter *.cs |
Where-object{$_.FullName -notlike "$includes*"}
}
# Second Script
Measure-Command {
$filter2 = ls $includes -Filter *.cs -Recurse
ls $root -Recurse -Filter *.cs |
Where-object{$filter2.name -eq $_.name -and $_.FullName -notlike "$includes*"}
}
In my first script, I get all the include files into a string array. Then i use that string array as a include param on the get-childitem. In the end, I filter out the include folder from the results.
In my second script, I enumerate everything and then filter after the pipe.
Remove the measure-command to see the results. I was using that to check the speed. With my dataset, the first one was 40% faster.
$FilesToFind = Get-ChildItem -Recurse 'c:\s\includes' -File -Include *.cs | Select Name
Get-ChildItem -Recurse C:\S -File -Include *.cs | ? { $_.Name -in $FilesToFind -and $_.Directory -notmatch '^c:\s\includes' } | Select Name, Directory
Create a list of file names to look for.
Find all files that are in the list but not part of the directory the list was generated from
Print their name and directory
I would really appreciate your help with this
I should first mention that I have been unable to find any specific solutions and I am very new to programming with powershell, hence my request
I wish to write (and later schedule) a script in powershell that looks for a file with a specific name - RFUNNEL and then renames this to R0000001. There will only be one of such 'RFUNELL' files in the folder at any time. However when next the script is run and finds a new RFUNNEL file I will this to be renamed to R0000002 and so on and so forth
I have struggled with this for some weeks now and the seemingly similar solutions that I have come across have not been of much help - perhaps because of my admittedly limited experience with powershell.
Others might be able to do this with less syntax, but try this:
$rootpath = "C:\derp"
if (Test-Path "$rootpath\RFUNNEL.txt")
{ $maxfile = Get-ChildItem $rootpath | ?{$_.BaseName -like "R[0-9][0-9][0-9][0-9][0-9][0-9][0-9]"} | Sort BaseName -Descending | Select -First 1 -Expand BaseName;
if (!$maxfile) { $maxfile = "R0000000" }
[int32]$filenumberint = $maxfile.substring(1); $filenumberint++
[string]$filenumberstring = ($filenumberint).ToString("0000000");
[string]$newName = ("R" + $filenumberstring + ".txt");
Rename-Item "$rootpath\RFUNNEL.txt" $newName;
}
Here's an alternative using regex:
[cmdletbinding()]
param()
$triggerFile = "RFUNNEL.txt"
$searchPattern = "R*.txt"
$nextAvailable = 0
# If the trigger file exists
if (Test-Path -Path $triggerFile)
{
# Get a list of files matching search pattern
$files = Get-ChildItem "$searchPattern" -exclude "$triggerFile"
if ($files)
{
# store the filenames in a simple array
$files = $files | select -expandProperty Name
$files | Write-Verbose
# Get next available file by carrying out a
# regex replace to extract the numeric part of the file and get the maximum number
$nextAvailable = ($files -replace '([a-z])(.*).txt', '$2' | measure-object -max).Maximum
}
# Add one to either the max or zero
$nextAvailable++
# Format the resulting string with leading zeros
$nextAvailableFileName = 'R{0:000000#}.txt' -f $nextAvailable
Write-Verbose "Next Available File: $nextAvailableFileName"
# rename the file
Rename-Item -Path $triggerFile -NewName $nextAvailableFileName
}