拓冰建站拓冰建站
首页 / 资讯中心 / 正文

PowerShell入门到实战:从CMD升级到对象管道自动化运维

Windows上那个蓝色的命令行窗口很多人用了十几年电脑都没点开过几次觉得那是运维和黑客才碰的东西。但如果你还在用CMD一条条敲dir、copy或者手动在资源管理器里翻文件夹找昨天改过的文件那确实有点亏。PowerShell这个东西微软从2006年就开始往系统里塞了到现在的Windows 10、Windows 11、Server 2016以上版本它已经是内置的标配组件不需要你额外装什么。它的定位很明确把Windows上那些零散的、靠鼠标点半天的管理操作变成可复用、可批量、可自动化的命令行和脚本。这篇文章不打算给你背语法手册而是从一个实际用Windows干活的人的角度把PowerShell到底是什么、和CMD有什么区别、日常能拿来干什么、脚本怎么写、坑在哪里一次讲透。不管你是刚接触命令行的小白还是用了多年CMD想升级的老手都能从里面找到能直接抄去用的东西。1. 从CMD到PowerShell为什么Windows要搞两套命令行1.1 CMD的历史包袱与能力天花板CMD这个东西严格来说叫命令提示符它的前身可以追溯到DOS时代。那个年代的操作系统设计思路很简单命令就是一个个独立的可执行程序你输入dir系统去找dir.exe或者内部命令表里的dir执行完把文本结果打到屏幕上结束。这种设计在几十年前够用但放到今天问题就很明显了。最核心的问题是CMD处理的是纯文本流。你运行ipconfig它吐出来一堆文字你想从中提取IP地址只能用findstr去匹配字符串匹配出来的还是一坨文本没法直接拿来做判断或者传给下一个命令做参数。比如你想“找出所有占用80端口的进程并杀掉”在CMD里你得先netstat -ano | findstr :80拿到PID然后肉眼找到那个数字再手动taskkill /PID 数字 /F。整个过程是断开的没法串成一条自动化的链路。另一个大问题是CMD的内置命令非常有限。真正干活的都是外部exe比如ping.exe、net.exe、sc.exe。这些exe的参数风格各不相同有的用/有的用-有的参数顺序还不能乱。你想批量做点事情写出来的批处理文件.bat基本就是一堆goto和if的堆砌可读性极差调试起来更是痛苦。1.2 PowerShell的设计哲学对象而非文本PowerShell最根本的改变是它传递的不是文本而是.NET对象。这句话听起来有点抽象但理解它是理解PowerShell一切行为的钥匙。举个例子。在CMD里运行dir你看到的是文件名、日期、大小这些文字。在PowerShell里运行Get-ChildItem这是dir在PowerShell里的别名你看到的也是类似的一列信息但实际上每一个条目都是一个FileInfo对象它身上带着几十个属性Name、Length、LastWriteTime、Extension、FullName、Attributes等等。你看到的表格只是PowerShell默认帮你挑了最常用的几个属性显示出来而已。这意味着什么意味着你可以直接对属性做操作。比如你想找出当前目录下所有大于10MB的文件在PowerShell里就是Get-ChildItem | Where-Object { $_.Length -gt 10MB }$_代表当前管道里的对象.Length直接取属性-gt是大于。整个逻辑是连贯的不需要做任何文本解析。这就是对象管道的威力。再比如你想把某个目录下所有.log文件按修改时间排序取最新的5个然后只看它们的文件名和大小Get-ChildItem *.log | Sort-Object LastWriteTime -Descending | Select-Object -First 5 Name, Length这条命令在CMD里几乎没法优雅地实现但在PowerShell里就是一行。而且Select-Object选出来的还是对象你可以继续往下传或者导出成CSV、JSON、XML格式转换都是内置的。1.3 两套命令行共存的现实意义既然PowerShell这么强为什么Windows不直接把CMD删掉原因很实际兼容性。几十年来无数的批处理脚本、安装程序、系统工具都依赖CMD的行为。很多老旧的exe在启动时就是调用cmd.exe /c来执行命令的。如果微软把CMD拿掉大量软件会直接崩掉。所以现在的局面是CMD还在但微软的重心早就转到PowerShell上了。从Windows 7开始PowerShell就内置了到Windows 10/11开始菜单里搜“PowerShell”直接就能打开Windows Server 2016以后很多图形化管理工具底层调用的就是PowerShell命令。你打开“服务器管理器”做一步操作它旁边会显示对应的PowerShell命令这就是微软在引导大家往脚本化、自动化方向走。对于普通用户来说不需要纠结“学哪个”。CMD的常用命令在PowerShell里基本都有别名dir、cd、copy、del这些都能用。你可以先在PowerShell里用你熟悉的CMD命令慢慢再学PowerShell的原生命令。两者不是替代关系而是可以混着用哪个顺手用哪个。2. 打开PowerShell的正确姿势与版本选择2.1 几种启动方式及其适用场景打开PowerShell的方法很多但不同方式打开的版本和权限不一样这一点很多人没注意。最直接的是按Win R输入powershell回车。这样打开的是当前用户权限的Windows PowerShell通常是5.1版本。适合日常查看信息、跑一些不需要管理员权限的脚本。第二种是在开始菜单搜索“PowerShell”出来的结果里会有“Windows PowerShell”和“Windows PowerShell ISE”。ISE是个带图形界面的脚本编辑器有代码补全和调试功能写脚本的时候比在纯命令行里舒服很多。不过ISE从PowerShell 7开始就不再更新了微软推荐用VS Code加PowerShell扩展。第三种是管理员权限打开。在开始菜单搜到PowerShell后右键选“以管理员身份运行”。很多系统级操作比如改服务启动类型、改注册表、装软件必须管理员权限否则会报“拒绝访问”。这个坑很常见新手经常拿着普通权限去执行需要提权的命令然后对着错误信息发懵。第四种是通过Windows Terminal。如果你装了Windows TerminalWin11默认自带Win10可以在商店装它可以把PowerShell、CMD、WSL等多个终端放在一个窗口里用标签页切换体验比单独开窗口好很多。而且Windows Terminal可以配置启动时默认打开哪个Shell。还有一种是在文件资源管理器的地址栏里直接输入powershell回车这样打开的PowerShell会自动把当前目录设成你所在的文件夹路径。这个技巧在需要针对某个目录操作时特别方便省得手动cd过去。2.2 Windows PowerShell 5.1与PowerShell 7的区别这里要分清两个东西Windows PowerShell和PowerShell。名字很像但不是一个东西。Windows PowerShell是微软从2006年开始随Windows发布的版本最后一个大版本是5.1它基于.NET Framework。你系统里自带的那个就是它路径在C:\Windows\System32\WindowsPowerShell\v1.0\下面。PowerShell没有“Windows”前缀是2018年以后微软推出的跨平台版本从6.0开始现在最新是7.x。它基于.NET Core后来叫.NET 5可以跑在Windows、Linux、macOS上。它的命令更统一性能更好而且还在持续更新。那普通用户用哪个我的建议是日常简单操作系统自带的5.1完全够用不用额外装东西。但如果你要写比较复杂的脚本或者需要用到一些新模块和新语法那就装PowerShell 7。两者可以共存不冲突。装完之后powershell命令打开的还是5.1pwsh命令打开的才是7.x。这个区别要记住不然你会疑惑为什么同一个命令在两个窗口里行为不一样。安装PowerShell 7最省事的方式是用wingetwinget install --id Microsoft.PowerShell --source winget或者去GitHub的PowerShell发布页下载msi安装包。装完之后建议把Windows Terminal的默认配置文件改成PowerShell 7这样以后打开终端直接就是新版本。2.3 执行策略为什么你的脚本跑不起来这是新手遇到的第一个大坑。你写了个.ps1脚本双击或者命令行里运行结果报错说“无法加载文件因为在此系统上禁止运行脚本”。这不是你的脚本有问题是PowerShell的执行策略Execution Policy在拦你。执行策略是微软设计的一道安全防线防止不明来源的脚本在你机器上随便跑。默认情况下客户端Windows的执行策略是Restricted意思是什么脚本都不让跑。你可以用这个命令查看当前策略Get-ExecutionPolicy要允许运行本地写的脚本可以改成RemoteSignedSet-ExecutionPolicy RemoteSignedRemoteSigned的意思是本地写的脚本可以直接跑从网上下载的脚本需要有数字签名才能跑。这样既方便自己写脚本又保留了对网络来源的警惕。改的时候需要管理员权限改完可以用Get-ExecutionPolicy确认一下。注意不要随便改成Unrestricted那个是什么脚本都放行包括从网上随便下的风险太大。RemoteSigned是日常使用最平衡的选择。还有一个临时绕过执行策略的方法就是在命令行里用-ExecutionPolicy Bypass参数powershell -ExecutionPolicy Bypass -File .\myscript.ps1这种方式只对当前这次执行有效不改系统设置。适合临时跑一个脚本又不想动全局配置的场景。3. 对象管道PowerShell最核心的思维方式3.1 管道传递的到底是什么前面提过PowerShell传的是对象这里展开讲清楚它到底怎么运作。在CMD里管道|传递的是文本。dir | findstr .txt的意思是把dir输出的文字一行一行喂给findstrfindstr在每一行里找包含.txt的找到就打印出来。整个过程是字符串匹配。在PowerShell里管道传递的是完整的.NET对象。Get-ChildItem | Where-Object { $_.Extension -eq .txt }的意思是Get-ChildItem返回一堆FileInfo对象每个对象带着所有属性Where-Object接收这些对象对每个对象检查它的Extension属性是否等于.txt符合条件的对象继续往下传。这个区别带来的直接好处是你不需要关心输出格式。CMD里你findstr匹配的时候得考虑dir输出的日期格式、空格数量、列对齐方式稍微换个系统语言或者换个目录匹配就失效了。PowerShell里你直接操作属性跟显示格式完全无关稳定得多。另一个好处是管道可以传任意类型的对象不只是文件。比如你查进程Get-Process | Where-Object { $_.CPU -gt 100 }Get-Process返回的是Process对象每个对象有CPU、WorkingSet、Id、ProcessName等属性。你可以按CPU排序、按内存筛选、按名称分组都是直接操作属性不需要解析文本。3.2 三个最常用的管道命令Where、Select、Sort管道里最常出现的三个命令是Where-Object、Select-Object和Sort-Object分别对应筛选、选择和排序。Where-Object用来过滤。它的简写是?完整写法是Where-Object。基本用法是Get-Service | Where-Object { $_.Status -eq Running }这行是找出所有正在运行的服务。$_是当前对象-eq是等于。常用的比较运算符还有-ne不等于、-gt大于、-lt小于、-like通配符匹配、-match正则匹配。Select-Object用来挑属性或者挑前几条。挑属性Get-Process | Select-Object Name, Id, CPU这样只显示进程名、ID和CPU三列。挑前几条Get-Process | Sort-Object CPU -Descending | Select-Object -First 10这行是按CPU降序排取前10个也就是最吃CPU的10个进程。Sort-Object用来排序简写是sort。默认升序加-Descending变降序。可以按多个属性排Get-ChildItem | Sort-Object Extension, LastWriteTime先按扩展名排扩展名相同的再按修改时间排。这三个命令组合起来基本能覆盖日常80%的数据处理需求。而且它们返回的还是对象可以继续往下传或者用Export-Csv导出成表格文件用ConvertTo-Json转成JSON。3.3 管道实战一条命令找出大文件并导出清单把前面讲的串起来做一个实际有用的东西找出某个目录下所有大于50MB的文件按大小降序排列导出成CSV。Get-ChildItem -Path D:\Downloads -Recurse -File | Where-Object { $_.Length -gt 50MB } | Sort-Object Length -Descending | Select-Object FullName, {NameSizeMB; Expression{[math]::Round($_.Length / 1MB, 2)}}, LastWriteTime | Export-Csv -Path D:\bigfiles.csv -NoTypeInformation -Encoding UTF8逐段解释一下。Get-ChildItem -Path D:\Downloads -Recurse -File是递归遍历Downloads目录下所有文件-File表示只要文件不要文件夹。Where-Object { $_.Length -gt 50MB }筛选大于50MB的。Sort-Object Length -Descending按大小降序。Select-Object里用了一个计算属性{NameSizeMB; Expression{...}}的意思是新建一个叫SizeMB的列值是把字节数除以1MB再保留两位小数。最后Export-Csv导出-NoTypeInformation去掉第一行的类型信息-Encoding UTF8保证中文路径不乱码。这条命令在CMD里要写成一个几十行的批处理还得处理各种边界情况在PowerShell里就是一条管道。这就是对象管道的价值。4. 日常运维中真正用得上的PowerShell场景4.1 文件批量处理重命名、分类、清理文件管理是PowerShell最实用的场景之一。比如你有一堆照片文件名是IMG_001.jpg这种想批量改成带日期的名字Get-ChildItem *.jpg | ForEach-Object { $newName {0:yyyyMMdd}_{1} -f $_.LastWriteTime, $_.Name Rename-Item -Path $_.FullName -NewName $newName }ForEach-Object是遍历每个对象-f是格式化字符串把修改时间按yyyyMMdd格式和原文件名拼起来然后Rename-Item重命名。执行前建议先加个-WhatIf参数预览一下会改哪些文件确认没问题再去掉-WhatIf真正执行。这个习惯能救你很多次。再比如按扩展名分类文件Get-ChildItem -File | Group-Object Extension | ForEach-Object { $folder $_.Name.TrimStart(.) if (-not (Test-Path $folder)) { New-Item -ItemType Directory -Name $folder } $_.Group | Move-Item -Destination $folder }Group-Object Extension按扩展名分组每组创建一个同名文件夹然后把该组的文件移进去。TrimStart(.)是去掉扩展名前面的点。清理旧文件也很常用。比如删除30天前的日志Get-ChildItem C:\Logs\*.log | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | Remove-Item(Get-Date).AddDays(-30)是当前时间往前推30天-lt是小于也就是修改时间早于30天前的文件。同样建议先-WhatIf预览。4.2 进程与服务管理查端口、杀进程、改启动类型查端口占用是高频需求。在CMD里你得netstat -ano | findstr :8080然后手动找PID。在PowerShell里可以一步到位Get-NetTCPConnection -LocalPort 8080 | Select-Object LocalAddress, LocalPort, State, OwningProcess拿到OwningProcess之后直接查是哪个进程Get-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess或者直接杀掉Stop-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess -Force这一串在CMD里要分好几步在PowerShell里可以嵌套着写。服务管理也很方便。查看某个服务的状态Get-Service -Name wuauserv | Select-Object Name, DisplayName, Status, StartType改启动类型为手动Set-Service -Name wuauserv -StartupType Manual启动或停止服务Start-Service -Name wuauserv Stop-Service -Name wuauserv -Force这些操作在图形界面的服务管理器里点几下也能做但如果你要对一批服务做同样的操作或者要把操作记录下来做成脚本PowerShell的优势就出来了。4.3 系统信息采集硬件、网络、磁盘一键摸清想快速了解一台机器的状况PowerShell几条命令就能搞定。看CPU和内存Get-CimInstance Win32_Processor | Select-Object Name, NumberOfCores, MaxClockSpeed Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property Capacity -SumGet-CimInstance是访问WMIWindows Management Instrumentation的现代方式能拿到几乎所有硬件信息。Win32_Processor是CPUWin32_PhysicalMemory是物理内存条Measure-Object -Sum把容量加起来。看磁盘空间Get-PSDrive -PSProvider FileSystem | Select-Object Name, {NUsedGB;E{[math]::Round($_.Used/1GB,2)}}, {NFreeGB;E{[math]::Round($_.Free/1GB,2)}}看网络配置Get-NetIPAddress -AddressFamily IPv4 | Select-Object InterfaceAlias, IPAddress, PrefixLength Get-NetAdapter | Select-Object Name, Status, LinkSpeed, MacAddress这些信息在图形界面里要翻好几个窗口才能看全在PowerShell里几行就出来了而且可以导出成报告。4.4 软件与更新管理winget与PowerShell的配合Windows 10/11自带的winget包管理器底层其实就是通过PowerShell来调用的。你可以用PowerShell批量查软件、装软件、升级软件。列出已安装的软件winget list搜索某个软件winget search python安装winget install --id Python.Python.3.12升级所有可升级的软件winget upgrade --allwinget的好处是它从官方源拉安装包比去各种下载站找exe安全得多。而且它可以在PowerShell脚本里调用实现自动化的软件部署。比如你新装一台机器写个脚本把常用软件一次性装齐省得一个个手动下载。5. 写一个能用的PowerShell脚本从需求到落地5.1 脚本的基本结构与参数定义PowerShell脚本就是扩展名为.ps1的文本文件里面写PowerShell命令。但一个“能用”的脚本和一堆命令的堆砌是两回事。好的脚本应该有参数、有注释、有错误处理。先看一个基本结构# .SYNOPSIS 清理指定目录下的旧文件 .DESCRIPTION 删除指定目录中修改时间超过指定天数的文件 .PARAMETER Path 要清理的目录路径 .PARAMETER Days 保留天数超过这个天数的文件会被删除 .EXAMPLE .\Clean-OldFiles.ps1 -Path C:\Logs -Days 30 # param( [Parameter(Mandatory$true)] [string]$Path, [Parameter(Mandatory$false)] [int]$Days 30 ) if (-not (Test-Path $Path)) { Write-Error 路径不存在: $Path exit 1 } $cutoff (Get-Date).AddDays(-$Days) $files Get-ChildItem -Path $Path -File | Where-Object { $_.LastWriteTime -lt $cutoff } if ($files.Count -eq 0) { Write-Host 没有需要清理的文件 exit 0 } $files | ForEach-Object { Write-Host 删除: $($_.FullName) Remove-Item -Path $_.FullName -Force } Write-Host 共清理 $($files.Count) 个文件这个脚本里有几个关键点。param()块定义参数[Parameter(Mandatory$true)]表示这个参数必填不填会提示。[string]和[int]是类型约束传错类型会报错。开头的注释块# ... #是帮助文档用Get-Help .\Clean-OldFiles.ps1可以查看。Test-Path检查路径是否存在Write-Error输出错误信息exit 1返回非零退出码表示失败。5.2 错误处理try-catch与-ErrorActionPowerShell默认的错误处理比较宽松很多错误只是打印一条红字就继续往下跑了。这在交互式使用没问题但在脚本里可能导致后续操作基于错误的状态继续执行产生更严重的后果。要精确控制错误行为用-ErrorAction参数。常用的值有Continue打印错误继续执行默认Stop把错误变成终止性错误可以用try-catch捕获SilentlyContinue不打印错误继续执行Ignore完全忽略比如删除文件时如果文件被占用会报错你希望脚本停下来Remove-Item -Path $file -ErrorAction Stop配合try-catchtry { Remove-Item -Path $file -ErrorAction Stop Write-Host 删除成功: $file } catch { Write-Warning 删除失败: $file原因: $($_.Exception.Message) }$_在catch块里代表错误对象$_.Exception.Message是错误信息。这样即使某个文件删不掉脚本也不会崩而是记录下问题继续处理下一个。还有一个全局设置$ErrorActionPreference可以设成Stop让整个脚本默认遇到错误就停。但这样太粗暴建议还是针对具体命令用-ErrorAction。5.3 让脚本定时跑任务计划程序与PowerShell的配合脚本写好了总不能每次手动去运行。Windows自带的任务计划程序Task Scheduler可以定时调用PowerShell脚本。用命令行创建定时任务$action New-ScheduledTaskAction -Execute pwsh.exe -Argument -NoProfile -File C:\Scripts\Clean-OldFiles.ps1 -Path C:\Logs -Days 30 $trigger New-ScheduledTaskTrigger -Daily -At 03:00 $principal New-ScheduledTaskPrincipal -UserId SYSTEM -RunLevel Highest Register-ScheduledTask -TaskName CleanOldLogs -Action $action -Trigger $trigger -Principal $principal这里-Execute pwsh.exe指定用PowerShell 7来跑-NoProfile表示不加载用户配置文件避免配置文件里的设置影响脚本-File指定脚本路径。-Daily -At 03:00是每天凌晨3点执行。-UserId SYSTEM表示以系统账户运行这样不需要用户登录也能执行-RunLevel Highest是最高权限。创建完之后可以用Get-ScheduledTask -TaskName CleanOldLogs查看用Start-ScheduledTask -TaskName CleanOldLogs手动触发一次测试。注意任务计划里跑PowerShell脚本执行策略的问题依然存在。如果脚本是从网络位置下载的可能会被拦。稳妥的做法是在脚本开头或者任务参数里加上-ExecutionPolicy Bypass。6. 那些年踩过的坑PowerShell常见问题排查6.1 中文乱码编码问题的根源与解决中文乱码是PowerShell里最烦人的问题之一。表现是脚本里的中文输出到控制台变成问号或者方块或者读取的文本文件内容乱码。根源在于编码不一致。Windows PowerShell 5.1默认使用系统ANSI编码简体中文系统是GBK而PowerShell 7默认使用UTF-8。当你用5.1写脚本保存成UTF-8运行时它按GBK去解读就乱了。反过来用7读GBK文件也会乱。解决办法有几个。第一统一用UTF-8 with BOM保存脚本文件。BOM是文件开头的几个字节用来标识编码PowerShell看到BOM就知道是UTF-8。VS Code里可以在右下角切换编码选“UTF-8 with BOM”再保存。第二在脚本开头显式设置输出编码[Console]::OutputEncoding [System.Text.Encoding]::UTF8 $OutputEncoding [System.Text.Encoding]::UTF8第三读取文件时指定编码Get-Content -Path data.txt -Encoding UTF8第四如果是从CMD里调用PowerShellCMD的代码页也会影响显示。可以先在CMD里执行chcp 65001切换到UTF-8代码页再运行PowerShell。实测下来最省心的组合是用PowerShell 7脚本存成UTF-8 with BOM文件读写都显式指定UTF8编码。这样基本不会遇到乱码。6.2 执行策略报错不同场景下的处理方式前面讲过执行策略这里补充几种常见场景的处理。场景一双击.ps1文件窗口一闪而过。这是因为默认双击是用记事本打开的或者执行完就关了。正确做法是右键选“使用PowerShell运行”或者在PowerShell窗口里.\script.ps1。场景二从网上下载的脚本跑不了报“未数字签名”。这是RemoteSigned策略在起作用。如果你信任这个脚本可以右键文件属性勾选“解除锁定”或者用Unblock-File命令Unblock-File -Path .\downloaded.ps1场景三在计划任务里跑脚本报执行策略错误。因为计划任务可能以不同用户身份运行执行策略可能不同。稳妥做法是在任务参数里加-ExecutionPolicy Bypass。场景四组策略强制了执行策略Set-ExecutionPolicy改不了。这种情况在企业环境常见需要联系管理员。临时绕过可以用-ExecutionPolicy Bypass参数但如果组策略明确禁止这个也可能被拦。6.3 命令找不到模块与路径问题有时候你照着教程敲命令报“无法将xxx识别为cmdlet、函数、脚本文件或可运行程序的名称”。这通常是几种原因。一是模块没装。很多命令来自特定模块比如Get-NetTCPConnection来自NetTCPIP模块Get-CimInstance来自CimCmdlets模块。系统自带的模块一般都有但有些需要额外安装。可以用Get-Module -ListAvailable查看已安装的模块用Install-Module装新模块。二是模块装了但没导入。PowerShell 3.0以后会自动导入常用模块但有些模块需要手动Import-Module。可以用Get-Command 命令名查看命令是否存在如果存在但用不了试试Import-Module 模块名。三是PATH环境变量问题。外部exe比如git、python如果不在PATH里PowerShell找不到。可以用$env:PATH查看当前PATH用where.exe 命令名注意是where.exe不是where因为where在PowerShell里是Where-Object的别名查找命令位置。四是32位和64位的问题。有些命令只在64位PowerShell里有如果你打开的是32位的路径在SysWOW64下面可能找不到。确认方法是在PowerShell里执行[Environment]::Is64BitProcess返回True就是64位。6.4 权限不足管理员权限与UAC的影响“拒绝访问”是另一个高频错误。PowerShell的权限继承自启动它的进程。如果你用普通用户权限打开PowerShell那里面执行的所有操作都是普通用户权限改系统目录、改注册表HKLM、改服务启动类型这些都会失败。解决办法就是以管理员身份运行PowerShell。但要注意管理员权限的PowerShell窗口和普通窗口是两个独立进程环境变量、当前目录都不共享。你在普通窗口里cd到某个目录再开管理员窗口还得重新cd。还有一个坑是UAC用户账户控制。即使你是管理员账户默认打开的PowerShell也是普通权限需要右键“以管理员身份运行”才会提权。这是Windows的安全设计防止恶意脚本悄悄提权。在脚本里如果需要提权可以用Start-Process加-Verb RunAsStart-Process pwsh -Verb RunAs -ArgumentList -File C:\Scripts\admin-task.ps1这会弹出一个UAC确认框用户点“是”之后才以管理员权限运行。这个方式适合需要用户确认的场景不适合全自动的任务。7. PowerShell还能怎么玩进阶方向与学习路径7.1 远程管理一条命令操作多台机器PowerShell的远程管理能力PowerShell Remoting是它区别于CMD的重要特性。通过WSMan或者SSH协议你可以在一台机器上执行命令作用到多台远程机器上。启用远程管理在目标机器上管理员权限Enable-PSRemoting -Force然后从管理机连接Enter-PSSession -ComputerName Server01 -Credential (Get-Credential)这会进入一个交互式会话你敲的命令实际在Server01上执行。退出用Exit-PSSession。更强大的是批量执行Invoke-Command -ComputerName Server01,Server02,Server03 -ScriptBlock { Get-Service -Name wuauserv | Select-Object Status }这会在三台机器上同时执行返回结果带机器名标识。对于管理多台服务器的场景这个能力比一台台远程桌面上去操作效率高太多。不过远程管理涉及网络配置、认证、防火墙等在企业环境里通常需要域环境支持。如果是工作组环境配置起来会麻烦一些需要配置TrustedHosts或者用HTTPS。7.2 与WMI/CIM的深度结合WMIWindows Management Instrumentation是Windows的底层管理接口几乎所有的硬件信息、系统配置、事件日志都能通过它访问。PowerShell通过Get-CimInstance推荐和Get-WmiObject旧版来调用WMI。举几个实用的例子。查系统启动时间(Get-CimInstance Win32_OperatingSystem).LastBootUpTime查已安装的软件列表Get-CimInstance Win32_Product | Select-Object Name, Version, Vendor不过Win32_Product有个坑查询它会触发MSI的重新配置检查可能导致某些软件弹出修复界面速度也慢。更好的方式是用注册表Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher | Where-Object { $_.DisplayName -ne $null }查事件日志Get-CimInstance Win32_NTLogEvent -Filter LogfileSystem AND EventType1 | Select-Object -First 20 TimeGenerated, SourceName, MessageEventType1是错误级别的事件。这个在排查系统问题时很有用。7.3 学习资源与进阶路线建议PowerShell的学习曲线其实不算陡但知识面很广。我的建议是分阶段来。第一阶段把CMD常用命令换成PowerShell写法。dir、cd、copy、del这些在PowerShell里都有别名先用起来。然后学Get-ChildItem、Get-Process、Get-Service、Get-Content这几个最常用的原生命令。第二阶段掌握管道三件套Where-Object、Select-Object、Sort-Object以及ForEach-Object。这四个命令能解决大部分数据处理需求。第三阶段学写脚本包括param()定义参数、try-catch错误处理、函数定义。能写出带参数的、可复用的脚本。第四阶段学模块和远程管理。了解Import-Module、Install-Module了解Invoke-Command和Enter-PSSession。学习资源方面微软官方的文档docs.microsoft.com/powershell是最权威的每个命令都有详细说明和示例。在PowerShell里用Get-Help 命令名 -Full可以看完整帮助Get-Help 命令名 -Examples只看示例。另外Get-Command可以列出所有可用命令Get-Member可以查看对象的属性和方法这两个是探索式学习的神器。遇到问题的时候Get-Help和搜索引擎基本能解决90%的问题。剩下的10%可能需要看源码或者去社区问。PowerShell的社区很活跃GitHub上的PowerShell仓库、各种技术论坛都有大量讨论。最后说一个心态问题。PowerShell的命令和参数确实多不可能全记住。不需要背需要的时候查就行。重要的是理解它的思维方式——对象管道、命令命名规范动词-名词、参数化——理解了这些具体命令查一下就会用。我用了这么多年常用的也就那几十个其他的都是用到再查。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门