ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PowerShell禁止运行脚本全解析:从执行策略原理到解决方案

PowerShell禁止运行脚本全解析:从执行策略原理到解决方案 “因为在此系统上禁止运行脚本”——如果你经常折腾PowerShell大概率被这句话拦过路。网上搜一圈答案五花八门有让你改注册表的有让你敲一堆命令的搞了半天也没弄明白为什么自己照着做就是不行。这篇文章我就把这个“禁止运行脚本”的来龙去脉一次讲透从最根上的机制原理到不同场景下最省事的处理办法再到你大概率会踩的隐藏坑全部给你捋清楚。内容适合刚接触PowerShell的新手也适合被这个问题反复折磨的运维和开发同学。1. 先弄明白PowerShell到底在防什么执行策略机制拆解1.1 执行策略不是安全边界很多人有个误解觉得PowerShell的执行策略ExecutionPolicy是一道安全墙设置成Restricted就能拦住病毒、拦住恶意脚本。这句话只对了一半。执行策略本质上更像一道“安全提示门”它的核心目的不是阻止恶意代码运行而是防止你在不知情的情况下双击运行了一个来源不明的.ps1脚本。它管的是“允许什么类型的脚本能在本机运行”而不是“脚本里面写了什么能不能跑”。在Windows系统里.ps1文件默认是用记事本关联打开的而不是像.exe那样直接双击执行。这个设计本身就说明微软的意图脚本应该被查看、被审阅而不是被蒙着头直接跑。执行策略是第二道闸门即便你把脚本内容看完了、确认没问题如果策略不允许照样跑不起来。1.2 从Restricted到Bypass执行策略的六个等级PowerShell的执行策略一共有六个取值从最严格到最宽松依次是策略含义典型使用场景Restricted禁止运行任何.ps1脚本只能交互式输入命令Windows客户端默认值AllSigned所有脚本必须有受信任的签名才能运行对安全要求较高的生产环境RemoteSigned本地创建的脚本可以直接跑从网上下载的脚本必须带签名最常见的推荐配置Unrestricted所有脚本都能运行但下载的脚本运行前会弹窗提醒个人开发环境Bypass所有脚本都能运行不弹窗、不提醒、无任何限制临时跑一次性脚本、自动化任务Undefined未设置会继承上一层作用域的策略需要清除某个作用域设置时这里要特别说明RemoteSigned的“本地”和“远程”判定标准不是看你脚本存放在哪个文件夹而是看脚本文件是否带有“来自互联网”的Zone.Identifier标记。你自己用记事本、VS Code新建的脚本没有这个标记属于“本地创建”从浏览器下载的脚本即便只是用U盘拷到另一台电脑只要文件属性里有“解除锁定”选项就被判定为“远程文件”。1.3 为什么要设计这么多层策略这就要说到PowerShell的执行策略其实是分作用域Scope的。它不是一个全局开关而是像一层一层的配置文件从高到低优先级分别是MachinePolicy —— 组策略计算机策略机器级优先级最高UserPolicy —— 组策略用户策略Process —— 当前进程最临时关掉窗口就没了CurrentUser —— 当前用户写注册表HKCULocalMachine —— 本机所有用户写注册表HKLM查询的时候用Get-ExecutionPolicy -List就能看到每一层的状态。绝大多数“改了不生效”的问题都是因为你在CurrentUser或LocalMachine层设了值但实际上某个更高优先级的层还有一个未定义的设置导致你设置的策略没被采用。2. 实操篇处理“禁止运行脚本”的几种典型场景2.1 第一次跑脚本按部就班修改执行策略如果你只是在自己电脑上跑几个自己写的或者同事发的脚本不需要搞得太复杂。我的建议是直接给当前用户设置RemoteSigned而不是给本机所有用户设置。右键开始菜单打开“Windows PowerShell管理员”或者直接在任务栏搜索PowerShell右键选择“以管理员身份运行”执行下面的命令Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned系统会弹出一个确认提示输入Y回车即可。设置完可以用Get-ExecutionPolicy -List验证一下如果看到CurrentUser这一行是RemoteSigned就说明配置成功了。这里有一个小细节-Scope CurrentUser和-Scope LocalMachine的区别。LocalMachine是写HKLM注册表影响这台机器上的所有用户CurrentUser只写HKCU只影响当前登录账号。个人电脑用CurrentUser就够了而且不需要管理员权限LocalMachine必须管理员权限也更安全。如果你在公司的域环境里LocalMachine这层建议别动出了问题域策略可能会被刷新覆盖。2.2 不想改系统设置一条命令临时绕过有时候你只是临时要跑一个脚本不想给系统留下永久性的策略修改也不想因为这个改动去和公司的安全团队解释半天。这时候有个更优雅的做法在启动PowerShell进程的时候通过参数临时指定执行策略。powershell -ExecutionPolicy Bypass -File C:\path\to\script.ps1这个命令的意思是启动一个新的PowerShell进程在这个进程里执行策略是Bypass脚本随便跑一点限制都没有。关键点是这个设置只在当前这个PowerShell进程的生命周期内有效进程退出后一切恢复原样。如果你已经在一个PowerShell窗口里想以Bypass策略运行某个脚本可以这样写Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass-Scope Process这层是临时作用域设置完只在当前这个控制台窗口有效关闭窗口自动失效非常适合“这次我想跑一下但不想改动系统”的场景。2.3 在批处理里调用PowerShell脚本怎么处理策略问题实际工作里经常会有这样的需求在.bat批处理文件里调用一个.ps1脚本做成双击就能运行的效果。如果用默认方式调用一样会撞上执行策略限制。正确的写法是这样echo off powershell -NoProfile -ExecutionPolicy Bypass -File %~dp0deploy.ps1这里两个参数值得说明一下。-NoProfile是跳过PowerShell的配置文件加载用来自定义环境变量的Profile脚本偶尔会影响执行环境-ExecutionPolicy Bypass是临时放开执行策略。用这种方式你不需要预先去改系统的执行策略批处理双击就能直接跑脚本。如果写成powershell -File %~dp0deploy.ps1没有后面的策略参数那就会撞上系统默认的Restricted限制。很多程序员写的bat脚本同事双击后莫名其妙报错就是这个原因。3. 你以为只有执行策略还有这些常见的拦路虎3.1 “无法将xxx项识别为cmdlet、函数、脚本文件或可运行程序的名称”这个报错和“禁止运行脚本”完全是两码事但经常被混在一起讨论。它出现的原因很简单你要执行的命令在当前的PATH环境变量里找不到。我见过最多的情况是装完Git后在PowerShell里输入git报这个错装完Node.js后输入npm报这个错用pip装完某个Python包输入对应的命令报这个错装了Maven后输入mvn报这个错本质都是同一个原因可执行文件的路径没有加到系统PATH里或者PowerShell是旧的实例没加载到最新的PATH环境变量。排查思路异常简单先用where.exe git看系统能不能找到git再用echo $env:PATH看当前会话的PATH里有没有包含git的安装目录。如果发现PATH里没有就去“系统设置 → 高级系统设置 → 环境变量”把对应工具的可执行文件目录加到Path变量里。加完必须要新开一个PowerShell窗口才生效老窗口是不会自动刷新的。如果确认PATH正确新窗口里还是报“无法识别”大概率是没重启终端直接重开窗口测试即可。3.2 脚本文件被系统“隔离”了取消互联网标记这一条是最隐蔽的坑。你从网上下载了一个脚本放到本地后发现运行不了即便执行策略已经是RemoteSigned了系统还是会在你运行的时候弹出一条“来自另一台计算机的文件已被阻止”的警告甚至干脆直接拒绝运行。原因在于Windows有一个“附件管理器”的机制标记了所有从Internet下载的文件。被标记的文件哪怕内容是纯文本的.ps1也会带上一个Zone.Identifier的备用数据流。解决办法是先看文件的标记。右键脚本文件选“属性”如果最底部有“解除锁定”复选框勾选后点确定即可。如果嫌一个一个解除锁定太麻烦可以用一条命令批量清理当前目录下所有ps1文件的MarkGet-ChildItem -Path C:\scripts\*.ps1 | Unblock-FileUnblock-File这个cmdlet就是专门干这个事的能批量移除文件的Zone.Identifier标记让它被系统识别为“本地创建的文件”。这个步骤做完RemoteSigned策略下就能正常跑了。3.3 管理员权限和脚本执行保护除了执行策略有些脚本本身就要求以管理员身份运行比如你想通过脚本修改系统服务、写入Program Files目录、操作IIS配置这些操作需要提权。PowerShell在普通权限下即使脚本内容合法也会在调用相关API时报“拒绝访问”的错看起来像是脚本执行受限实际上是你权限不够。这时需要右键PowerShell图标选择“以管理员身份运行”再执行脚本。这也是为什么我在前面第2节里特别强调设置执行策略时要用管理员身份开一个PowerShell窗口。另外有一种情况是Win10/Win11的安全中心会拦截下载的脚本文件。如果你在“Windows安全中心 → 应用和浏览器控制 → 智能应用控制”里开启了强保护模式脚本文件即使没有Zone标记也可能会被拦截。遇到这种情况建议临时关闭Smart App Control或者用-ExecutionPolicy Bypass参数运行。4. 从零到一PowerShell脚本从“被禁止”到“正常运行”的完整实操4.1 场景一全新Win10/11环境第一次跑.ps1部署脚本假设你刚从公司拿到一台新电脑准备跑一个本地的环境初始化脚本。目前系统的执行策略是默认的Restricted任何脚本都跑不了。你也不想为了跑一个脚本就给电脑开太多的权限核弹。我的处理顺序是这样的第一步先在PowerShell里确认当前策略状态Get-ExecutionPolicy -List第二步给当前用户设置RemoteSignedSet-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force加-Force是为了跳过那个“是否要更改执行策略”的交互确认脚本化的操作里特别好用。第三步验证脚本是否正常运行.\init.ps1这里.前缀很重要。在PowerShell里直接输入脚本名系统不会自动去当前目录找。必须在脚本名前加上.\代表“当前目录下的这个文件”跟Linux的./一个道理。这一步的报错“不是内部或外部命令也不是可运行的程序或批处理文件”其实和“禁止运行脚本”不同就是没用对路径访问符。4.2 场景二批量部署想要在所有机器上统一放开策略如果你要帮公司部署一批机器手动一台台设置很累。可以用本地组策略统一配置或者通过命令批量推。我常用的方式是在PowerShell里用Invoke-Command远程批量执行$computers (PC01, PC02, PC03) Invoke-Command -ComputerName $computers -ScriptBlock { Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned -Force }注意这里需要远端机器开启WinRM服务而且要用有管理员权限的域账号执行。如果只是几台机器也可以用psexec \\PC01 powershell -command Set-ExecutionPolicy RemoteSigned -Force这种方式但psexec在部分环境里会被杀毒软件拦截不是首选。对于域环境更正规的做法是配置组策略计算机配置 → 管理模板 → Windows 组件 → Windows PowerShell → 打开脚本执行。设置为“允许本地脚本和远程签名脚本”。这样域内所有电脑会自动生效不需要逐个登录处理。4.3 场景三开机自启脚本怎样绕开策略又能稳定运行很多做自动化的人会把PowerShell脚本挂到开机自启里。最常见的方式是放到启动文件夹shell:startup但直接放.ps1文件开机时只会弹出一个记事本窗口根本不会执行脚本。你必须放一个.bat或者一个快捷方式然后通过参数调用PowerShell执行脚本。我在实际方案里是这样做的先创建脚本放在稳定路径比如C:\Scripts\startup-task.ps1。然后在启动文件夹放一个run-startup.bat文件内容如下echo off powershell -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\startup-task.ps1这样开机后bat会被执行进而调用PowerShell运行脚本。-ExecutionPolicy Bypass参数在这个场景里就很有用了因为启动文件夹里的bat任务是系统登录时启动的如果你没有提前配置执行策略就可能因为Restricted默认值弹报错。加上Bypass参数后就不会有任何干扰。如果你需要开机自启的任务涉及多步骤更好的做法是用任务计划程序。创建一个基本任务触发器选“登录时”操作选“启动程序”程序填powershell.exe添加参数-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\startup-task.ps1。任务计划程序的好处是可以用SYSTEM账户运行还能设置“不管用户是否登录都要运行”比启动文件夹更可靠。5. 常见问题速查照着这张表排查就够了下面这个表是我在实际操作中积累的排查经验遇到类似问题可以直接照着查报错或现象根本原因快速解决因为在此系统上禁止运行脚本ExecutionPolicy是RestrictedSet-ExecutionPolicy -Scope CurrentUser RemoteSigned已成功更新执行策略但在更具体的作用域中定义的策略组策略MachinePolicy/UserPolicy层覆盖了当前设置用rsop.msc查看哪个策略对象覆盖了去组策略层面修改无法将git/npm/mvn识别为cmdletPATH环境变量未配置或配置后未重开终端检查系统PATH重开PowerShell窗口运行下载的脚本报“未能加载文件或程序集”脚本文件带Zone.Identifier标记属性里勾选解除锁定或Unblock-File.ps1文件双击后自动用记事本打开系统默认关联就是记事本不会执行脚本右键 → 使用PowerShell运行或通过cmd/bat调用脚本报“系统找不到指定的路径”脚本内部相对路径错误脚本开头先cd $PSScriptRoot提示“未对文件进行数字签名”AllSigned策略下脚本没有有效签名临时改RemoteSigned或对脚本签名PowerShell窗口运行正常bat调用时报错bat里没有加-ExecutionPolicy Bypass在调用命令中显式指定策略设置执行策略时报参数错误用了32位/64位PowerShell混用统一用64位PowerShell或者设置时同时检查两个版本安装PowerShell 5.1失败错误码-2146869246通常和.NET Framework版本或WMF包冲突有关先升级到.NET 4.5或通过“程序和功能”检查WMF是否已存在5.1 最容易被忽略的坑32位和64位PowerShell的执行策略不互通这个坑我踩过不止一次。电脑上有两个PowerShell一个是C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe64位一个是C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe32位。我个人在多个32位工具配合PowerShell二开时遇到过在64位窗口里把执行策略改成了RemoteSigned结果某个老程序调用32位PowerShell跑脚本依然报“禁止运行脚本”。因为两个版本各自维护着独立的执行策略配置。设置的时候最好两个都设置一遍# 64位 Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force # 32位 C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -Command Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force同理如果你在用VS Code的集成终端也要注意它默认调的是哪个版本的PowerShell。可以在VS Code里按CtrlShiftP输入“Terminal: Select Default Profile”查看当前默认终端避免在自己没意识到的情况下换了个架构环境。5.2 脚本编码和中文乱码和“禁止运行”一样常见但没人说除了执行策略另一个高频吐槽点是脚本内容本身没毛病但里面的中文全部变成了乱码导致脚本逻辑判断出错。尤其是在PowerShell 5.1里脚本文件的编码处理方式比较老旧。比如你用VS Code写了一个.ps1脚本保存时默认用的是UTF-8带BOM或者不带BOM。Windows PowerShell 5.1对无BOM的UTF-8文件默认会尝试用系统ANSI代码页在中文系统里就是GBK/GB2312去解析然后里面所有中文字符串就全部乱套了。最靠谱的解决方案有两个第一个写脚本时在文件开头加上[Console]::OutputEncoding [System.Text.Encoding]::UTF8第二个推荐安装更高版本的PowerShell 7它默认使用UTF-8处理脚本文件不乱码、不报错和PowerShell 5.1完全兼容还能用更多新语法。如果你不想安装新版本那就在VS Code保存的时候设置成“UTF-8 with BOM”编码。BOM这个标记会告诉Windows PowerShell“别猜了我这里是UTF-8”这样中文就能正常显示了。5.3 关于PowerShell 7和5.1的兼容顺带说一嘴很多同学用着用着会想升级PowerShell版本然后在网上下载PowerShell 5.1安装包时出错。实际上Win10/11自带的Windows PowerShell 5.1已经足够稳定能解决95%的日常脚本执行问题。如果你想要更好的跨平台支持、更丰富的语法比如三元运算符、并行循环那么装PowerShell 7更值得。安装PowerShell 7之后要注意它的默认执行策略和Windows PowerShell 5.1是各自独立的不会继承你之前给5.1设置过的策略。所以升级完PowerShell 7之后你可能还得重新设置一次执行策略否则一样会报“禁止运行脚本”。在PowerShell 7里查看和设置执行策略的命令和5.1完全一样Get-ExecutionPolicy -List Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force而且PowerShell 7安装后新版终端会默认使用它蓝白配色也变成了蓝黑配色一眼就能看出来。6. 收尾两个能显著提升效率的小技巧最后再分享我实际使用中的两个固定操作。第一个我习惯在开发机全局用一个初始化脚本把常用函数和自动化脚本的目录都注册好。这个脚本会在每次打开PowerShell时自动加载。但如果你默认执行策略限制太严PowerShell配置文件也会被禁止运行导致自定义的函数和别名全都没了。所以我先把执行策略设成RemoteSigned再在Profile文件里集中管理这些设置。这样打开任何PowerShell窗口该有的环境都在不用每次重新配。如果不想走Profile流程也可以用-NoProfile参数临时绕过但那样就别再抱怨为什么命令用不了了。第二个为了避免“到处改策略”带来的风险我强烈建议区分电脑角色。个人开发机、测试机可以设成RemoteSigned甚至Bypass都行方便折腾。但生产服务器、域控制器保持Restricted或AllSigned脚本全部走签名流程。这一条如果执行到位能少很多被安全团队找喝茶的麻烦。改执行策略这件事本身不复杂复杂的是一堆连锁反应。把原理弄明白剩下的就是见招拆招。希望这篇文章能一次帮到你。
返回列表