从Powershell ISE中的另一个PS1脚本调用PowerShell脚本PS1


137

我想在Powershell ISE中的第二个myScript2.ps1脚本中调用myScript1.ps1脚本的执行。

MyScript2.ps1中的以下代码在Powershell管理中正常运行,但在PowerShell ISE中不起作用:

#Call myScript1 from myScript2
invoke-expression -Command .\myScript1.ps1

从PowerShell ISE执行MyScript2.ps1时,出现以下错误:

无法将术语“。\ myScript1.ps1”识别为cmdlet,函数,脚本文件或可运行程序的名称。检查名称的拼写,或者是否包含路径,请验证路径是否正确,然后重试。

Answers:


83

为了找到脚本的位置,请使用Split-Path $MyInvocation.MyCommand.Path(确保在脚本上下文中使用此位置)。

此示例脚本可以说明您应使用该原因而不是其他任何原因。

## ScriptTest.ps1
Write-Host "InvocationName:" $MyInvocation.InvocationName
Write-Host "Path:" $MyInvocation.MyCommand.Path

这是一些结果。

PS C:\ Users \ JasonAr>。\ ScriptTest.ps1
InvocationName:。\ ScriptTest.ps1
路径:C:\ Users \ JasonAr \ ScriptTest.ps1

PS C:\ Users \ JasonAr> 。\ ScriptTest.ps1
InvocationName:。
路径:C:\ Users \ JasonAr \ ScriptTest.ps1

PS C:\ Users \ JasonAr>&“。\ ScriptTest.ps1”
调用名称:&
路径:C:\ Users \ JasonAr \ ScriptTest.ps1

PowerShell 3.0和更高版本中,您可以使用自动变量$PSScriptRoot

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C:\ Users \ jarcher>。\ ScriptTest.ps1
脚本:C:\ Users \ jarcher \ ScriptTest.ps1
路径:C:\ Users \ jarcher

最近添加的内容:如果您担心自动变量的变化(或者,实际上,只需要“固定”代码),则可能要使用“写输出”而不是“写主机”。
KlaymenDK

20
最好在答案中看到使用分割路径的示例。您还需要显示确实在另一个脚本中调用一个脚本。
杰里米

37

MyScript1.ps1的当前路径与myScript2.ps1不同。您可以获取MyScript2.ps1的文件夹路径,并将其连接到MyScript1.ps1,然后执行它。两个脚本必须位于同一位置。

## MyScript2.ps1 ##
$ScriptPath = Split-Path $MyInvocation.InvocationName
& "$ScriptPath\MyScript1.ps1"

我该如何初始化$ MyInvocation变量?
Nicola Celiento

您没有,这是一个自动变量。
谢伊·利维

它可以工作,但是在实际执行被调用脚本之前会遇到以下错误:Split-Path:由于参数为空字符串,因此无法将参数绑定到参数“ Path”。在第4行:25个字符:25 + $ ScriptPath =拆分路径<<<< $ MyInvocation.InvocationName + CategoryInfo:InvalidData:(:) [Split-Path],ParameterBindingValidationException + FullyQualifiedErrorId:ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento 2011年

创建一个新脚本,在其中放置$ MyInvocation.InvocationName并运行该脚本。您是否获得了脚本的路径?
谢伊·利维

@JasonMArcher-为什么相反?据我所知,两者给出相同的输出?
manojlds 2011年

35

我正在从myScript2.ps1调用myScript1.ps1。

假设两个脚本都在同一位置,请首先使用以下命令获取脚本的位置:

$PSScriptRoot

然后,像这样添加您要调用的脚本名称:

& "$PSScriptRoot\myScript1.ps1"

这应该工作。


3
& "$PSScriptRoot\myScript1.ps1"够了
Guoweihui '18

19

一线解决方案:

& ((Split-Path $MyInvocation.InvocationName) + "\MyScript1.ps1")

很好,但是为什么不只& '.\MyScript1.ps'将脚本驻留在同一目录中呢?
JoePC '19

3
那是使用当前目录而不是脚本目录。当然,他们经常是相同的...但并非总是如此!
noelicus

9

这只是答案的附加信息,以便将参数传递到另一个文件中

你在哪里争论

PrintName.ps1

Param(
    [Parameter( Mandatory = $true)]
    $printName = "Joe"    
)


Write-Host $printName

如何调用文件

Param(
    [Parameter( Mandatory = $false)]
    $name = "Joe"    
)


& ((Split-Path $MyInvocation.InvocationName) + "\PrintName.ps1") -printName $name

如果您不提供任何输入,它将默认为“ Joe”,并将作为参数传递给PrintName.ps1文件中的printName参数,文件将依次打印出“ Joe”字符串


4

您可能已经找到了答案,但这是我的工作。

我通常将此行放在安装脚本的开头:

if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } #In case if $PSScriptRoot is empty (version of powershell V.2).  

然后,我可以使用$ PSScriptRoot变量作为当前脚本(路径)的位置,如下面的示例所示:

if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } #In case if $PSScriptRoot is empty (version of powershell V.2).  

Try {
If (Test-Path 'C:\Program Files (x86)') {
    $ChromeInstallArgs= "/i", "$PSScriptRoot\googlechromestandaloneenterprise64_v.57.0.2987.110.msi", "/q", "/norestart", "/L*v `"C:\Windows\Logs\Google_Chrome_57.0.2987.110_Install_x64.log`""
    Start-Process -FilePath msiexec -ArgumentList $ChromeInstallArgs -Wait -ErrorAction Stop
    $Result= [System.Environment]::ExitCode
} Else {
    $ChromeInstallArgs= "/i", "$PSScriptRoot\googlechromestandaloneenterprise_v.57.0.2987.110.msi", "/q", "/norestart", "/L*v `"C:\Windows\Logs\Google_Chrome_57.0.2987.110_Install_x86.log`""
    Start-Process -FilePath msiexec -ArgumentList $ChromeInstallArgs -Wait -ErrorAction Stop
    $Result= [System.Environment]::ExitCode
    }

} ### End Try block


Catch  {
    $Result = [System.Environment]::Exitcode
    [System.Environment]::Exit($Result)
   }
[System.Environment]::Exit($Result)

根据您的情况,您可以更换

开始过程...

调用表达式$ PSScriptRoot \ ScriptName.ps1

您可以在Microsoft网站上了解有关$ MYINVOCATION和$ PSScriptRoot自动变量的更多信息:https ://msdn.microsoft.com/zh-cn/powershell/reference/5.1/microsoft.powershell.core/about/about_about_automatic_variables


4

要轻松地在与调用者相同的文件夹(或子文件夹)中执行脚本文件,可以使用以下命令:

# Get full path to the script:
$ScriptRoute = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, "Scriptname.ps1"))

# Execute script at location:
&"$ScriptRoute"

3

我对此有疑问。我没有使用任何聪明的$MyInvocation东西来修复它。如果通过右键单击脚本文件并选择,edit然后从ISE中打开第二个脚本来打开ISE,则只需使用常规。\ script.ps1语法即可调用另一个脚本。我的猜测是,ISE具有当前文件夹的概念,像这样打开它会将当前文件夹设置为包含脚本的文件夹。当我在正常使用中从另一个脚本中调用一个脚本时,我只是使用。\ script.ps1,IMO修改脚本以使其在ISE中正常工作是错误的...


2

我有一个类似的问题,并以此方式解决了。

我的工作目录是通用脚本文件夹和服务器根目录中的特定脚本文件夹,我需要调用特定脚本文件夹(该脚本文件夹使用特定问题的参数调用通用脚本)。所以工作目录是这样的

\Nico\Scripts\Script1.ps1
             \Script2.ps1
      \Problem1\Solution1.ps1
               \ParameterForSolution1.config
      \Problem2\Solution2.ps1
               \ParameterForSolution2.config

Solutions1和Solutions2在Scripts文件夹中调用PS1,加载存储在ParameterForSolution中的参数。因此,在powershell ISE中,我运行此命令

.\Nico\Problem1\Solution1.PS1

Solution1.PS1中的代码是:

# This is the path where my script is running
$path = split-path -parent $MyInvocation.MyCommand.Definition

# Change to root dir
cd "$path\..\.."

$script = ".\Script\Script1.PS1"

$parametro = "Problem1\ParameterForSolution1.config"
# Another set of parameter Script1.PS1 can receive for debuggin porpuose
$parametro +=' -verbose'

Invoke-Expression "$script $parametro"

2

我将我的例子提交考虑。这就是我在制作的工具中从控制器脚本中调用一些代码的方式。完成工作的脚本也需要接受参数,因此此示例说明了如何传递参数。它确实假定被调用的脚本与控制器脚本(进行调用的脚本)位于同一目录中。

[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]
$Computername,

[Parameter(Mandatory = $true)]
[DateTime]
$StartTime,

[Parameter(Mandatory = $true)]
[DateTime]
$EndTime
)

$ZAEventLogDataSplat = @{
    "Computername" = $Computername
    "StartTime"    = $StartTime
    "EndTime"      = $EndTime
}

& "$PSScriptRoot\Get-ZAEventLogData.ps1" @ZAEventLogDataSplat

上面是一个接受3个参数的控制器脚本。这些在param块中定义。然后,控制器脚本调用名为Get-ZAEventLogData.ps1的脚本。为了示例,此脚本还接受相同的3个参数。当控制器脚本调用完成工作的脚本时,它需要调用它并传递参数。上面显示了我如何通过喷溅来实现。


1

如何在脚本中运行PowerShell内置脚本?

您如何使用内置脚本,例如

Get-Location
pwd
ls
dir
split-path
::etc...

这些由计算机运行,并自动检查脚本的路径。

同样,我可以通过将脚本名称放在脚本块中来运行自定义脚本

::sid.ps1 is a PS script I made to find the SID of any user
::it takes one argument, that argument would be the username
echo $(sid.ps1 jowers)


(returns something like)> S-X-X-XXXXXXXX-XXXXXXXXXX-XXX-XXXX


$(sid.ps1 jowers).Replace("S","X")

(returns same as above but with X instead of S)

转到powershell命令行并键入

> $profile

这会将路径返回到每次您打开应用程序时PowerShell命令行将执行的文件的路径。

看起来像这样

C:\Users\jowers\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1

转到“文档”,查看是否已经有WindowsPowerShell目录。我没有,所以

> cd \Users\jowers\Documents
> mkdir WindowsPowerShell
> cd WindowsPowerShell
> type file > Microsoft.PowerShellISE_profile.ps1

现在,我们已经创建了脚本,该脚本将在每次打开PowerShell应用程序时启动。

这样做的原因是,我们可以添加自己的文件夹来保存所有自定义脚本。让我们创建该文件夹,在Mac / Linux存放脚本的目录之后,我将其命名为“ Bin”。

> mkdir \Users\jowers\Bin

现在,我们希望$env:path每次打开应用程序时将该目录添加到我们的变量中,因此返回WindowsPowerShell目录并

> start Microsoft.PowerShellISE_profile.ps1

然后添加

$env:path += ";\Users\jowers\Bin"

现在,只要将脚本保存在该“ Bin”目录中,外壳程序就会自动找到您的命令。

重新启动powershell,它应该是最早执行的脚本之一。

重新加载后在命令行上运行此命令,以在path变量中查看新目录:

> $env:Path

现在,我们可以从命令行或从另一个脚本中调用脚本,就像这样:

$(customScript.ps1 arg1 arg2 ...)

如您所见,我们必须使用.ps1扩展名来调用它们,直到为它们创建别名为止。如果我们想得到幻想。


哇,谢谢你,这里有很多东西。但是这里已经有9个其他答案。这有何不同?它提供了哪些其他信息?
斯蒂芬·劳奇

这样做可以使我们在其他脚本中使用自定义脚本,就像在脚本中使用内置脚本一样。这样做,只要将脚本保存在路径中的目录中,当您在命令行或其他脚本中使用自定义脚本时,计算机就会自动找到该自定义脚本的路径
Tyler Curtis Jowers
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.