web-dev-qa-db-ja.com

フォルダをアーカイブしてファイルの名前を変更するスクリプト

私の目標は、コピーを介してフォルダーを自動的にアーカイブし、元のフォルダーとその中のファイルの名前を現在の日付に変更してから、古い本番ファイルをクリーンアップするために使用できる.batを用意することです。

  1. ターゲットフォルダを "完了"ディレクトリにコピーします
  2. Previous Name_Today's Date(MMDDYY)の形式を使用してソースフォルダーの日付を更新します
  3. Current Name_Today's Date(MMDDYY)の形式を使用して、ソースフォルダー内のINDDファイルの日付を更新します。
  4. "クリーン"ソースフォルダ内のすべての.VPSおよび.PDFsファイルを削除してソースフォルダ

私は初心者ですが、調査と情報源からこのコードをまとめました。

@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

私の最終目標は、ソースフォルダーとアーカイブフォルダーのディレクトリパスを変更して、このスクリプトをさまざまなクライアントファイルで再利用できるようにすることです。


現在の問題

現状では、スクリプトはアーカイブフォルダファイルをコピーおよび作成せず、ターゲットフォルダだけでなくすべてのディレクトリからすべてのVPSおよびPDFファイルを削除します。

日付チェックを正しく実行して、それを変数として使用して、将来のフォルダーやファイルの名前を変更するかどうかはわかりません。

FOR /M *.indd /C "cmd /c rename @file \"@fname - today.indd\""がファイルの名前を変更するのに正しいかどうかわかりません。名前は、PO番号(6桁)、タイトル、アンダースコア、日付の順です。

たとえば、123456_Life_Kit_020819。


助けていただければ幸いです!


スクリプトが実行する必要があることの例を次に示します

enter image description here

WHOLEフォルダーをそれぞれの_OLD/Archiveフォルダーにコピーします。次に、フォルダとコンテンツ拡張子の名前を「現在の日付」に変更します。次に、新しい日付ディレクトリの.pdfファイルと.vpsファイルのみを削除します。

これはフォルダ構造の例です。

メインディレクトリ:

enter image description here

サブディレクトリの1つ内:

enter image description here

名前を変更しようとしているのは、日付(コピー後)のあるMAINディレクトリフォルダーと、サブディレクトリ内のファイルだけです。

他のフォルダの名前を変更する必要はありません。

2
Ovaryraptor

以下に、PowerShellを使用しているためハイブリッドのバッチスクリプトを含めましたが、動的にビルドして実行しますが、それに応じてdest=変数値ごとのアーカイブ先が使用されます。

Robocopy を使用したアプローチを使用して、宛先/アーカイブフォルダーから再帰的に削除するファイル拡張子の種類を除外しました。これにより、不必要にコピーされないため、削除する必要がなくなります。

たくさんのPowerShellコマンドレットなどを使用したので、それらをすべてリストするのではなく、その他のリソースセクションにいくつか追加しました。さらに理解したい場合は学習します。

バッチスクリプト

注:以下のスクリプトの上部にある相関変数(src=dest=、およびexcludedFiles=)ごとに、ソース、宛先、および除外ファイルを設定するだけです。次に、クリックして実行します。

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ロジック

注:これは、使用する場合のPowerShellのみですが、$Main =変数値をのアーカイブフォルダーパスの値に設定するだけです。実行時に現在の日付の文字で更新されるmmddyy文字列を含むフォルダーとファイル。

$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バージョン2.0互換ロジック

バッチ(PS 2.0)

注:以下のスクリプトの上部にある相関変数(src=dest=、およびexcludedFiles=)ごとに、ソース、宛先、および除外ファイルを設定するだけです。次に、クリックして実行します。

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注:これを.ps1拡張子の付いたテキストファイルとしてG:\Folder\Archiver.ps1などのフォルダーに保存し、PowerShellコマンドラインからドットを入力します。単一の空白スペース、次に二重引用符で囲まれた完全なスクリプト名とパスを押します 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"};                                                             
    }                                                                                                                              
};    

その他のリソース

3
Pimp Juice IT

私はあなたのためのPowerShellソリューションを持っています。

archiver.ps1archiver.bat、そしてシェルラインにそれを開始するように命令します。 PS1ファイルとBATファイルを同じフォルダー(選択した場所)に配置します。名前の変更は、アンダースコアと6桁の「_ ######」を目的としています。

BATファイルは4つのパラメータを取ります:

  1. 再帰検索のベースとなるルートフォルダ。

  2. 変更するファイル/フォルダ名のサブセクション例: "Annual_"

  3. 変更する2番目のファイル/フォルダー名サブセクション例: "Life_"

  4. 作成/追加するアーカイブフォルダの名前。例: "_ OLD"

ファイルArchiver.ps1:

Param(
     [Parameter(Position=0)] [string]$rootFolder = "C:\scripting\archiver"

     ,[Parameter(Position=1)] [string]$folderName1 = "ANNUAL_"

     ,[Parameter(Position=2)] [string]$folderName2 = "LIFE_"

     ,[Parameter(Position=3)] [string]$archiveFolder = "_OLD"
)
BEGIN
{

$today = get-date -UFormat %m%d%y

$folderName1 = "*"+$folderName1+"*"

$folderName2 = "*"+$folderName2+"*"

$startFolders = GCI -Path $rootFolder -Recurse -Include $folderName1, $folderName2 -Exclude $archiveFolder -Directory

pushd
foreach ($fold in $startFolders){
    cd $fold
    if(-not (Test-Path $archiveFolder)){md $archiveFolder | Out-Null}
    $theseFilez = gci -File
    if($theseFilez){
        foreach ($filez in $theseFilez){
            Copy-Item $filez $archiveFolder -Force
            if($filez -like "*.indd" -and $filez -notlike "*_$today*"){$filez | Rename-Item -NewName {$filez.Name -replace '[_]\d{6}',('_'+$today)}}
        }
    Remove-Item "*.pdf"
    Remove-Item "*.vps"
    }
    if($fold -notlike "*_$today*"){$fold | Rename-Item -NewName {$fold.Name -Replace '[_]\d{6}',('_'+$today)}}
}

popd

}

PROCESS{}
END{}

File Archiver.Bat(1行)

start powershell -File Archiver.ps1 -rootFolder "%1" -folderName1 "%2" -folderName2 "%3" -archiveFolder "%4"

コマンドシェルの呼び出し:

archiver c:\scripting\archiver LIFE_ ANNUAL_ _OLD

または、ダブルクリックして実行するバッチファイルの場合は、次のようにバッチファイルにパラメータを入力するだけです。

start powershell -File Archiver.ps1 -rootFolder "C:\scripting\archiver" -folderName1 "ANNUAL_" -folderName2 "LIFE_" -archiveFolder "_OLD"

2番目のgciコマンドで編集が「-Exclude $ archiveFolder」を「-File」に変更

編集2- 2つのファイル/フォルダー名を調整し、「ダブルクリック」して実行するバッチファイルも含めます。

SimonSの提案に従って、3つの交換された日/月/年を月/日/年に編集します。

1
Brian

私も(ついに)PowerShellソリューションを手に入れました。

PowerShellプロファイルを作成 そしてその中に関数を配置する必要があります。これで、PowerShellを起動するたびに使用できるようになります。

Param()ブロックの$Destinationパスを任意のバックアップ先パスに変更します。

関数の使用方法の例を次に示します。

# This will backup the specified path to the default destination specified in the function
Backup-Folder "C:\install\TestApp"

# You can also Backup multiple paths at once
Backup-Folder "C:\install\TestApp","D:\somepath\xy_020317"

# You can also overwrite the destination where the folder should be backed up to
Backup-Folder "C:\install\TestApp" -Destination "G:\MyNewFavoriteBackupLocation"

# You can also overwrite the setting for what Extensions to delete
Backup-Folder "C:\install\TestApp" -DeleteExtensions ".xlsx",".docx",".pdf"

# You can combine all of the above to be as flexible as you'd like
Backup-Folder "C:\install\TestApp","D:\somepath\xy_020317" -Destination "E:\xy" -DeleteExtensions ".ai"

ところで。私はあなたのコメントから、バッチ呼び出しが必要だと思います。この関数をPowerShellプロファイルに配置することで、次の行を使用して、好きな場所(デスクトップなど)に*.batファイルを作成できます。

powershell "Backup-Folder 'C:\foo\folder1', 'C:\bar\ANNUAL_323232', 'E:\somewhere'"

この関数は次のようになります。

  • フォルダ全体を$Destinationにバックアップします
  • フォルダ内の$DeleteExtensionsで指定された拡張子を持つすべてのファイルを削除します
  • フォルダとそのファイルの名前を変更する必要があるかどうかを確認します。変更しない場合は名前を変更しません
  • 日付が以前と同じでない場合は、フォルダとファイルの名前が新しい日付に変更されます
  • ファイルに日付がない場合は、追加されます

完全にコメント化された関数は次のとおりです。

function Backup-Folder {

    Param(
        [ValidateScript({ Test-Path $_ })]
        [string[]]$Path,
        [string]$Destination = "C:\install\_DONE",
        [string[]]$DeleteExtensions = @(".pdf",".vps")
    )

    # Creating Destination Directory if not already present
    mkdir $Destination -ErrorAction SilentlyContinue > $null

    # Getting the Date.
    $Date = (Get-Date).ToString("MMddyy")

    # Looping over each path
    foreach ($p in $path) {

        # Copy the whole folder to the destination
        Copy-Item $p $Destination -Recurse -Force

        # Get Folder Data
        $Folder = Get-Item $p 

        # Get Old and New Name
        $Folder.Name -match '\d{6}' > $null
        $Old = $Matches.GetEnumerator() | select -expand Value
        $New = if ($Old) { $Folder.Name -replace $Old,$Date } 
               else { "{0}_{1}" -f $Folder.Name,$Date }

        # if the Old Date is not the same as the new date Rename Folders and return them 
        # else return the original folder object
        $RenamedFolder = if ($Old -ne $Date) { Rename-Item $Folder -NewName $New -PassThru }
                         else { $Folder }

        # Get all Files in subfolder and loop over them
        # Add -Recurse after $RenamedFolder if you also want the script to go through 
        # all files of all subdirectories
        Get-ChildItem $RenamedFolder | ? { !$_.PsIsContainer } | foreach {

            # if the extension should be deleted, delete it
            if ($_.Extension -in $DeleteExtensions) {
                # Delete Item
                Remove-Item $_.FullName -Force
            }
            # else rename it.
            else {
                # Get Old and New Name
                $_.BaseName -match '\d{6}' > $null
                $OldName = $Matches.GetEnumerator() | select -expand Value
                $NewName = if ($OldName) { $_.Name -replace $OldName,$Date } 
                           else { "{0}_{1}{2}" -f $_.BaseName,$Date,$_.Extension }

                # Finally Rename Item if the Old Date is not the same as the new date
                if ($OldName -ne $Date) { Rename-Item $_.FullName -NewName $NewName }
            }
        }
    }
}

また、保持するファイル拡張子を指定できるロジックを含めることもできます。さらに、必要に応じて、削除するファイル拡張子を指定することもできます。

1
SimonS

logrotate を使用します

これがまさにその目的です。

設定ファイルlogrotate.conf

/tmp/mydir/* {
    daily
    dateext
    olddir /tmp/myarchive
}

次に、それを実行します。

touch /tmp/mydir/mylog1.txt /tmp/mydir/myotherlog2.txt
logrotate -vf ./logrotate.conf -s mystatus.logrotate

詳細モードでは、このようなものが表示されます。

reading config file ./logrotate.conf
olddir is now /tmp/myarchive
Reading state from file: mystatus.logrotate
Allocating hash table for state file, size 64 entries
Creating new state
Creating new state
Creating new state
Creating new state

Handling 1 logs

rotating pattern: /tmp/mydir/*  forced from command line (no old logs will be kept)
olddir is /tmp/myarchive, empty log files are rotated, old logs are removed
considering log /tmp/mydir/mylog1.txt
  Now: 2019-02-18 00:08
  Last rotated at 2019-02-18 00:00
  log needs rotating
considering log /tmp/mydir/myotherlog2.txt
  Now: 2019-02-18 00:08
  Last rotated at 2019-02-18 00:00
  log needs rotating
rotating log /tmp/mydir/mylog1.txt, log->rotateCount is 0
dateext suffix '-20190218'
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
renaming /tmp/mydir/mylog1.txt to /tmp/myarchive/mylog1.txt-20190218
disposeName will be /tmp/myarchive/mylog1.txt-20190218
removing old log /tmp/myarchive/mylog1.txt-20190218
rotating log /tmp/mydir/myotherlog2.txt, log->rotateCount is 0
dateext suffix '-20190218'
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
renaming /tmp/mydir/myotherlog2.txt to /tmp/myarchive/myotherlog2.txt-20190218
disposeName will be /tmp/myarchive/myotherlog2.txt-20190218
removing old log /tmp/myarchive/myotherlog2.txt-20190218

logrotateはすでにすべてのLinuxシステムにあります。すでにシステムで実行されている可能性があり(/etc/logrotate.confまたは/etc/logrotate.conf.d/を参照)、Logwot8を使用してWindowsにインストールできます。

0
Evan Carroll