常用Powershell脚本
视频缩略图广告清理
<#
.SYNOPSIS
清除视频文件内嵌的广告缩略图/封面图,递归处理指定文件夹
#>
#Requires -Version 5.1
param(
[string]$FolderPath = ""
)
# -------------------------- 配置项 --------------------------
$videoExtensions = @(".mp4", ".mkv", ".avi", ".mov", ".m4v", ".flv", ".wmv", ".webm", ".rmvb", ".ts")
$deleteSidecarImages = $true # 是否删除与视频同名的外部图片文件(广告封面)
$imageExtensions = @(".jpg", ".jpeg", ".png", ".bmp", ".webp")
$tempSuffix = "_clean_temp" # 临时文件后缀
# -----------------------------------------------------------
# 检查 ffmpeg 是否可用
function Test-FFmpeg {
try {
$null = ffmpeg -version 2>&1
return $true
}
catch {
return $false
}
}
# 主函数
function Invoke-VideoThumbnailCleaner {
param([string]$RootFolder)
if (-not (Test-Path -LiteralPath $RootFolder -PathType Container)) {
Write-Host "错误:文件夹不存在 - $RootFolder" -ForegroundColor Red
return
}
# 获取所有视频文件
Write-Host "`n正在扫描视频文件..." -ForegroundColor Cyan
$videoFiles = Get-ChildItem -LiteralPath $RootFolder -Recurse -File |
Where-Object { $videoExtensions -contains $_.Extension.ToLower() }
if ($videoFiles.Count -eq 0) {
Write-Host "未找到任何视频文件。" -ForegroundColor Yellow
return
}
Write-Host "找到 $($videoFiles.Count) 个视频文件,开始处理...`n" -ForegroundColor Green
$successCount = 0
$skipCount = 0
$failCount = 0
$deletedImageCount = 0
foreach ($file in $videoFiles) {
Write-Host "[$($successCount + $failCount + $skipCount + 1)/$($videoFiles.Count)] 处理: $($file.FullName)"
$tempPath = Join-Path $file.DirectoryName ($file.BaseName + $tempSuffix + $file.Extension)
try {
# ffmpeg 重新封装:只保留第1个视频流 + 所有音频 + 所有字幕,丢弃附加图片流
# -map 0:v:0 只取第一个视频流(主视频,排除缩略图附加流)
# -map 0:a? 保留所有音频流
# -map 0:s? 保留所有字幕流
# -c copy 直接复制流,不重新编码
$ffmpegArgs = @(
"-i", "`"$($file.FullName)`"",
"-map", "0:v:0",
"-map", "0:a?",
"-map", "0:s?",
"-c", "copy",
"-y",
"`"$tempPath`""
)
$process = Start-Process -FilePath "ffmpeg" -ArgumentList $ffmpegArgs `
-NoNewWindow -Wait -PassThru -RedirectStandardError "$env:TEMP\ffmpeg_err.log"
if ($process.ExitCode -eq 0 -and (Test-Path $tempPath)) {
# 替换原文件
Remove-Item -LiteralPath $file.FullName -Force
Move-Item -LiteralPath $tempPath -Destination $file.FullName -Force
$successCount++
Write-Host " ✓ 清理完成" -ForegroundColor Green
}
else {
$skipCount++
Write-Host " ⊘ 无需清理或处理失败,跳过" -ForegroundColor Yellow
if (Test-Path $tempPath) { Remove-Item $tempPath -Force -ErrorAction SilentlyContinue }
}
}
catch {
$failCount++
Write-Host " ✗ 处理出错: $($_.Exception.Message)" -ForegroundColor Red
if (Test-Path $tempPath) { Remove-Item $tempPath -Force -ErrorAction SilentlyContinue }
}
# 删除同名外部广告图片
if ($deleteSidecarImages) {
foreach ($imgExt in $imageExtensions) {
$sidecarImg = Join-Path $file.DirectoryName ($file.BaseName + $imgExt)
if (Test-Path -LiteralPath $sidecarImg -PathType Leaf) {
Remove-Item -LiteralPath $sidecarImg -Force
$deletedImageCount++
Write-Host " 🗑 删除外部图片: $($file.BaseName)$imgExt" -ForegroundColor DarkGray
}
}
}
}
# 输出统计
Write-Host "`n==================== 处理完成 ====================" -ForegroundColor Cyan
Write-Host "总视频数: $($videoFiles.Count)"
Write-Host "成功清理: $successCount" -ForegroundColor Green
Write-Host "跳过/无需清理: $skipCount" -ForegroundColor Yellow
Write-Host "处理失败: $failCount" -ForegroundColor Red
if ($deleteSidecarImages) {
Write-Host "删除外部图片: $deletedImageCount" -ForegroundColor DarkGray
}
Write-Host "==================================================" -ForegroundColor Cyan
}
# ====================== 主程序入口 ======================
Clear-Host
Write-Host "===== 视频缩略图广告清理工具 =====" -ForegroundColor Magenta
Write-Host "依赖: 系统需已安装 ffmpeg 并加入环境变量`n"
# 检查 ffmpeg
if (-not (Test-FFmpeg)) {
Write-Host "错误:未检测到 ffmpeg,请先安装 ffmpeg 并添加到系统 PATH 环境变量。" -ForegroundColor Red
Write-Host "下载地址: https://ffmpeg.org/download.html"
Read-Host "按回车键退出"
exit 1
}
Write-Host "✓ ffmpeg 检测正常`n" -ForegroundColor Green
# 获取文件夹路径
if ([string]::IsNullOrWhiteSpace($FolderPath)) {
$FolderPath = Read-Host "请输入要处理的视频文件夹路径"
}
# 去除路径两端引号
$FolderPath = $FolderPath.Trim('"', "'")
# 执行处理
Invoke-VideoThumbnailCleaner -RootFolder $FolderPath
Write-Host "`n按回车键退出..."
Read-Host | Out-NullHosts文件管理GUI
# 检查是否以管理员身份运行
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
# 不是管理员:启动一个新的管理员 PowerShell 窗口,并传递当前脚本路径
$scriptPath = $MyInvocation.MyCommand.Definition
Start-Process powershell -ArgumentList "-NoExit", "-ExecutionPolicy Bypass", "-File `"$scriptPath`"" -Verb RunAs
exit # 原进程退出
}
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# 定义hosts文件路径(需要管理员权限)
$hostsPath = "$env:SystemRoot\System32\drivers\etc\hosts"
# 检查hosts文件是否存在,如果不存在则创建
if (-not (Test-Path $hostsPath)) {
try {
# 创建空的hosts文件
Set-Content -Path $hostsPath -Value "# Hosts file created by Hosts Manager`n" -Encoding ASCII -Force
}
catch {
[System.Windows.Forms.MessageBox]::Show("无法创建hosts文件。请以管理员身份运行此程序。", "权限错误", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
}
# 默认host组 - 可以随时在此添加或修改组
$defaultHostGroups = @{
"图书发布" = @(
"100.95.23.67 book1.cikaros.local",
"100.95.23.67 book2.cikaros.local",
"100.95.23.67 book3.cikaros.local"
)
"Google" = @(
"142.250.184.196 www.google.com",
"142.250.184.196 google.com",
"142.250.184.196 www.google.com.hk"
)
"YouTube" = @(
"142.250.184.206 www.youtube.com",
"142.250.184.206 youtube.com"
)
"Facebook" = @(
"31.13.64.35 www.facebook.com",
"31.13.64.35 facebook.com"
)
"Twitter" = @(
"104.244.42.1 www.twitter.com",
"104.244.42.1 twitter.com"
)
"GitHub" = @(
"140.82.114.4 github.com",
"140.82.114.4 www.github.com",
"140.82.114.3 api.github.com"
)
# 可以随时在这里添加新组
"Microsoft" = @(
"13.107.246.40 www.microsoft.com",
"13.107.246.40 microsoft.com"
)
}
# 创建主窗口
$form = New-Object System.Windows.Forms.Form
$form.Text = "Hosts文件管理器"
$form.Size = New-Object System.Drawing.Size(950, 750)
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Sizable
$form.Font = New-Object System.Drawing.Font("Microsoft YaHei", 9)
$form.MinimumSize = New-Object System.Drawing.Size(800, 600)
# 创建主布局容器
$mainTable = New-Object System.Windows.Forms.TableLayoutPanel
$mainTable.Dock = [System.Windows.Forms.DockStyle]::Fill
$mainTable.ColumnCount = 1
$mainTable.RowCount = 4
$mainTable.Padding = New-Object System.Windows.Forms.Padding(10)
$mainTable.CellBorderStyle = [System.Windows.Forms.TableLayoutPanelCellBorderStyle]::None
# 1. 列表视图 (占70%高度)
$hostsList = New-Object System.Windows.Forms.ListView
$hostsList.View = [System.Windows.Forms.View]::Details
$hostsList.FullRowSelect = $true
$hostsList.GridLines = $true
$hostsList.Dock = [System.Windows.Forms.DockStyle]::Fill
$hostsList.MultiSelect = $true
$hostsList.HeaderStyle = [System.Windows.Forms.ColumnHeaderStyle]::Nonclickable
# $hostsList.DoubleBuffered = $true # 减少闪烁
# 添加列 - 关键修正:确保列定义正确
$ipColumn = New-Object System.Windows.Forms.ColumnHeader
$ipColumn.Text = "IP地址"
$ipColumn.Width = 200
$ipColumn.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Left
$domainColumn = New-Object System.Windows.Forms.ColumnHeader
$domainColumn.Text = "域名"
$domainColumn.Width = 650
$domainColumn.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Left
$hostsList.Columns.Add($ipColumn) | Out-Null
$hostsList.Columns.Add($domainColumn) | Out-Null
# 2. 操作按钮行 (占10%高度)
$buttonPanel1 = New-Object System.Windows.Forms.FlowLayoutPanel
$buttonPanel1.Dock = [System.Windows.Forms.DockStyle]::Fill
$buttonPanel1.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight
$buttonPanel1.WrapContents = $false
$buttonPanel1.Padding = New-Object System.Windows.Forms.Padding(0, 5, 0, 5)
$buttonPanel1.AutoSize = $true
$addButton = New-Object System.Windows.Forms.Button
$addButton.Text = "添加新记录"
$addButton.Size = New-Object System.Drawing.Size(120, 35)
$addButton.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$buttonPanel1.Controls.Add($addButton)
$removeButton = New-Object System.Windows.Forms.Button
$removeButton.Text = "删除选中记录"
$removeButton.Size = New-Object System.Drawing.Size(120, 35)
$removeButton.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$buttonPanel1.Controls.Add($removeButton)
# 3. 默认组区域 (占10%高度)
$groupPanel = New-Object System.Windows.Forms.FlowLayoutPanel
$groupPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
$groupPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight
$groupPanel.WrapContents = $false
$groupPanel.Padding = New-Object System.Windows.Forms.Padding(0, 5, 0, 5)
$groupPanel.AutoSize = $true
$defaultGroupLabel = New-Object System.Windows.Forms.Label
$defaultGroupLabel.Text = "快速应用默认组:"
$defaultGroupLabel.Size = New-Object System.Drawing.Size(120, 25)
$defaultGroupLabel.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$defaultGroupLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
$groupPanel.Controls.Add($defaultGroupLabel)
$defaultGroupCombo = New-Object System.Windows.Forms.ComboBox
$defaultGroupCombo.Size = New-Object System.Drawing.Size(150, 25)
$defaultGroupCombo.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$defaultGroupCombo.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList
# 关键修改:自动从$defaultHostGroups获取组名
$groupNames = $defaultHostGroups.Keys | Sort-Object # 按字母顺序排序
if ($groupNames.Count -gt 0) {
$defaultGroupCombo.Items.AddRange($groupNames)
$defaultGroupCombo.SelectedIndex = 0 # 默认选择第一个组
}
else {
$defaultGroupCombo.Items.Add("无可用组")
$defaultGroupCombo.SelectedIndex = 0
}
$groupPanel.Controls.Add($defaultGroupCombo)
$applyButton = New-Object System.Windows.Forms.Button
$applyButton.Text = "应用所选组"
$applyButton.Size = New-Object System.Drawing.Size(120, 35)
$applyButton.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$groupPanel.Controls.Add($applyButton)
# 4. 保存/退出按钮行 (占10%高度)
$buttonPanel2 = New-Object System.Windows.Forms.FlowLayoutPanel
$buttonPanel2.Dock = [System.Windows.Forms.DockStyle]::Fill
$buttonPanel2.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft
$buttonPanel2.WrapContents = $false
$buttonPanel2.Padding = New-Object System.Windows.Forms.Padding(0, 5, 0, 5)
$buttonPanel2.AutoSize = $true
$saveButton = New-Object System.Windows.Forms.Button
$saveButton.Text = "保存更改"
$saveButton.Size = New-Object System.Drawing.Size(120, 35)
$saveButton.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$buttonPanel2.Controls.Add($saveButton)
$exitButton = New-Object System.Windows.Forms.Button
$exitButton.Text = "退出"
$exitButton.Size = New-Object System.Drawing.Size(120, 35)
$exitButton.Margin = New-Object System.Windows.Forms.Padding(5, 0, 5, 0)
$buttonPanel2.Controls.Add($exitButton)
# 添加所有控件到主布局
$mainTable.Controls.Add($hostsList, 0, 0)
$mainTable.Controls.Add($buttonPanel1, 0, 1)
$mainTable.Controls.Add($groupPanel, 0, 2)
$mainTable.Controls.Add($buttonPanel2, 0, 3)
# 设置行高比例
$mainTable.RowStyles.Clear()
$mainTable.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 70)))
$mainTable.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 10)))
$mainTable.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 10)))
$mainTable.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 10)))
# 添加主布局到窗体
$form.Controls.Add($mainTable)
# 关键修正:正确加载hosts文件
function Load-HostsFile {
$hostsList.Items.Clear()
try {
$content = Get-Content $hostsPath
foreach ($line in $content) {
$trimmedLine = $line.Trim()
# 跳过注释行和空行
if ($trimmedLine -eq "" -or $trimmedLine.StartsWith("#")) {
continue
}
# 使用正则表达式分割IP和域名
# 先尝试按制表符分割
$tabSplit = $trimmedLine -split "`t+", 2
if ($tabSplit.Count -ge 2) {
$ip = $tabSplit[0].Trim()
$domain = $tabSplit[1].Trim()
}
else {
# 按多个空格分割
$spaceSplit = $trimmedLine -split "\s+", 2
if ($spaceSplit.Count -ge 2) {
$ip = $spaceSplit[0].Trim()
$domain = $spaceSplit[1].Trim()
}
else {
# 如果无法正确分割,使用整个行作为IP
$ip = $trimmedLine
$domain = ""
}
}
# 只添加有效的记录
if ($ip -ne "" -and $ip -match "^(\d{1,3}\.){3}\d{1,3}$") {
$item = New-Object System.Windows.Forms.ListViewItem($ip)
# 关键修正:正确添加子项作为第二列
$item.SubItems.Add($domain) | Out-Null
$hostsList.Items.Add($item) | Out-Null
}
}
# 状态反馈
if ($hostsList.Items.Count -eq 0) {
# 添加示例项以显示格式
$item = New-Object System.Windows.Forms.ListViewItem("127.0.0.1")
$item.SubItems.Add("localhost") | Out-Null
$item.ForeColor = [System.Drawing.Color]::Gray
$hostsList.Items.Add($item) | Out-Null
$item = New-Object System.Windows.Forms.ListViewItem("127.0.0.1")
$item.SubItems.Add("example.com") | Out-Null
$item.ForeColor = [System.Drawing.Color]::Gray
$hostsList.Items.Add($item) | Out-Null
}
}
catch {
[System.Windows.Forms.MessageBox]::Show("无法读取hosts文件: $_`n请确保以管理员身份运行此程序。", "错误", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
}
}
# 应用默认组
$applyButton.Add_Click({
$selectedGroup = $defaultGroupCombo.SelectedItem
$groupEntries = $defaultHostGroups[$selectedGroup]
$added = 0
$existing = 0
foreach ($entry in $groupEntries) {
$parts = $entry -split "\s+", 2
if ($parts.Count -ge 2) {
$ip = $parts[0].Trim()
$domain = $parts[1].Trim()
# 检查是否已存在
$exists = $false
foreach ($item in $hostsList.Items) {
# 关键修正:正确检查子项
if ($item.Text -eq $ip -and $item.SubItems[1].Text -eq $domain) {
$exists = $true
break
}
}
if (-not $exists) {
$item = New-Object System.Windows.Forms.ListViewItem($ip)
$item.SubItems.Add($domain) | Out-Null
$hostsList.Items.Add($item) | Out-Null
$added++
}
else {
$existing++
}
}
}
if ($added -gt 0 -or $existing -gt 0) {
$message = ""
if ($added -gt 0) {
$message += "$added 条新记录已添加。`n"
}
if ($existing -gt 0) {
$message += "$existing 条记录已存在,未重复添加。"
}
[System.Windows.Forms.MessageBox]::Show($message, "操作完成", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
}
else {
[System.Windows.Forms.MessageBox]::Show("未添加任何新记录。", "提示", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
}
})
# 添加新记录
$addButton.Add_Click({
$newRecordForm = New-Object System.Windows.Forms.Form
$newRecordForm.Text = "添加新记录"
$newRecordForm.Size = New-Object System.Drawing.Size(500, 200)
$newRecordForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$newRecordForm.Font = $form.Font
$newRecordForm.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog
$newRecordForm.MaximizeBox = $false
$newRecordForm.MinimizeBox = $false
$newRecordForm.ShowIcon = $false
$tableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
$tableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.ColumnCount = 2
$tableLayoutPanel.RowCount = 3
$tableLayoutPanel.Padding = New-Object System.Windows.Forms.Padding(20, 15, 20, 15)
$tableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 80)))
$tableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100)))
$tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 30)))
$tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 30)))
$tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 40)))
$ipLabel = New-Object System.Windows.Forms.Label
$ipLabel.Text = "IP地址:"
$ipLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
$ipLabel.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.Controls.Add($ipLabel, 0, 0)
$ipBox = New-Object System.Windows.Forms.TextBox
$ipBox.Dock = [System.Windows.Forms.DockStyle]::Fill
$ipBox.Text = "127.0.0.1"
$tableLayoutPanel.Controls.Add($ipBox, 1, 0)
$domainLabel = New-Object System.Windows.Forms.Label
$domainLabel.Text = "域名:"
$domainLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
$domainLabel.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.Controls.Add($domainLabel, 0, 1)
$domainBox = New-Object System.Windows.Forms.TextBox
$domainBox.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.Controls.Add($domainBox, 1, 1)
$buttonFlow = New-Object System.Windows.Forms.FlowLayoutPanel
$buttonFlow.Dock = [System.Windows.Forms.DockStyle]::Fill
$buttonFlow.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft
$okButton = New-Object System.Windows.Forms.Button
$okButton.Text = "确定"
$okButton.Size = New-Object System.Drawing.Size(80, 30)
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$okButton.Enabled = $false
$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Text = "取消"
$cancelButton.Size = New-Object System.Drawing.Size(80, 30)
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
# 验证输入
$validateInput = {
$ip = $ipBox.Text.Trim()
$domain = $domainBox.Text.Trim()
$okButton.Enabled = ($ip -ne "" -and $domain -ne "" -and $ip -match "^(\d{1,3}\.){3}\d{1,3}$")
}
$ipBox.Add_TextChanged($validateInput)
$domainBox.Add_TextChanged($validateInput)
$buttonFlow.Controls.Add($okButton)
$buttonFlow.Controls.Add($cancelButton)
$tableLayoutPanel.Controls.Add($buttonFlow, 1, 2)
$newRecordForm.Controls.Add($tableLayoutPanel)
$newRecordForm.AcceptButton = $okButton
$newRecordForm.CancelButton = $cancelButton
$dialogResult = $newRecordForm.ShowDialog()
if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK) {
$ip = $ipBox.Text.Trim()
$domain = $domainBox.Text.Trim()
# 检查是否已存在
$exists = $false
foreach ($item in $hostsList.Items) {
if ($item.Text -eq $ip -and $item.SubItems[1].Text -eq $domain) {
$exists = $true
break
}
}
if (-not $exists) {
$item = New-Object System.Windows.Forms.ListViewItem($ip)
$item.SubItems.Add($domain) | Out-Null
$hostsList.Items.Add($item) | Out-Null
}
else {
[System.Windows.Forms.MessageBox]::Show("该记录已存在", "重复记录", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Warning)
}
}
})
# 删除选中记录
$removeButton.Add_Click({
if ($hostsList.SelectedItems.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("请先选择要删除的记录。", "提示", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
return
}
$count = $hostsList.SelectedItems.Count
$result = [System.Windows.Forms.MessageBox]::Show("确定要删除选中的 $count 条记录吗?", "确认删除", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Warning)
if ($result -eq [System.Windows.Forms.DialogResult]::Yes) {
# 创建副本避免在迭代时修改集合
$itemsToRemove = New-Object System.Collections.ArrayList
foreach ($item in $hostsList.SelectedItems) {
$null = $itemsToRemove.Add($item)
}
foreach ($item in $itemsToRemove) {
$hostsList.Items.Remove($item)
}
[System.Windows.Forms.MessageBox]::Show("$($itemsToRemove.Count) 条记录已删除。", "删除成功", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
}
})
# 保存更改
$saveButton.Add_Click({
try {
# 创建备份
$backupPath = "$hostsPath.bak_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Copy-Item $hostsPath $backupPath -Force
# 准备新内容
$newContent = @()
$newContent += "# Hosts file managed by Hosts Manager"
$newContent += "# Last updated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$newContent += ""
# 添加所有记录
foreach ($item in $hostsList.Items) {
# 跳过示例项(灰色文本)
if ($item.ForeColor -eq [System.Drawing.Color]::Gray) {
continue
}
# 关键修正:正确获取子项
$ip = $item.Text
$domain = $item.SubItems[1].Text
if ($ip -match "^(\d{1,3}\.){3}\d{1,3}$" -and $domain -ne "") {
$newContent += "$ip`t$domain"
}
}
# 保存文件
$newContent | Set-Content $hostsPath -Encoding ASCII -Force
[System.Windows.Forms.MessageBox]::Show("hosts文件已成功保存!`n备份已创建: $backupPath", "保存成功", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
}
catch {
[System.Windows.Forms.MessageBox]::Show("保存hosts文件时出错: $_`n请确保以管理员身份运行此程序。", "错误", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
# 尝试恢复备份
if (Test-Path $backupPath) {
try {
Copy-Item $backupPath $hostsPath -Force
[System.Windows.Forms.MessageBox]::Show("已自动恢复备份文件。", "恢复成功", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
}
catch {
[System.Windows.Forms.MessageBox]::Show("无法恢复备份: $_", "恢复失败", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
}
}
}
})
# 退出应用
$exitButton.Add_Click({
$dialogResult = [System.Windows.Forms.MessageBox]::Show("是否要退出程序?", "确认退出", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Question)
if ($dialogResult -eq [System.Windows.Forms.DialogResult]::Yes) {
$form.Close()
}
})
# 添加双击编辑功能
$hostsList.Add_MouseDoubleClick({
param($sender, $e)
if ($hostsList.SelectedItems.Count -eq 0) {
return
}
$selectedItem = $hostsList.SelectedItems[0]
$originalIp = $selectedItem.Text
$originalDomain = $selectedItem.SubItems[1].Text
# 跳过示例项(灰色文本)
if ($selectedItem.ForeColor -eq [System.Drawing.Color]::Gray) {
[System.Windows.Forms.MessageBox]::Show("这是示例记录,不能编辑。", "提示", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
return
}
$editForm = New-Object System.Windows.Forms.Form
$editForm.Text = "编辑记录"
$editForm.Size = New-Object System.Drawing.Size(500, 200)
$editForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$editForm.Font = $form.Font
$editForm.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog
$editForm.MaximizeBox = $false
$editForm.MinimizeBox = $false
$editForm.ShowIcon = $false
$tableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
$tableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.ColumnCount = 2
$tableLayoutPanel.RowCount = 3
$tableLayoutPanel.Padding = New-Object System.Windows.Forms.Padding(20, 15, 20, 15)
$tableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 80)))
$tableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100)))
$tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 30)))
$tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 30)))
$tableLayoutPanel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 40)))
$ipLabel = New-Object System.Windows.Forms.Label
$ipLabel.Text = "IP地址:"
$ipLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
$ipLabel.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.Controls.Add($ipLabel, 0, 0)
$ipBox = New-Object System.Windows.Forms.TextBox
$ipBox.Dock = [System.Windows.Forms.DockStyle]::Fill
$ipBox.Text = $originalIp
$tableLayoutPanel.Controls.Add($ipBox, 1, 0)
$domainLabel = New-Object System.Windows.Forms.Label
$domainLabel.Text = "域名:"
$domainLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
$domainLabel.Dock = [System.Windows.Forms.DockStyle]::Fill
$tableLayoutPanel.Controls.Add($domainLabel, 0, 1)
$domainBox = New-Object System.Windows.Forms.TextBox
$domainBox.Dock = [System.Windows.Forms.DockStyle]::Fill
$domainBox.Text = $originalDomain
$tableLayoutPanel.Controls.Add($domainBox, 1, 1)
$buttonFlow = New-Object System.Windows.Forms.FlowLayoutPanel
$buttonFlow.Dock = [System.Windows.Forms.DockStyle]::Fill
$buttonFlow.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft
$okButton = New-Object System.Windows.Forms.Button
$okButton.Text = "确定"
$okButton.Size = New-Object System.Drawing.Size(80, 30)
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$okButton.Enabled = $false
$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Text = "取消"
$cancelButton.Size = New-Object System.Drawing.Size(80, 30)
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
# 验证输入
$validateInput = {
$ip = $ipBox.Text.Trim()
$domain = $domainBox.Text.Trim()
$okButton.Enabled = ($ip -ne "" -and $domain -ne "" -and $ip -match "^(\d{1,3}\.){3}\d{1,3}$")
}
$ipBox.Add_TextChanged($validateInput)
$domainBox.Add_TextChanged($validateInput)
$buttonFlow.Controls.Add($okButton)
$buttonFlow.Controls.Add($cancelButton)
$tableLayoutPanel.Controls.Add($buttonFlow, 1, 2)
$editForm.Controls.Add($tableLayoutPanel)
$editForm.AcceptButton = $okButton
$editForm.CancelButton = $cancelButton
$dialogResult = $editForm.ShowDialog()
if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK) {
$ip = $ipBox.Text.Trim()
$domain = $domainBox.Text.Trim()
# 检查是否已存在(排除当前记录)
$exists = $false
foreach ($item in $hostsList.Items) {
if ($item -ne $selectedItem -and $item.Text -eq $ip -and $item.SubItems[1].Text -eq $domain) {
$exists = $true
break
}
}
if (-not $exists) {
$selectedItem.Text = $ip
$selectedItem.SubItems[1].Text = $domain
}
else {
[System.Windows.Forms.MessageBox]::Show("该记录已存在", "重复记录", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Warning)
}
}
})
# 初始加载hosts文件
Load-HostsFile
# 显示关于框
$form.Add_Shown({
[System.Windows.Forms.MessageBox]::Show("欢迎使用Hosts文件管理器!`n`n提示:`n• 双击记录可编辑`n• 请以管理员身份运行以保存更改`n• 每次保存会自动创建备份", "使用提示", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
$form.Activate()
})
# 显示窗口
[void]$form.ShowDialog()常用Powershell脚本
https://blog.cikaros.cn/archives/chang-yong-powershelljiao-ben