尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Windows PowerShell入门到实战:从CMD迁移与自动化运维指南

Windows PowerShell入门到实战:从CMD迁移与自动化运维指南 1. 从CMD到PowerShell为什么Windows用户需要了解这个“超级命令行”很多人第一次接触命令行都是从CMD开始的。那个黑底白字的窗口敲几个dir、ipconfig、ping感觉已经够用了。但只要你稍微深入一点Windows的日常运维、批量处理或者自动化任务就会发现CMD的局限性非常明显——它本质上是一个继承自DOS时代的命令解释器字符串处理能力弱管道传递的是纯文本面对结构化数据几乎无能为力。PowerShell就是在这个背景下出现的。它不是简单地把CMD换了个名字而是从底层重新设计的一套命令行环境和脚本语言。你可以把它理解成“命令行的升级版脚本语言的合体”既能在交互式窗口里一条条敲命令也能把几十条命令写成一个.ps1脚本文件批量执行既能操作文件系统也能管理注册表、服务、进程、证书、网络配置甚至直接调用.NET类库和REST API。这篇文章适合哪些人看如果你是刚接触Windows命令行的新手想搞清楚PowerShell和CMD到底有什么区别、该学哪个如果你是运维人员日常需要批量处理文件、查看系统信息、配置服务如果你是开发人员想在Windows上做自动化构建、环境初始化、日志分析——那这篇内容基本能覆盖你从入门到能上手干活所需要的核心知识。我自己的经历是早年一直用CMD写批处理后来遇到一个需求要批量读取几百个文本文件提取其中符合特定格式的行然后汇总成一张表。用CMD写光是字符串截取就能把人逼疯。换成PowerShell之后一个Get-Content配合Select-String和Export-Csv几行就搞定了。从那以后我就彻底转向了PowerShell。下面我会从设计思路、核心概念、实操步骤、常见问题几个维度把PowerShell这个东西讲透。不堆砌术语尽量用实际场景来说明它为什么这么设计、怎么用最顺手。2. PowerShell的核心设计思路与基础概念拆解2.1 为什么PowerShell不是“CMD 2.0”CMD的设计哲学是“命令参数文本输出”。每个命令独立运行输出就是一堆字符下一个命令如果想用上一个命令的结果只能靠文本解析。这就导致批处理脚本非常脆弱——换个语言环境、换个输出格式脚本就挂了。PowerShell的设计哲学完全不同。它的核心是对象管道。每个命令PowerShell里叫cmdlet输出的不是纯文本而是.NET对象。对象有属性、有方法下一个命令可以直接访问这些属性不需要做字符串解析。举个例子Get-Process | Where-Object { $_.CPU -gt 100 } | Select-Object Name, CPU, Id这条命令的意思是获取所有进程筛选出CPU时间超过100的然后只显示名称、CPU时间和进程ID。整个过程没有字符串切割没有列位置计算因为Get-Process输出的就是对象Where-Object直接比较对象的CPU属性Select-Object直接选取属性。这种设计带来的好处是脚本更稳定、更可读、更容易维护。你不需要关心输出格式是左对齐还是右对齐不需要数第几列是进程名对象属性名就是唯一的访问入口。2.2 命令的命名规范动词-名词PowerShell的cmdlet命名遵循一个非常严格的规范动词-名词。比如Get-Process获取进程Set-Service设置服务New-Item新建项目文件或目录Remove-Item删除项目Start-Service启动服务Stop-Process停止进程这个规范的好处是自解释性极强。你看到Get-就知道是获取看到Set-就知道是修改看到New-就知道是创建。常用的动词就那么几十个记住之后即使遇到没见过的cmdlet也能大致猜出它是干什么的。你可以用Get-Verb查看PowerShell认可的所有动词列表。虽然第三方模块不一定严格遵守但微软官方模块和大多数主流模块都是遵循这个规范的。2.3 执行策略为什么脚本默认不能运行这是新手最容易踩的坑。你写了一个.ps1脚本双击运行或者用命令行执行结果报错无法加载文件 xxx.ps1因为在此系统上禁止运行脚本。这不是Bug而是PowerShell的安全机制。执行策略Execution Policy控制脚本的运行权限默认是Restricted也就是禁止运行任何脚本文件。这么设计是为了防止用户无意中运行恶意脚本。常见的执行策略有策略名称说明Restricted默认值禁止运行脚本RemoteSigned本地脚本可运行远程下载的脚本需要数字签名AllSigned所有脚本都需要数字签名Unrestricted所有脚本都可运行不推荐Bypass什么都不阻止适合临时执行查看当前策略Get-ExecutionPolicy修改策略需要管理员权限Set-ExecutionPolicy RemoteSigned注意修改执行策略不是“打开开关”那么简单它决定了你系统的安全边界。日常开发机器建议用RemoteSigned服务器上建议用AllSigned或保持Restricted只在必要时临时用Bypass执行特定脚本。2.4 PowerShell版本5.1和7.x的区别Windows自带的PowerShell通常是5.1版本路径在C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe。而最新的PowerShell 7.x是跨平台的可以单独安装路径通常是C:\Program Files\PowerShell\7\pwsh.exe。两者的主要区别跨平台5.1只能在Windows上跑7.x可以在Windows、Linux、macOS上跑性能7.x基于.NET Core启动更快部分命令执行效率更高兼容性7.x对部分旧模块的兼容性不如5.1尤其是依赖.NET Framework的模块新特性7.x支持三元运算符、管道链运算符、并行执行等新语法如果你只是做Windows日常运维5.1基本够用。如果你需要跨平台脚本或者想用新语法建议安装7.x。两者可以共存互不影响。3. 核心细节解析与实操要点3.1 帮助系统学会自己查文档PowerShell自带完整的帮助系统但默认只安装了基本帮助详细帮助需要手动更新Update-Help如果网络环境不允许可以用-Online参数直接打开在线文档Get-Help Get-Process -Online查看命令帮助的常用方式Get-Help Get-Process # 基本帮助 Get-Help Get-Process -Examples # 只看示例 Get-Help Get-Process -Full # 完整帮助 Get-Command -Name Get-* # 查找所有Get开头的命令 Get-Command -Verb Set # 查找所有Set动词的命令实操心得我刚开始学的时候遇到不认识的命令就Get-Help一下看Examples部分基本就能明白怎么用。这比在网上搜教程快得多而且准确。3.2 管道PowerShell的灵魂管道符号|在CMD里也有但CMD的管道传递的是文本PowerShell传递的是对象。这个区别决定了PowerShell能做的事情远比CMD多。举个实际例子。假设你要找出当前系统中占用内存最多的前5个进程Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5 Name, WorkingSet64拆解一下Get-Process获取所有进程对象Sort-Object WorkingSet64 -Descending按内存占用降序排列Select-Object -First 5取前5个Name, WorkingSet64只显示名称和内存占用整个过程没有一行字符串处理代码因为每一步操作的都是对象。再比如你要查看某个服务的状态并启动它Get-Service -Name wuauserv | Start-Service如果服务已经启动Start-Service会报错。你可以加个判断Get-Service -Name wuauserv | Where-Object { $_.Status -eq Stopped } | Start-Service这就是对象管道的威力你可以像搭积木一样把命令串起来每个命令处理上一个命令输出的对象。3.3 变量与数据类型PowerShell的变量以$开头不需要声明类型但可以显式指定$name Windows $count 10 $items (a, b, c) # 数组 $hash {NameTest; Value123} # 哈希表查看变量类型$name.GetType().Name常见数据类型类型示例说明Stringhello字符串Int42整数Double3.14浮点数Boolean$true/$false布尔值Array(1,2,3)数组Hashtable{a1;b2}哈希表PSCustomObject[PSCustomObject]{...}自定义对象注意PowerShell是弱类型语言但底层基于.NET所以实际上每个值都有明确的.NET类型。用GetType()可以查看具体类型这在调试时非常有用。3.4 条件判断与循环条件判断if ($count -gt 5) { Write-Output 大于5 } elseif ($count -eq 5) { Write-Output 等于5 } else { Write-Output 小于5 }比较运算符和C语言不同PowerShell用的是-gt大于、-lt小于、-eq等于、-ne不等于这种形式。这么设计是为了避免被误认为重定向符号。循环# foreach循环 foreach ($item in $items) { Write-Output $item } # for循环 for ($i 0; $i -lt 10; $i) { Write-Output $i } # while循环 $i 0 while ($i -lt 10) { Write-Output $i $i }3.5 函数与模块定义函数function Get-SystemInfo { param( [string]$ComputerName localhost ) $os Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName [PSCustomObject]{ Name $os.Caption Version $os.Version LastBoot $os.LastBootUpTime } }调用Get-SystemInfo Get-SystemInfo -ComputerName SERVER01模块是函数的集合可以打包分发。查看已加载的模块Get-Module查看可用模块Get-Module -ListAvailable4. 实操过程与核心环节实现4.1 环境准备与基本配置第一次打开PowerShell建议先做几件事第一步以管理员身份运行很多系统级操作需要管理员权限。右键点击PowerShell图标选择“以管理员身份运行”。第二步查看版本$PSVersionTable这会显示当前PowerShell的详细版本信息包括PSVersion、PSEdition、OS等。第三步设置执行策略Set-ExecutionPolicy RemoteSigned -Scope CurrentUser-Scope CurrentUser表示只对当前用户生效不需要管理员权限也不会影响其他用户。第四步更新帮助文档Update-Help -Force如果网络不通可以跳过这一步用-Online参数查在线文档。第五步配置ProfileProfile是每次启动PowerShell时自动执行的脚本。查看Profile路径$PROFILE创建Profile文件if (!(Test-Path $PROFILE)) { New-Item -Path $PROFILE -ItemType File -Force } notepad $PROFILE在Profile里可以放常用函数、别名、环境变量设置。比如我习惯在里面加一个快速打开当前目录的命令function Open-Here { explorer.exe . } Set-Alias -Name oh -Value Open-Here这样每次启动PowerShell敲oh就能打开当前目录的资源管理器。4.2 文件与目录操作实战PowerShell操作文件系统非常方便。以下是一些高频操作列出目录内容Get-ChildItem -Path C:\Temp -Recurse -File | Select-Object FullName, Length, LastWriteTime批量重命名假设要把C:\Photos下所有.jpeg文件改成.jpgGet-ChildItem -Path C:\Photos -Filter *.jpeg | ForEach-Object { $newName $_.Name -replace \.jpeg$, .jpg Rename-Item -Path $_.FullName -NewName $newName }批量替换文件内容把C:\Config下所有.config文件中的localhost替换成192.168.1.100Get-ChildItem -Path C:\Config -Filter *.config | ForEach-Object { (Get-Content $_.FullName) -replace localhost, 192.168.1.100 | Set-Content $_.FullName }统计文件夹大小$size (Get-ChildItem -Path C:\Temp -Recurse -File | Measure-Object -Property Length -Sum).Sum {0:N2} MB -f ($size / 1MB)实操心得批量操作文件之前先用-WhatIf参数预览结果。比如Rename-Item -WhatIf会告诉你“如果执行会重命名哪些文件”但不会真正执行。这个参数在大多数修改类cmdlet上都可用是防止误操作的神器。4.3 系统信息查询与监控查看系统信息Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object Caption, Version, LastBootUpTime, TotalVisibleMemorySize, FreePhysicalMemory查看磁盘空间Get-CimInstance -ClassName Win32_LogicalDisk -Filter DriveType3 | Select-Object DeviceID, {NameSizeGB;Expression{[math]::Round($_.Size/1GB,2)}}, {NameFreeGB;Expression{[math]::Round($_.FreeSpace/1GB,2)}}查看服务状态Get-Service | Where-Object { $_.StartType -eq Automatic -and $_.Status -ne Running } | Select-Object Name, DisplayName, Status这条命令找出所有“自动启动但当前未运行”的服务非常适合排查系统问题。查看事件日志Get-EventLog -LogName System -EntryType Error -Newest 20 | Select-Object TimeGenerated, Source, Message实时监控CPU和内存while ($true) { $cpu (Get-CimInstance -ClassName Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average $mem Get-CimInstance -ClassName Win32_OperatingSystem $memUsed [math]::Round(($mem.TotalVisibleMemorySize - $mem.FreePhysicalMemory) / 1MB, 2) Write-Host CPU: $cpu% | Memory Used: $memUsed GB Start-Sleep -Seconds 2 }4.4 网络配置与排查查看IP配置Get-NetIPAddress -AddressFamily IPv4 | Select-Object InterfaceAlias, IPAddress, PrefixLength测试网络连通性Test-NetConnection -ComputerName www.example.com -Port 443这个命令比ping和telnet加起来都好用能同时测试DNS解析、路由可达性和端口连通性。查看端口占用Get-NetTCPConnection -LocalPort 8080 | Select-Object LocalAddress, LocalPort, State, OwningProcess找到进程ID后可以进一步查看进程名Get-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess关闭占用端口的进程Stop-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess -Force注意Stop-Process -Force会强制终止进程可能导致数据丢失。执行前确认进程是否真的需要关闭。4.5 远程管理PowerShell支持远程管理可以在本地操作远程计算机。启用远程管理在目标计算机上管理员权限Enable-PSRemoting -Force建立远程会话Enter-PSSession -ComputerName SERVER01 -Credential (Get-Credential)在远程计算机上执行命令Invoke-Command -ComputerName SERVER01 -ScriptBlock { Get-Service | Where-Object { $_.Status -eq Running } }批量在多台计算机上执行$computers (SERVER01, SERVER02, SERVER03) Invoke-Command -ComputerName $computers -ScriptBlock { Get-CimInstance Win32_OperatingSystem | Select-Object PSComputerName, Caption, LastBootUpTime }4.6 计划任务与自动化创建计划任务$action New-ScheduledTaskAction -Execute PowerShell.exe -Argument -File C:\Scripts\DailyReport.ps1 $trigger New-ScheduledTaskTrigger -Daily -At 08:00 $principal New-ScheduledTaskPrincipal -UserId SYSTEM -LogonType ServiceAccount Register-ScheduledTask -TaskName DailyReport -Action $action -Trigger $trigger -Principal $principal查看计划任务Get-ScheduledTask | Where-Object { $_.TaskName -like *Report* }手动触发计划任务Start-ScheduledTask -TaskName DailyReport4.7 错误处理与调试基本错误处理try { Get-Content C:\NotExist.txt -ErrorAction Stop } catch { Write-Output 出错了: $($_.Exception.Message) }常用错误处理参数参数说明-ErrorAction Stop遇到错误立即停止进入catch块-ErrorAction SilentlyContinue忽略错误继续执行-ErrorAction Continue显示错误继续执行默认-ErrorVariable把错误保存到变量调试脚本Set-PSDebug -Trace 1 # 开启跟踪 # 执行你的脚本 Set-PSDebug -Off # 关闭跟踪或者在脚本中设置断点Wait-Debugger5. 常见问题与排查技巧实录5.1 中文乱码问题这是国内用户最常见的问题之一。PowerShell 5.1默认使用系统区域设置的编码如果系统是中文Windows默认代码页是GBK但很多脚本文件保存为UTF-8就会导致中文乱码。现象脚本中的中文输出变成乱码或者读取UTF-8文件时中文显示异常。解决方法方法一修改PowerShell的默认编码[Console]::OutputEncoding [System.Text.Encoding]::UTF8方法二在脚本文件开头指定编码# 保存脚本时选择“UTF-8 with BOM”编码方法三读取文件时指定编码Get-Content -Path file.txt -Encoding UTF8方法四修改系统区域设置中的“Beta版使用Unicode UTF-8提供全球语言支持”实操心得我试过各种方案最稳妥的是把脚本文件保存为“UTF-8 with BOM”同时在Profile里设置[Console]::OutputEncoding [System.Text.Encoding]::UTF8。这样无论是交互式输出还是脚本执行中文都不会乱码。5.2 执行策略导致的脚本无法运行现象无法加载文件 xxx.ps1因为在此系统上禁止运行脚本。排查步骤查看当前执行策略Get-ExecutionPolicy -List查看生效的策略Get-ExecutionPolicy修改策略Set-ExecutionPolicy RemoteSigned -Scope CurrentUser如果修改后仍然报错检查是否有组策略覆盖Get-ExecutionPolicy -List如果MachinePolicy或UserPolicy显示为Restricted说明是域策略控制的需要联系域管理员。5.3 命令找不到或模块未加载现象Get-XXX : 无法将“Get-XXX”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。排查步骤确认命令是否存在Get-Command -Name Get-XXX确认模块是否已加载Get-Module -Name XXX查看可用模块Get-Module -ListAvailable | Where-Object { $_.Name -like *XXX* }手动导入模块Import-Module -Name XXX如果模块未安装可以通过Install-Module安装需要PowerShell 5.0以上Install-Module -Name XXX -Scope CurrentUser5.4 权限不足现象拒绝访问或无法执行操作因为权限不足。解决方法以管理员身份运行PowerShell检查当前用户是否在管理员组whoami /groups | findstr Administrators对于远程操作检查凭据和防火墙设置5.5 管道命令执行顺序问题现象管道命令没有按预期执行或者输出结果不对。常见原因PowerShell的管道是流式处理但某些命令会缓冲所有输入后再输出。比如Sort-Object必须等所有输入到齐后才能排序。排查技巧用Tee-Object把中间结果保存到文件查看每一步的输出用ForEach-Object { $_ | Out-String }查看对象内容用Get-Member查看对象的属性和方法Get-Process | Get-Member # 查看进程对象有哪些属性5.6 性能问题现象脚本执行很慢尤其是处理大量数据时。常见原因和优化方法问题优化方法频繁调用外部命令尽量用内置cmdlet替代大量字符串拼接用-join或StringBuilder逐条处理数据用管道批量处理频繁写文件收集后一次性写入使用追加数组用ArrayList或List示例不推荐的写法$result () foreach ($item in $items) { $result $item # 每次都会创建新数组性能极差 }推荐的写法$result [System.Collections.Generic.List[object]]::new() foreach ($item in $items) { $result.Add($item) }5.7 常见问题速查表问题可能原因解决方法脚本无法运行执行策略限制Set-ExecutionPolicy RemoteSigned中文乱码编码不一致设置UTF-8编码脚本保存为UTF-8 with BOM命令找不到模块未加载Import-Module或Install-Module权限不足非管理员运行以管理员身份运行管道输出为空上一步无输出检查上一步命令是否正确远程连接失败WinRM未启用Enable-PSRemoting -Force变量值为空变量未赋值用$null检查加-ErrorAction Stop脚本执行慢频繁数组追加用List替代数组6. 从CMD迁移到PowerShell的实用对照很多CMD用户想转PowerShell但习惯了CMD的命令一时改不过来。这里整理一份常用命令对照表功能CMDPowerShell列出目录dirGet-ChildItem切换目录cdSet-Location创建目录mdNew-Item -ItemType Directory删除文件delRemove-Item复制文件copyCopy-Item移动文件moveMove-Item查看文件内容typeGet-Content查找文件dir /sGet-ChildItem -Recurse查找内容findstrSelect-String查看进程tasklistGet-Process结束进程taskkillStop-Process查看服务sc queryGet-Service启动服务net startStart-Service停止服务net stopStop-Service查看IPipconfigGet-NetIPAddress测试连接pingTest-NetConnection查看路由route printGet-NetRoute查看端口netstatGet-NetTCPConnection环境变量setGet-ChildItem Env:设置变量set VARvalue$env:VAR value清屏clsClear-Host查看历史doskey /historyGet-History命令帮助command /?Get-Help command实操心得刚开始用PowerShell时可以先用Get-Alias查看CMD命令对应的PowerShell别名。比如dir、cd、type这些在PowerShell里都能用因为它们是别名。但别名只适合交互式使用写脚本时建议用完整的cmdlet名称可读性更好。6.1 别名系统过渡期的好帮手PowerShell内置了大量别名让CMD用户能平滑过渡Get-Alias -Definition Get-ChildItem输出会显示dir、ls、gci都是Get-ChildItem的别名。查看所有别名Get-Alias创建自定义别名Set-Alias -Name np -Value notepad注意别名只在当前会话有效重启PowerShell就没了。要永久生效需要写入Profile文件。6.2 从批处理到脚本的思维转变CMD批处理的核心是“命令序列文本处理”PowerShell脚本的核心是“对象操作管道”。这个思维转变很重要。举个例子。CMD里要获取所有正在运行的服务名称sc query state running | findstr SERVICE_NAME输出是一堆文本要提取服务名还得用for /f循环切割。PowerShell里Get-Service | Where-Object { $_.Status -eq Running } | Select-Object -ExpandProperty Name直接输出服务名列表每个名称是一个字符串对象可以直接传给下一个命令。再比如要统计某个目录下每种文件类型的数量CMD里几乎没法优雅地实现。PowerShell里Get-ChildItem -Path C:\Temp -File | Group-Object Extension | Select-Object Name, Count | Sort-Object Count -Descending一行命令搞定。7. 进阶方向与日常使用建议7.1 值得掌握的进阶技能正则表达式PowerShell的-match、-replace、Select-String都支持正则处理文本时非常强大。2024-01-15 -match \d{4}-\d{2}-\d{2}JSON和XML处理PowerShell内置ConvertTo-Json、ConvertFrom-Json、ConvertTo-Xml等命令处理API返回数据非常方便。$data Invoke-RestMethod -Uri https://api.example.com/data $data | ConvertTo-Json -Depth 5CIM/WMI查询获取硬件信息、系统配置的利器。Get-CimInstance -ClassName Win32_PhysicalMemory | Select-Object Manufacturer, Capacity, SpeedDesired State Configuration (DSC)声明式配置管理适合批量配置服务器。PowerShell Gallery模块仓库可以找到大量第三方模块。Find-Module -Name Pester # 查找测试框架 Install-Module -Name Pester -Scope CurrentUser7.2 日常使用中的小技巧快速打开当前目录的终端在文件资源管理器地址栏输入powershell回车就能在当前目录打开PowerShell。使用Windows TerminalWindows Terminal是一个现代化的终端应用支持多标签、多Shell、自定义主题。可以把PowerShell、CMD、WSL放在同一个窗口里。配置PSReadLinePSReadLine是PowerShell的增强模块提供语法高亮、智能补全、历史搜索等功能。Windows 10以上默认已安装。Set-PSReadLineOption -PredictionSource History Set-PSReadLineOption -PredictionViewStyle ListView这样输入命令时会显示历史记录建议按右箭头补全。使用VS Code编写脚本VS Code配合PowerShell扩展提供语法高亮、智能提示、调试功能写脚本效率翻倍。常用快捷键快捷键功能CtrlC中断当前命令CtrlL清屏CtrlR搜索历史命令Tab自动补全CtrlSpace显示补全列表F7显示历史命令列表CtrlAltShift?显示快捷键帮助7.3 安全注意事项不要随意执行来源不明的脚本尤其是网上复制的一行命令比如irm xxx | iex这种形式它会直接下载并执行远程脚本。执行前至少要看清楚脚本内容。使用签名脚本在生产环境中建议对脚本进行数字签名并设置执行策略为AllSigned。最小权限原则不要所有操作都用管理员权限。日常操作使用普通权限需要时再提权。审计脚本执行可以通过组策略开启脚本块日志记录记录所有执行的脚本内容便于审计和排查。7.4 学习资源推荐官方文档Microsoft Learn上的PowerShell文档是最权威的学习资料PowerShell Gallery查找和安装模块GitHub大量开源PowerShell项目和脚本可以参考社区论坛遇到问题可以在技术社区提问通常很快能得到解答我个人的习惯是遇到重复性的操作就想想能不能用PowerShell自动化。哪怕每次只省几分钟积累下来也是可观的时间。而且写脚本的过程本身就是在梳理流程、加深理解。一开始可能觉得麻烦但一旦形成习惯你会发现很多以前觉得繁琐的事情现在几行命令就搞定了。最后分享一个我常用的调试技巧在脚本关键位置插入Write-Host输出中间变量或者用Start-Sleep暂停执行观察每一步的结果。虽然简单但比任何高级调试工具都直接有效。
返回列表