Chiama lo script PowerShell PS1 da un altro script PS1 all'interno di Powershell ISE


138

Voglio l'esecuzione di una chiamata per uno script myScript1.ps1 all'interno di un secondo script myScript2.ps1 all'interno di Powershell ISE.

Il seguente codice all'interno di MyScript2.ps1, funziona bene da Powershell Administration, ma non funziona all'interno di PowerShell ISE:

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

Ottengo il seguente errore quando eseguo MyScript2.ps1 da PowerShell ISE:

Il termine ". \ MyScript1.ps1" non è riconosciuto come nome di un cmdlet, funzione, file di script o programma eseguibile. Controlla l'ortografia del nome o se è stato incluso un percorso, verifica che il percorso sia corretto e riprova.

Risposte:


83

Per trovare la posizione di uno script, utilizzare Split-Path $MyInvocation.MyCommand.Path(assicurarsi di utilizzarlo nel contesto dello script).

Il motivo per cui dovresti usarlo e non altro può essere illustrato con questo script di esempio.

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

Ecco alcuni risultati

PS C: \ Users \ JasonAr>. \ ScriptTest.ps1
InvocationName:. \ ScriptTest.ps1
Percorso: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Users \ JasonAr>. . \ ScriptTest.ps1
InvocationName:.
Percorso: C: \ Users \ JasonAr \ ScriptTest.ps1

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

In PowerShell 3.0 e versioni successive è possibile utilizzare la variabile automatica $PSScriptRoot:

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

Un'aggiunta tardiva: se sei preoccupato per la varianza (o, in realtà, vuoi solo un codice "solido") probabilmente vorrai usare "Write-Output" piuttosto che "Write-Host".
KlaymenDK,

20
Sarebbe bello vedere un esempio di utilizzo di Split-Path nella risposta. Devi anche mostrare la chiamata di uno script all'interno di un altro script davvero.
Jeremy,

37

Il percorso corrente di MyScript1.ps1 non è lo stesso di myScript2.ps1. È possibile ottenere il percorso della cartella di MyScript2.ps1 e concatenarlo in MyScript1.ps1 e quindi eseguirlo. Entrambi gli script devono trovarsi nella stessa posizione.

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

Come devo inizializzare la variabile $ MyInvocation?
Nicola Celiento,

No, è una variabile automatica.
Shay Levy,

Funziona, ma ottiene il seguente errore prima dell'esecuzione effettiva dello script chiamato: Split-Path: impossibile associare l'argomento al parametro 'Path' perché è una stringa vuota. Alla riga: 4 char: 25 + $ ScriptPath = Split-Path <<<< $ MyInvocation.InvocationName + CategoryInfo: InvalidData: (:) [Split-Path], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed, Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento,

crea un nuovo script inserisci: $ MyInvocation.InvocationName in esso ed esegui lo script. Ottieni il percorso della sceneggiatura?
Shay Levy,

@JasonMArcher - Perché invece? Per quanto ne so entrambi danno lo stesso risultato?
manojlds,

36

Sto chiamando myScript1.ps1 da myScript2.ps1.

Supponendo che entrambi gli script si trovino nella stessa posizione, innanzitutto ottenere la posizione dello script utilizzando questo comando:

$PSScriptRoot

E, quindi, aggiungi il nome dello script che desideri chiamare in questo modo:

& "$PSScriptRoot\myScript1.ps1"

Questo dovrebbe funzionare.


3
& "$PSScriptRoot\myScript1.ps1"è abbastanza
Weihui Guo,

19

Una soluzione di linea:

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

Questo è carino, ma perché non solo & '.\MyScript1.ps'se lo script risiede nella stessa directory?
JoePC,

3
Sta usando la directory corrente non la directory degli script. Sicuramente sono spesso uguali ... ma non sempre!
Noelicus,

9

Queste sono solo informazioni aggiuntive alle risposte per passare l'argomento in un altro file

Dove ti aspetti una discussione

PrintName.ps1

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


Write-Host $printName

Come chiamare il file

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


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

Se non si fornisce alcun input, verrà impostato automaticamente "Joe" e questo verrà passato come argomento nell'argomento printName nel file PrintName.ps1 che a sua volta stamperà la stringa "Joe"


4

Potresti aver già trovato la risposta, ma ecco cosa faccio.

Di solito inserisco questa riga all'inizio dei miei script di installazione:

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

Quindi posso usare la variabile $ PSScriptRoot come posizione dello script corrente (percorso), come nell'esempio seguente:

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)

Nel tuo caso, puoi sostituirlo

Avvia processo ... linea con

Invoke-Expression $ PSScriptRoot \ ScriptName.ps1

Puoi leggere ulteriori informazioni sulle variabili automatiche $ MYINVOCATION e $ PSScriptRoot sul sito Microsoft: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables


4

Per eseguire facilmente un file di script nella stessa cartella (o sottocartella di) del chiamante, è possibile utilizzare questo:

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

# Execute script at location:
&"$ScriptRoute"

3

Ho avuto un problema con questo. $MyInvocationTuttavia non ho usato nulla di intelligente per risolverlo. Se apri ISE facendo clic con il pulsante destro del mouse su un file di script e selezionando editquindi apri il secondo script all'interno di ISE, puoi invocare l'uno dall'altro semplicemente usando la normale sintassi. \ Script.ps1 . La mia ipotesi è che ISE abbia la nozione di una cartella corrente e aprirla in questo modo imposta la cartella corrente sulla cartella contenente gli script. Quando invoco uno script da un altro in uso normale, utilizzo semplicemente . \ Script.ps1 , IMO è sbagliato modificare lo script solo per farlo funzionare correttamente in ISE ...


2

Ho avuto un problema simile e l'ho risolto in questo modo.

La mia directory di lavoro è una cartella di script generale e una cartella di script particolare serveral nella stessa radice, ho bisogno di chiamare una cartella di script particolare (che chiama lo script generale con il parametro del problema specifico). Quindi la directory di lavoro è così

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

Solutions1 e Solutions2 chiamano PS1 nella cartella Scripts caricando il parametro memorizzato in ParameterForSolution. Quindi in PowerShell ISE eseguo questo comando

.\Nico\Problem1\Solution1.PS1

E il codice all'interno di 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

Inoltro il mio esempio per considerazione. Ecco come chiamo del codice da uno script del controller negli strumenti che creo. Anche gli script che eseguono il lavoro devono accettare i parametri, quindi questo esempio mostra come passarli. Presuppone che lo script chiamato sia nella stessa directory dello script del controller (script che effettua la chiamata).

[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

Quanto sopra è uno script del controller che accetta 3 parametri. Questi sono definiti nel blocco param. Lo script del controller quindi chiama lo script denominato Get-ZAEventLogData.ps1. Ad esempio, questo script accetta anche gli stessi 3 parametri. Quando lo script del controller chiama lo script che fa il lavoro, deve chiamarlo e passare i parametri. Quanto sopra mostra come lo faccio splattando.


1

Come si eseguono gli script integrati di PowerShell all'interno degli script?

Come usi gli script integrati come

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

Questi sono gestiti dal tuo computer, controllando automaticamente il percorso dello script.

Allo stesso modo, posso eseguire i miei script personalizzati inserendo semplicemente il nome dello script nel blocco di 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)

Passare alla riga di comando di PowerShell e digitare

> $profile

Ciò restituirà il percorso a un file che la nostra riga di comando di PowerShell eseguirà ogni volta che apri l'app.

Sarà così

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

Vai a Documenti e vedi se hai già una directory WindowsPowerShell. Non l'ho fatto, quindi

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

Ora abbiamo creato lo script che verrà avviato ogni volta che apriamo l'app PowerShell.

La ragione per cui lo abbiamo fatto è stata quella di poter aggiungere la nostra cartella che contiene tutti i nostri script personalizzati. Creiamo quella cartella e la chiamerò "Bin" come le directory in cui Mac / Linux contiene i suoi script.

> mkdir \Users\jowers\Bin

Ora vogliamo che la directory venga aggiunta alla nostra $env:pathvariabile ogni volta che apriamo l'app, quindi torna alla WindowsPowerShellDirectory e

> start Microsoft.PowerShellISE_profile.ps1

Quindi aggiungi questo

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

Ora la shell troverà automaticamente i tuoi comandi, purché tu salvi i tuoi script in quella directory "Bin".

Riavvia il PowerShell e dovrebbe essere uno dei primi script da eseguire.

Eseguilo sulla riga di comando dopo averlo ricaricato per vedere la tua nuova directory nella variabile path:

> $env:Path

Ora possiamo chiamare i nostri script dalla riga di comando o da un altro script semplicemente come questo:

$(customScript.ps1 arg1 arg2 ...)

Come vedi, dobbiamo chiamarli con l' .ps1estensione fino a quando non creiamo alias per loro. Se vogliamo essere fantasiosi.


Wow, grazie per questo, c'è molto qui. Ma ci sono altre 9 risposte già qui. In che cosa differisce? Quali informazioni aggiuntive sta fornendo?
Stephen Rauch,

Ciò ci consente di utilizzare i nostri script personalizzati all'interno di altri script, nello stesso modo in cui gli script integrati vengono utilizzati all'interno dei nostri script. Fallo e fintanto che salvi i tuoi script nella directory che hai inserito nel tuo percorso, il computer troverà automaticamente il percorso dello script personalizzato quando lo usi sulla riga di comando o in un altro script
Tyler Curtis Jowers,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.