'How do I amend this PS script to move files into the correct folders?
My current PS script is:
$loc = "C:\Users\USER\Desktop\New folder1"
$files = Get-ChildItem -Path $loc
for ($i=0; $i -lt $files.Count; $i++)
{
$outfile = $files[$i].FullName
$filename = Split-Path -Path $outfile -Leaf -Resolve
$Year = $filename -replace "Status_\d{0}(\d{4})[\d_]*.txt",'$1'
$Month = $filename -replace "Status_\d{4}(\d{2})[\d_]*.txt",'$1'
$folderYYYY = Join-Path -Path $loc -ChildPath $Year
$folderMM = Join-Path -Path $folderYYYY -ChildPath $Month
$ExistsYYYY = Test-Path $folderYYYY
$ExistsMM = Test-Path $folderMM
If (!$ExistsYYYY)
{
New-Item -Type directory -Path $folderYYYY
}
If (!$ExistsMM)
{
New-Item -Type directory -Path $folderMM
}
Move-Item $outfile $folderMM
}
This script is supposed to move files currently residing in the $loc directory, into YYYY-MM subfolders. If the YYYY or MM subfolder does not exist, then it gets created. If the subfolder path already exists, then the file is moved into this subfolder.
The filename is always in this format:
Status_20180215_074559.txt
So for the above file, YYYY would map to 2018, and MM would map to 02
From testing the script - If the YYYY subfolder does not exist, then the script works great. If the YYYY subfolder already exists, then I end up with the following paths created by the script:
C:\Users\USER\Desktop\New folder1\2018
C:\Users\USER\Desktop\New folder1\2018\02
C:\Users\USER\Desktop\New folder1\2018\2018
The file is moved into the below path by the above script:
C:\Users\USER\Desktop\New folder1\2018\02
I also get the below error:
Move-Item : Access to the path 'C:\Users\USER\Desktop\New folder1\2018' is denied.
At line:14 char:10
+ Move-Item <<<< $outfile $folder
+ CategoryInfo : WriteError: (C:\Users\USER...ew folder1\2018:DirectoryInfo) [Move-Item], IOException
+ FullyQualifiedErrorId : MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand
Any way to stop the creation of the below path:
C:\Users\USER\Desktop\New folder1\2018\2018
Also, how to resolve the error being thrown?
Many thanks
Edit: Tried @Theo script, but I get the below issues:
I then removed all the comments and empty lines out, thinking that may be causing some issue somewhere, but then I get the below error:
So, after some help from someone else, the issue with my script was the $files line - it should have been looking for files only:
$files = Get-ChildItem -Path "$loc\*.txt"
Also, the amended PS script very helpfully provided by @Theo also works, as I have PS version 2
Solution 1:[1]
Your code is quite confusing and overly complex. There is no need to check each part of the destination for the file separately, because the New-Item
cmdlet can create a full path in one go.
Also, it is much simpler to pipe through the results of Get-Childitem
using ForEach-Object
and within that loop use the $_
automatic variable.
Something like this:
$loc = "C:\Users\USER\Desktop\New folder1"
Get-ChildItem -Path $loc -File -Filter 'Status_*' | # get a list of files with names starting with 'Status_'
Where-Object { $_.BaseName -match '_\d{8}_\d{6}$' } | # filter files that have the '_date_time' format
ForEach-Object { # loop through
# join the year and month as partial destination path
$targetpath = '{0}\{1}' -f $_.Name.Substring(7,4), $_.Name.Substring(11,2)
# ceate the full destination path for the file
$destination = Join-Path -Path $loc -ChildPath $targetpath
# check if the path exists and if not, create it
if (!(Test-Path -Path $destination -PathType Container)) {
$null = New-Item -Path $destination -ItemType Directory
}
# now move the file to the destination path
$_ | Move-Item -Destination $destination
}
Edit
It seems you are using PowerShell version 2.0 and then the -File
switch does not exist. For that version you need to adapt the code like this:
$loc = "C:\Users\USER\Desktop\New folder1"
Get-ChildItem -Path $loc -Filter 'Status_*' |
Where-Object { !$_.PSIsContainer -and $_.BaseName -match '_\d{8}_\d{6}$' } |
ForEach-Object {
# join the year and month as partial destination path
$targetpath = '{0}\{1}' -f $_.Name.Substring(7,4), $_.Name.Substring(11,2)
# ceate the full destination path for the file
$destination = Join-Path -Path $loc -ChildPath $targetpath
# check if the path exists and if not, create it
if (!(Test-Path -Path $destination -PathType Container)) {
$null = New-Item -Path $destination -ItemType Directory
}
# now move the file to the destination path
$_ | Move-Item -Destination $destination
}
Solution 2:[2]
easy old fasion bash way, example:
p:\DANE\telefony\Marcin\Archiwum>..\..\move-archive.bat
move IMG-20220119-WA0000.jpg 2022\2022-01\
move IMG-20220119-WA0001.jpg 2022\2022-01\
code of move-archive.bat
@echo off
rem not %var% but !var! give us access to internal loop variable value with enabledelayedexpansion.
setlocal enabledelayedexpansion
rem Run by scheduler script in p:\dane\telefony\marcin\move-archive.bat
rem p:
rem cd p:\dane\telefony\marcin\archiwum
FOR %%V IN (*.*) DO (
rem echo "****** %%V *********"
SET filedate=%%~tV
rem echo !filedate!
SET fileyear=!filedate:~6,4!
rem echo !fileyear!
SET filemonth=!filedate:~3,2!
rem echo !filemonth!
rem create directory as yyyy\yyyy-MM
mkdir !fileyear!\!fileyear!-!filemonth! 2>nul
echo move %%V !fileyear!\!fileyear!-!filemonth!\
move %%V !fileyear!\!fileyear!-!filemonth!\ >nul
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | SiB |