如何从批处理文件中运行PowerShell脚本

264

我正尝试在PowerShell中运行这个脚本。我已将以下脚本保存为ps.ps1并放在我的桌面上。

$query = "SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2"
Register-WMIEvent -Query $query -Action { invoke-item "C:\Program Files\abc.exe"}

我已经制作了一个批处理脚本来运行这个PowerShell脚本。

@echo off
Powershell.exe set-executionpolicy remotesigned -File  C:\Users\SE\Desktop\ps.ps1
pause

但是我遇到了这个错误:

在此输入图片描述


请注意,如果您在执行脚本时出现奇怪的错误,而在从PowerShell中调用脚本时却可以正常工作,则可能需要在批处理文件中使用pwsh.exe而不是powershell.exe。 简单解释:powershell.exe是v5.1-,而pwsh.exe是6.0+。更多信息 - ruffin
9个回答

355

您需要使用 -ExecutionPolicy 参数:

Powershell.exe -executionpolicy remotesigned -File  C:\Users\SE\Desktop\ps.ps1
否则,PowerShell会将参数视为要执行的代码行。尽管Set-ExecutionPolicy是一个cmdlet,但它没有-File参数。

1
你不需要以管理员身份运行才能更改执行策略吗?因为我认为它会更改注册表中的一个条目。 - Kellen Stuart
1
@KolobCanyon:要更改它,您需要成为管理员。但是上面的操作并不会更改它,它只是指定给定实例的执行策略应该是什么。 - Joey
3
哈哈,所以实际上您可以在不成为管理员的情况下重写此策略。这是一个安全问题吗? - Kellen Stuart
4
如果你有运行 PowerShell 的权限,那么你几乎可以做任何其他事情。请注意,执行策略并不意味着 PowerShell 比它本来具有的权限更多。在某种程度上,它仅仅是一种便利,以避免意外运行你可能不想运行的内容。类似于在当前目录中添加 ./ 前缀和在 Unix 上设置可执行标志。 - Joey
1
@Rajeev:不是的。虽然在Linux上,你可能需要使用pwsh,全部小写。 - Joey
显示剩余2条评论

143

我在我的博客文章中解释了为什么要从批处理文件中调用PowerShell脚本以及如何实现。您可以在这里找到。

基本上,这就是您要寻找的内容:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& 'C:\Users\SE\Desktop\ps.ps1'"

如果你需要以管理员身份运行PowerShell脚本,可以使用以下命令:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""C:\Users\SE\Desktop\ps.ps1""' -Verb RunAs}"

但我建议不要将整个PowerShell脚本的路径硬编码,而是将批处理文件和PowerShell脚本文件放在同一个目录中,就像我的博客文章所描述的那样。


当我在cmd窗口中键入命令行时,Invoke-WebRequest正常工作,但每当我从批处理文件中运行它时,它返回404。我正在尝试PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass Invoke-WebRequest https://www.example.com/example.ics -OutFile C:\_my\script.ics' -Verb RunAs}";powershell -Command "Invoke-WebRequest https://www.example.com/example.ics -OutFile c:\_my\file.ics",或使用-File选项将其保存在.ps1文件中,或(New-Object Net.WebClient).DownloadFile。有什么想法吗? - Chris
尝试使用-ExecutionPolicy Unrestricted。我猜Bypass选项不会给PowerShell网络访问权限。 - deadlydog

32

如果你想在不使用完全限定路径的情况下从当前目录运行,可以使用:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& './ps.ps1'"

22

如果你运行一个调用PowerShell的批处理文件作为管理员,最好像这样运行它,这样可以避免所有麻烦:

powershell.exe -ExecutionPolicy Bypass -Command "Path\xxx.ps1"

最好使用Bypass...


10
这样可以让批处理文件中包含PowerShell代码(保存为test.cmd或test.bat)。
<# :
  @echo off
    powershell /nologo /noprofile /command ^
        "&{[ScriptBlock]::Create((cat """%~f0""") -join [Char[]]10).Invoke(@(&{$args}%*))}"
  exit /b
#>

Write-Host Hello, $args[0] -fo Green
# * Your program goes here * ...

1
非常酷的技巧。[Char[]]10是什么?它有任何限制吗? - jackhab
[%~f0]表示调用者的完全限定路径名(Fully-Qualified Path Name of Invoker)(参考链接:https://dev59.com/9JTfa4cB1Zd3GeqPSY5n#35685743)。`@( )是数组子表达式运算符,$( )是子表达式运算符。(参考链接:https://ss64.com/ps/syntax-operators.html)。$args`表示传递给脚本或函数的参数。(参考链接:https://ss64.com/ps/syntax-args.html) - JGFMK
这是一个很棒的解决方案,因为它支持 Read-Host 和你传递给它的参数! - xjcl
@jackhab [Char[]]10 是第十个ASCII字符,即 \n(换行符)。 - xjcl
@jackhab [Char[]]10 是第十个ASCII字符,即 \n。这是因为 cat/Get-Content 将文件读取为字符串列表,所以需要使用换行符进行连接。一个更简单的替代方法是只需 cat -Raw '%~f0',则不需要进行连接 :) - xjcl

6

我也在这里发布了:如何在批处理文件中运行PowerShell命令

遵循这个线程:
https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/converting-powershell-to-batch


你可以使用此PowerShell函数将任何PowerShell脚本轻松转换为批处理文件:

function Convert-PowerShellToBatch
{
    param
    (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [string]
        [Alias("FullName")]
        $Path
    )
 
    process
    {
        $encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes((Get-Content -Path $Path -Raw -Encoding UTF8)))
        $newPath = [Io.Path]::ChangeExtension($Path, ".bat")
        "@echo off`npowershell.exe -NoExit -encodedCommand $encoded" | Set-Content -Path $newPath -Encoding Ascii
    }
}


要将目录中所有的PowerShell脚本转换,只需运行以下命令:

Get-ChildItem -Path <DIR-PATH> -Filter *.ps1 |
  Convert-PowerShellToBatch

其中“path”是所需文件夹的路径。例如:

Get-ChildItem -Path "C:\path\to\powershell\scripts" -Filter *.ps1 |
  Convert-PowerShellToBatch


要将一个 PowerShell 脚本转换为简体中文,只需运行以下命令:

Get-ChildItem -Path <FILE-PATH> |
  Convert-PowerShellToBatch

其中的路径是指所需文件的路径。

转换后的文件位于源目录中。即,<FILE-PATH><DIR-PATH>

将它们结合起来:
创建一个.ps1文件(PowerShell脚本),其中包含以下代码:

function Convert-PowerShellToBatch
{
    param
    (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [string]
        [Alias("FullName")]
        $Path
    )
 
    process
    {
        $encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes((Get-Content -Path $Path -Raw -Encoding UTF8)))
        $newPath = [Io.Path]::ChangeExtension($Path, ".bat")
        "@echo off`npowershell.exe -NoExit -encodedCommand $encoded" | Set-Content -Path $newPath -Encoding Ascii
    }
}

# change <DIR> to the path of the folder in which the desired powershell scripts are.
# the converted files will be created in the destination path location (in <DIR>).
Get-ChildItem -Path <DIR> -Filter *.ps1 |
  Convert-PowerShellToBatch

不要忘记,如果你只想转换一个文件而不是多个文件,可以替换以下内容。
Get-ChildItem -Path <DIR> -Filter *.ps1 |
  Convert-PowerShellToBatch

用这个:

Get-ChildItem -Path <FILE-PATH> |
  Convert-PowerShellToBatch

就像我之前解释的那样。


3

如果您想运行一些脚本,可以使用Set-executionpolicy -ExecutionPolicy Unrestricted,然后用Set-executionpolicy -ExecutionPolicy Default重新设置。

请注意,执行策略仅在启动其执行时检查(或者似乎是这样),因此您可以在后台运行作业并立即重置执行策略。

# Check current setting
Get-ExecutionPolicy

# Disable policy
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
# Choose [Y]es

Start-Job { cd c:\working\directory\with\script\ ; ./ping_batch.ps1 example.com | tee ping__example.com.txt }
Start-Job { cd c:\working\directory\with\script\ ; ./ping_batch.ps1 google.com  | tee ping__google.com.txt  }

# Can be run immediately
Set-ExecutionPolicy -ExecutionPolicy Default
# [Y]es

3

另一种从批处理中执行ps脚本的简单方法是将其直接放置在ECHO和重定向字符之间(>和>>),例如:

@echo off
set WD=%~dp0
ECHO New-Item -Path . -Name "Test.txt" -ItemType "file" -Value "This is a text string." -Force > "%WD%PSHELLFILE.ps1"
ECHO add-content -path "./Test.txt" -value "`r`nThe End" >> "%WD%PSHELLFILE.ps1"
powershell.exe -ExecutionPolicy Bypass -File "%WD%PSHELLFILE.ps1"
del "%WD%PSHELLFILE.ps1"

最后一行删除了创建的临时文件。


这个方法可以运行,但是会显示一个空的CMD窗口。有没有办法显示PowerShell的输出结果? - Tomblarom

1
如果你的 PowerShell 登录脚本在 2012 服务器上延迟了 5 分钟(就像我的情况),那么服务器上有一个组策略设置 - '配置登录脚本延迟',默认设置为 '未配置',这会导致登录脚本延迟 5 分钟后才执行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接