Administrator
Published on 2026-01-11 / 1 Visits
0
0

一文吃透 Windows 脚本世界 ——.bat 与 .ps1 的本质、语法、工程级用法全解析


很多人“会用脚本”,但说不清脚本。
真正的差距,往往从 bat 和 ps1 的理解深度 开始拉开。


一、为什么 Windows 会同时存在 .bat.ps1

这是一个历史 + 架构演进的问题。

  • .ps1 是 PowerShell 脚本文件的扩展名,用于编写和执行 PowerShell 脚本。

  • .bat 是 Windows 批处理脚本文件的扩展名,用于编写和执行一系列 Windows 命令。

1️⃣ .bat 的诞生背景

.bat(Batch File)来自 DOS 时代,核心设计目标只有一个:

把人工在命令行里敲的命令,一次性自动执行

所以它的设计思想是:

  • 命令逐行执行

  • 一切皆字符串

  • 几乎没有“语言设计”

2️⃣ .ps1 的出现原因

随着 Windows 成为服务器操作系统、企业级平台,仅靠 bat 已经不够:

  • 需要批量管理服务

  • 需要操作注册表、AD、WMI

  • 需要结构化数据(XML / JSON)

  • 需要远程管理

于是 PowerShell 诞生了,而 .ps1 是它的脚本载体。

PowerShell 不是 CMD 的升级版,而是全新的自动化平台


二、.bat 是什么?

1️⃣ 执行模型

  • 执行程序:cmd.exe

  • 执行方式:逐行解释

  • 失败不会自动终止(除非你自己判断)

cmd.exe /c test.bat

2️⃣ 核心特征(记住这 4 点)

  1. 无对象概念

  2. 变量全是字符串

  3. 依赖系统内置命令

  4. 错误处理极弱

3️⃣ bat 的“变量系统”

set VAR=value
echo %VAR%

⚠️ 注意:

  • %VAR%文本替换

  • 不是运行时计算

  • 循环里要用 !VAR!(延迟展开)


三、.bat 的完整语法体系

1️⃣ 基本结构

@echo off
rem 这是注释
echo Hello World
pause

关键字

含义

@echo off

关闭命令回显

rem

注释

pause

等待按键


2️⃣ 条件判断(if)

if exist test.txt (
    echo 文件存在
) else (
    echo 文件不存在
)

常见判断:

  • exist

  • ==

  • errorlevel

if %errorlevel% neq 0 echo 执行失败

这是 bat 最容易写出 bug 的地方。


3️⃣ 循环(for)

for %%i in (*.log) do echo %%i

for /f(最反人类的语法):

for /f "tokens=2 delims=:" %%i in ('ipconfig') do echo %%i

📌 bat 最大的痛点:

能做的事 ≠ 好做的事


四、.ps1 是什么?

1️⃣ 本质定位

.ps1PowerShell 脚本文件

而 PowerShell 本身是:

基于 .NET 的面向对象自动化语言

这句话极其重要。


2️⃣ 执行模型

  • 执行程序:powershell.exe / pwsh.exe

  • 命令返回的不是文本,而是 对象

Get-Service

返回的是:

System.ServiceProcess.ServiceController

而不是字符串。


五、.ps1 的语法体系

1️⃣ 变量与类型

$name = "Windows"
$count = 10

支持强类型:

[int]$port = 443

2️⃣ 条件判断(if)

if ($port -eq 443) {
    Write-Host "HTTPS"
} else {
    Write-Host "Other"
}

对比 bat:可读性直接碾压


3️⃣ 循环(foreach / for)

foreach ($svc in Get-Service) {
    if ($svc.Status -eq "Stopped") {
        Write-Host $svc.Name
    }
}

📌 这里 $svc 是对象,不是字符串。


4️⃣ 管道(PowerShell 灵魂)

Get-Service | Where-Object Status -eq "Running"

这就是 PowerShell 能彻底干掉 bat 的原因。


5️⃣ 函数(企业级脚本必备)

function Restart-MyService {
    param($Name)
    Restart-Service $Name
}

六、执行策略(为什么 ps1 默认跑不了)

1️⃣ 执行策略是什么?

PowerShell 引入了 Execution Policy

防止脚本被恶意执行

常见策略:

策略

含义

Restricted

禁止脚本

RemoteSigned

本地允许

Bypass

全放行

2️⃣ 企业最常用方式

powershell -ExecutionPolicy Bypass -File deploy.ps1

📌 注意:这是“临时放行”,不改系统策略。


七、.bat.ps1 的工程级对比

维度

bat

ps1

自动化能力

极高

可维护性

错误处理

原始

完整

日志能力

几乎没有

原生支持

适合规模

中 / 大

企业标准

淘汰中

主流

一句话总结:

bat 能跑
ps1 能长期维护


八、真实企业场景建议

❌ 不要再用 bat 的场景

  • 安全整改脚本

  • 批量系统配置

  • 运维巡检

  • 自动化部署

✅ ps1 的黄金场景

  • 等保 / 分保脚本

  • 批量漏洞修复

  • 服务巡检

  • 日志采集

  • AD / 注册表管理


九、一个现实真相

很多“只会 bat 的运维”,
本质上还停留在 人工命令自动化阶段

而 PowerShell 做的是:

系统能力的程序化控制

这是两个时代。


十、总结

.bat 是历史的产物
.ps1 是 Windows 自动化的基石

懂 bat 是入门
精通 ps1 才是职业护城河


十一、【实战】Windows信息检查脚本

功能说明:

检查Windows主机的硬件配置,系统安装时间,系统版本,硬件序列号等。

具体脚本内容:

GetSystemInfo.ps1文件内容如下所示

# ========================================================
# 版权所有 © 2025 笨熊呆呆瓜
# 联系方式:842668578@qq.com
# 用途:收集本机系统信息(时间、主机名、用户、BIOS、硬盘、IP与MAC等)
# ========================================================

# 确保脚本路径正确
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Get-Location }
Set-Location -Path $scriptDir

# 获取时间、主机名、用户、操作系统信息
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$hostname = $env:COMPUTERNAME
$username = $env:USERNAME
$osinfo = Get-CimInstance Win32_OperatingSystem
$osname = $osinfo.Caption
$installTime = $osinfo.InstallDate.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")

# 构造输出文件路径
$outputFile = Join-Path $scriptDir "system_info_${hostname}_${timestamp}.txt"

# 初始化输出
Set-Content -Path $outputFile -Value "===== 系统信息收集 =====" -Encoding UTF8
Add-Content -Path $outputFile -Value "导出时间:$timestamp" -Encoding UTF8
Add-Content -Path $outputFile -Value "系统安装时间:$installTime" -Encoding UTF8
Add-Content -Path $outputFile -Value "主机名:$hostname" -Encoding UTF8
Add-Content -Path $outputFile -Value "当前用户:$username" -Encoding UTF8
Add-Content -Path $outputFile -Value "操作系统:$osname" -Encoding UTF8
Add-Content -Path $outputFile -Value "" -Encoding UTF8

# BIOS 序列号
Add-Content -Path $outputFile -Value "[设备序列号 - BIOS SerialNumber]" -Encoding UTF8
(Get-CimInstance Win32_BIOS).SerialNumber | Add-Content -Path $outputFile -Encoding UTF8
Add-Content -Path $outputFile -Value "" -Encoding UTF8

# 物理硬盘序列号
Add-Content -Path $outputFile -Value "[硬盘序列号 - Disk Serial Numbers]" -Encoding UTF8
Get-PhysicalDisk | ForEach-Object {
    "硬盘: $($_.FriendlyName) - 序列号: $($_.SerialNumber)" |
        Add-Content -Path $outputFile -Encoding UTF8
}
Add-Content -Path $outputFile -Value "" -Encoding UTF8

# 网卡 IP 和 MAC 配对输出(清晰配对)
Add-Content -Path $outputFile -Value "[网络接口 - IP 与 MAC 地址配对]" -Encoding UTF8

$adapters = Get-NetAdapter | Where-Object { $_.Status -eq "Up" }

foreach ($adapter in $adapters) {
    $name = $adapter.Name
    $mac = $adapter.MacAddress
    $ips = Get-NetIPAddress -InterfaceAlias $name -AddressFamily IPv4 | Where-Object { $_.IPAddress -ne $null }

    if ($ips.Count -eq 0) {
        Add-Content -Path $outputFile -Value "接口: $name" -Encoding UTF8
        Add-Content -Path $outputFile -Value "  IP地址: 无" -Encoding UTF8
        Add-Content -Path $outputFile -Value "  MAC地址: $mac" -Encoding UTF8
    } else {
        foreach ($ip in $ips) {
            Add-Content -Path $outputFile -Value "接口: $name" -Encoding UTF8
            Add-Content -Path $outputFile -Value "  IP地址: $($ip.IPAddress)" -Encoding UTF8
            Add-Content -Path $outputFile -Value "  MAC地址: $mac" -Encoding UTF8
        }
    }

    Add-Content -Path $outputFile -Value "" -Encoding UTF8
}

# 控制台驻留(兼容所有 PowerShell 版本)
Write-Host "`n系统信息已导出到:" -NoNewline
Write-Host "$outputFile" -ForegroundColor Green
Write-Host "请按任意键退出..."
[void][System.Console]::ReadKey($true)

BAT文件RunSystemInfo.bat内容如下所示

@echo off
:: ========================================================
:: 版权所有 © 2025 笨熊呆呆瓜
:: 联系方式:842668578@qq.com
:: 用途:调用 PowerShell 脚本收集本机系统信息
:: ========================================================

powershell -ExecutionPolicy Bypass -NoExit -File "%~dp0GetSystemInfo.ps1"

运行BAT文件

执行过程如下所示

生成如下结果文件

文件内容如下所示


Comment