I have a bunch of files with the same string in them and would like to remove them
Dir | Rename-Item -NewName { $_.Name -replace " (my string here)","" }
However, this does not seem to be removing the string from all the files that have that string in the file name. Do I need ReGex?
There is a space before the ( which makes me think I need ReGex in some way.
So I was right about needing ReGex with how Powershell does stuff:
Dir | Rename-Item -NewName { $_.Name -replace "(\s*) \(STRING HERE\)","" }
-replace does indeed use regex(case-insensitive).
You can achieve the same result without regex with the use of the .replace which is a string method like so:
Get-ChildItem -path 'your path' |
Rename-Item -NewName { $_.BaseName.replace(' (my string here)','') + $_.extension } -WhatIf
notice the use of $_.basename instead of name. this is because name consists of both filename and extension whereas basename does not.
Related
I got a problem with powershell and some pdfs names
So there is a bunch of them:
2021_01_21_Aneks_nr2.pdf
2021_11_31_Aneks_nr3.pdf
2021_05_04_Aneks_nr4.pdf
I need to replace "_" with "-" but only near date.
Output should look like this:
2021-05-04_Aneks_nr4.pdf
I'm new to programming and couldn't find solution in internet.
I was using this code :
Get-Childitem | foreach { rename item $_ $_.Name.Replace("_","-") }
But it works on all "_" so I cant use it in this scenario.
Thanks for help! :)
Using the -replace operator instead of the dot net method you can use regex. And there you can specify to replace only underlines between digits:
Get-ChildItem |
ForEach-Object {
Rename-Item -Path $_.FullName -NewName $($_.Name -replace '(?<=\d)_(?=\d)', '-')
}
Here you go
#Loop through files
get-childitem [path] | ForEach-Object {
#match pattern
$null = $_.name -match '\d{4}_\d{2}_\d{2}'
#get matching pattern
$pattern = $matches[0]
#replace _ with -
$replace = $pattern -replace '_','-'
#build new name
$newName = $_.name -replace $pattern,$replace
#rename file
rename-item -Path $_.fullname -NewName $newName
}
It matches the current name of the file for the pattern '\d{4}_\d{2}_\d{2}', gets the matching string, replaces _ with - and finally build the new name by replacing the matching string with the updated version.
I have modified several thousand files with a various things requested by the owners.
Now, I need to add one final thing and I am not 100% on how to do it.
Scenario is as follows - all files have a 10 digit number at the start, I need to add a hyphen after the number. String is a variable but it is always the same length.
1234567890abcdefgh.xls would be an example
I have used GCI to make changes to symbols and static parts but not sure how to call for insertion in a specific place of a file (after the 10th character of a variable string)
Any ideas would be most welcome!
You can use the $matches you get from the capturing groups of a -match comparison:
(Get-ChildItem -Path 'X:\WhereTheFilesAre' -File) |
Where-Object { $_.BaseName -match '^(\d{10})([^-].*)' } |
Rename-Item -NewName { '{0}-{1}{2}' -f $matches[1], $matches[2], $_.Extension }
or by using the Substring() method:
(Get-ChildItem -Path 'X:\WhereTheFilesAre' -File) |
Where-Object { $_.BaseName -match '^\d{10}[^-]' } |
Rename-Item -NewName { $_.Name.Substring(0,10) + '-' + $_.Name.Substring(10) }
or use the regex -replace operator:
(Get-ChildItem -Path 'X:\WhereTheFilesAre' -File) |
Where-Object { $_.BaseName -match '^\d{10}[^-]' } |
Rename-Item -NewName { $_.Name -replace '^(\d{10})', '$1-' }
You can use string.Insert() to insert a string into another at a specific offset:
PS ~> '1234567890abcdefgh.xls'.Insert(10, '-')
1234567890-abcdefgh.xls
To apply to all files in a directory, you could do something like this:
Get-ChildItem -File |Where-Object Name -match '^\d{10}[^-]' |Rename-Item -NewName { $_.Name.Insert(10, '-') }
The regular expression pattern ^\d{10}[^-] will only match file names that start with 10 digits followed by something other than a hyphen (to avoid renaming files that already comply with the naming convention)
I have a folder with media files named by timestamp like following yyyyMMdd_HHmmss_*.*. I need to rename them to yyyy-MM-dd HH-mm-ss *.*
For example I need to rename file 20181019_210353_BURST2.jpg to 2018-10-19 21-03-53 BURST2.jpg
There is a my ugly approach
PS E:> gci | Rename-Item -NewName { $_.Name.Substring(0,4) + '-' + $_.Name.Substring(4,2) + '-' + $_.Name.Substring(6,2) + ' ' + $_.Name.Substring(9,2) + '-' + $_.Name.Substring(11,2) + '-' + $_.Name.Substring(13,2) + $_.Name.Substring(15) }
What is the right command to obtain my purpose?
If it is concision you're looking for, you can use the -replace operator with the following regex:
Get-ChildItem -File -Filter *.jpg | Rename-Item -NewName {
$_.Name -replace '(^\d{2})?(\d{2})(\d{2})(\d{2})_', '$1$2-$3-$4 '
} -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
An explanation of the regex, as well as the ability to experiment with it and the substitution expression, can be found on this regex101.com page.
Your method will work, but you will need to provide a -Path parameter to Rename-Item. The short answer is that the string will need to be broken down into the components to use in the new name.
If you want to have some regex fun, you could use something like this. When you are convinced that the files will be renamed correctly, remove the -WhatIf from the Rename-Item command.
Get-ChildItem |
ForEach-Object {
if ($_.Name -match '^(....)(..)(..)_(..)(..)(..)(.*)') {
$NewName = "$($Matches[1..3] -join '-') $($Matches[4..6] -join '-')$($Matches[7])"
Rename-Item -Path $_.FullName -NewName $NewName -WhatIf
}
}
I'm trying to write a script in PowerShell that searches folders for files containing unnecessary periods, then mass removes the periods from the file names.
ex. Example.File.doc ---> ExampleFile.doc
Whenever I run the code, the console returns the following: "Rename-Item : Cannot bind argument to parameter 'NewName' because it is an empty string."
Does anyone know what the issue is?
Thanks in advance for any help!
$files = get-childitem -path "C:\XXXX\XXXX\XXXX" -Recurse
foreach($file in $files) {
if($file.Name -match ".") {
$newName = $file.Name -ireplace (".", "")
Rename-Item $file.FullName $newName
Write-Host "Renamed" $file.Name "to $newName at Location:" $file.FullName
}
}
One thing about string replacing: When I tried your example without escaping the period, it didn't replace anything and returned nothing (empty string), which I believe answers your "Cannot bind argument to parameter 'NewName' because it is an empty string"
This worked by escaping the period. Also, it works with or without the parenthesis.
$string = "the.file.name"
$newstring = $string -ireplace "\.", ""
// output: thefilename
$newstring.length
// output: 11
$othernewstring = $string -ireplace ("\.", "")
// output: thefilename
$othernewstring.length
// output: 11
// What the OP tried
$donothingstring = $string -ireplace (".", "")
// output:
$donothingstring.length
// output: 0
There is some additional information on string replace here, just for reference https://vexx32.github.io/2019/03/20/PowerShell-Replace-Operator/
$file.Name -ireplace (".", "")
invariably returns an empty string, because the -replace operator (-ireplace is just an alias[1]) operates on regexes (regular expressions), in which metacharacter . matches any character[2].
Since -replace always replaces all matches it finds, all characters in the input are replaced with the empty string, yielding an empty string overall, and passing an empty string via $newName to the (positionally implied) -NewName parameter of Rename-Item predictably causes the error message you saw.
To match a . character verbatim in a regex, you must escape it as \.:
$file.Name -replace '\.', '' # Note: no (...) needed; `, ''` optional
Note that it's generally better to use '...' quoting rather than "..." for regexes and string literals meant to be used verbatim.
However:
This would also remove the . char. in the filename extension, which is undesired.
Also, your command can be streamlined and simplified, as the solution below shows.
A concise, single-pipeline solution:
Get-ChildItem -File -Path "C:\XXXX\XXXX\XXXX" -Recurse -Include *.*.* |
Rename-Item -NewName { ($_.BaseName -replace '\.') + $_.Extension } -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
-File limits matching to files (not also directories).
-Include *.*.* limits matching to file names that contain at least 2 . chars.
Piping the files to rename directly from Get-ChildItem to Rename-Item allows you to specify the -NewName argument as a delay-bind script block ({ ... }), which can dynamically derive the new name from the name of the respective input file, using the properties of the System.IO.FileInfo instances received from Get-ChildItem.
$_.BaseName -replace '\.' removes all literal . chars. (escaped as \. in the context of the regex (regular expression) that the -replace operator operates on) from the file base name (the part without the (last) filename extension).
Note: not specifying a replacement operand is the same as specifying '', the empty string, resulting in the effective removal of the matched string; in other words: ... -replace '\.' is the same as ... -replace '\.', ''
+ $_.Extension appends the original extension to the modified base name.
[1] -replace is case-insensitive by default, as all PowerShell operators are; -ireplace just makes that fact explicit; there's also the -creplace variant, where the c indicates that the operation is case-sensitive.
[2] in single-line strings; in multi-line strings, . by default doesn't match \n (newlines), though this can be changed via inline matching option (?s) at the start of the regex.
There are a few other issues here. You should filter your Get-ChildItem results to return only files by including the -File switch.
Your current script will replace the last . before your file's extension which will cause some problems. You need to use the $File.BaseName and $File.Extension attributes to address this problem.
Substitute -ireplace with the .replace() method.
Lastly, you need to use the -like condition in your If statement. The -match condition is used for regexes and will not work correctly here.
$files = get-childitem -Recurse -File
foreach($file in $files) {
if($file.BaseName -like "*.*") {
$newName = $file.BaseName.Replace(".","") + $file.Extension
Rename-Item $file.FullName $newName
Write-Host "Renamed" $file.Name "to $newName at Location:" $file.FullName
}
}
Here's another solution that takes advantage of PowerShell's pipeline (remove the -WhatIf after you've tested which files will be renamed).
It also uses a lookahead regular expression to replace all but the last dot in the filename.
Get-ChildItem -Recurse `
<# Only select files that have more than one '.' in their name #> `
| Where-Object { ($_.Name.ToCharArray() | Where-Object {$_ -eq '.'} | Measure-Object ).Count -gt 1 } `
`
<# Change the location to the directory and rename so you don't have deal with the directory name #> `
<# Also, use a lookahead regex to replace all but the last dot. #> `
| ForEach-Object { Push-Location $_.Directory; Rename-Item $_ ($_.Name -replace "\.(?=.*?\.)", "") -Verbose -WhatIf; Pop-Location }
Here's a more concise version of the same commands using aliases:
dir -r | ?{ ($_.Name.ToCharArray() | ?{ $_ -eq '.' } | measure ).Count -gt 1 } | %{ pushd $_.Directory; ren $_ ($_.Name -replace "\.(?=.*?\.)", "") -v -wh; popd }
Can anyone tell me if they think there is something wrong with this Powershell script.
Dir |
where {$_.extension -eq ".txt"} |
Rename-Item –NewName { $_.name –replace “.“,”-” }
For each text file in the current directory, I'm trying to replace all periods in the file names with hyphens. Thanks ahead of time.
As the others have said, -replace uses regex (and "." is a special character in regex). However, their solutions are forgetting about the fileextension and they are acutally removing it. ex. "test.txt" becomes "test-txt" (no extension). A better solution would be:
dir -Filter *.txt | Rename-Item -NewName { $_.BaseName.replace(".","-") + $_.Extension }
This also uses -Filter to pick out only files ending with ".txt" which is faster then comparing with where.
-replace operates on regex, you need to escape '.':
rename-item -NewName { $_.Name -replace '\.', '-' }
Otherwise you will end up with '----' name...
The name property of a file object in powershell is of type string.
That means, you could also use the static string method replace like follows and don't care about regex' reserved characters:
dir | ? { $_.extension -eq ".txt" } | rename-item -newname { $_.name.replace(".","-") }