我正在使用数以千计的备份文件,其中许多只是混乱的空间。
我们的员工使用的程序会在每次打开电子表格时创build电子表格的备份以进行编辑。 每个备份都是根据电子表格+date+时间命名的新文件。 我们为每个客户提供一个单独的备份目录,每个目录都有多个电子表格和每个电子表格的多个备份。
最后,我们有一个文件结构充满了这样的文件:
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.文件名中的date和时间是不重要的,因为我可以使用文件信息中的date和时间。 但文件名不能最终改变。
我曾经用powershell玩过一些,我已经用gci把它们移动到自己的文件位置。 我也可以从文件名中去除date和时间string。 我还发现了一个PowerShell脚本来从一个特定的目录中除去2个最新的文件。 但是我对如何有select地删除我想要的东西感到茫然。
到目前为止,我已经写/修改了下面的代码:
$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调用中,让它通过一个复杂的目录结构来清除每个目录中较旧的备份。
这将删除基于每个公司文件夹的“钥匙”的每个文件,除了两个最新的一个基于LastWriteTimeUTC
在这个代码中, $local:allFiles = @{}; 在Filter-BackupFiles函数中是一个key-value hastable,其中的KEY是12345_12345.bas (在RegEx中名为select的fileKey ,在我的例子中它是前一个_符号之前的所有东西)之前的一部分文件名ans VALUE是文件对象数组不是文件名)。 对于每个文件,我添加(使用Add-Member )的一个属性为soring(在我的情况下它是LastWriteTimeUTC ,你可以在你的情况下做一些其他的事情)
然后为每个键(这是文件名前缀)sorting文件对象的列表,并添加到删除列表除了两个( $Script:KeepMostRecent = 2 )第一个文件(这意味着两个最新的文件,因为它们按date下降sorting)除去列表。
$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