Renaming files in bulk, depending on the subfolder they are in - powershell

I'm trying to rename a bunch of files in a bunch of subfolders.
I want them to have a 'prefix', that coresponds with the subfolder they are placed in.
Example:
Main folder:
Subfolder1
Subfolder2
Subfolder3
All the files in Subfolder1, should be renamed to "Subfolder1_filename.pdf", and the same for the rest of the folders.
$dir = 'C:\Users\user\desktop\testfolder\'
foreach ($i in $dir){
$foldername = Get-ChildItem $dir -name
cd $newdir
rename-item -NewName {$foldername + "_" + $_.Name}
}

$Files = Get-ChildItem -Path $Dir -Recurse -File
ForEach ($File in $Files)
{
$FolderName = ((Split-Path -Path $File.FullName -Parent) -split '\\')[-1]
$FileName = $File.Name
Rename-Item -Path $File.FullName -NewName "${FolderName}_$FileName"
}
This will accomplish renaming them according to their container, but you would need to utilize Move-Item if you want to move+rename, or something of that nature.

Related

How can I append the creation date to all files in a folder and the subfolders in PowerShell?

I have a small script that can successfully copy all the files from folders and subfolders and append the creation time, but the files in the subfolders do not have the creation time appended to their names.
How can I append the creation date to all files in a folder and the subfolders?
My current script is:
$path = "C:\test1"
$destination = "C:\test2"
Get-ChildItem -path $path | ForEach-Object{
$newname = $_.CreationTime.toString("yyyy-MM-dd") + $_.BaseName +$_.Extension
(Copy-Item -Recurse -Path $_.FullName -Destination ( Join-Path $destination $newname))
}
You were really close, but the -Recurse switch should have been on Get-ChildItem and within the loop you need to make sure the destination subfolder paths exist.
Try
$source = "C:\test1"
$destination = "C:\test2"
Get-ChildItem -Path $source -File -Recurse | ForEach-Object {
# create the new target folderpath for the copy
$targetPath = Join-Path -Path $destination -ChildPath $_.DirectoryName.Substring($source.Length)
# make sure the target path exists, if not create it
$null = New-Item -ItemType Directory -Path $targetPath -Force
# create a new filename with CreationDate prefixed
$newName = '{0:yyy-MM-dd}{1}{2}' -f $_.CreationTime, $_.BaseName, $_.Extension
# copy the file
$_ | Copy-Item -Destination (Join-Path -Path $targetPath -ChildPath $newname) -Force
}
While you could create your own recursive method to copy files and rename them as you go, it would be easier to use Copy-Item recursively and rename the files and folders afterwards:
$Source = "src"
$Destination = "dst"
Copy-Item -Recurse $Source $Destination
foreach ($Item in (Get-ChildItem -Recurse -File $Destination)) {
Rename-Item $Item ($Item.Name + "-" + $Item.CreationTime.toString("yyyy-MM-dd"))
}

Coping files from multiple sub folders using powershell

Copy file from multiple sub-folder to another multiple sub-folder
example :
C:\Nani\Code\Relase4\database1\tables
C:\Nani\Code\Relase1\database1\tables
C:\Nani\Code\Relase2\database1\tables
C:\Nani\Code\Relase3\cycle1\database1\tables
C:\Nani\Code\Relase1\database1.02.tables
I have .sql files in above all folders and i want to copy to
C\Build\database1\tables
if database1\tables directory is not there , i have to create it too ,
$sourceFolder = "C:\Nani\Code"
$targetFolder = "C\Build"
Get-Childitem $sourceFolder -recurse -filter "*.sql" -Exclude $exclude | %{
#If destination folder doesn't exist
if (!(Test-Path $targetFolder -PathType Container)) {
#Create destination folder
New-Item -Path $targetFolder -ItemType Directory -Force
}
Copy-Item -Path $_.FullName -Destination $targetFolder -Recurse -force
}
above code is not creating sub folders in destination ,
I have kept the script very simple for your understanding and commented the sections.
Make sure you add all the validations for paths and error handling. Else if any of the files is giving any issue, then it wont proceed and will break the loop.
Script:
#Keeping all the sources in an array
$Sources = #("C:\Nani\Code\Relase4\database1\tables",
"C:\Nani\Code\Relase1\database1\tables",
"C:\Nani\Code\Relase2\database1\tables",
"C:\Nani\Code\Relase3\cycle1\database1\tables",
"C:\Nani\Code\Relase1\database1.02.tables")
$Destination="C\Build\database1\tables\"
#Iterating each source folder
foreach($source in $sources)
{
#Getting all the sql files under an iteration folder recursively
$files=Get-ChildItem -Path $source -Filter "*.sql" -Recurse
#Iterating all the files underneath a single source folder
foreach ($file in $files)
{
#Copying the files for a single folder to the destination
Copy-Item $file.PSPath -Destination ("$Destination" + ($file.PSParentPath | Split-Path -Leaf) + '_' + $file)
}
}
Hope it helps.
Try this, I am creating each folder first before copying files into it.
$sourceFolder = "C:\Nani\Code"
$targetFolder = "C:\Build"
$sources = Get-Childitem $sourceFolder -recurse -filter "*.sql" -Exclude $exclude | Select FullName, DirectoryName
foreach ($source in $sources)
{
$Releasepath = [regex]::match($source.DirectoryName,'C:\\Nani\\Code\\Release\d').Value
$split = $Releasepath.Replace("\","\\")
$targetfolderLeaf = $source.DirectoryName -split $split | select -Last 1
$targetfolderpath = $targetFolder+$targetfolderLeaf
if (!(Test-Path $targetfolderpath -PathType Container)) {
#Create destination folder
New-Item -Path $targetfolderpath -ItemType Directory -Force
}
Copy-Item -Path $source.FullName -Destination $targetfolderpath -Recurse -force
}

Rename After Copy - Powershell

I am trying to use powershell to copy one type of file (.xlsx) from one folder to another.
Once the copy is completed, I would like the extension on the original file to be changed. (.xlsx to .cmp)
I have the copy part down (below) but I am lost when it comes to the rename. Can you guys please help. I am a PS noob! Thank you.
$src = "C:\Users\x\Documents\Test1"
$dst = "C:\Users\x\Documents\Test2"
Get-ChildItem $src -Filter "*.xlsx" | Move-Item -Destination $dst -Force
As far as I know, you'll have to iterate over your files to be able to perform this rename.
# Set-up variables
$sourcePath = "C:\temp"
$sourceExtension = "txt"
$destinationPath = "C:\temp2"
$destinationExtension = "cmp"
# Grab the list of files
$files = Get-ChildItem -Path $sourcePath -Filter "*.$sourceExtension"
# Loop over the files
foreach ($file in $files) {
# Construct the new file name
$newFileName = (Join-Path -Path $destinationPath -ChildPath $file.BaseName) + ".$destinationExtension"
Write-Output "New File Name = $newFileName"
# Move the file to the new destination with its new name!
Move-Item -Path $file.FullName -Destination $newFileName
}
Note: BaseName = filename without extension
This should do it:
$src = "C:\Users\x\Documents\Test1"
$dst = "C:\Users\x\Documents\Test2"
Get-ChildItem $src -Filter "*.xlsx" | ForEach-Object {
Copy-Item $_ -Destination $dst
Rename-Item $_ -NewName ($_.Name -Replace '.xlsx','.cmp')
}
Uses a ForEach-Object loop to go through each item in the $src folder. Then for each item (represented inside the loop as $_) we use Copy-Item to copy it to the destination Then use Rename-Item with a -Replace to change the file extension.

Moving Files to Folder Based on Filename

I have several thousand files in a single directory. Many of these files need to be grouped together in their own directory based off a part of the filename. I need a part of the filename to be the destination folder name. I put dashes around the part of the filename I need the directory to be named.
For instance, the following files are located in a single directory:
filea-123-.PDF
fileb-123-.PDF
filec-456-.PDF
filed-123-.PDF
file3-456-.PDF
I need all files with "-123-" to be moved to a folder called "123". Likewise, I need all files with "-456-" to be moved to a folder called "456" and so on.
Here is what I have so far:
$dir = "C:\convert"
$filelist = (Get-Item $dir).GetFiles()
foreach ($file in $filelist)
{
$newdir = $file.Name -match '-\d+-'
Move-Item $file -Destination "C:\convert\$matches[0]"
}
I've also tried this:
$dir = "C:\convert"
$filelist = (Get-Item $dir).GetFiles()
foreach ($file in $filelist)
{
$pieces = $file-split"-"
$start = $pieces.Count*-1
$folder = $pieces[$Start..-2]-join" "
$destination = "C:\convert\{0}" -f $folder
if (Test-Path $destination -PathType Container)
{
Move-Item -Path $filename -Destination $destination
}
}
Try this
$dir = "C:\convert"
$filelist = #(Get-ChildItem $dir)
ForEach ($file in $filelist){
# Gets the '123' part
$folder = $file.Name.Split("-")[1]
#Test if folder exists.
Set-Location ($dir+'\'+$folder)
#If no folder, create folder.
if(!$?){ mkdir ($dir+'\'+$folder) }
#Move item keeping same name.
Move-Item $file.FullName ($dir+'\'+$folder+'\'+$file.Name)
}
}
Use a capturing group in your regular expression for extracting the number from the filename:
Get-ChildItem $dir -File | Where-Object {
$_.Name -match '-(\d+)-.pdf$'
} | ForEach-Object {
Move-Item $_.FullName ('{0}\{1}' -f $dir, $matches[1])
}
or like this, since Move-Item can read directly from the pipeline:
Get-ChildItem $dir -File | Where-Object {
$_.Name -match '-(\d+)-.pdf$'
} | Move-Item -Destination {'{0}\{1}' -f $dir, $matches[1]}
I like Ansgars approach, If the sub folders still have to be created:
Get-ChildItem -Path $dir -Filter "*-*-.PDF" |
Where-Object Name -match '-(\d+)-.pdf$' |
ForEach-Object {
$DestDir = Join-Path $dir $matches[1]
If (!(Test-Path $DestDir)) {mkdir $DestDir|Out-Null}
$_|Move-Item -Destination $DestDir
}

Copy Wav files older than 3 months to archive, creating year\month paths

I was hoping someone can help me out with this script which is currently baffling me, I'm not very good at powershell ;)
What I'm trying to achieve is a script that will scan folders and subfolders of my source, looking for *.wav files older than 60 days and then move them to an archive destination, creating a folder structure of \year\month
This is what i've got
$SourceDir = "d:\test"
$DestinationDir = "e:\test"
$files = get-childitem $SourceDir *.wav
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
where-object {$_.LastWriteTime -lt (get-date).AddDays(-61)} | move-item $file.fullname $Directory
}
The script runs without error but doesn't move files :/
--
Following on from Keiths comments below, my script looks as so:
$SourceDir = "d:\test\"
$DestinationDir = "e:\test\"
$date = (get-date).AddDays(-91)
$files = get-childitem -literalpath $SourceDir *.wav
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
if ($file.LastWriteTime -lt $date) {
Write-Host $file
move-item -LiteralPath $file.fullname -Destination $Directory
}
}
And is working perfectly! Thanks Keith
Where-Object is never at the beginning of a pipeline. It requires input to populate the $_ variable you usually use to compare against. Replace that line with:
if ($file.LastWriteTime -lt (get-date).AddMonths(-3)) {
move-item $file.fullname $Directory
}
Although I would compute the date outside the loop:
$date = (get-date).AddMonths(-3)
And use that inside the loop:
...
if ($file.LastWriteTime -lt $date) {
Move-Item -LiteralPath $file.fullname -Destination $Directory
}
...