Tentando usar o powershell para apagar seletivamente arquivos de backup antigos

3

Estou trabalhando com uma unidade com milhares de arquivos de backup, muitos dos quais são apenas espaços confusos.

O programa que nossos funcionários usam cria um backup de uma planilha toda vez que eles abrem um para edição. Cada backup é um novo arquivo chamado de acordo com a planilha + a data + a hora. Temos um diretório de backup separado para cada um de nossos clientes, e cada diretório tem várias planilhas e vários backups de cada planilha.

No final, temos uma estrutura de arquivos com arquivos como este:

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

Precisamos apenas manter os dois backups mais recentes de qualquer folha em particular. Dos 8 arquivos listados aqui, eu gostaria de manter 6. A data e a hora no nome do arquivo não são importantes, já que posso usar a data e a hora das informações do arquivo. Mas os nomes de arquivos não podem acabar alterados.

Eu brinquei com o powershell, e eu já usei o gci para movê-los para um local de arquivo próprio. Eu também posso retirar as seqüências de data e hora dos nomes dos arquivos. Eu também encontrei um script powershell para remover todos, mas os 2 arquivos mais recentes de um diretório específico. Mas eu não sei como deletar seletivamente o que eu quero.

Até agora, escrevi / modifiquei o seguinte código:

$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

Isso me fornece uma lista das planilhas individuais. Mas eles não sabem como trabalhar a partir dessa lista para voltar à lista original e remover todos os últimos backups de cada planilha, exceto os dois últimos.

Idealmente, eu gostaria de colocar o parâmetro -Recurse de volta na chamada gci e fazer com que ele passe por uma estrutura de diretórios complexa para eliminar backups mais antigos em todos os diretórios.

    
por Brian 25.11.2015 / 22:35

1 resposta

0

Isso removerá todos os arquivos com base na "chave" de cada pasta da empresa, exceto dois mais novos A filtragem é baseada em LastWriteTimeUTC

Nesse código, a função $local:allFiles = @{}; in Filter-BackupFiles é um valor-chave hastable, onde THE KEY faz parte do nome do arquivo antes de 12345_12345.bas (a seleção fileKey no RegEx, no meu exemplo, é tudo antes último símbolo _ ) ans O VALOR é uma matriz de objetos de arquivo (não nomes de arquivo). Para cada arquivo eu adiciono (usando Add-Member ) um atributo para soring (no meu caso é LastWriteTimeUTC , você pode fazer outra coisa no seu caso)

Em seguida, para cada chave (que é prefixo do nome do arquivo), classifico a lista de objetos de arquivo e adiciono à lista de remoção todos, exceto dois ( $Script:KeepMostRecent = 2 ) primeiros arquivos (isso significa dois arquivos mais novos, porque foram ordenados por data).

$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

Então a saída será

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
    
por 28.02.2016 / 09:05

Tags