Moving Files to Folder Based on Filename - powershell

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
}

Related

Moving files not woking in powershell

I have a code:
cls
$folderPath = 'Y:\lit\Retail\abc\abc\FTP-FromClient\AMS\2022-03-23'
$files = Get-ChildItem $folderPath
$destination='Y:\lit\Retail\abc\abc\FTP-FromClient\AMS\2022-03-23\bz2'
$leftfiles=('20220322054419',
'20220322083959',
'20220322084715',
'20220322085207',
'20220322085250',
'20220322085858',
'20220322090236',
'20220322090410',
'20220322090450'
'20220322170306')
foreach($j in $leftfiles)
{
foreach($f in $files)
{
if ($f -contains $j)
{
Move-Item $f.FullName $destination
}
}
}
In this $folderPath I have some files:
$folderPath = 'Y:\lit\Retail\abc\abc\FTP-FromClient\AMS\2022-03-23'
File naming has some naming convention as which matches with the numbers inside the aray:
Colly_20220322054419.dat.bz2
Colly_1_20220322084715.dat.bz2
Colly_3_20220322085207.dat
I only need to move all the files to the destination ,if filename contains the number inside array elements. So I tried using -contains to move the file but it's not working:
foreach($j in $leftfiles)
{
foreach($f in $files)
{
if ($f -contains $j)
{
Move-Item $f.FullName $destination
}
}
}
Your code could be simplified if you use a Where-Object clause that filters the files to move using the regex -match operator
$folderPath = 'Y:\lit\Retail\abc\abc\FTP-FromClient\AMS\2022-03-23'
$destination = 'Y:\lit\Retail\abc\abc\FTP-FromClient\AMS\2022-03-23\bz2'
$leftfiles = '20220322054419', '20220322083959','20220322084715','20220322085207','20220322085250',
'20220322085858','20220322090236','20220322090410','20220322090450','20220322170306'
# first make sure the destination folder exists
$null = New-Item -Path $destination -ItemType Directory -Force
# join the items from $leftfiles with a pipe symbol (=the regex 'OR')
$regex = $leftfiles -join '|'
Get-ChildItem -Path $folderPath -File |
Where-Object { $_.BaseName -match $regex } |
Move-Item -Destination $destination
If you want to test this out first, append switch -WhatIf to the Move-Item line. THat way, nothing actually gets moved. Only in the console, it is displayed what would be moved

PowerShell Script (foreach-loop problems)

I have a short question, but I am standing on the wall for too long now, so I have to ask you....
The situation is:
I have a special filetype, in different folders and subfolders.
I already managed to find the files, write them into a TXT-File and I also managed to split the path so I can name a ZIP-File with the Folder-Name and Date.
But the only thing I do not get is how to only zip the special file of folder1 in a Zip-archiv "folder1-date.zip" and the file of folder2 in a Zip-archiv "folder2-date.zip".
Code part looks like this:
[string[]]$dirs = (Split-Path (Split-Path -Path $output -Parent) -Leaf | Foreach-Object { $i++; $_ })
[string[]]$arrayFromFile = Get-content -Path 'C:\TEMP\output.txt'
foreach ($file in $arrayFromFile) {
foreach ($dir in $dirs){
#
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip }
}
The Problem is, that every file with the extension found is in every ZIP-Archiv (logic because it is a foreach in a foreach) but I can not find the right way to do it....
Thank you for the help!
This will get the desired outcome and not have to save output to a text file.
$origin = "C:\TEMP\"
$filetyp = ".stl, .vol, .pct, .tif"
$destination = "C:\Daten\zipstore\"
$date = $(Get-Date -Format d)
$fileNames = Get-ChildItem "$origin" -Recurse | Where {$_.extension -eq ".stl"} | ForEach-Object { $_.FullName }
foreach ($file in $fileNames) {
$dir = (Split-Path (Split-Path -Path $file -Parent) -Leaf)
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip
}
Thank you for the answer! Here you have the whole code:
# Variablen Definition:
#
$origin = "C:\TEMP\"
$filetyp = ".stl, .vol, .pct, .tif"
$destination = "C:\Daten\zipstore\"
$date = $(Get-Date -Format d)
#
#
# Auslesen aller Files die bestimmte Dateiendung haben:
#
Get-ChildItem "$origin" -Recurse | Where {$_.extension -eq ".stl"} | ForEach-Object { $_.FullName } > C:\TEMP\output.txt
#
#
# Remove filename, keep path to file / split and only keep last directory:
#
$output = Get-content C:\TEMP\output.txt
$i = 0
#
[string[]]$dirs = (Split-Path (Split-Path -Path $output -Parent) -Leaf | Foreach-Object { $i++; $_ })
#
#
# Create ZIP-Archiv:
#
[string[]]$arrayFromFile = Get-content -Path 'C:\TEMP\output.txt'
foreach ($file in $arrayFromFile) {
foreach ($dir in $dirs){
#
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip }
}
#
#
# Delete files not needed anymore:
Remove-Item -Path $origin -Include *.txt -Recurse -Force
#
Maybe this helps!

Trying to use powershell to put files in folders based on their extension and the name of the folder

I have a directory with three files: .xlsx, .docx, and .txt, I also have folders in that same directory called xlsx, docx and txt. Basically trying to put each file into its corresponding folder, as a way to practice my PowerShell skills. I'm very new to PowerShell and have tried the following. I can tell its wrong, but I'm not quite sure why.
$folders = Get-ChildItem -Directory
$files = Get-ChildItem -File
foreach ($file in $files) {
foreach ($folder in $folders) {
if ("*$file.extension*" -like "*$folder.Name*") {
move-item $file -Destination "C:\Users\userA\Desktop\$folder.name"
}
}
}
Try the code below. With the Where-Object function, you find the corresponding file. I remove the dot because it is included in the extension otherwise.
$folders = Get-ChildItem -Directory
$files = Get-ChildItem -File
foreach ($file in $files) {
$folder = $folders | Where-Object { $_.Name -Like $file.Extension.Replace(".","") }
Move-Item -Path $file -Destination $folder
}
In your example, be careful how your strings are actually been interpreted. If you have "*$item.Name*" the string actually "* variable.Name*". In this case you need to use "*$($var.Name)*" in order to get the correct string.
Here are some adjustments to your approach that make it work. Breaking the -Destination parameter out to a separate variable $newpath lets you set a debug statement there so you can easily examine what it's creating.
$folders = Get-ChildItem -Directory
$files = Get-ChildItem -File
foreach ($file in $files) {
foreach ($folder in $folders) {
if ($file.extension.trim(".") -like $folder.Name) {
$newpath = ("{0}\{1}" -f $folder.FullName, $file.Name)
move-item $file -Destination $newpath
}
}
}
You could even create target folders for extensions if they do not exist yet:
$SourceFolder = C:\sample
$TargetFolder = D:\sample
Get-ChildItem -Path $SourceFolder -File |
ForEach-Object{
$DesinationFolder = Join-Path -Path $TargetFolder -ChildPath $_.Extension.TrimStart('.')
if(-not (Test-Path -Path $DesinationFolder)){
New-Item -Path $DesinationFolder -ItemType Directory | Out-Null
}
Copy-Item -Path $_.FullName -Destination $DesinationFolder -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.

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
}
...