Recursively add an extension to a group of files in PowerShell Version. 4 - powershell-4.0

I'm looking at how to add an extension recursively to an entire folder structure. This line does what I need, but only for the current folder. I need to do the same for the subfolders structure.
Get-ChildItem -File | % { mv ($_.BaseName+"") ($_.BaseName+".png") }
But I keep getting this error:
Cannot find path 'C:\Users\Jess...\' because it does not exist.
I used the search, however I only founded a solution for the Bash, not the PowerShell. So I couldn't get the -Recurse to work in the same way.
Get-ChildItem -File -Recurse | % { mv ($_.BaseName+"") ($_.BaseName+".png") }

Here's a way to get the full pathname. In powershell 6 this isn't an issue.
Get-ChildItem -File -Recurse | % { $_ | mv -destination ($_.Name + '.png' ) -whatif }
Or
Get-ChildItem -File -Recurse | ? { ! $_.extension } |
mv -destination { $_.Name + '.png' } -whatif

Related

Is there a way to rename files in bulk by the name of their folder?

I'm trying to write a PowerShell script that goes into every folder in a certain directory, and every child with the parent.
Example:
Z:\Folder1\File.txt
Z:\Folder1\Picture.jpeg
Z:\Folder1\Data.csv
Z:\Folder2\File.txt
Z:\Folder2\Picture.jpeg
Z:\Folder2\Data.csv
=
Z:\Folder1\Folder1.txt
Z:\Folder1\Folder1.jpeg
Z:\Folder1\Folder1.csv
Z:\Folder2\Folder2.txt
Z:\Folder2\Folder2.jpeg
Z:\Folder2\Folder2.csv
I have this so far
dir | rename-item -NewName {$_.name -replace *,"Folder1"}
Please let me know how I can loop through every folder, and how I can rename them based on the folder name.
Thanks!
This should do what you're asking:
Get-ChildItem Z:\Folder* -Directory | Get-ChildItem -File | Rename-Item -NewName { $_.DirectoryName.split('\')[-1] + $_.Extension } -WhatIf
Adjust the folder name filter (.\Folder*) as required and remove the -WhatIf if you're satisfied with the changes it will make.
Obviously this doesn't account for where you might have a name clash if there are two files in the folder with the same extension. The following would do that:
$FilesToRename = Get-ChildItem Z:\Folder* -Directory | Get-ChildItem -File
foreach ($FileToRename in $FilesToRename) {
$NewName = $FileToRename.DirectoryName.split('\')[-1] + $FileToRename.Extension
$NewFile = Join-Path $FileToRename.Directory $NewName
$i = 0
While (Test-Path $NewFile) {
$i = $i++
$NewName = $FileToRename.DirectoryName.split('\')[-1] + "[$i]" + $FileToRename.Extension
$NewFile = Join-Path $FileToRename.Directory $NewName
}
$FileToRename | Rename-Item -NewName $NewName
}

Removing trailing and ending blank spaces in folder and file names on Windows in bulk

I tried following Remove leading spaces in Windows file names but it's not working for my use case.
I have a lot of folders and filenames that either have a blank space at the front or at the end. How would I go about removing those spaces in bulk?
This was the command-line command I used after following the linked post:
for /R %A IN ("* ") do #for /F "tokens=*" %B IN ("%~nxA") do #ren "%A" "%B"
But it didn't work out.
Update: thank you to all who replied trying to help. I think there is just a Windows-level glitch in the file system. I ended up just having to manually create new folders without leading and trailing spaces and then dragging all the files over manually then renaming those to non-trailing and leading names as well.
It's unclear whether or not you want a PowerShell solution, but there's a reasonable assumption to be made you might.
If you wanted a PowerShell solution, you could try this:
function Test-LeadingTrailingWhitespace {
param(
[Parameter(Mandatory)]
[String]$String
)
$String[0] -eq ' ' -Or $String[-1] -eq ' '
}
Get-ChildItem -Path "<path_to_folder>" | ForEach-Object {
if ($_.PSIsContainer -And (Test-LeadingTrailingWhitespace -String $_.Name)) {
$Destination = Split-Path -Path $_.FullName -Parent
$NewName = $_.Name.Trim()
Move-Item -Path $_ -Destination (Join-Path -Path $Destination -ChildPath $NewName)
}
elseif (Test-LeadingTrailingWhitespace -String $_.BaseName) {
$Destination = Split-Path -Path $_.FullName -Parent
$NewName = $_.BaseName.Trim() + $_.Extension
Move-Item -Path $_ -Destination (Join-Path -Path $Destination -ChildPath $NewName)
}
}
To be on the safe side, you could add -WhatIf or -Confirm on the Move-Item cmdlet. The former will tell you what would have changed without that parameter without actually making any changes (like a 'dry run'). The latter will prompt you for confirmation before making each change, giving you a chance to validate incrementally and not make changes en masse from the moment you hit enter.
Trim() is a method available for all strings in PowerShell:
Returns a new string in which all leading and trailing occurrences of a set of specified characters from the current string are removed.
You can loop over files and folder and check if they actually have a leading or trailing whitespace before renaming, this would avoid errors like:
Rename-Item: Source and destination path must be different.
We can use the -match matching operator with a simple regex ^\s|\s$ (starts with whitespace or ends with whitespace - regex101 link for a simple example) to see if the file or folder should be renamed:
Get-ChildItem path\to\startingfolder -Recurse | ForEach-Object {
$newName = switch($_) {
# handle folders
{ $_.PSIsContainer -and $_.Name -match '^\s|\s$' } {
$_.Name.Trim()
break
}
# handle files
{ $_.BaseName -match '^\s|\s$' -or $_.Extension -match '^\s|\s$' } {
$_.BaseName.Trim() + $_.Extension.Trim()
break
}
# if none of the above conditions were true, continue with next item
Default {
return
}
}
Rename-Item -LiteralPath $_.FullName -NewName $newName
}
Personally, I'd do this in two steps to rename folders and files separately. This to overcome the problem that when a folder is renamed, the items inside that folder all have a new path.
Using switch -Force allows renaming items such as hidden or read-only files
Using -ErrorAction SilentlyContinue swallows the error when the new name is equal to the existing name
$rootPath = 'X:\thepath'
# first the folders and subfolders (deepest nesting first)
(Get-ChildItem -Path $rootPath -Directory -Recurse | Sort-Object FullName -Descending) |
Rename-Item -NewName {$_.Name.Trim()} -Force -ErrorAction SilentlyContinue
# next the files
(Get-ChildItem -Path $rootPath -File -Recurse) |
Rename-Item -NewName {'{0}{1}' -f $_.BaseName.Trim(), $_.Extension.Trim()} -Force -ErrorAction SilentlyContinue

Rename all folders in Directory to single digit or character with Powershell

I have a directory in Windows 10 where all the files have names that are too long for windows to handle.
I want to delete these files.
I have discovered that renaming the folder allows me to reduce the path name enough to delete the folder.
For example Changing "Desktop" and it's subfolders to "1" (so the path is 1/1/1/1/file.filetype)
What I have tried is:
Get-ChildItem $path -Recurse -Filter * | Rename-Item -NewName { $_.name -replace *, '1'} -verbose
However this seems to throw an error on *
Is there an easy way to do this or what can I change?
Edit:
Dir | %{Rename-Item $_ -NewName ("{0}" -f $nr++)}
Works on one level but I am having trouble making that recursive through the child folders
Get-ChildItem $path -Recurse | %{Rename-Item $_ -NewName ("{0}" -f $nr++)}
throws this error among others:
Rename-Item : Cannot rename because item at 'designable.nib' does not exist.
If you know you will not loose anything by renaming all folders, this would help. This does not change filenames. This will recursively call the method to rename the folder until the process is able to find the next number.
NOTE: If you take away -Directory, it will update the filenames as well.
function RenameToLeastNumbers ($item, $number) {
try {
$newName = $item.Name -replace $item.Name, $number
Rename-Item $item.FullName -NewName $newName -ErrorAction Stop
}
catch
{
$number = $number + 1
if ($number -gt 100) {
return
}
RenameToLeastNumbers $item $number
}
}
Get-ChildItem -Directory -Recurse -Path C:\Temp\Dates | % { RenameToLeastNumbers $_ 1 }
All the folders under Dates will be renamed starting with 1. If Dates have three folders, they will be renamed to 1, 2, 3. Same thing will happen at each of their childrens and so on.
what folders look like
dir C:\temp\Dates -Name -Recurse
1
2
3
1\1
1\1\This is a text document.txt
2\1
3\1
I tried this process and did not once see the error for many many directories nested in 100s of folders. (created a test folder with nothing but directories and kept copying them within each).
function RenameFolderAndSubFolders {
param($item, $number)
$subfolders = Get-ChildItem $item.FullName -Directory
foreach ($folder in $subfolders) {
RenameFolderAndSubFolders $folder 1
}
while ($true){
try {
Write-Output "Renaming: $($item.FullName)"
Rename-Item $item.FullName -NewName $number -ErrorAction Stop
return
}
catch {}
$number = $number + 1
}
}
Get-ChildItem -Directory -Path C:\Temp\Dates | % { RenameFolderAndSubFolders -item $_ -number 1 }
Let me know how this works.

Counting folders with Powershell

Does anybody know a powershell 2.0 command/script to count all folders and subfolders (recursive; no files) in a specific folder ( e.g. the number of all subfolders in C:\folder1\folder2)?
In addition I also need also the number of all "leaf"-folders. in other words, I only want to count folders, which don't have subolders.
In PowerShell 3.0 you can use the Directory switch:
(Get-ChildItem -Path <path> -Directory -Recurse -Force).Count
You can use get-childitem -recurse to get all the files and folders in the current folder.
Pipe that into Where-Object to filter it to only those files that are containers.
$files = get-childitem -Path c:\temp -recurse
$folders = $files | where-object { $_.PSIsContainer }
Write-Host $folders.Count
As a one-liner:
(get-childitem -Path c:\temp -recurse | where-object { $_.PSIsContainer }).Count
To answer the second part of your question, of getting the leaf folder count, just modify the where object clause to add a non-recursive search of each directory, getting only those that return a count of 0:
(dir -rec | where-object{$_.PSIsContainer -and ((dir $_.fullname | where-object{$_.PSIsContainer}).count -eq 0)}).Count
it looks a little cleaner if you can use powershell 3.0:
(dir -rec -directory | where-object{(dir $_.fullname -directory).count -eq 0}).count
Another option:
(ls -force -rec | measure -inp {$_.psiscontainer} -Sum).sum
This is a pretty good starting point:
(gci -force -recurse | where-object { $_.PSIsContainer }).Count
However, I suspect that this will include .zip files in the count. I'll test that and try to post an update...
EDIT: Have confirmed that zip files are not counted as containers. The above should be fine!
Get the path child items with recourse option, pipe it to filter only containers, pipe again to measure item count
((get-childitem -Path $the_path -recurse | where-object { $_.PSIsContainer }) | measure).Count

Power shell to loop subfolders according to sequence

I would like to use power shell to loop all subfolders and run all the files in it. But, if my root contain 3 subfolders, I would like to loop and list it accordingly to the sequence where : Subfolder C , Subfolder B and Subfolder A so that the file execution will run according to the sequence ( C-->B-->A) .
Below is my coding.
Get-ChildItem -path "C:\Root\subfolders\" -recurse -Filter *.sql | foreach-object -process { $_.FullName }|
ForEach-Object {
sqlcmd -i $_
}
Give this a try, get all folders of C:\Root\subfolders and foreach folder found get its files recursively :
Get-ChildItem C:\Root\subfolders |
Where-Object {$_.PSIsContainer} |
Foreach-Object {Get-ChildItem $_.FullName -Recurse -Filter *.sql | Foreach-Object {sqlcmd -i $_.FullName} }

Resources