PowerShell script to remove characters from files and folders - powershell

I am trying to recursively remove certain characters from files and folders using a PowerShell script. Below is the script that I have found, but it will only remove underscores from files, not folders. There are a few characters which will need to be removed, but I am fine with having a script for each character if need be. It does recursively change files in the folders, but no folders are 'fixed'.
Current PowerShell script:
'dir -Recurse | where {-not $_.PsIscontainer -AND $_.name -match "_"} | foreach {
$New = $_.name.Replace("_","")
Rename-Item -path $_.Fullname -newname $New -passthru
}'

As pointed out in the comments the core of your issue is that you are excluding folders with the -Not $_.PsIscontainer component of your Where block.
dir -recurse | where {$_.name -match "_"} | ...
The second issue that you are having is most likely that since you are changing folder names the children you had previously inventoried with dir/Get-ChildItem would then have incorrect paths. One way to address this would be to process files first then folders.
$filesandfolders = Get-ChildItem -recurse | Where-Object {$_.name -match "_"}
$filesandfolders | Where-Object {!$_.PsIscontainer} | foreach {
$New=$_.name.Replace("_","")
Rename-Item -path $_.Fullname -newname $New -passthru -WhatIf
}
$filesandfolders | Where-Object {$_.PsIscontainer} | foreach {
$New=$_.name.Replace("_","")
Rename-Item -path $_.Fullname -newname $New -passthru -WhatIf
}
By no means the prettiest solution but it would work. It processes all the files first, then the folders. Remove the -Whatifs when you are sure it would do what you expect
Other characters
You had mentioned there were other characters that you were looking to remove. That wouldn't be a tall order. You could be using regex for this so lets try that.
$characters = "._"
$regex = "[$([regex]::Escape($characters))]"
$filesandfolders = Get-ChildItem -recurse | Where-Object {$_.name -match $regex}
$filesandfolders | Where-Object {!$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
Rename-Item -path $_.Fullname -newname $New -passthru -WhatIf
}
$filesandfolders | Where-Object {$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
Rename-Item -path $_.Fullname -newname $New -passthru -WhatIf
}
That would remove all of the periods and underscores from those files and folders.
Not tested but you might even be able to get it down to these few lines
$characters = "._"
$regex = "[$([regex]::Escape($characters))]"
$filesandfolders = Get-ChildItem -recurse | Where-Object {$_.name -match $regex}
$filesandfolders | Where-Object {!$_.PsIscontainer} | Rename-Item -NewName ($_.name -Replace $regex) -PassThru -WhatIf
$filesandfolders | Where-Object {$_.PsIscontainer} | Rename-Item -NewName ($_.name -Replace $regex) -PassThru -WhatIf

Related

Powershell recursively return paths but limit depth to 3

In PowerShell, how might one return a set of paths but limit the depth of the result to 3
Here is my folder structure...
d:\testfiles\run\test01\success\build
d:\testfiles\run\test01\success\result
d:\testfiles\run\test02\fail\build
d:\testfiles\run\test02\fail\result
d:\testfiles\run\test03\exp\ready\build
d:\testfiles\run\test03\exp\ready\result
This command returns the full list of folders
Get-ChildItem -Directory d:\testfiles\run\ -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "build|result"} | % { $_.FullName }
What I would like to get is the list of folders truncated to 3 deep, ie...
d:\testfiles\run\test01
d:\testfiles\run\test01
d:\testfiles\run\test02
d:\testfiles\run\test02
d:\testfiles\run\test03
d:\testfiles\run\test03
So, this seems to return the folders as expected...
Get-ChildItem -directory -recurse | Where-Object {$_.Name -match "^test01$|^test02$|^test03$"} | % { $_.fullname.split('\')[0..3] + '' -join '"\"' -replace ':"\\', ':\' -replace '\\"$', ''}
But this throws an error...
Get-ChildItem -directory -recurse | Where-Object {$_.Name -match "^test01$|^test02$|^test03$"} | Move-Item -Destination { $_.fullname.split('\')[0..3] + '' -join '"\"' -replace ':"\\', ':\' -replace '\\"$', ''}
The error I get...
Move-Item : Illegal characters in path.
At line:1 char:109

How to execute two commands in Powershell after using Where {(...)}

How can I run both 'rename' command and 'hidden' command after I filtered files using Where condition. Each command runs well on its own when placed first, but the second one is neglected.
Get-ChildItem -Recurse -Force | Where {(
$_.Extension -ne ".mp3" -and
$_.Extension -ne ".wmv" )} |
Set-ItemProperty -Name Attributes -Value "Hidden" -WhatIf |
Rename-Item -NewName {$_.Name -replace $_.Extension, -join($_.Extension, ".notmusic")} -
WhatIf
For-Each:
Get-ChildItem -Recurse -Force | Where {( $_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv" )} | ForEach-Object {
$_ | Set-ItemProperty -Name Attributes -Value "Hidden" -WhatIf
$_ | Rename-Item -NewName { $_.Name -replace $_.Extension, -join($_.Extension, ".notmusic")} -WhatIf
}
I use ForEach-Object
Get-ChildItem -Recurse -Force | Where {( $_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv" )} | ForEach-Object {
Set-ItemProperty -Name Attributes -Value "Hidden" -Path $_.FullName -WhatIf
Rename-Item -Path $_.FullName -NewName "$($_.Name).notmusic" -WhatIf
}
I add in Set-ItemProperty -Path
Set-ItemProperty -Name Attributes -Value "Hidden" -Path $_.FullName -WhatIf
i change Rename-Item -Path and -NewName
Rename-Item -Path $_.FullName -NewName "$($_.Name).notmusic"
I see the first couple stanzas grab files in your directory that are not mp3 or wmv files.
Get-ChildItem -Recurse -Force | Where {($_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv")}
That part is good. But since you're taking two actions on each file, you should then pipe to a ForEach-Object in the form of
... | ForEach-Object {
# do something
# do something else
}
And since you're not piping directly into the Set-ItemProperty cmdlet, you'll pass it the path of the filename as such:
Set-ItemProperty -Path $_.FullName -Name Attributes -Value "Hidden"
Then we get to your rename command. Looks like you want the name to be filename.notmusic. Again, we'll need to pass the file path to the cmdlet. Also note how using subexpressions is a clean/nice way of defining the new name
Rename-Item -Path $_.FullName -NewName "$($_.BaseName).notmusic"
Ok so put it all together and we have:
Get-ChildItem -Recurse -Force | Where-Object {($_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv")} | ForEach-Object {
Set-ItemProperty -Path $_.FullName -Name Attributes -Value "Hidden" -WhatIf
Rename-Item -Path $_.FullName -NewName "$($_.BaseName).notmusic" -WhatIf
}

How to include folders in Powershell -include string

I am doing some batch file name updates and am having trouble including folders. I have it currently set to target only specific file types, but I also want to include folders. Since folders don't have an extension I am unsure how to specify folders in the "-include" string. Any help would be greatly appreciated.
Here is what I am currently working with, but it ignores folders when I would like them included.
Get-ChildItem k:/toolbox/powershell -Include *.gif, *.jpg, *.png, *.xls,
*.xlsx, *.ppt, *.pptx, *.doc, *.docx, *.pdf -recurse | where {$_.name -match
"_"} | foreach {
$New=$_.name.Replace("_","-")
Rename-Item -path $_.Fullname -newname $New -passthru
}
(Get-Item '~\Desktop\*') | foreach { $FolderName = $_.name.Replace("_","-"); Rename-Item -path $_.fullname -newname $FolderName -passthru }
I would just add 2nd statement:
Get-ChildItem "k:/toolbox/powershell" -Recurse |where mode -eq d----- | where {$_.name -match "_"} | foreach {$New=$_.name.Replace("_","-")
Rename-Item -path $_.Fullname -newname $New -passthru }
If you run Get-ChildItem "k:/toolbox/powershell" you will receive a list of items where the "Mode" is "d-----" for directories, hence you can use that filter criteria for directories

I want to remove recursively square brackets from file names

I have a lot of files in a directory containing square brackets for example:
Filename 1 [12454365].txt
I tried the following script but it's giving me the an error.
get-childitem -recurse | foreach { move-item -literalpath $_.name ($_.name -replace '\[.*\]', '')}
Error message
move-item : A device attached to the system is not functioning.
Only want to remove square brackets not everything in between!
If you specify -Recurse, you will need to specify the file with FullName because it will be targeted other than the current directory.
(Get-ChildItem -File -Recurse) | foreach {
$dest = Join-Path $_.DirectoryName ($_.Name -replace "[\[\]]")
Move-Item -LiteralPath $_.FullName $dest
}
Also, it is better to use Rename-Item for file renaming.
(Get-ChildItem -File -Recurse) | Rename-Item -NewName { $_.Name -replace "[\[\]]" }
I believe the issue is that you are replacing the brackets and everything in between.
Get-ChildItem * -Filter "*`[*`]*" | Rename-Item -NewName { $_.name -replace '\[','' -replace '\]','' }

Too many files to rename

Renaming pdf-files with the command
get-childitem | % { rename-item $_ "2017-$_"}
renames correctly 33 files but applying the same command to more than 33 files produces filenames looking like 2017-2017-2017...-original.name.
How can I surmount that limitation for which I have not found any explication?
Since Rename-Item accepts piped input there is no need for a ForEach,
to exclude files beginning with 2017- :
Get-ChildItem *.pdf -exclude 2017-*.pdf |
Rename-Item -Newname { $_.Name -replace '^','2017-' } -whatif
to exclude any year/4digit-number prefix :
Get-ChildItem *.pdf |
Where-Object Name -notmatch '^\d{4}-' |
Rename-Item -Newname { $_.Name -replace '^','2017-' } -whatif
If the output looks OK, remove the -whatif
Looks like your code is chasing it's tail (i.e. it's renaming things that have already been renamed). Capture the list of files into a variable, then loop through that, renaming the captured list of files:
$filesToRename = Get-ChildItem -Filter '*.pdf'
$filesToRename | ForEach-Object {
Rename-Item -Path $_.FullName -NewName "2017-$($_.FullName)"
}
If you want to exclude already renamed files:
$prefix = '2017-'
$filesToRename = Get-ChildItem -Filter '*.pdf' | Where-Object { !$_.Name.StartsWith($prefix) }
$filesToRename | ForEach-Object {
Rename-Item -Path $_.FullName -NewName "$prefix$($_.FullName)"
}