Chame o script PS1 do PowerShell de outro script PS1 dentro do Powershell ISE


138

Quero execução de chamada para um script myScript1.ps1 dentro de um segundo script myScript2.ps1 dentro do Powershell ISE.

O código a seguir no MyScript2.ps1 funciona bem na Administração do Powershell, mas não funciona no PowerShell ISE:

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

Eu obtenho o seguinte erro ao executar o MyScript2.ps1 no PowerShell ISE:

O termo '. \ MyScript1.ps1' não é reconhecido como o nome de um cmdlet, função, arquivo de script ou programa operável. Verifique a ortografia do nome ou, se um caminho foi incluído, verifique se o caminho está correto e tente novamente.

Respostas:


83

Para encontrar a localização de um script, use Split-Path $MyInvocation.MyCommand.Path(certifique-se de usá-lo no contexto do script).

O motivo pelo qual você deve usar isso e não qualquer outra coisa pode ser ilustrado com este script de exemplo.

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

Aqui estão alguns resultados.

PS C: \ Usuários \ JasonAr>. \ ScriptTest.ps1
InvocationName:. \ ScriptTest.ps1
Caminho: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Usuários \ JasonAr>. . \ ScriptTest.ps1
InvocationName:.
Caminho: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Users \ JasonAr> & ". \ ScriptTest.ps1"
InvocationName: &
Caminho: C: \ Users \ JasonAr \ ScriptTest.ps1

No PowerShell 3.0 e posterior, você pode usar a variável automática $PSScriptRoot:

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C: \ Usuários \ jarcher>. \ ScriptTest.ps1
Script: C: \ Usuários \ jarcher \ ScriptTest.ps1
Caminho: C: \ Users \ jarcher

Uma adição tardia: se você está preocupado com a variação (ou, na verdade, apenas deseja um código "sólido"), provavelmente deseja usar "Write-Output" em vez de "Write-Host".
KlaymenDK

20
Seria bom ver um exemplo de uso de Split-Path na resposta. Você também precisa mostrar a chamada de um script dentro de outro script.
28418 Jeremy

37

O caminho atual de MyScript1.ps1 não é o mesmo que myScript2.ps1. Você pode obter o caminho da pasta MyScript2.ps1 e concatená-lo para MyScript1.ps1 e, em seguida, executá-lo. Ambos os scripts devem estar no mesmo local.

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

Como eu tenho que inicializar a variável $ MyInvocation?
Nicola Celiento

Você não, é uma variável automática.
Shay Levy

Funciona, mas obtém o seguinte erro antes da execução do script chamado: Split-Path: Não é possível vincular o argumento ao parâmetro 'Path' porque é uma string vazia. Na linha: 4 de char: 25 + $ ScriptPath = split-Path <<<< $ MyInvocation.InvocationName + CategoryInfo: InvalidData: (:) [Split-Path], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed, Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento

crie um novo script, coloque: $ MyInvocation.InvocationName nele e execute o script. Você entende o caminho do script?
Shay Levy

@JasonMArcher - Por que, em vez disso? Tanto quanto eu sei, ambos dão a mesma saída?
manojlds

36

Estou chamando myScript1.ps1 de myScript2.ps1.

Supondo que os dois scripts estejam no mesmo local, primeiro obtenha o local do script usando este comando:

$PSScriptRoot

E, em seguida, acrescente o nome do script que você deseja chamar assim:

& "$PSScriptRoot\myScript1.ps1"

Isso deve funcionar.


3
& "$PSScriptRoot\myScript1.ps1"é suficiente
Weihui Guo

19

Solução de uma linha:

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

Isso é legal, mas por que não apenas & '.\MyScript1.ps'se o script reside no mesmo diretório?
JoePC

3
Isso está usando o diretório atual, não o diretório de scripts. Claro que muitas vezes são os mesmos ... mas nem sempre!
Noelicus

9

Esta é apenas uma informação adicional para as respostas, a fim de passar o argumento para outro arquivo

Onde você espera argumento

PrintName.ps1

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


Write-Host $printName

Como chamar o arquivo

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


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

Se você não não fornecer qualquer entrada que será o padrão para "Joe" e isso vai ser passado como argumento em argumento printName em PrintName.ps1 arquivo que por sua vez imprimir o "Joe" corda


4

Você já deve ter encontrado a resposta, mas aqui está o que eu faço.

Eu costumo colocar esta linha no início dos meus scripts de instalação:

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

Então eu posso usar a variável $ PSScriptRoot como um local do script atual (caminho), como no exemplo abaixo:

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)

No seu caso, você pode substituir

Iniciar processo ... alinhado com

Invoke-Expression $ PSScriptRoot \ ScriptName.ps1

Você pode ler mais sobre as variáveis ​​automáticas $ MYINVOCATION e $ PSScriptRoot no site da Microsoft: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables


4

Para executar facilmente um arquivo de script na mesma pasta (ou subpasta de) do chamador, você pode usar isso:

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

# Execute script at location:
&"$ScriptRoute"

3

Eu tive um problema com isso. Eu não usei nada inteligente $MyInvocationpara consertar isso. Se você abrir o ISE clicando com o botão direito do mouse em um arquivo de script e selecionando editabrir o segundo script a partir do ISE, poderá invocar um do outro usando a sintaxe normal . \ Script.ps1 . Meu palpite é que o ISE tem a noção de uma pasta atual e abri-la assim define a pasta atual para a pasta que contém os scripts. Quando invoco um script de outro em uso normal, apenas uso . \ Script.ps1 , IMO é errado modificar o script apenas para fazê-lo funcionar no ISE corretamente ...


2

Eu tive um problema semelhante e resolvi desta maneira.

Meu diretório de trabalho é uma pasta de script geral e uma pasta de script específica para servidor na mesma raiz, preciso chamar uma pasta de script específica (que chama de script geral com o parâmetro do problema específico). Então diretório de trabalho é assim

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

Solutions1 e Solutions2 chamam o PS1 na pasta Scripts carregando o parâmetro armazenado em ParameterForSolution. Assim, no PowerShell ISE, eu executo este comando

.\Nico\Problem1\Solution1.PS1

E o código dentro de 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

Submeto meu exemplo para consideração. É assim que eu chamo algum código de um script do controlador nas ferramentas que eu faço. Os scripts que executam o trabalho também precisam aceitar parâmetros, portanto, este exemplo mostra como passá-los. Ele assume que o script que está sendo chamado está no mesmo diretório que o script do controlador (script que faz a chamada).

[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

O acima é um script de controlador que aceita 3 parâmetros. Eles são definidos no bloco param. O script do controlador chama o script Get-ZAEventLogData.ps1. Por uma questão de exemplo, este script também aceita os mesmos três parâmetros. Quando o script do controlador chama o script que faz o trabalho, ele precisa chamá-lo e passar os parâmetros. O exemplo acima mostra como eu faço isso splatting.


1

Como você executa scripts internos do PowerShell dentro de seus scripts?

Como você usa scripts internos como

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

Esses são executados pelo seu computador, verificando automaticamente o caminho do script.

Da mesma forma, eu posso executar meus scripts personalizados apenas colocando o nome do script no bloco de scripts

::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)

Vá para a linha de comando do PowerShell e digite

> $profile

Isso retornará o caminho para um arquivo que nossa linha de comando do PowerShell executará toda vez que você abrir o aplicativo.

Isso parecerá assim

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

Vá para Documentos e veja se você já possui um diretório WindowsPowerShell. Eu não fiz, então

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

Agora, criamos o script que será iniciado sempre que abrirmos o aplicativo PowerShell.

A razão pela qual fizemos isso foi para podermos adicionar nossa própria pasta que contém todos os nossos scripts personalizados. Vamos criar essa pasta e chamo-a de "Bin" após os diretórios nos quais o Mac / Linux contém seus scripts.

> mkdir \Users\jowers\Bin

Agora queremos que esse diretório seja adicionado à nossa $env:pathvariável toda vez que abrirmos o aplicativo, volte para o WindowsPowerShellDiretório e

> start Microsoft.PowerShellISE_profile.ps1

Então adicione isso

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

Agora, o shell encontrará automaticamente seus comandos, desde que você salve seus scripts nesse diretório "Bin".

Reinicie o PowerShell e deve ser um dos primeiros scripts executados.

Execute isso na linha de comando após recarregar para ver seu novo diretório na sua variável de caminho:

> $env:Path

Agora podemos chamar nossos scripts a partir da linha de comando ou de outro script, da seguinte maneira:

$(customScript.ps1 arg1 arg2 ...)

Como você vê, devemos chamá-los com a .ps1extensão até criarmos pseudônimos para eles. Se queremos ser extravagantes.


Uau, obrigado por isso, há muito aqui. Mas já existem 9 outras respostas aqui. Como isso difere? Que informações adicionais estão fornecendo?
Stephen Rauch

Isso nos permite usar nossos scripts personalizados dentro de outros scripts - da mesma maneira que os scripts internos são usados ​​dentro de nossos scripts. Faça isso e contanto que você salve seus scripts no diretório que colocou no caminho, o computador encontrará automaticamente o caminho do script personalizado quando você o usar na linha de comando ou em outro script
Tyler Curtis Jowers
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.