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


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

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

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

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

1.1、.bat 的诞生背景

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

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

所以它的设计思想是:

  • 命令逐行执行

  • 一切皆字符串

  • 几乎没有“语言设计”

1.2、.ps1 的出现原因

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

  • 需要批量管理服务

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

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

  • 需要远程管理

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

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


二、.bat 是什么?

2.1、执行模型

  • 执行程序:cmd.exe

  • 执行方式:逐行解释

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

cmd.exe /c test.bat

2.2、核心特征

  1. 无对象概念

  2. 变量全是字符串

  3. 依赖系统内置命令

  4. 错误处理极弱

2.3、bat 的“变量系统”

set VAR=value
echo %VAR%

⚠️ 注意:

  • %VAR%文本替换

  • 不是运行时计算

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


三、.bat 的完整语法体系

3.1、基本结构

@echo off
rem 这是注释
echo Hello World
pause
关键字 含义
@echo off 关闭命令回显,未关闭回显时,每条命令都会先被打印出来,再执行并显示结果。
rem 注释,rem 为注释命令,一般用来给程序加上注解,该命令后的内容不被执行,但能回显,::用于进行文本的注释,执行后即使打开echo on也不会回显内容
pause 等待按键,用于暂停批处理脚本执行,显示本地化提示(如‘请按任意键继续...’),并等待用户任意按键后才继续。其核心价值在于防止命令窗口闪退

@echo off
title REM 和 :: 最小回显测试

echo 先关闭回显
echo.
pause

echo on
REM 这一行是 REM
:: 这一行是 ::
echo 这一行是普通 echo 输出

@echo off
echo.
echo 测试完成
pause

执行后结果如下所示

3.2、条件判断(if)

@echo off
title IF 输入判断示例

set /p a=请输入一个数字:

if %a%==1 (
echo 你输入的是 1
) else (
echo 你输入的不是 1
)

pause

常见判断:

  • exist

  • ==

  • errorlevel

if %errorlevel% neq 0 echo 执行失败

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


3.3、循环(for)

@echo off

for %%i in (*.txt) do echo 找到文件:%%i

pause

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

/f 表示 按行读取文本内容并进行解析

@echo off
title 获取本机 IPv4 地址示例

echo 正在获取本机 IPv4 地址...
echo.

for /f "tokens=2 delims=:" %%i in ('ipconfig ^| findstr /i "IPv4"') do echo 本机IPv4地址:%%i

echo.
pause

bat 最大的痛点:

能做的事 ≠ 好做的事


四、.ps1 是什么?

4.1、本质定位

.ps1PowerShell 脚本文件

而 PowerShell 本身是:

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

这句话极其重要。


4.2、执行模型

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

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

Get-Service

返回的是:

System.ServiceProcess.ServiceController

而不是字符串。


五、.ps1 的语法体系

5.1、变量与类型

$name = "Windows"
$count = 10

支持强类型:

[int]$port = 443

Windows 默认不允许直接运行 .ps1 脚本,运行需要配置如下命令

配置只对当前 PowerShell 临时允许

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser


5.2、条件判断(if)

$port = 443

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

对比 bat:可读性直接碾压


5.3、循环(foreach / for)

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

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


5.4、管道(PowerShell 灵魂)

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

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


5.5、函数(企业级脚本必备)

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

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

6.1、执行策略是什么?

PowerShell 引入了 Execution Policy

防止脚本被恶意执行

常见策略:

策略 含义
Restricted 禁止脚本
RemoteSigned 本地允许
Bypass 全放行

6.2、企业最常用方式

powershell -ExecutionPolicy Bypass -File deploy.ps1

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


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

维度 bat ps1
自动化能力 极高
可维护性
错误处理 原始 完整
日志能力 几乎没有 原生支持
适合规模 中 / 大
企业标准 淘汰中 主流

bat 能跑 ps1 能长期维护


八、真实企业场景建议

 8.1、不再用 bat 的场景

  • 安全整改脚本

  • 批量系统配置

  • 运维巡检

  • 自动化部署

8.2、ps1 的黄金场景

  • 等保 / 分保脚本

  • 批量漏洞修复

  • 服务巡检

  • 日志采集

  • AD / 注册表管理


九、一个现实真相

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

而 PowerShell 做的是:

系统能力的程序化控制

这是两个时代。

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

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


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

功能说明:

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

具体脚本内容:

GetSystemInfo.ps1文件内容如下所示

# ========================================================
# 版权所有 © 2026 笨熊呆呆瓜
# 联系方式: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
:: ========================================================
:: 版权所有 © 2026 笨熊呆呆瓜
:: 联系方式:842668578@qq.com
:: 用途:调用 PowerShell 脚本收集本机系统信息
:: ========================================================

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

运行BAT文件

执行过程如下所示

生成如下结果文件

文件内容如下所示

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐