根据日期撤销TFS签出
param(
[datetime] $TargetDate = ([datetime]"2025-09-15"),
[switch] $DoIt = $false,
[string] $TfExePath = "tf",
[string] $Root = ".",
[string[]] $ExcludeExtensions = @(".csproj") # 可传入多个,例如: -ExcludeExtensions ".csproj",".vbproj"
)
$target = $TargetDate.Date
Write-Host "Root: $Root"
Write-Host "TargetDate: $target"
Write-Host "Dry-run: $(-not $DoIt)"
Write-Host "TfExePath: $TfExePath"
Write-Host "Exclude extensions: $($ExcludeExtensions -join ', ')"
Write-Host ""
try {
$items = Get-ChildItem -Path $Root -Recurse -File -ErrorAction Stop
} catch {
Write-Error "Scan failed: $_"
exit 1
}
# 过滤:按 LastWriteTime 且排除指定扩展(不区分大小写)
$excludeSet = $ExcludeExtensions | ForEach-Object { $_.ToLowerInvariant() }
$matched = $items |
Where-Object {
($_.LastWriteTime.Date -eq $target) -and
(-not ($excludeSet -contains ($_.Extension.ToLowerInvariant())))
} |
Select-Object -ExpandProperty FullName
if (-not $matched -or $matched.Count -eq 0) {
Write-Host "No files found with LastWriteTime = $target (after excluding extensions)." -ForegroundColor Yellow
exit 0
}
Write-Host "Found $($matched.Count) files. Sample:" -ForegroundColor Green
$matched | Select-Object -First 20 | ForEach-Object { Write-Host $_ }
if (-not $DoIt) {
Write-Host ""
Write-Host "Dry-run mode. To execute undo, re-run with -DoIt." -ForegroundColor Yellow
Write-Host "Example (dry-run):"
Write-Host " powershell -ExecutionPolicy Bypass -File .\scripts\undo-by-lastwritetime.ps1 -TargetDate 2025-09-15 -Root .."
Write-Host "Example (execute):"
Write-Host " powershell -ExecutionPolicy Bypass -File .\scripts\undo-by-lastwritetime.ps1 -TargetDate 2025-09-15 -Root .. -DoIt"
Write-Host "如果要排除更多扩展: -ExcludeExtensions \".csproj\",\".vbproj\""
exit 0
}
# 验证 tf.exe 可用
try {
Get-Command $TfExePath -ErrorAction Stop | Out-Null
} catch {
Write-Error "tf.exe not found. Run in Developer Command Prompt for VS or provide -TfExePath."
exit 1
}
$counts = @{Undone = 0; NoPending = 0; Failed = 0}
foreach ($f in $matched) {
Write-Host "Undoing: $f" -NoNewline
try {
$out = & $TfExePath undo "$f" /noprompt 2>&1
if ($LASTEXITCODE -eq 0 -and ($out -match "Undo" -or $out -match "undo successful" -or $out -match "Undoed")) {
Write-Host " -> Undone" -ForegroundColor Green
$counts.Undone++
} elseif ($out -match "No pending changes" -or $out -match "no pending changes" -or $out -match "No changes found") {
Write-Host " -> No pending changes" -ForegroundColor Yellow
$counts.NoPending++
} else {
Write-Host " -> Result: $out" -ForegroundColor Cyan
$counts.Failed++
}
} catch {
Write-Host " -> Failed: $_" -ForegroundColor Red
$counts.Failed++
}
}
Write-Host ""
Write-Host ("Summary: Undone: {0}`nNoPending: {1}`nFailed: {2}" -f $counts.Undone, $counts.NoPending, $counts.Failed)