Sunday, November 23, 2014

windows - Script to archive folder and rename files


My goal is to have a .bat that I can use to automatically archive folders via copy, rename the original folder and the files within with the current date and then clean out old production files.



  1. Copy target folders to the "Completed" directory

  2. Update date on the source folders using the format Previous Name_Today's Date (MMDDYY)

  3. Update the date of the INDD files within the source folder using the format Current Name_Today's Date (MMDDYY)

  4. "Clean" the source folder by deleting all .VPS and .PDFs files within the source folder


I am a novice but I have pieced together this code from research and sources:


@echo off
setlocal enabledelayedexpansion
for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined MyDate set MyDate=%%x
set today=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%
xcopy /s /e /q /y "G:\...\Annual_*" "G:\...\_DONE\"
xcopy /s /e /q /y "G:\...\Life_*" "G:\...\_DONE\"
MOVE "G:\...\Annual_*" "G:\...\Annual_today"
MOVE "G:\...\Life_today" "G:\...\Life_today"
FOR /M *.indd /C "cmd /c rename @file \"@fname - today.indd\""
del /s "G:\...\Annual_today" *.pdf
del /s "G:\...\Annual_today" *.vps
del /s "G:\...\Life_today" *.pdf
del /s "G:\...\Life_today" *.vps
"G:\...\New_Job.bat" > output.txt

My end goal is to be able to change the directory path for the source and archive folders so I can reuse this script for different clients files.




Current Issues


As it stands the script doesn't copy and create an archive folder files and just, deletes all VPS and PDF files from all directories, not just the target folder.


I'm not sure if I'm performing the date check correctly to then use it as a variable to rename future folders and files.


I don't know if FOR /M *.indd /C "cmd /c rename @file \"@fname - today.indd\"" is correct to rename the files. The names are a PO number (6digits) then a title, underscore and then the date.


123456_Life_Kit_020819 for example.




Help would be greatly appreciated!




Here's an Example of what the script should do


enter image description here


Copies the WHOLE folder to the _OLD/Archive folder for each one. Then renames the folder and the contents extensions to the "current date". Then deletes the .pdf and .vps files in the NEW date directories only.


Here is an example of the folder structure.


Main directory:


enter image description here


Inside one of the subdirectories:


enter image description here


The only things I'm trying to rename are the MAIN directory folders with the dates (after copying) and then the files within the subdirectory.


No other folders need to be renamed.


Answer



I've included a batch script below that is sort of hybrid since it uses PowerShell but it dynamically builds and executes it but the archive destination per the dest= variable value is used for processing accordingly.


I did use an approach with Robocopy to exclude the file extension types that you want recursively deleted from the destination/archive folder so it simply doesn't copy unnecessarily and thus no need to delete.


I used a whole bunch of PowerShell cmdlets and such so rather than list them all out, I've included some of those in the Further Resources section for additional learning if you desire to understand further.


Batch Script



Note: Just set the the source, destination, and excluded files per the correlated variables (src=, dest=, and excludedFiles=) at
the top of the script below then simply click to run.



SET "src=G:\Folder\Production"
SET "dest=G:\Folder\__Archive"
SET "fname=*.*"
SET "excludedFiles=*.pdf *.vps"
Robocopy "%src%" "%fname%" "%dest%" /E /XF %excludedFiles%
CALL :PSScript
SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0
CD /D "%PowerShellDir%"
Powershell -ExecutionPolicy Bypass -Command "& '%PSScript%'"
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
EXIT
:PSScript
SET PSScript=%temp%\~tmp%~n0.ps1
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
ECHO $Main ^= "%dest%"; >"%PSScript%"
ECHO $Today ^= ^(^("{0:MMddyy}" -f ^(get-date^).AddHours^(0^)^).ToString^(^)^) >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem -Directory $Main ^| ^? {$_ -match "([0-9]{6})"}^); >>"%PSScript%"
ECHO $Folders ^| %% { >>"%PSScript%"
ECHO If^($_ -match "([0-9]{6})"){ >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $oBase ^= ^(Split-Path -path $_.Fullname -leaf^); >>"%PSScript%"
ECHO $nBase ^= ^($oBase.Replace^($matches[1],$Today^)^); >>"%PSScript%"
ECHO Rename-Item "$root\$oBase" "$root\$nBase"; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem -Directory $Main ^| ^? {$_.Name -match "([0-9]{6})"}^).FullName; >>"%PSScript%"
ECHO $Files ^= ^($Folders ^| %% {Get-ChildItem "$_\*" -File -Include *.indd} ^| ^? {$_.Name -match "[0-9]{6}.*?([0-9]{6})"}^); >>"%PSScript%"
ECHO $Files ^| %% { >>"%PSScript%"
ECHO If^($_.Name -match "[0-9]{6}.*?([0-9]{6})"^) >>"%PSScript%"
ECHO { >>"%PSScript%"
ECHO $x ^= $matches[1]; >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $nName ^= ^($_.Name.Replace^($x,$today^)^); >>"%PSScript%"
ECHO If^(!^(Test-Path "$root\$nName"^)^){Rename-Item $_.FullName "$root\$nName"}; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
GOTO :EOF



PowerShell Logic



Note: This is the PowerShell alone in case you want to use it, but you simply set the $Main = variable value to be that of the archive
folder path of the folders and files with the mmddyy string that
gets updated with those characters of the current date when run.



$Main = "G:\Folder\__Archive";
$Today = (("{0:MMddyy}" -f (get-date).AddHours(0)).ToString())
$Folders = (Get-ChildItem -Directory $Main | ? {$_ -match "([0-9]{6})"});
$Folders | % {
If($_ -match "([0-9]{6})"){
$root = (Split-Path -path $_.Fullname);
$oBase = (Split-Path -path $_.Fullname -leaf);
$nBase = ($oBase.Replace($matches[1],$Today));
Rename-Item "$root\$oBase" "$root\$nBase";
}
};
$Folders = (Get-ChildItem -Directory $Main | ? {$_.Name -match "([0-9]{6})"}).FullName;
$Files = ($Folders | % {Get-ChildItem "$_\*" -File -Include *.indd} | ? {$_.Name -match "[0-9]{6}.*?([0-9]{6})"});
$Files | % {
If($_.Name -match "[0-9]{6}.*?([0-9]{6})")
{
$x = $matches[1];
$root = (Split-Path -path $_.Fullname);
$nName = ($_.Name.Replace($x,$today));
If(!(Test-Path "$root\$nName")){Rename-Item $_.FullName "$root\$nName"};
}
};



PowerShell Version 2.0 Compatible Logic


Batch (PS 2.0)



Note: Just set the the source, destination, and excluded files per the correlated variables (src=, dest=, and excludedFiles=) at
the top of the script below then simply click to run.



SET "src=G:\Folder\Production"
SET "dest=G:\Folder\__Archive"
SET "fname=*.*"
SET "excludedFiles=*.pdf *.vps"
Robocopy "%src%" "%fname%" "%dest%" /E /XF %excludedFiles%
CALL :PSScript
SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0
CD /D "%PowerShellDir%"
Powershell -ExecutionPolicy Bypass -Command "& '%PSScript%'"
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
EXIT
:PSScript
SET PSScript=%temp%\~tmp%~n0.ps1
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
ECHO $Main ^= "%dest%"; >"%PSScript%"
ECHO $Today ^= ^(^("{0:MMddyy}" -f ^(get-date^).AddHours^(0^)^).ToString^(^)^); >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem $Main ^| ^? {^($_.PSIsContainer^) -and ^($_ -match "([0-9]{6})"^)}^); >>"%PSScript%"
ECHO $Folders ^| %% { >>"%PSScript%"
ECHO If^($_ -match "([0-9]{6})"^){ >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $oBase ^= ^(Split-Path -path $_.Fullname -leaf^); >>"%PSScript%"
ECHO $nBase ^= ^($oBase.Replace^($matches[1],$Today^)^); >>"%PSScript%"
ECHO Rename-Item "$root\$oBase" "$root\$nBase"; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem $Main ^| ^? {^($_.PSIsContainer^) -and ^($_ -match "([0-9]{6})"^)}^); >>"%PSScript%"
ECHO $Files ^= ^($Folders ^| %% {Get-ChildItem $_.FullName -Recurse -Include *.indd ^| ^? {^(!$_.PSIsContainer^) -and ^($_.Name -match "[0-9]{6}.*?([0-9]{6})"^)}}^);>>"%PSScript%"
ECHO $Files ^| %% { >>"%PSScript%"
ECHO If^($_.Name -match "[0-9]{6}.*?([0-9]{6})"^) >>"%PSScript%"
ECHO { >>"%PSScript%"
ECHO $x ^= $matches[1]; >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $nName ^= ^($_.Name.Replace^($x,$today^)^); >>"%PSScript%"
ECHO If^(!^(Test-Path "$root\$nName"^)^){Rename-Item $_.FullName "$root\$nName"}; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
GOTO :EOF

PowerShell (PS 2.0)



Easy Execute Note: Save this as a text file with a .ps1 extension to a folder such as G:\Folder\Archiver.ps1 and then from
the PowerShell command line put a dot, a single blank space, and then
the full script name and path enclosed by double quotes press
Enter.


enter image description here



$Main = "G:\Folder\__Archive";
$Today = (("{0:MMddyy}" -f (get-date).AddHours(0)).ToString());
$Folders = (Get-ChildItem $Main | ? {($_.PSIsContainer) -and ($_ -match "([0-9]{6})")});
$Folders | % {
If($_ -match "([0-9]{6})"){
$root = (Split-Path -path $_.Fullname);
$oBase = (Split-Path -path $_.Fullname -leaf);
$nBase = ($oBase.Replace($matches[1],$Today));
Rename-Item "$root\$oBase" "$root\$nBase";
}
};
$Folders = (Get-ChildItem $Main | ? {($_.PSIsContainer) -and ($_ -match "([0-9]{6})")});
$Files = ($Folders | % {Get-ChildItem $_.FullName -Recurse | ? {(!$_.PSIsContainer) -and ($_.Name -match "[0-9]{6}.*?([0-9]{6})")}});
$Files | % {
If($_.Name -match "[0-9]{6}.*?([0-9]{6})")
{
$x = $matches[1];
$root = (Split-Path -path $_.Fullname);
$nName = ($_.Name.Replace($x,$today));
If(!(Test-Path "$root\$nName")){Rename-Item $_.FullName "$root\$nName"};
}
};



Further Resources


No comments:

Post a Comment

linux - How to SSH to ec2 instance in VPC private subnet via NAT server

I have created a VPC in aws with a public subnet and a private subnet. The private subnet does not have direct access to external network. S...