【问题标题】:Call PowerShell script PS1 from another PS1 script inside Powershell ISE从 Powershell ISE 中的另一个 PS1 脚本调用 PowerShell 脚本 PS1
【发布时间】:2011-10-12 14:05:03
【问题描述】:

我想在 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、函数、脚本文件或可运行程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确并重试。

【问题讨论】:

    标签: powershell


    【解决方案1】:

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

    这个示例脚本可以说明您应该使用它而不是其他任何东西的原因。

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

    以下是一些结果。

    PS C:\Users\JasonAr> .\ScriptTest.ps1 调用名称:.\ScriptTest.ps1 路径:C:\Users\JasonAr\ScriptTest.ps1 PS C:\Users\JasonAr> 。 .\ScriptTest.ps1 调用名称:。 路径: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

    【讨论】:

    • 迟来的补充:如果您担心方差(或者,实际上,只是想要“可靠”代码),您可能想要使用“Write-Output”而不是“Write-Host”。
    • 很高兴看到答案中使用拆分路径的示例。您还需要显示在另一个脚本中调用一个脚本。
    【解决方案2】:

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

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

    $PSScriptRoot
    

    然后,附加您要调用的脚本名称,如下所示:

    & "$PSScriptRoot\myScript1.ps1"
    

    这应该可行。

    【讨论】:

    • & "$PSScriptRoot\myScript1.ps1" 就够了
    • & $PSScriptRoot\myScript1.ps1 足够了(不带引号)
    • @GregorSimončič 仅当变量不包含空白字符时。如果变量包含空格,则未引用的命令可能会由于将命令“拆分”为两部分而引入语法错误。保留引号是最安全的方法。
    【解决方案3】:

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

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

    【讨论】:

    • 我必须如何初始化 $MyInvocation 变量?
    • 你没有,它是一个自动变量。
    • 它可以工作,但在真正执行被调用脚本之前会出现以下错误:Split-Path:无法将参数绑定到参数'Path',因为它是一个空字符串。在 line:4 char:25 + $ScriptPath = Split-Path
    • 创建一个新脚本,在其中放入:$MyInvocation.InvocationName 并运行该脚本。你得到脚本的路径了吗?
    • @JasonMArcher - 为什么?据我所知,两者都给出相同的输出?
    【解决方案4】:

    一线解决方案:

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

    【讨论】:

    • 这很好,但如果脚本位于同一目录中,为什么不直接使用& '.\MyScript1.ps'
    • 这是使用当前目录而不是脚本目录。当然它们通常是相同的......但并非总是如此!
    • 我质疑同一行 - 如果您在调用它之前运行“Set-Location”命令移动到该文件夹​​,则应该通过设置位置并同时使其成为当前位置来实现.
    • 首先,这不再是单行了:)​​。但是,它仅适用于您不介意更改工作目录的情况,这是一种假设,而不是好的做法。
    【解决方案5】:

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

    你期望争论的地方

    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" 字符串

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

        您可能已经找到了答案,但这就是我所做的。

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

        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/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables

        【讨论】:

          【解决方案8】:

          我遇到了类似的问题,就这样解决了。

          我的工作目录是同一个根目录下的一个通用脚本文件夹和几个特定脚本文件夹,我需要调用特定脚本文件夹(它使用特定问题的参数调用通用脚本)。 所以工作目录是这样的

          \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"
          

          【讨论】:

            【解决方案9】:

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

            [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 个参数。当控制器脚本调用执行工作的脚本时,它需要调用它并传递参数。上面显示了我是如何通过喷溅来做到这一点的。

            【讨论】:

              【解决方案10】:

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

              【讨论】:

              • 否决了这个,因为问题是脚本在不从包含它的文件夹运行时无法工作。这不是要专门修改脚本以在 ISE 中工作,而是要修改脚本以使其具有足够的可移植性和灵活性,以处理从不同目录运行的情况。在这种情况下,代码的行为不应取决于您从何处调用它。
              【解决方案11】:

              如何在脚本中运行 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”目录中,shell 就会自动找到您的命令。

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

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

              > $env:Path
              

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

              $(customScript.ps1 arg1 arg2 ...)
              

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

              【讨论】:

              • 哇,谢谢,这里有很多东西。但是这里已经有 9 个其他答案。这有什么不同?它提供了哪些额外信息?
              • 这样做允许我们在其他脚本中使用我们的自定义脚本——就像在我们的脚本中使用内置脚本一样。这样做,只要将脚本保存在路径中的目录中,当您在命令行或其他脚本中使用自定义脚本时,计算机将自动找到它的路径
              【解决方案12】:

              您还可以使用以下命令:

              $Patch = Join-Path -Path $PSScriptRoot -ChildPath "\patch.ps1"<br>
              Invoke-Expression "& `"$Patch`""
              

              【讨论】:

                【解决方案13】:

                如果上面的变量为空,您可能正在使用 PowerShell ISE。在这种情况下尝试:

                if ($psISE)
                {
                    Split-Path -Path $psISE.CurrentFile.FullPath        
                }
                else
                {
                    $global:PSScriptRoot
                }

                看看这个discussion

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-03-03
                  • 2015-07-07
                  • 1970-01-01
                  • 2017-01-01
                  • 2018-10-31
                  相关资源
                  最近更新 更多