尝试使用 powershell 选择性地删除旧的备份文件

尝试使用 powershell 选择性地删除旧的备份文件

我正在使用一个有数千个备份文件的驱动器,其中许多文件只是占用了杂乱的空间。

我们员工使用的程序每次打开电子表格进行编辑时都会创建一个备份。每个备份都是一个新文件,其名称按照电子表格 + 日期 + 时间命名。我们为每个客户设置了一个单独的备份目录,每个目录都有多个电子表格,每个电子表格都有多个备份。

最后,我们得到一个包含如下文件的文件结构:

Companyx/backup/abssheet_091210_111006.bps    
Companyx/backup/abssheet_091210_133335.bps    
Companyx/backup/xyzsheet_091210_145223.bps    
Companyx/backup/xyzsheet_100803_100332.bps    
Companyx/backup/xyzsheet_100812_111244.bps
Companyy/backup/gnu_sheet_081029_110455.bps
Companyy/backup/gnu_sheet_081029_111233.bps
Companyy/backup/gnu_sheet_081029_112355.bps

我们只需要保留任何特定工作表的最近 2 个备份。在我在此处列出的 8 个文件中,我希望保留 6 个。文件名中的日期和时间并不重要,因为我可以使用文件信息中的日期和时间。但文件名最终无法更改。

我已经尝试过一些 powershell,并且已经使用 gci 将它们移动到它们自己的文件位置。我还可以从文件名中删除日期和时间字符串。我还找到了一个 powershell 脚本,用于从特定目录中删除除 2 个最新文件之外的所有文件。但我不知道如何有选择地删除我想要删除的内容。

到目前为止,我已经编写/修改了以下代码:

$newlist = New-Object System.Collections.Generic.List[System.String]
$fulllist = gci . | where {-not $_.PsIsContainer} | sort Name
$array = @()

foreach ($object in $fulllist)
{
    $string = $object.name
    $psworiginal = $string.Replace("_"+($string -split "_")[-1]," ")
    $psworiginal2 = $psworiginal.Replace("_"+($psworiginal -split "_")[-1]," ")
    $newlist.Add($psworiginal2)
}

$newlist = $newlist | select -unique

这给了我一份个人电子表格的列表。但我不确定如何从该列表返回原始列表并删除除每个电子表格的最新 2 个备份之外的所有内容。

理想情况下,我希望将 -Recurse 参数放回 gci 调用中,并让其通过复杂的目录结构来清除每个目录中的旧备份。

答案1

这将从每个公司文件夹中删除基于“密钥”的每个文件,但保留两个最新的文件。过滤基于LastWriteTimeUTC

在此代码中,$local:allFiles = @{};inFilter-BackupFiles函数是一个键值表,其中键是文件名之前的一部分12345_12345.basfileKeyRegEx 中的命名选择,在我的示例中,它是最后一个_符号之前的所有内容),值是文件对象数组(不是文件名)。对于每个文件,我添加(使用Add-Member)一个用于排序的属性(在我的情况下是LastWriteTimeUTC,您可以在您的例子中执行其他操作)

然后对于每个键(即文件名前缀),我对文件对象列表进行排序,并将除两个($Script:KeepMostRecent = 2)第一个文件之外的所有文件添加到删除列表中(这意味着两个最新的文件,因为它们按日期降序排序)。

$Script:StartPath = 'D:\Test_1'
$Script:KeepMostRecent = 2;
$Script:BackupSubfolder = 'backup'
$Script:RegexFilter = '^(?<fileKey>.*)_\d+_\d+\.bps$'
$Script:SimulatingMode = $true
#In my case regex is overriden because of file names
$Script:RegexFilter = '^(?<fileKey>.+)_[^_]+\.txt$' #THIS IS DEV OVERRIDE
Function Log-Error {
    Param (
        [Parameter(Mandatory=$true)]
        [String]$LogMessage
    )
    Write-Host -ForegroundColor Yellow "Error: $($LogMessage)";
}
#End of Log-Error

Function Get-Companies {
    Param (
        [Parameter(Mandatory=$true)]
        [String]$SearchBase
    )
    $local:companyDirectoies = @()
    try {
        $local:companyDirectoies = @(Get-ChildItem -Path $SearchBase -Recurse:$false -ErrorAction Stop | Where-Object {$_.psIsContainer -eq $true} -ErrorAction Stop | ForEach-Object {return $_.FullName} -ErrorAction Stop )
    } catch {
        Log-Error -LogMessage $([String]::Format("Error while getting companies list: {0}", $_.Exception.Message))
        return $null
    }
    return $local:companyDirectoies
}

Function Get-BackupFiles {
        Param (
        [Parameter(Mandatory=$true)]
        [String]$CompanyDirectoryPath
    )
    $local:files = @();
    try {
        $local:files = @( Get-ChildItem -Path $CompanyDirectoryPath -Recurse:$false -ErrorAction Stop | Where-Object {$_.psIsContainer -eq $false} -ErrorAction Stop)
    } catch {
        Log-Error -LogMessage $([String]::Format("Error while getting Backup file list for path {0}: {1}", $CompanyDirectoryPath ,$_.Exception.Message))
        return $null
    }
    return $local:files
}

Function Filter-BackupFiles {
    Param (
        [Parameter(Mandatory=$true)]
        [Object[]]$CompanyBackupFiles
    )
    $local:allFiles = @{};
    $local:filesToRemove = @()
    foreach ($local:f in $CompanyBackupFiles) {
        $local:lastFileDate = $local:f.LastWriteTimeUtc
        $local:f | Add-Member -MemberType NoteProperty -Name 'LastDate' -Value $( $local:lastFileDate ) 
        $local:fileName = $local:f.Name
        if ($local:fileName -match $Script:RegexFilter) {
            $local:fileKey = $Matches['fileKey']
            #Use NotCContains ir you need case-sensitive filtering
            if ($local:allFiles.Keys -notcontains $local:fileKey) {
                $local:allFiles[$local:fileKey] = @()
            }
            $local:allFiles[$local:fileKey] += @($local:f)
        } else {
            Log-Error -LogMessage $([String]::Format( "Error - the file name {0} does not match regEx. None will be processed for this list",$local:fileName))
            return $null
        }
    }
    foreach ($local:k in $local:allFiles.Keys) {
        Write-Host -ForegroundColor White "Checking files for key $($local:k)"
        $local:files = @( $local:allFiles[$local:k] | Sort-Object -Property 'LastDate' -Descending  )
        $local:filesToKeep = $Script:KeepMostRecent
        foreach ($local:f in $local:files) {
            $local:filesToKeep--
            Write-Host -ForegroundColor White -NoNewline "$($local:f.FullName)`t$($local:f.LastDate)"
            if ($local:filesToKeep -lt 0) {
                $local:filesToRemove += @($local:f.FullName)
                Write-Host -ForegroundColor Red "`tMARKED TO REMOVE"
            } else {
                Write-Host -ForegroundColor Green "`tMARKED TO LIVE"
            }
        }
    }
    return $local:filesToRemove
}

Function _main {
    $local:AllFilesToRemove = @()
    $local:companiesPathList = @(Get-Companies -SearchBase $Script:StartPath)
    if ($local:companiesPathList.Count -le 0) {
        Log-Error -LogMessage "Companies list is empty"
        return
    }
    forEach ($local:comanyPath in $local:companiesPathList) {
        Write-Host -ForegroundColor White "`r`n`r`nProcessing company on path $($local:comanyPath)"
        $local:companyBackupFolder = ""
        try {
            $local:companyBackupFolder = $( Join-Path -Path $local:comanyPath -ChildPath $Script:BackupSubfolder -ErrorAction Stop )
            $local:allCompanyFiles =  Get-BackupFiles -CompanyDirectoryPath $local:companyBackupFolder -ErrorAction Stop 
        } catch {
            Log-Error -LogMessage "Error getting backup files for company $($local:comanyPath) : $($_.Exception.Message)"
        }
        if (($local:allCompanyFiles.Count -le 0) -or ($local:allCompanyFiles -eq $null)) {
            Log-Error -LogMessage "Company $($local:companyBackupFolder) does not have files in backup. Will ignore it."
            continue
        }
        $local:companyFilesToRemove =  Filter-BackupFiles -CompanyBackupFiles $local:allCompanyFiles 
        if (($local:companyFilesToRemove.Count -le 0) -or ($local:companyFilesToRemove -eq $null)) {
            Write-Host -ForegroundColor Cyan "Company $($local:comanyPath) does not have files to remove. Will ignore it."
            continue
        }
        Write-Host -ForegroundColor White "Company $($local:comanyPath) have $($local:companyFilesToRemove.Count) file to remove"
        $local:AllFilesToRemove += @( $local:companyFilesToRemove )
    }
    Write-Host -ForegroundColor White "Totally we have $($local:AllFilesToRemove.Count) files to remove" 
    foreach ($local:f in $local:AllFilesToRemove) {
        Write-Host -ForegroundColor White "Removing $($local:f)"
        try {
            Remove-Item -Path $local:f -Force -Confirm:$false -WhatIf:$Script:SimulatingMode -ErrorAction Stop
        } catch {
            Log-Error -LogMessage "Error removing file $($local:f) : $($_.Exception.Message)"
        }
    }
}

_main

因此输出将是

Processing company on path D:\Test_1\Company1
Checking files for key File1_Custom_Name
D:\Test_1\Company1\backup\File1_Custom_Name_bak1.txt    02/28/2016 07:07:38 MARKED TO LIVE
D:\Test_1\Company1\backup\File1_Custom_Name_Bak2.txt    02/28/2016 07:06:38 MARKED TO LIVE
D:\Test_1\Company1\backup\File1_Custom_Name_Bak3.txt    02/28/2016 07:05:38 MARKED TO REMOVE
Checking files for key File2
D:\Test_1\Company1\backup\File2_Bak1.txt    02/28/2016 07:07:38 MARKED TO LIVE
D:\Test_1\Company1\backup\File2_Bak2.txt    02/28/2016 07:06:38 MARKED TO LIVE
D:\Test_1\Company1\backup\File2_Bak3.txt    02/28/2016 07:05:38 MARKED TO REMOVE
Company D:\Test_1\Company1 have 2 file to remove


Processing company on path D:\Test_1\Company2
Checking files for key File2
D:\Test_1\Company2\backup\File2_Bak3.txt    02/28/2016 07:58:34 MARKED TO LIVE
D:\Test_1\Company2\backup\File2_Bak2.txt    02/28/2016 07:58:31 MARKED TO LIVE
D:\Test_1\Company2\backup\File2_Bak1.txt    02/28/2016 07:58:28 MARKED TO REMOVE
Checking files for key File4
D:\Test_1\Company2\backup\File4_Bak1.txt    02/28/2016 07:59:43 MARKED TO LIVE
D:\Test_1\Company2\backup\File4_Bak3.txt    02/28/2016 07:58:42 MARKED TO LIVE
D:\Test_1\Company2\backup\File4_Bak2.txt    02/28/2016 07:58:39 MARKED TO REMOVE
Checking files for key File1
D:\Test_1\Company2\backup\File1_Bak3.txt    02/28/2016 07:58:25 MARKED TO LIVE
D:\Test_1\Company2\backup\File1_Bak2.txt    02/28/2016 07:58:22 MARKED TO LIVE
D:\Test_1\Company2\backup\File1_bak1.txt    02/28/2016 07:58:17 MARKED TO REMOVE
Company D:\Test_1\Company2 have 3 file to remove


Processing company on path D:\Test_1\Company3
Checking files for key File2
D:\Test_1\Company3\backup\File2_Bak1.txt    02/28/2016 07:07:38 MARKED TO LIVE
D:\Test_1\Company3\backup\File2_Bak2.txt    02/28/2016 07:06:38 MARKED TO LIVE
D:\Test_1\Company3\backup\File2_Bak3.txt    02/28/2016 07:05:38 MARKED TO REMOVE
Checking files for key File4
D:\Test_1\Company3\backup\File4_Bak1.txt    02/28/2016 07:07:38 MARKED TO LIVE
D:\Test_1\Company3\backup\File4_Bak2.txt    02/28/2016 07:06:38 MARKED TO LIVE
D:\Test_1\Company3\backup\File4_Bak3.txt    02/28/2016 07:05:38 MARKED TO REMOVE
Checking files for key File1
D:\Test_1\Company3\backup\File1_bak1.txt    02/28/2016 07:07:38 MARKED TO LIVE
D:\Test_1\Company3\backup\File1_Bak2.txt    02/28/2016 07:06:38 MARKED TO LIVE
D:\Test_1\Company3\backup\File1_Bak3.txt    02/28/2016 07:05:38 MARKED TO REMOVE
Company D:\Test_1\Company3 have 3 file to remove
Totally we have 8 files to remove
Removing D:\Test_1\Company1\backup\File1_Custom_Name_Bak3.txt
Removing D:\Test_1\Company1\backup\File2_Bak3.txt
Removing D:\Test_1\Company2\backup\File2_Bak1.txt
Removing D:\Test_1\Company2\backup\File4_Bak2.txt
Removing D:\Test_1\Company2\backup\File1_bak1.txt
Removing D:\Test_1\Company3\backup\File2_Bak3.txt
Removing D:\Test_1\Company3\backup\File4_Bak3.txt
Removing D:\Test_1\Company3\backup\File1_Bak3.txt

相关内容