PowerShell多轮迭代中Remove-Item失效:路径无效错误排查
问题:PowerShell备份脚本迭代删除远程文件时出现无效路径错误
执行数据库表备份任务,将生成的.bak文件复制至远程服务器并仅保留同表最新备份。首次迭代一切正常,但从第二次迭代开始,执行Remove-Item -LiteralPath $fileToRemove -Force时触发「Invalid Path」错误,错误路径示例为\remoteServer\BACKUP\BACKUP\database\table2_20230911_160158.bak(路径开头缺少双反斜杠)。
问题根源
- 数组定义错误:
$ServerInstances中"database"对应的数组是@("table1,table2"),这是一个包含单个字符串元素的数组,而非两个独立的表名。循环时会把"table1,table2"当作一个整体处理,导致后续路径匹配、文件操作全部异常。 - 远程路径格式问题:
$RemoteBackupDir使用了PowerShell提供程序前缀Microsoft.PowerShell.Core\FileSystem::,拼接子路径时可能引发路径解析异常。 - 旧文件删除逻辑冗余:通过索引遍历删除文件的方式易出错,可直接通过排序后选择要删除的文件批量处理。
修复后的代码
# Set variables $BackupDir = "D:\Backup\Backup_Job" # 移除PowerShell提供程序前缀,直接使用UNC路径 $RemoteBackupDir = "\\remoteServer\BACKUP\BACKUP" $Timestamp = Get-Date -Format "yyyyMMdd_HHmmss" # 修正数组定义:每个表名作为独立元素 $ServerInstances = @{ "database" = @("table1", "table2") } $LogPath = "D:\Backup\Logs.txt" "BackupStarted - $Timestamp" | Out-File -Append -FilePath $LogPath if (!(Test-Path $BackupDir)) { New-Item -ItemType Directory -Path $BackupDir } try { foreach($databaseName in $ServerInstances.Keys) { $backupFolder = Join-Path -Path $BackupDir -ChildPath $databaseName $remoteBackupFolder = Join-Path -Path $RemoteBackupDir -ChildPath $databaseName if (!(Test-Path $backupFolder)) { New-Item -ItemType Directory -Path $backupFolder } if (!(Test-Path $remoteBackupFolder)) { New-Item -ItemType Directory -Path $remoteBackupFolder } foreach($tableName in $ServerInstances.$databaseName) { # 查找当前表的所有备份文件 $filesToDelete = Get-ChildItem -Path $remoteBackupFolder -Filter "${tableName}*.bak" # 按创建时间升序排序,旧文件在前 $sortedFilesToDelete = $filesToDelete | Sort-Object CreationTime $numberOfCopiesToKeep = 1 # 直接选择需要删除的文件(排除最新的N份) $filesToRemove = $sortedFilesToDelete | Select-Object -First ($sortedFilesToDelete.Count - $numberOfCopiesToKeep) foreach($fileToRemove in $filesToRemove) { "$($fileToRemove.FullName)" | Out-File -Append -FilePath $LogPath Remove-Item -LiteralPath $fileToRemove.FullName -Force } $backupFilePath = Join-Path -Path $backupFolder -ChildPath "${tableName}_${Timestamp}.bak" $remoteFilePath = Join-Path -Path $remoteBackupFolder -ChildPath "${tableName}_${Timestamp}.bak" "$databaseName $tableName $backupFilePath" | Out-File -Append -FilePath $LogPath Backup-SqlDatabase -ServerInstance $databaseName -Database $tableName -BackupFile $backupFilePath Copy-Item -Path $backupFilePath -Destination $remoteFilePath -Force } } # 清理本地备份文件 Get-ChildItem -Path $BackupDir -Recurse | Remove-Item -Recurse -Force } catch { $line = $_.InvocationInfo.ScriptLineNumber "Error - $($_.Exception.Message) - Date- $Timestamp - Line- $line" | Out-File -Append -FilePath $LogPath } finally { # 确保本地备份文件被清理 if (Test-Path $BackupDir) { Get-ChildItem -Path $BackupDir -Recurse | Remove-Item -Recurse -Force } }
关键修改点
- 修正
$ServerInstances的数组定义,将表名拆分为独立元素:@("table1", "table2") - 移除
$RemoteBackupDir的PowerShell提供程序前缀,使用标准UNC路径 - 使用
Join-Path拼接路径,避免手动拼接字符串导致的格式错误 - 简化旧文件删除逻辑,直接通过
Select-Object -First筛选要删除的文件,避免索引遍历的潜在问题 - 优化本地文件清理逻辑,增加路径存在检查
内容的提问来源于stack exchange,提问作者salttoinjury
相关产品推荐
相关产品推荐

