Appelez le script PowerShell PS1 à partir d'un autre script PS1 dans Powershell ISE


138

Je veux exécuter un appel pour un script myScript1.ps1 dans un second script myScript2.ps1 dans Powershell ISE.

Le code suivant dans MyScript2.ps1, fonctionne correctement à partir de l'administration Powershell, mais ne fonctionne pas dans PowerShell ISE:

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

J'obtiens l'erreur suivante lorsque j'exécute MyScript2.ps1 à partir de PowerShell ISE:

Le terme «. \ MyScript1.ps1» n'est pas reconnu comme le nom d'une applet de commande, d'une fonction, d'un fichier de script ou d'un programme utilisable. Vérifiez l'orthographe du nom ou, si un chemin était inclus, vérifiez que le chemin est correct et réessayez.

Réponses:


83

Afin de trouver l'emplacement d'un script, utilisez Split-Path $MyInvocation.MyCommand.Path(assurez-vous de l'utiliser dans le contexte du script).

La raison pour laquelle vous devriez utiliser cela et rien d'autre peut être illustrée avec cet exemple de script.

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

Voici quelques résultats.

PS C: \ Utilisateurs \ JasonAr>. \ ScriptTest.ps1
InvocationName:. \ ScriptTest.ps1
Chemin: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Utilisateurs \ JasonAr>. . \ ScriptTest.ps1
InvocationName:.
Chemin: C: \ Users \ JasonAr \ ScriptTest.ps1

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

Dans PowerShell 3.0 et versions ultérieures, vous pouvez utiliser la variable automatique $PSScriptRoot:

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C: \ Utilisateurs \ jarcher>. \ ScriptTest.ps1
Script: C: \ Users \ jarcher \ ScriptTest.ps1
Chemin: C: \ Users \ jarcher

Un ajout tardif: si vous vous inquiétez de la variance (ou, en fait, si vous voulez simplement du code "solide"), vous voudrez probablement utiliser "Write-Output" plutôt que "Write-Host".
KlaymenDK

20
Il serait bon de voir un exemple d'utilisation de Split-Path dans la réponse. Vous devez également montrer vraiment l'appel d'un script dans un autre script.
Jeremy

37

Le chemin d'accès actuel de MyScript1.ps1 n'est pas le même que myScript2.ps1. Vous pouvez obtenir le chemin du dossier de MyScript2.ps1 et le concaténer en MyScript1.ps1, puis l'exécuter. Les deux scripts doivent être au même emplacement.

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

Comment dois-je initialiser la variable $ MyInvocation?
Nicola Celiento

Vous ne le faites pas, c'est une variable automatique.
Shay Levy

Cela fonctionne, mais obtenez l'erreur suivante avant d'exécuter réellement le script appelé: Split-Path: Impossible de lier l'argument au paramètre «Path» car il s'agit d'une chaîne vide. À la ligne: 4 char: 25 + $ ScriptPath = Split-Path <<<< $ MyInvocation.InvocationName + CategoryInfo: InvalidData: (:) [Split-Path], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowedShitPower, Microsoft.PowerCath
Nicola Celiento

créez un nouveau script mettez: $ MyInvocation.InvocationName dedans et exécutez le script. Obtenez-vous le chemin du script?
Shay Levy

@JasonMArcher - Pourquoi plutôt? Autant que je sache, les deux donnent le même résultat?
manojlds

36

J'appelle myScript1.ps1 depuis myScript2.ps1.

En supposant que les deux scripts se trouvent au même emplacement, obtenez d'abord l'emplacement du script à l'aide de cette commande:

$PSScriptRoot

Et, ensuite, ajoutez le nom du script que vous souhaitez appeler comme ceci:

& "$PSScriptRoot\myScript1.ps1"

Cela devrait fonctionner.


3
& "$PSScriptRoot\myScript1.ps1"est assez
Weihui Guo

19

Solution une ligne:

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

C'est bien, mais pourquoi pas simplement & '.\MyScript1.ps'si le script réside dans le même répertoire?
JoePC

3
Cela utilise le répertoire actuel et non le répertoire de script. Bien sûr, ils sont souvent les mêmes ... mais pas toujours!
noelicus

9

Ce ne sont que des informations supplémentaires aux réponses afin de passer l'argument dans un autre fichier

Où vous attendez une dispute

PrintName.ps1

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


Write-Host $printName

Comment appeler le fichier

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


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

Si vous ne fournissez aucune entrée, il sera par défaut "Joe" et cela sera passé comme argument dans l'argument printName dans le fichier PrintName.ps1 qui imprimera à son tour la chaîne "Joe"


4

Vous avez peut-être déjà trouvé la réponse, mais voici ce que je fais.

Je place généralement cette ligne au début de mes scripts d'installation:

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

Ensuite, je peux utiliser la variable $ PSScriptRoot comme emplacement du script actuel (chemin), comme dans l'exemple ci-dessous:

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)

Dans votre cas, vous pouvez remplacer

Processus de démarrage ... ligne avec

Invoke-Expression $ PSScriptRoot \ ScriptName.ps1

Vous pouvez en savoir plus sur les variables automatiques $ MYINVOCATION et $ PSScriptRoot sur le site de Microsoft: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables


4

Pour exécuter facilement un fichier de script dans le même dossier (ou sous-dossier de) que l'appelant, vous pouvez utiliser ceci:

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

# Execute script at location:
&"$ScriptRoute"

3

J'ai eu un problème avec ça. $MyInvocationCependant, je n'ai utilisé aucun truc intelligent pour résoudre ce problème. Si vous ouvrez l'ISE en cliquant avec le bouton droit sur un fichier de script et en sélectionnant editpuis ouvrez le deuxième script de l'intérieur de l'ISE, vous pouvez invoquer l'un de l'autre en utilisant simplement la syntaxe normale . \ Script.ps1 . Ma conjecture est que l'ISE a la notion d'un dossier courant et l'ouvrir comme ceci place le dossier courant au dossier contenant les scripts. Quand j'invoque un script à partir d'un autre en utilisation normale, j'utilise juste . \ Script.ps1 , IMO il est faux de modifier le script juste pour le faire fonctionner correctement dans l'ISE ...


2

J'ai eu un problème similaire et je l'ai résolu de cette façon.

Mon répertoire de travail est un dossier de script général et un dossier de script particulier de serveur dans la même racine, je dois appeler un dossier de script particulier (qui appelle le script général avec le paramètre du problème particulier). Donc, le répertoire de travail est comme ça

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

Solutions1 et Solutions2 appellent le PS1 dans le dossier Scripts en chargeant le paramètre stocké dans ParameterForSolution. Donc, dans PowerShell ISE, j'exécute cette commande

.\Nico\Problem1\Solution1.PS1

Et le code à l'intérieur de Solution1.PS1 est:

# 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

Je soumets mon exemple pour examen. C'est ainsi que j'appelle du code à partir d'un script de contrôleur dans les outils que je crée. Les scripts qui font le travail doivent également accepter des paramètres, donc cet exemple montre comment les transmettre. Il suppose que le script appelé se trouve dans le même répertoire que le script du contrôleur (script effectuant l'appel).

[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

Ce qui précède est un script de contrôleur qui accepte 3 paramètres. Ceux-ci sont définis dans le bloc param. Le script du contrôleur appelle ensuite le script nommé Get-ZAEventLogData.ps1. A titre d'exemple, ce script accepte également les 3 mêmes paramètres. Lorsque le script du contrôleur appelle le script qui effectue le travail, il doit l'appeler et transmettre les paramètres. Ce qui précède montre comment je le fais en éclaboussant.


1

Comment exécutez-vous des scripts intégrés PowerShell à l'intérieur de vos scripts?

Comment utilisez-vous des scripts intégrés comme

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

Ceux-ci sont exécutés par votre ordinateur, vérifiant automatiquement le chemin du script.

De même, je peux exécuter mes scripts personnalisés en mettant simplement le nom du script dans le bloc de script

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

Accédez à la ligne de commande PowerShell et tapez

> $profile

Cela renverra le chemin vers un fichier que notre ligne de commande PowerShell exécutera à chaque fois que vous ouvrirez l'application.

Il ressemblera à ceci

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

Accédez à Documents et voyez si vous avez déjà un répertoire WindowsPowerShell. Je n'ai pas, donc

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

Nous avons maintenant créé le script qui se lancera chaque fois que nous ouvrirons l'application PowerShell.

Nous avons fait cela pour pouvoir ajouter notre propre dossier contenant tous nos scripts personnalisés. Créons ce dossier et je le nommerai "Bin" après les répertoires dans lesquels Mac / Linux contient ses scripts.

> mkdir \Users\jowers\Bin

Maintenant, nous voulons que ce répertoire soit ajouté à notre $env:pathvariable chaque fois que nous ouvrons l'application, alors revenez au WindowsPowerShellrépertoire et

> start Microsoft.PowerShellISE_profile.ps1

Puis ajoutez ceci

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

Maintenant, le shell trouvera automatiquement vos commandes, tant que vous sauvegardez vos scripts dans ce répertoire "Bin".

Relancez le PowerShell et ce devrait être l'un des premiers scripts à s'exécuter.

Exécutez ceci sur la ligne de commande après le rechargement pour voir votre nouveau répertoire dans votre variable de chemin:

> $env:Path

Maintenant, nous pouvons appeler nos scripts depuis la ligne de commande ou depuis un autre script aussi simplement que ceci:

$(customScript.ps1 arg1 arg2 ...)

Comme vous le voyez, nous devons les appeler avec l' .ps1extension jusqu'à ce que nous leur fassions des alias. Si nous voulons avoir de la fantaisie.


Wow, merci pour cela, il y en a beaucoup ici. Mais il y a déjà 9 autres réponses ici. En quoi cela diffère-t-il? Quelles informations supplémentaires fournit-il?
Stephen Rauch

Cela nous permet d'utiliser nos scripts personnalisés dans d'autres scripts - de la même manière que les scripts intégrés sont utilisés dans nos scripts. Faites cela et tant que vous enregistrez vos scripts dans le répertoire que vous avez mis dans votre chemin, l'ordinateur trouvera automatiquement le chemin du script personnalisé lorsque vous l'utilisez sur la ligne de commande ou dans un autre script
Tyler Curtis Jowers
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.