Powershell: batch rename files, add counter in front (with leading 0) - powershell-ise

I am trying (as so many others) to batch rename files in a folder, by adding a counter to the front of the filename with leading zeros.
Here is what I have:
b.txt
c.txt
...
zzz.txt
Here is what I want:
001_b.txt
002_c.txt
...
893_zzz.txt
My code so far:
$originalFiles = Get-ChildItem "C:\Users\abc\" -Filter *.txt
$i = 1
ForEach ($originalFile in $originalFiles) {
Rename-Item -Path $originalFile.FullName -NewName (($originalFile.Directory.FullName) + "\" + $i + $originalFile.Name)
$i++
}
I am missing the underscore between the the number and the filename. And I am missing the leading zeros.
Any suggestions are welcome.
Sorry for this basic question, this is my first PowerShell experience.

This should do the trick:
$MyPath = "C:\Users\abc\"
$i=1
Get-ChildItem -Path $MyPath -Filter "*.txt" | Sort-Object | ForEach-Object {
Rename-Item -Path $_.FullName -NewName (Join-Path -Path $_.Directory.FullName -ChildPath "$('{0:d3}' -f $i)_$($_.Name)")
$i++
}
Keep in mind that if you will have 1000 or more files, you will need more than 3 digits

Related

powershell v2 - rename a file whose name matches a string containing a wildcard

I'm trying to create a script to rename a file that matches a given filename, with a wildcard character. e.g.
I have a folder containing the following files:
201412180900_filename_123.log
201412181000_filename_123.log
201412181100_filename_456.log
filename_789.log
I want to scan through this folder, and append the current time to the start of any file starting with the word 'filename'
I have the following so far:
$d = Get-Date -format "yyyyMMddHHmm"
$dir = "C:\test"
$file = "filename*.log"
get-childitem -Path "$dir" | where-object { $_.Name -like "$file" } | rename-item -path $_ -newname $d."_".$_.name
but it doesn't work.
As I see it the individual sections 'should' work from my reading of the documentation, but clearly something is wrong. If someone can point it out it would be appreciated.
We're getting closer. It would appear that -path in the rename-item section needs to be $dir$_ as $_ (seemingly) only contains the filename. (The get-help example suggests it needs to be the full path and filename)
If I take out the rename-item section and replace it with %{write-host $d"_"$_} it gives the correct new filename
However, simply placing this into rename-item section still doesn't update the filename.
rename-item -path $dir$_ -newname $d"_"$_
SUCCESS
the correct syntax appears to be:
get-childitem -Path "$dir" | where-object { $_.Name -like "$file" } | %{rename-item -path $dir$_ -newname $d"_"$_}
The missing element was the %{ ... } surrounding the rename-item section which enabled me to reference $_
$d = Get-Date -format "yyyyMMddHHmm"
$dir = "C:\test"
$file = "filename*.log"
get-childitem -Path $dir | where-object { $_.Name -like $file } | %{ rename-item -LiteralPath $_.FullName -NewName "$d`_$($_.name)" }
This should work, assuming that the errors were relating to "Cannot bind argument to parameter 'Path'", and the NewName string.
Issues included:
Not being able to reference $_ when not in a foreach style block (see here)
The Concatenation issue raised by #alroc
You could, instead of passing the pipeline object to a Foreach-Object, pass directly to the Rename-Item - but I'm unsure quite how to reference the name of the object for the -NewName parameter.
I don't recall . being a string concatenation operator in PowerShell (I may be wrong). Try this:
rename-item -path $_ -newname "$d_$($_.name)"
Or this
rename-item -path $_ -newname ($d + "_" + $_.name)
Or even this
rename-item -path $_ -newname ({0}_{1} -f $d,$_.name)
See the answers here
Yet another way to do it without using foreach or %, but a script block instead:
get-childitem -Path "$dir" -filter $file | rename-item -newname { $d + "_" + $_.name }
See the examples in the doc for rename-item: https://msdn.microsoft.com/en-us/powershell/reference/3.0/microsoft.powershell.management/rename-item There's a -replace operator too, but it can't use wildcards? Oh, you don't need wildcards:
get-childitem -Path "$dir" -filter $file | rename-item -newname { $_.name -replace 'filename',($d + '_filename') }

What is wrong with this script to create files in all subfolders?

I have a directory tree, consisting of several layers, within which I want to create 30 placeholder files, recursively in each folder.
The tree looks something like this:
--F:\inbox\test
----folder1
------subfolder1
------subfolder2
----folder2
------subfolder1
------subfolder2
----folder3
------subfolder1
------subfolder2
Here is what I have.
$folders = gci -path f:\inbox\test -recurse | where {$_.PsIsContainer}
foreach ($folder in $folders) {
1..30 | % { New-Item -Name "$_.txt" -Value (get-date).tostring() -Itemtype file -force}
}
This just creates 30 files in the root folder. I know I am missing something in my logic.
You're not telling new-item where to put the file, so it uses the current working directory. Fortunately, this is easliy fixed with the -Path parameter for the cmdlet.
$folders = gci -path f:\inbox\test -recurse | where {$_.PsIsContainer}
foreach ($folder in $folders) {
1..30 | % { New-Item -Path $folder.FullName -Name "$_.txt" -Value (get-date).tostring() -Itemtype file -force}
}

Unable to collect *.bak files as a single object

I am new to PowerShell.
I wanted to write a simple program to list all *.bak files which I can then either sort by date or size as shown below.
$Drives = Get-WMIObject -class win32_logicaldisk -filter "DriveType = 3" ;
foreach ($d in $Drives){
If (($d.deviceId -ne "C:") -and ($d.VolumeName -ne "PAGEFILE")) {
$backups += Get-ChildItem -Path $d.deviceID -Recurse -filter *.bak
}
This generally works fine except when say for example D: drive has only one *.bak file.
In that case I get an error.
Method invocation failed because [System.IO.FileInfo] doesn't contain a method named 'op_Addition'.
At F:\work\PowerShell\DiskSpace\generate-disk-report-v2.ps1:39 char:13
+ $backups += <<<< Get-ChildItem -Path $d.deviceID -Recurse -filter *.bak
+ CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
If I add an additional junk.bak to that drive, it works fine.
In my case, I found that the variable needs to be initialized as an array and Get-ChildItem needs to be returned as an array even, or especially, if it's only returning one file.
In your case:
$backups = #() - (Before calling Get-ChildItem)
and
$backups = #(Get-ChildItem -Path $d.deviceID -Recurse -filter *.bak) - (Cast as an array)

Powershell: Count items in a folder with PowerShell

I'm trying to write a very simple PowerShell script to give me the total number of items (both files and folders) in a given folder (c:\MyFolder). Here's what I've done:
Write-Host ( Get-ChildItem c:\MyFolder ).Count;
The problem is, that if I have 1 or 0 items, the command does not work---it returns nothing.
Any ideas?
You should use Measure-Object to count things. In this case it would look like:
Write-Host ( Get-ChildItem c:\MyFolder | Measure-Object ).Count;
or if that's too long
Write-Host ( dir c:\MyFolder | measure).Count;
and in PowerShell 4.0 use the measure alias instead of mo
Write-Host (dir c:\MyFolder | measure).Count;
I finally found this link:
https://blogs.perficient.com/microsoft/2011/06/powershell-count-property-returns-nothing/
Well, it turns out that this is a quirk caused precisely because there
was only one file in the directory. Some searching revealed that in
this case, PowerShell returns a scalar object instead of an array.
This object doesn’t have a count property, so there isn’t anything to
retrieve.
The solution -- force PowerShell to return an array with the # symbol:
Write-Host #( Get-ChildItem c:\MyFolder ).Count;
If you need to speed up the process (for example counting 30k or more files) then I would go with something like this..
$filepath = "c:\MyFolder"
$filetype = "*.txt"
$file_count = [System.IO.Directory]::GetFiles("$filepath", "$filetype").Count
Only Files
Get-ChildItem D:\ -Recurse -File | Measure-Object | %{$_.Count}
Only Folders
Get-ChildItem D:\ -Recurse -Directory | Measure-Object | %{$_.Count}
Both
Get-ChildItem D:\ -Recurse | Measure-Object | %{$_.Count}
You can also use an alias
(ls).Count
Recursively count files in directories in PowerShell 2.0
ls -rec | ? {$_.mode -match 'd'} | select FullName, #{N='Count';E={(ls $_.FullName | measure).Count}}
In powershell you can to use severals commands, for looking for this commands digit: Get-Alias;
So the cammands the can to use are:
write-host (ls MydirectoryName).Count
or
write-host (dir MydirectoryName).Count
or
write-host (Get-ChildrenItem MydirectoryName).Count
To count the number of a specific filetype in a folder.
The example is to count mp3 files on F: drive.
( Get-ChildItme F: -Filter *.mp3 - Recurse | measure ).Count
Tested in 6.2.3, but should work >4.

rename file with add length (in bytes) power shell

i have a problem : in files name i have to write their lengths
for example qwerty.tmp → qwerty_12039.tmp ! please help
use:
get-childitem c:\Folder | rename-item -NewName {$_.name -replace ".tmp", $_length ".tmp"}
but it doesn't work
You left '.' there. Also: I would use BaseName instead:
ls C:\folder | Rename-Item -NewName { $_.BaseName + $_.Length + '.tmp' }

Resources