本文目录导读:

我来介绍几种编写自动安装补丁脚本的方法,根据不同的操作系统和使用场景:
Windows PowerShell 补丁安装脚本
基础版本
# patch_installer.ps1
# 配置参数
$PatchPath = "C:\Patches" # 补丁存放路径
$LogFile = "C:\Logs\patch_install.log"
$PatchExtension = "*.msu" # Windows补丁文件类型
# 创建日志函数
function Write-Log {
param($Message)
$TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$TimeStamp - $Message" | Out-File -FilePath $LogFile -Append
Write-Host "$TimeStamp - $Message"
}
# 创建日志目录
if (!(Test-Path (Split-Path $LogFile))) {
New-Item -Path (Split-Path $LogFile) -ItemType Directory -Force
}
# 获取所有补丁文件
$patchFiles = Get-ChildItem -Path $PatchPath -Filter $PatchExtension
Write-Log "开始安装补丁,共发现 $($patchFiles.Count) 个补丁文件"
# 遍历安装补丁
foreach ($patch in $patchFiles) {
try {
Write-Log "正在安装: $($patch.Name)"
# 方法1: 使用wusa.exe安装MSU补丁
$process = Start-Process -FilePath "wusa.exe" -ArgumentList "$($patch.FullName) /quiet /norestart" -Wait -PassThru
# 检查安装结果
if ($process.ExitCode -eq 0 -or $process.ExitCode -eq 3010) {
Write-Log "成功安装: $($patch.Name) (退出码: $($process.ExitCode))"
Rename-Item $patch.FullName "$($patch.FullName).installed" -ErrorAction SilentlyContinue
} else {
Write-Log "安装失败: $($patch.Name) (退出码: $process.ExitCode)"
# 记录失败补丁
$patch.Name | Out-File -FilePath "C:\Logs\failed_patches.txt" -Append
}
}
catch {
Write-Log "错误安装 $($patch.Name) : $_"
}
}
Write-Log "补丁安装完成"
高级版本(带重启控制和错误处理)
# advanced_patch_installer.ps1
param(
[string]$PatchDirectory = "C:\Patches",
[switch]$ForceReboot,
[switch]$DryRun
)
# 全局变量
$script:LogFile = "C:\Logs\patch_install.log"
$script:InstalledPatches = @()
$script:FailedPatches = @()
# 日志函数
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = "[$timestamp] [$Level] $Message"
Write-Host $logMessage -ForegroundColor $(if ($Level -eq "ERROR") {"Red"} else {"Green"})
Add-Content -Path $script:LogFile -Value $logMessage
}
# 检查系统要求
function Test-SystemRequirements {
Write-Log "检查系统要求..."
# 检查磁盘空间
$drive = Get-PSDrive C
if ($drive.Free -lt 10GB) {
Write-Log "磁盘空间不足,至少需要10GB可用空间" "ERROR"
return $false
}
# 检查Windows服务是否正常运行
if (!(Get-Service -Name wuauserv).Status -eq "Running") {
Write-Log "Windows Update服务未运行" "WARNING"
}
return $true
}
# 安装单个补丁
function Install-SinglePatch {
param([string]$PatchPath)
$patchName = Split-Path $PatchPath -Leaf
Write-Log "开始安装: $patchName"
if ($DryRun) {
Write-Log "[模拟] 将安装: $patchName"
return "SIMULATED"
}
try {
$process = Start-Process -FilePath "wusa.exe" -ArgumentList "$PatchPath /quiet /norestart" -Wait -PassThru
switch ($process.ExitCode) {
0 { Write-Log "成功: $patchName"; return "SUCCESS" }
3010 { Write-Log "成功(需要重启): $patchName"; return "SUCCESS_PENDING_REBOOT" }
2359302 { Write-Log "补丁已安装: $patchName"; return "ALREADY_INSTALLED" }
default {
Write-Log "失败 ($($process.ExitCode)): $patchName" "ERROR"
return "FAILED"
}
}
}
catch {
Write-Log "安装异常: $_" "ERROR"
return "FAILED"
}
}
# 主函数
function Main {
Write-Log "=== 开始补丁安装脚本 ==="
# 检查补丁目录
if (!(Test-Path $PatchDirectory)) {
Write-Log "补丁目录不存在: $PatchDirectory" "ERROR"
exit 1
}
# 检查系统要求
if (!(Test-SystemRequirements)) {
Write-Log "系统要求未满足,退出脚本" "ERROR"
exit 1
}
# 获取补丁列表并按依赖排序
$patches = Get-ChildItem -Path $PatchDirectory -Filter "*.msu" | Sort-Object Name
if ($patches.Count -eq 0) {
Write-Log "未找到补丁文件"
exit 0
}
Write-Log "发现 $($patches.Count) 个补丁"
# 安装补丁
$rebootRequired = $false
foreach ($patch in $patches) {
$result = Install-SinglePatch -PatchPath $patch.FullName
switch ($result) {
"SUCCESS" {
$script:InstalledPatches += $patch.Name
Rename-Item $patch.FullName "$($patch.FullName).installed"
}
"SUCCESS_PENDING_REBOOT" {
$script:InstalledPatches += $patch.Name
$rebootRequired = $true
Rename-Item $patch.FullName "$($patch.FullName).installed"
}
"ALREADY_INSTALLED" {
Write-Log "跳过(已安装): $($patch.Name)"
Rename-Item $patch.FullName "$($patch.FullName).installed"
}
"FAILED" {
$script:FailedPatches += $patch.Name
}
}
}
# 输出摘要
Write-Log "=== 安装摘要 ==="
Write-Log "成功安装: $($script:InstalledPatches.Count) 个补丁"
if ($script:FailedPatches.Count -gt 0) {
Write-Log "失败补丁: $($script:FailedPatches.Count) 个"
$script:FailedPatches | ForEach-Object { Write-Log " - $_" "ERROR" }
}
if ($rebootRequired) {
Write-Log "系统需要重启以完成补丁安装"
if ($ForceReboot) {
Write-Log "自动重启系统..."
Restart-Computer -Force
} else {
Write-Log "请手动重启系统"
}
}
# 发送邮件通知(可选)
# Send-MailMessage -To "admin@company.com" -Subject "补丁安装完成" ...
}
# 执行主程序
Main
Linux/Unix Bash 补丁安装脚本
#!/bin/bash
# patch_installer.sh
# 配置
PATCH_DIR="/var/tmp/patches"
LOG_FILE="/var/log/patch_install.log"
BACKUP_DIR="/var/backups/patches/$(date +%Y%m%d)"
# 日志函数
log() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
# 检查root权限
check_root() {
if [[ $EUID -ne 0 ]]; then
log "ERROR" "请使用root权限运行此脚本"
exit 1
fi
}
# 创建备份目录
create_backup() {
log "INFO" "创建备份目录: $BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
# 备份配置文件
cp -r /etc/yum.repos.d "$BACKUP_DIR/repos_backup"
log "INFO" "备份完成"
}
# 自动检测发行版
detect_distro() {
if [[ -f /etc/redhat-release ]]; then
echo "redhat"
elif [[ -f /etc/debian_version ]]; then
echo "debian"
else
echo "unknown"
fi
}
# RPM系统(CentOS/RHEL/Fedora)
install_rpm_patches() {
log "INFO" "开始安装RPM补丁"
# 清理缓存
yum clean all
# 更新包列表
yum makecache
# 检查是否有挂起的更新
updates=$(yum check-update 2>/dev/null | grep -c "\.\(i386\|x86_64\)")
log "INFO" "有 $updates 个更新可用"
if [[ "$updates" -gt 0 ]]; then
# 安装安全更新
if yum update -y --security; then
log "INFO" "安全更新安装成功"
else
log "ERROR" "安全更新安装失败"
return 1
fi
fi
# 安装本地补丁文件
for patch_file in "$PATCH_DIR"/*.rpm; do
if [[ -f "$patch_file" ]]; then
log "INFO" "安装补丁: $(basename $patch_file)"
if rpm -Uvh "$patch_file"; then
log "INFO" "补丁安装成功: $(basename $patch_file)"
mv "$patch_file" "$BACKUP_DIR/"
else
log "ERROR" "补丁安装失败: $(basename $patch_file)"
fi
fi
done
}
# Debian系统(Ubuntu/Debian)
install_debian_patches() {
log "INFO" "开始安装Debian补丁"
# 更新软件包列表
apt-get update
# 计算可用更新
updates=$(apt-get -s upgrade 2>/dev/null | grep -c "^Inst")
log "INFO" "有 $updates 个更新可用"
if [[ "$updates" -gt 0 ]]; then
# 安装安全更新
if DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends; then
log "INFO" "安全更新安装成功"
else
log "ERROR" "安全更新安装失败"
return 1
fi
fi
# 安装本地补丁
for patch_file in "$PATCH_DIR"/*.deb; do
if [[ -f "$patch_file" ]]; then
log "INFO" "安装补丁: $(basename $patch_file)"
if dpkg -i "$patch_file"; then
log "INFO" "补丁安装成功: $(basename $patch_file)"
mv "$patch_file" "$BACKUP_DIR/"
else
log "ERROR" "补丁安装失败: $(basename $patch_file)"
# 尝试修复依赖
apt-get install -f -y
fi
fi
done
}
# 检查重启需求
check_reboot_needed() {
if [[ -f /var/run/reboot-required ]]; then
log "WARNING" "系统需要重启"
return 0
else
log "INFO" "系统无需重启"
return 1
fi
}
# 发送通知
send_notification() {
local subject=$1
local message=$2
# 邮件通知(需要配置mail命令)
# echo "$message" | mail -s "$subject" admin@example.com
# 或使用curl发送到API服务
# curl -H "Content-Type: application/json" -d "{\"text\":\"$subject: $message\"}" https://api.example.com/notify
}
# 主函数
main() {
log "INFO" "=== 开始自动补丁安装脚本 ==="
# 检查root权限
check_root
# 检查补丁目录是否存在
if [[ ! -d "$PATCH_DIR" ]]; then
mkdir -p "$PATCH_DIR"
log "INFO" "创建补丁目录: $PATCH_DIR"
fi
# 创建备份
create_backup
# 检测系统类型并安装
distro=$(detect_distro)
log "INFO" "检测到操作系统: $distro"
case $distro in
redhat)
install_rpm_patches
;;
debian)
install_debian_patches
;;
*)
log "ERROR" "不支持的操作系统"
exit 1
;;
esac
# 检查是否需要重启
if check_reboot_needed; then
read -p "系统需要重启,是否立即重启? (y/n): " answer
if [[ "$answer" == "y" ]]; then
log "INFO" "正在重启系统..."
send_notification "补丁安装完成" "系统即将重启"
reboot
fi
fi
log "INFO" "=== 补丁安装脚本完成 ==="
send_notification "补丁安装完成" "补丁安装脚本执行完毕"
}
# 执行主函数
main "$@"
Windows批处理脚本(.bat)
@echo off
REM ====================================
REM 自动补丁安装脚本
REM ====================================
setlocal enabledelayedexpansion
REM 配置参数
set PATCH_DIR=C:\Patches
set LOG_FILE=C:\Logs\patch_install.log
set BACKUP_DIR=C:\Backup\patches
REM 检查管理员权限
net session >nul 2>&1
if %errorlevel% neq 0 (
echo 请以管理员身份运行此脚本
pause
exit /b 1
)
REM 创建目录
if not exist "%PATCH_DIR%" mkdir "%PATCH_DIR%"
if not exist "%LOG_FILE%" (
if not exist "C:\Logs\" mkdir "C:\Logs"
echo Patch Installer Script Started at %date% %time% > "%LOG_FILE%"
)
REM 日志函数
echo. >> "%LOG_FILE%"
echo ======================================== >> "%LOG_FILE%"
echo Starting patch installation at %date% %time% >> "%LOG_FILE%"
echo ======================================== >> "%LOG_FILE%"
REM 备份系统状态
echo Creating system restore point...
wmic /namespace:\\root\default path SystemRestore call create "Before patch installation" >> "%LOG_FILE%"
REM 遍历安装MSU补丁
echo Scanning for patches in %PATCH_DIR%...
set PATCH_COUNT=0
set SUCCESS_COUNT=0
set FAIL_COUNT=0
for %%f in ("%PATCH_DIR%\*.msu") do (
set /a PATCH_COUNT+=1
echo. >> "%LOG_FILE%"
echo Installing patch: %%~nxf >> "%LOG_FILE%"
REM 用wusa安装补丁
wusa "%%f" /quiet /norestart
if %errorlevel% equ 0 (
echo Successfully installed: %%~nxf >> "%LOG_FILE%"
set /a SUCCESS_COUNT+=1
REM 重命名已安装的文件
ren "%%f" "%%~nxf.installed"
) else (
echo Failed to install: %%~nxf (Error: %errorlevel%) >> "%LOG_FILE%"
set /a FAIL_COUNT+=1
)
)
REM 输出统计信息
echo. >> "%LOG_FILE%"
echo ======================================== >> "%LOG_FILE%"
echo Installation Summary at %date% %time% >> "%LOG_FILE%"
echo Total Patches: %PATCH_COUNT% >> "%LOG_FILE%"
echo Successfully Installed: %SUCCESS_COUNT% >> "%LOG_FILE%"
echo Failed: %FAIL_COUNT% >> "%LOG_FILE%"
echo ======================================== >> "%LOG_FILE%"
REM 检查是否需要重启
if %SUCCESS_COUNT% gtr 0 (
echo.
echo Some patches were installed successfully.
echo Please reboot your system to complete the installation.
choice /m "Do you want to reboot now?"
if %errorlevel% equ 1 (
shutdown /r /t 30 /c "Rebooting to complete patch installation"
)
)
echo.
echo Patch installation process completed. Check %LOG_FILE% for details.
pause
使用自动化工具(推荐)
Ansible Playbook 示例
---
- name: Automatic Patch Installation
hosts: all
become: yes
vars:
patch_dir: /var/tmp/patches
log_file: /var/log/patch_install.log
tasks:
- name: Create patch directory
file:
path: "{{ patch_dir }}"
state: directory
- name: Copy patches to target
copy:
src: "{{ item }}"
dest: "{{ patch_dir }}/"
loop:
- patch1.rpm
- patch2.rpm
- name: Apply patches (RHEL/CentOS)
yum:
name: "{{ patch_dir }}/*.rpm"
state: present
when: ansible_os_family == "RedHat"
- name: Apply patches (Debian/Ubuntu)
apt:
deb: "{{ item }}"
loop: "{{ lookup('fileglob', '{{ patch_dir }}/*.deb') }}"
when: ansible_os_family == "Debian"
- name: Check if reboot needed
stat:
path: /var/run/reboot-required
register: reboot_required
- name: Reboot if needed
reboot:
msg: "Rebooting to apply patches"
reboot_timeout: 300
when: reboot_required.stat.exists
使用建议
- 测试环境先行:在生产环境使用前,务必备份并测试
- 日志记录:保留完整日志便于问题追溯
- 错误处理:处理常见错误情况(磁盘空间、权限、依赖等)
- 通知机制:设置邮件或通知,了解安装结果
- 回滚准备:制定回滚计划,以防补丁导致问题
- 分阶段部署:分批安装,先测试组,再逐步推广
选择哪种方案取决于你的具体需求、操作系统环境和管理工具,建议优先使用专业的补丁管理工具。