Appending string to the end of all file names in PowerShell - powershell

I have files look like
data.svg
map.svg
aplicationp.svg
...
*.svg
I am trying to add -b string to the end of all files names bu using power shell rename command like
D:\icons> Dir | Rename-Item -NewName {$_.name -replace ".","-b."}
to get these
data-b.svg
map-b.svg
application-b.svg
but this is not changing anything. How can I achieve this?

Powershell's -replace operator is based on regular expressions. And since . is a wildcard in regex, what should be happening is that each character in the file name is being replaced with the resulting string. So test.txt would become -b.-b.-b.-b.-b.-b.-b in your example.
You likely want to use the Replace method of the .NET String type like this instead.
dir | Rename-Item -NewName { $_.Name.Replace('.','-b.') }
If you want to keep using -replace, you need to escape the . in your expression like this.
dir | Rename-Item -NewName { $_.Name -replace '\.','-b.' }
Both of these have a couple edge case problems that you may want to avoid. The first is narrowing the scope of your dir (which is just an alias for Get-ChildItem) to avoid including files or directories you don't actually want to rename. The second is that a simple replace in the file name doesn't account for file names that contain multiple dots. So you may want to ultimately do something like this if you only care about SVG files that may have multiple dots.
Get-ChildItem *.svg -File | Rename-Item -NewName { "$($_.BaseName)-b$($_.Extension)" }

The replace operator uses regex. Therefore your . needs to be escaped, otherwise it just stands for any character. I would generally make sure to be as specific as possible when writing regexes. The following is a possible solution
Get-ChildItem *.svg | Rename-Item -NewName { $_.name -Replace '\.svg$','-c.svg' }
The $ anchors the expression to the end of the string which makes sure it only changes the extension and not any other text inside the file names.

Related

rename batch of files

is there a way rename multiple items in a way that words switch place or move word to the end of the phrase/item name ?
ABCD 12550.txt into 12550 ABCD.txt
im assuming this will start with Rename-Item, but what then?
There is a space between words/phrases
Use Rename-Item with a delay-bind script block, in which you can parse and reconstruct each file name.
The following example uses the -replace operator to match and capture the base file name's first word as well as the remaining one(s), and reverses their order (effectively moves the first word to the end):
Get-ChildItem *.txt |
Rename-Item -WhatIf -NewName {
($_.BaseName -replace '^(\S+) +(.+)', '$2 $1') + $_.Extension
}
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.

Remove "." in file name while retaining file extension

I am trying to use PS to rename a bunch files within a big share and one of the requirements is to remove a dot from the file name. I have tested a few things with my rather basic skills and of course the most basic of scripts zap the file extension.
I finally came up with something like this:
gci *.xlsx | rename-item -newname {$_.Name.replace(".","") + $_.extension }
But that adds the extension to the end of the filename (while keeping the file extension intact)
I thought I could zap the last four symbols using something like this:
gci *.xlsx | rename-item -newname { $_.basename.substring(0,$_.basename.length-4) + $_.extension }
Overall this seems like an overly complicated operation which could also mess up files without dots (unless I specify xlsx as only 4 symbols to be removed)
Would anyone be able to point me in the right direction to an easier solution? ;-)
You were on the right track with your second attempt: using the .BaseName and .Extension properties of the [System.IO.FileInfo] instances[1] output by Get-ChildItem allows you to modify the base name (the file name without its extension) separately, and then re-append the extension to form the full file name:
Get-ChildItem *.xlsx |
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.
The above uses the regex-based -replace operator to remove all . instances from the base name; because . is a regex metacharacter (representing any single character), it must be escaped as \. in order to be used literally.
In this simple case, you could have used the [string] type's .Replace() method as well ($_.BaseName.Replace('.', '')), but -replace offers more features and has fewer surprises - see this answer for more information.
Case in point: Say you wanted to remove only the first . from the base name; -replace allows you to do that as follows (but you couldn't do it with .Replace()):
'foo.bar.baz' -replace '\.(.*)$', '$1' # -> 'foobar.baz'
[1] .BaseName isn't a native property of this type; instead, it is a property that PowerShell decorates instances of the type with, using its ETS (Extended Type System).

Replace text in files within a folder PowerShell

I have a folder that contains files like 'goodthing 2007adsdfff.pdf', 'betterthing 2007adfdsw.pdf', and 'bestthing_2007fdsfad.pdf', I want to be able to rename each, eliminating all text including 2007 OR _2007 to the end of the string keeping .pdf and getting this result: 'goodthing.pdf' 'betterthing.pdf' 'bestthing.pdf' I've tried this with the "_2007", but haven't figured out a conditional to also handle the "2007". Any advice on how to accomplish this is greatly appreciated.
Get-ChildItem 'C:Temp\' -Name -Filter *.pdf | foreach { $_.Split("_2017")[0].substring(0)}
Try the following:
Get-ChildItem 'C:\Temp' -Name -Filter *.pdf |
Rename-Item -NewName { $_.Name -replace '[_ ][^.]+' } -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.
The above uses Rename-Item with a delay-bind script block and the -replace operator as follows:
Regex [_ ][^.]+ matches everything from the first space or _ char. (character set [ _]) through to the following literal . char. ([^.]+ matches one or more chars. other than (^) than .) - that is, everything from the first / _ through to the filename extension (excluding the .).
Note: To guard against file names such as _2017.pdf matching (which would result in just .pdf as the new name), use the following regex instead: '(?<=.)[_ ][^.]+'
By not providing a replacement operand to -replace, what is matched is replace with the empty string and therefore effectively removed.
The net effect is that input files named
'goodthing 2007adsdfff.pdf', 'betterthing 2007adfdsw.pdf', 'bestthing_2007fdsfad.pdf'
are renamed to
'goodthing.pdf', 'betterthing.pdf', 'bestthing.pdf'
Without knowing the names of all the potential files, I can offer this solution that is 100%:
PS> $flist = ("goodthing 2007adsdfff.pdf","betterthing 2007adfdsw.pdf","bestthing_2007fdsfad.pdf")
PS> foreach ($f in $flist) {$nicename = ($f -replace "([\w\s]+)2007.*(\.\w+)", '$1$2') -replace "[\s_].","." ;$nicename}
goodthing.pdf
betterthing.pdf
bestthing.pdf
Two challenges:
the underscore is actually part of the \w character class. So the alternative to the above is to complicate the regex or try to assume that there will always be only one '_' before the 2007. Both seemed risky to me.
if there are spaces in filenames, there is no telling if you might encounter more than one. This solution removes only the one right before 2007.
The magic:
The -replace operator enables you to quickly capture text in () and re-use it in variables like $1$2. If you have more complex captures, you just have to figure out the order they are assigned.
Hope this helps.

Removing Parts of a File Name based on a Delimiter

I have various file names that are categorized in two different ways. They either just have a code like: "866655" or contain a suffix and prefix "eu_866655_001". My hope is to write to a text file the names of files in the same format. I cannot figure out a successful method for removing the suffix and prefix.
Currently this what I have in my loop in Powershell:
$docs = Get-ChildItem -Path $source | Where-Object {$_.Name -match '.doc*'}
if ($docs.basename -contians 'eu_*')
{
Write-Output ([io.fileinfo]"$doc").basename.split("_")
}
I'm hoping to turn "eu_866655_001" into "866655" by using "_" as the delimiter.
I'm aware that the answer is staring me down but I still can't seem to figure it out.
You could do something like the following. Feel free to tweak the -Filter on the Get-ChildItem command.
$source = 'c:\path\*'
$docs = Get-ChildItem -Path $source -File -Filter "*_*_*" -Include '*.doc','*.docx'
$docs | Rename-Item -NewName { "{0}{1}" -f $_.Basename.Split('_')[1],$_.Extension }
The important things to remember is that in order to use the -Include switch, you need an * at the end of the -Path value.
Explanation:
-Filter allows us to filter on names that contain two underscores separating three substrings.
-Include allows us to only list files ending in extensions .docx and .doc.
Rename-Item -NewName supports delayed script binding. This allows us use a scriptblock to perform any necessary operations for each piped object (each file).
Since the target files will always have two underscores, the .Split('_') method will result in an three index array delimited by the _. You have specified that you always want the second delimited substring and that is represented by index 1 ([1]).
The format operator (-f) puts the substring and extension together, completing the file name.

remove random text from file name

I have a folder full of files which have had some text prepended to the filenames. For example:
program1.m has become John Smith 23423_file_program1.m.
program2.m has become Jane Doe 235_file_program2.m.
The number of characters that have been prepended is not consistent, but the substring file_ is always the final set of characters I wish to remove. Is there anyway to remove all characters up to and including the file_ in a folder full of files? This was my attempt, but as expect the * does not work in this scenario:
get-childitem *.m | foreach { rename-item $_ $_.Name.Replace("*file_","") }
This should do the trick. There are other ways to do this as well so don't be surprised if you find another one.
get-childitem *.m -Filter *.m | ForEach{
Rename-Item -Path $_.FullName -NewName ($_.Name -replace ".*file_")
}
Or shorter
get-childitem -Filter *.m | Rename-Item -NewName {$_.Name -replace ".*file_"}
You had the right idea but the issue you have is the string .replace() method is looking to match static strings and does not use wildcards. The way you had it it expected an asterisks to appear in the string which one did not.
Instead we use -replace which supports regex. .*file_ would satisfy the requirement of remov[ing] all characters up to and including the _file. Since you just want it removed we don't offer a replacement string.
If regex is not your friend you should try and warm up to him. If not some old school methods work just as well.
$file = "blah_file_program.m"
$file.Substring($file.LastIndexOf("_") + 1)
program.m