I am trying to move files to a certain folder if they start with a letter and delete them if they start with anything other than a letter.
My code:
Function moveOrDelete($source, $dest)
{
$aToZ = '^[a-zA-Z].*'
$notALetter = '^[^a-zA-Z].*'
Get-ChildItem -Path $source\$aToZ -Recurse | Move-Item -Destination $dest
Get-ChildItem -Path $source\$notALetter -Recurse | Remove-Item
}
As I understand it the caret will match on the first character when it's outside of the brackets. In other words, the regex in the $aToZ variable will match anything that begins with a letter. the .* part will allow the rest of the file name to be anything. The caret inside the brackets negates the statement so if the file name begins with anything other than a letter it will match. I can't get it to work and I'm not getting any errors which leads me to believe that my regex is wrong.
I have checked this with online tools including this one: https://regex101.com/ and they check out.
I have also used variations of the regex like ^[a-zA-Z] that don't work. Some patterns like [a-zA-Z]* move the files but it's not the pattern that I want.
Here is how I'm calling the funcion:
moveOrDelete ".\source" ".\dest"
And here are the sample file names I'm using:
a.txt
z.txt
1.txt
.txt
The -Path argument doesn't understand regular expressions, it takes a string and can perform wildcarding but not complex string processing.
So, you need to check the name of each file against the regex with the -match operator. The following should help:
Function moveOrDelete($source, $dest)
{
$aToZ = '^[a-zA-Z].*'
$notALetter = '^[^a-zA-Z].*'
Get-ChildItem -Path $source -Recurse | Where-Object { $_.name -match $aToZ } | Move-Item -Destination $dest
Get-ChildItem -Path $source -Recurse | Where-Object { $_.name -match $notALetter } | Remove-Item
}
Here, you need to filter the file names with the Where-Object cmdlet, then pipe to the move or remove.
Related
I am looking for a way to remove several special characters from filenames via a powershell script.
My filenames look like this:
[Report]_first_day_of_month_01_(generated_by_powershell)_[repnbr1].txt
I have been puzzling over removing the [] and everything between them, the () and everything between those, and removing all the _'s as well, with the desired result being a filename that looks like this:
first day of month 01.txt
Thus far, I have tried the below solution to no avail. I have run each of these from the directory in which the files reside.
Get-ChildItem -Path .\ -Filter *.mkv | %{
$Name = $_.Name
$NewName = $Name -Replace "(\s*)\(.*\)",''
$NewName2 = $NewName -Replace "[\s*]\[.*\]",''
$NewName3 = $NewName2 -Replace "_",' '
Rename-Item -Path $_ -NewName $NewName3
}
Since it does not work even if I try and do one set at a time like this:
Get-ChildItem -Path .\ -Filter *.mkv | %{
$Name = $_.Name
$NewName = $Name -Replace "(\s*)\(.*\)",''
Rename-Item -Path $_ -NewName $NewName
}
I assume there is an inherent flaw in the way I am trying to accomplish this task. That being said, I would prefer to use the Rename-Item cmdlet rather than using a move-item solution.
gci *.txt | Rename-Item -NewName {$_ -replace '_*(\[.*?\]|\(.*?\))_*' -replace '_+', ' '}
The rename is a regex which matches [text] or (text) blocks and replaces them with nothing. Parentheses and brackets need escaping in regexes to match them literally. It matches them with optional leading or trailing underscores to get [Report]_ or _[repnbr1] because it would leave _ at the start or end of the name and they would become leading/trailing spaces, which is annoying. Then it replaces remaining underscores with spaces.
See the regex working here: Regex101
I am writing a quick PowerShell script to replace all periods except the last instance.
EG:
hello. this. is a file.name.doc → hello this is a filename.doc
So far from another post I was able to get this regexp, but it does not work with PowerShell:
\.(?=[^.]*\.)
As per https://www.regex101.com/, it only matches the first occurrence of a period.
EDIT:
Basically I need to apply this match and replace to a directory with sub directories. So far I have this:
Get-ChildItem -Filter "*.*" | ForEach {
$_.BaseName.Replace('.','') + $_.Extension
}
But it does not actually replace the items, and I do not think it is recursive.
I tried a few variations:
Get-Item -Filter "*.*" -Recurse |
Rename-Item -NewName {$_.BaseName.Replace(".","")}
but I get the error message
source and destination path must be different
I had the PowerShell side of things working but was stuck on the RegEx part. I was able to match either all the "." or only the last "." which was part of the file extension. Then I found this post with the missing link: \.(?=[^.]*\.)
I added that to the rest of the PowerShell command and it worked perfectly.
Get-ChildItem -Recurse | Rename-Item -NewName {$_.Name -replace '\.(?=[^.]*\.)',' ' }
Exclude files that don't have a period in their basename from being renamed:
Get-ChildItem -File -Recurse | Where-Object { $_.BaseName -like '*.*' } |
Rename-Item -NewName {$_.BaseName.Replace('.', '') + $_.Extension}
For every file in a directory I wish to remove lines that match a regular expression (beginning with |B for example) using powershell.
I think I can do this via Get-ChildItem on the directory, foreach-object, get-content and some sort of if -match but I'm really struggling to fit it all together.
Any help would be massively appreciated. This is the first time I've ever written a powershell script.
Something like the below should get you in the right direction
$files = Get-ChildItem "C:\your\dir"
foreach ($file in $files) {
$c = Get-Content $file.fullname | where { $_ -notmatch "^\|B" }
$c | Set-Content $file.fullname
}
I need to search file names in a directory for position based characters. I am looking for files with parenthesis within parenthesis.
like this:
# 2262281102-03_Cutting_Plate_Lower_Stop_(Anschlag_Cutting_Frame_(Schnittgestell)_unten)_400kN
GET-CHILDITEM C:\BU\p -recurse | WHERE-OBJECT {$_.nAME -MATCH "(?!)((?!)((!?))(!?))(!?)"}
I also need to match any file with 4+ letters and no parenthesis. ie:
# 2277131504-03_Haltebolzen_platte
GET-CHILDITEM C:\BU\p -EXCLUDE "*)*" -recurse | WHERE-OBJECT {$_.nAME -MATCH "\W\.[^\W]"}
I've got this:
$tests = #(
'2262281102-03_Cutting_Plate_Lower_Stop_(Anschlag_Cutting_Frame_(Schnittgestell)_unten)_400kN',
'2277131504-03_Haltebolzen_platte'
)
$regex = '^.*\(.*\(.*\).*\).*$|^[^()]*[a-z]{4}[^()]*$'
$tests -match $regex
2262281102-03_Cutting_Plate_Lower_Stop_(Anschlag_Cutting_Frame_(Schnittgestell)_unten)_400kN
2277131504-03_Haltebolzen_platte
I know a common characteristic of the file names of a number of unwanted files on my Windows computer. How can I remove all of these files from a given folder or folder hierarchy with a single regular expression PowerShell command?
You can pipe a Get-ChildItem command through a Where-Object filter that accepts a RegEx pattern, and then pipe that into Remove-Item. I think that will get you a faster, and better result than using Select-String. With a command like:
Get-ChildItem $Path | Where{$_.Name -Match "<RegEx Pattern>"} | Remove-Item
The Name attribute will only match the name of the file or folder, along with a file's extension. It will not match against other things along the path. This will pass a FileInfo object down the pipe, which Remove-Item takes as piped input and will remove the files in question.
If you want to include sub folders of your path you would add the -Recurse switch to your Get-ChildItem command, and it would look like this:
Get-ChildItem $Path -Recurse | Where{$_.Name -Match "<RegEx Pattern>"} | Remove-Item
If you only want to delete files you can specify that in the Where statement by looking at the FileInfo object's PSIsContainer property and inverting it by prefixing the object with an exclamation point like such:
Get-ChildItem $Path -Recurse | Where{$_.Name -Match "<RegEx Pattern>" -and !$_.PSIsContainer} | Remove-Item
You can use the command,
ls -name | select-string -pattern ".*\(\d+\).*" | %{rm $_}
Where the content of the quotation marks is your regular expression. The regex in this example searches for files that have (#) in the file name, where # is any nonnegative integer. This is useful for deleting duplicates in a folder where the same set of files have been dumped many times, such as by a music manager.
If you add a -r after the -name
ls -name -r | select-string -pattern ".*\(\d+\).*" | %{rm $_}
it will recurse through subfolders and delete matching files in all subfolders.
The structure of the command is as follows:
ls is an alias for the powershell command get-childitem. It lists all elements in the current folder. The -name argument specifies that only the names are to be produced; I don't want other information like file size.
select-string is mostly equivalent to UNIX grep, where it matches a pattern (regex) to a bunch of line-separated strings. The -pattern parameter sets the cmdlet up to take a regex.
%{rm $} is a foreach loop. It is saying, "for each line piped into me (from select-string in this case)", do the following action, where $ is the given line. In this case we are rm-ing the item, where rm is an alias for Remove-Item.
I'd use this:
(Get-ChildItem -Path $Path | Select -ExpandProperty Fullname) -match <regex> | Remove-Item
(Get-ChildItem -Path $Path -Recurse | Select -ExpandProperty Fullname) -match <regex> | Remove-Item
or if you've got V3 or higher so you have automatic member enumeration:
(Get-ChildItem -Path $Path).Fullname -match <regex> | Remove-Item
(Get-ChildItem -Path $Path -Recurse).Fullname -match <regex> | Remove-Item
Name is only going to work if your current working directory is the directory you're deleting files from, and all of the files are in that directory (a recurse may find more than one file with the same name, but different paths).