Wrote the following code to move files to a specific Year-Month folder on a drive. However, I would also like to zip the folder I wrote to at the end of the operation. How do I do that?
# Get the files which should be moved, without folders
$files = Get-ChildItem 'D:\NTPolling\InBound\Archive' -Recurse | where {!$_.PsIsContainer}
# List Files which will be moved
# $files
# Target Filder where files should be moved to. The script will automatically create a folder for the year and month.
$targetPath = 'D:\SalesXMLBackup'
foreach ($file in $files)
{
# Get year and Month of the file
# I used LastWriteTime since this are synced files and the creation day will be the date when it was synced
$year = $file.LastWriteTime.Year.ToString()
$month = $file.LastWriteTime.Month.ToString()
# Out FileName, year and month
$file.Name
$year
$month
# Set Directory Path
$Directory = $targetPath + "\" + $year + "\" + $month
# Create directory if it doesn't exsist
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
# Move File to new location
$file | Move-Item -Destination $Directory
}
The intention is to move these files into a folder and zip them and archive them for later use. So I will schedule this once a month to run for the previous month
If you're using PowerShell v5 then you can use the Compress-Archive function:
Get-ChildItem $targetPath | Compress-Archive -DestinationPath "$targetPath.zip"
This will compress D:\SalesXMLBackup to D:\SalesXMLBackup.zip
This is the code I am using for unzipping all the files in a directory. You just need to modify it enough to zip instead of unzipping.
$ZipReNameExtract = Start-Job {
#Ingoring the directories that a search is not require to check
$ignore = #("Tests\","Old_Tests\")
#Don't include "\" at the end of $loc - it will stop the script from matching first-level subfolders
$Files=gci $NewSource -Fecurse | Where {$_.Extension -Match "zip" -And $_.FullName -Notlike $Ignore}
Foreach ($File in $Files) {
$NewSource = $File.FullName
#Join-Path is a standard Powershell cmdLet
$Destination = Join-Path (Split-Path -parent $File.FullName) $File.BaseName
Write-Host -Fore Green $Destination
#Start-Process needs the path to the exe and then the arguments passed seperately.
Start-Process -FilePath "C:\Program Files\7-Zip\7z.exe" -ArgumentList "x -y -o $NewSource $Destination" -Wait
}
}
Wait-Job $ZipReNameExtract
Receive-Job $ZipReNameExtract
Let me know if it helps.
The UnderDog...
Related
I am trying to make simple powershell script that is archiving files coming in daily. Every file has date at the beggining of its name, for example: 20211220_Something.csv, 20211220_SomethingElse.txt, 20211219_Something.csv, 20211219_SomethingElse.txt etc...
I would like to make script that collects all files with extensions (*.txt, *.csv, *.xslx) from specifict directories which are:
\\Main\Files and \\Main\Files\SecondaryFiles
and archives all files with above extensions to for example \\Main\Files\archive\2021\12\20.12.zip
where 2021, 12 and 20.12 are elements of date provided in file name prefix. Inside 20.12.zip we have all files from \\Main\Files with directory named "SecondaryFiles" in which theres all files from the \\Main\Files\SecondaryFiles. After archiving i would like to delete all the files that i just zipped.
Right now i have this piece of code which loop through all files in the \Main\ dir and extracts date prefix. I have tried using [Datetime]::parseexact() method but it doesnt work since my loop returns whole path. Anybody has any idea how to approach this?
$Date = Get-Date
$Day = $Date.Day
$Month = Date.Month
$Year = $Date.Year
$directoryPath = "\\Main\Files\archive'"+$Year+"\"+$Month
$files = Get-ChildItem -Path "\\Main\Files" -Include *.txt, *.csv, *.xlsx -Recurse
for ($i=0; $i -lt $files.Count; $i++){
$temp = $files[$i].FullName.split("_")[1]
}
if(!Test-Path -path $directoryPath){
New-Item -ItemType directory -Path $directoryPath
}
Compress-Archive -Path "\\Main\Files", "\\Main\Files\*.txt", "\\Main\Files\*.csv", "\\Main\Files\*.xlsx", "\\Main\Files\SecondaryFiles\*.txt", "\\Main\Files\SecondaryFiles\*.csv", "\\Main\Files\SecondaryFiles\*.xlsx" -Update -DestinationPath "\\Main\Files\archive\$Year\$Month\$Day.$Month.zip"
Then i am removing items from the original directory.
Also one thing worth mentioning is that I cant be sure if folder contains only files from todays date. So script should work fine when theres files from like all week lets say 20211214 till 20211220.
So again i would like to Compress-Archive files like i did above but instead todays date the path would contain extracted date from file name prefix.
Use Group-Object to group all files having the same date prefix together and use that to create the output subdirectories, the final .zip file and also to remove the original files after zipping.
$sourcePath = '\\Main\Files'
$destination = '\\Main\Files\archive'
Get-ChildItem -Path $sourcePath -Include '*.txt', '*.csv', '*.xlsx' -Recurse |
# select only files that start with 8 digits followed by an underscore
Where-Object { $_.BaseName -match '^\d{8}_' } |
# group the files on the date part and loop trhough these groups
Group-Object { $_.BaseName.Substring(0,8) } | ForEach-Object {
# split the date part into variables. Automatic variable $_ represents one Group,
# so we can take that group's Name to split into date parts
$year, $month, $day = $_.Name -split '(\d{4})(\d{2})(\d{2})' -ne ''
# construct the target folder path for the zip file
$targetPath = Join-Path -Path $destination -ChildPath ('{0}\{1}' -f $year, $month)
# create the new sub directory if it does not yet exist
$null = New-Item -Path $targetPath -ItemType Directory -Force
# create the full path and filename for the zip file
$zip = Join-Path -Path $targetPath -ChildPath ('{0}.{1}.zip' -f $day, $month)
# compress the files in the group
Compress-Archive -Path $_.Group.FullName -DestinationPath $zip -Update
# here is where you can delete the original files after zipping
$_.Group | Remove-Item -WhatIf
}
Note I have added switch -WhatIf to the Remove-Item cmdlet. This is a safety switch, so you are not actually deleting anything yet. The cmdlet now only displays what would be deleted. Once you are happy with this output, remove that -WhatIf switch so the files are deleted.
I am trying to create a powershell script that does the following:
Move the latest 3 subfolders(a-b-c with files) into a new folder with today's date without moving older files
Security has 3 subfolders generated today along with subfolders from previous days.
$localpath ="D:\Security\"
Get-ChildItem $localpath -Recurse | foreach {
$DateofFile = $_.LastWriteTime.ToShortDateString()
$Todaysfolder = Get-Date $DateofFile -Format yyyMMdd
$targetpath = $Todaysfolder
Create directory if it doesn't exsist
if (!(Test-Path $targetpath))
{
New-Item $targetpath -type directory
}
Get-ChildItem $localpath | Move-Item -Destination $targetpath
}
Process right now is grabbing all files - even the ones that were not created today and grouping them into one folder. This script will run at the end of the day to move those 3 subfolders (A-B-C) into today's folder "20200520" example
There's no need to recurse Get-ChildItem when moving the entire folder - saves you looping through contained files.
$FromPath ="C:\fromtest"
$ToPath = "C:\totest\"+(Get-Date -Format yyyMMdd)
$FoldersToMove = Get-ChildItem $FromPath |
Where-Object{$_.LastWriteTime -ge (Get-Date).date}
#Create directory if it doesn't exsist
if (!(Test-Path $ToPath)){
New-Item $ToPath -type directory
}
foreach ($Folder in $FoldersToMove){
$Folder | Move-Item -Destination $ToPath
}
This is my first time posting so I apologize if the formatting is unclear or incorrect. I'll try my best to have things look better as I go.
I am trying to create a power shell script that will create a folder with the year and prior month.
I then want to move a certain ext or files only into the folder that was created.
My issue right now is that any text file inside Temp or Temp\files will be moved into the folder that gets created.
On top of that the files that were moved already once would move again the following month and the information in the prior folder will be gone.
Is there any way I can have it just move the files that are outside the folder into the new folder?
My other issue now is I would like to create the same date format as a prefix to the text document example: 201902-_Name.txt
I haven't figured out the 2nd part and I kinda sorta figured out the 1st part except for it grabs anything inside temp and moves it to the new folder it creates.
# Get the files which should be moved, without folders
$files = Get-ChildItem 'C:\Temp\' -Recurse | where {!$_.PsIsContainer}
# List Files which will be moved
$files
# Target Folder where files should be moved to. The script will automatically create a folder for the year and month.
$targetPath = 'C:\Temp\files\'
foreach ($file in $files){
# Get year and Month of the file
# I used LastWriteTime since this are synced files and the creation day will be the date when it was synced
$year = $file.LastWriteTime.Year.ToString()
$month = (Get-Date).AddMonths(-1).ToString('MM')
$monthname = (Get-Culture).DateTimeFormat.GetAbbreviatedMonthName($month)
# Out FileName, year and month
$file.Name
$year
$month
$monthname
# Set Directory Path
$Directory = $targetPath + "\" + $year + $month
# Create directory if it doesn't exsist
if (!(Test-Path $Directory)){
New-Item $directory -type directory
}
# Move File to new location
$file | Move-Item -Destination $Directory
}
The by far easiest way to tackle your problem #1 is to have the files moved to a target folder that is NOT inside the source folder.
If that is not what you want, then you need to add an extra test for the Get-ChildItem cmdlet to filter out any files that are in the target folder.
Something like this should work:
$sourcePath = 'C:\Temp\' #'# The folder in which the files to move are
$targetPath = 'C:\Temp\files\' #'# The folder where the files should be moved to
# Get the files which should be moved, without folders and exclude any file that is in the target folder
$files = Get-ChildItem $sourcePath -File -Recurse | Where-Object { $_.FullName -notlike "$targetPath*" }
# for PowerShell version below 3.0 use this:
# $files = Get-ChildItem 'C:\Temp\' -Recurse | Where-Object {!$_.PsIsContainer -and $_.FullName -notlike "$targetPath*"}
# List Files which will be moved
# $files
foreach ($file in $files){
# Get year and Month of the file
# I used LastWriteTime since this are synced files and the creation day will be the date when it was synced
$year = $file.LastWriteTime.Year
$month = (Get-Date).AddMonths(-1).ToString('MM') # last month from current date
$monthname = (Get-Culture).DateTimeFormat.GetAbbreviatedMonthName($month)
# Out FileName, year and month
# $file.Name
# $year
# $month
# $monthname
$dateString = '{0}{1}' -f $year, $month
# Set Directory Path
$Directory = Join-Path -Path $targetPath -ChildPath $dateString
# Create directory if it doesn't exsist
if (!(Test-Path $Directory -PathType Container)){
New-Item $Directory -ItemType Directory | Out-Null
}
# Move File to new location and prepend the date prefix to its name
$targetFile = Join-Path -Path $Directory -ChildPath ('{0}-{1}' -f $dateString, $file.Name)
$file | Move-Item -Destination $targetFile -Force
}
As you can see, by using the same $dateString variable, the Move-Item cmdlet not only moves, but renames the files aswell.
Hope this helps
I have thousands of files spanning 5 years which I would like to move into year/month folders. The file names all end with
_yyyy_mm_dd_wxyz.dat
I'm looking for ideas on how I can generate such file folders and move the files into the appropriate folders yyyy/mm using the windows command shell.
You'll need a Regular Expression with (capture groups) to extract year/month from the filename.
Assuming the year/month folder should be placed directly in files parent location.
untested with -Version 2
## Q:\Test\2018\07\23\SO_51485727.ps1
Push-Location 'x:\folder\to\start'
Get-ChildItem *_*_*_*_*.dat |
Where-Object {$_.BaseName -match '_(\d{4})_(\d{2})_\d{2}_[a-z]+$'} | ForEach-Object {
$TargetDir = "{0}\{1}" -f $Matches[1],$Matches[2]
if (!(Test-Path $TargetDir)){MD $TargetDir | Out-Null}
$_ | Move -Destination $TargetDir
}
Sample tree /f after running the script on my ramdriive:
PS A:\> tree /F
A:.
├───2017
│ └───07
│ test_2017_07_24_xyz.dat
└───2018
└───07
test_2018_07_24_xyz.dat
I have created this little quick and dirty script.
Things have been put in more variables than strictly needed, they could be combined in a single line, but I feel this adds clarity which I hope help you understand what happens.
As a note, I have used the date the item was last written to (created or edited).
If you want only the date the file was created and not the time the file was last edited, you could change LastWriteTime to CreationTime
#Load all files from the folder you wish to move on
$items = Get-ChildItem -Path "C:\SomeFolder\RestofPathToYourFiles"
foreach($item in $items) {
#Creates variables for year, month and day
$FolderYear = "$($item.LastWriteTime.Year)"
$FolderMonth = "$($item.LastWriteTime.Month)"
$FolderDay = "$($item.LastWriteTime.Day)"
#create variable with the new directory path
$NewPath = $item.Directory.FullName + "\" + $FolderYear + "\" + $FolderMonth + "\" + $FolderDay
#create variable with the new full path of the file
$NewFullPath = $NewPath + "\" + $item.Name
#test if the folder already is created, if not, create it
if((Test-Path -Path $NewPath) -eq $false) {
New-Item -Force -path $NewPath -Type Directory
}
#move the item to the new folder
Move-Item -Path $item.FullName -Destination $NewFullPath -Force
}
At the simplest, I'd do something like the following:
Determine the year and month related to a file
See if a folder exists already. If not, create it
Move the file
Example...
foreach ($file in $(ls .\stuff.txt)) {
$m = $file.LastWriteTime.Month.ToString("00")
$y = $file.LastWriteTime.Year
$dir = "{0}-{1}" -f $y, $m
New-Item -Name $dir -ItemType directory -ErrorAction SilentlyContinue | Out-Null
Move-Item -Path $file.Fullname -Destination $dir
}
I have been given a business requirement to move some files every month into a file folder format similar to the below. I have used powershell before to move files to a folder that already exists and I have read some things about powershell creating and naming folders but is there a way to do it monthly without changing the folder name it creates every month?
Client 1
Reports 2018
01Jan
02Feb
03Mar
etc.
Client 2
Reports 2018
01Jan
02Feb
03Mar
etc.
So ideally, it would be a script that would create a folder for the month it is run and then move all files in a directory that were created/modified that month into their monthly folder.
Is this possible?
some code I have tried:
Get-ChildItem \\test\d$\Reports*.xlsx -Recurse | foreach {
$x = $_.LastWriteTime.ToShortDateString()
$new_folder_name = Get-Date $x -Format yyyy.MM
$des_path = "c:\test\test2\$new_folder_name"
if (test-path $des_path){
move-item $_.fullname $des_path
} else {
new-item -ItemType directory -Path $des_path
move-item $_.fullname $des_path
}
}
::
cd "\\test\d$\Reports\client1"
$fso = new-object -ComObject scripting.filesystemobject
$fso.CreateFolder("\03Mar")
cd "\\test\d$\Reports\client2"
$fso = new-object -ComObject scripting.filesystemobject
$fso.CreateFolder("\03Mar")
repeat for 20 clients but as you could tell this gets hard to keep up with every month since you have to go update the 03 to 04 and mar to april and further on.
EDIT:
As requested the structure is as follows:
Client 1 - folder
Saved Reports - folder
2017 - folder
01Jan - folder
report 1
02Feb - folder
2018 - folder
01Jan - folder
02Feb - folder
Repeating for 20+ clients
Also EDIT:
# Get the files which should be moved, without folders
$files = Get-ChildItem '\\test\d$\Reports\client\saved reports' -Recurse | where {!$_.PsIsContainer}
# List Files which will be moved
$files
# Target Filder where files should be moved to. The script will automatically create a folder for the year and month.
$targetPath = '\\test\d$\Reports\client\2018 client reports'
foreach ($file in $files)
{
# Get year and Month of the file
# I used LastWriteTime since this are synced files and the creation day will be the date when it was synced
$year = $file.LastWriteTime.Year.ToString()
$month = $file.LastWriteTime.Month.ToString("00")
$monthname = (Get-Culture).DateTimeFormat.GetAbbreviatedMonthName($month)
# Out FileName, year and month
$file.Name
$year
$month
$monthname
# Set Directory Path
$Directory = $targetPath + "\" + $month + $monthname
# Create directory if it doesn't exsist
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
# Move File to new location
$file | Move-Item -Destination $Directory
}
The above seems to be working, but I have to have this entire block of code for every client and will have to change the year each time, any way to generalize this or not?
Last Edit:
Also -- is there a way to do $month -1 so the folder says the last month name not the current month name?
Thanks,
You will need to use the following Cmdlets:
New-Item -Path $path -Name "$((Get-Date).Month)_$((Get-Date).Year)" -ItemType Directory
Get-ChildItem $directoryWTheFiles -File -Recurse | where {$_.CreationTime.Month -eq ((Get-Date).Month) -or $_.LastWriteTime.Month -eq ((Get-Date).Month)} | Move-Item -Destination $dest
I haven't tested it, but this should get you to a 70% completion on that script.
Here is what I have so far... it is just an expansion on Roque Sosa's answer
$folderName = "$(Get-Date -format MM)$(Get-Date -format MMM)"
New-Item -Path $path -Name $folderName -ItemType Directory
$destination = "$path/$folderName/"
Get-ChildItem $directoryWTheFiles -File -Recurse |
Where-Object {$_.LastWriteTime.Month -eq ((Get-Date).Month) -and $_.LastWriteTime.Year -eq ((Get-Date).Year)} |
Move-Item -Destination $destination
This at least gets the folder name formatted correctly as you have shown above. Then it also moves the files that match the month and year of the lastwritetime attribute.
Once you give me the structure of the client folders you are searching I can update more specific to your situation.
I managed to find an answer to this, thank you for your help.
I have updated my post with the code.
Thanks again