简体   繁体   中英

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

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 }

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
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM