Wywołaj skrypt PowerShell PS1 z innego skryptu PS1 wewnątrz Powershell ISE


137

Chcę wykonać wywołanie skryptu myScript1.ps1 wewnątrz drugiego skryptu myScript2.ps1 wewnątrz Powershell ISE.

Poniższy kod w MyScript2.ps1, działa dobrze z Powershell Administration, ale nie działa w PowerShell ISE:

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

Otrzymuję następujący błąd, gdy wykonuję MyScript2.ps1 z PowerShell ISE:

Wyrażenie „. \ MyScript1.ps1” nie jest rozpoznawane jako nazwa polecenia cmdlet, funkcji, pliku skryptu lub programu operacyjnego. Sprawdź pisownię nazwy lub, jeśli ścieżka została dołączona, sprawdź, czy jest ona poprawna i spróbuj ponownie.

Odpowiedzi:


83

Aby znaleźć lokalizację skryptu, użyj Split-Path $MyInvocation.MyCommand.Path(upewnij się, że używasz tego w kontekście skryptu).

Powód, dla którego powinieneś tego używać, a nie czegokolwiek innego, nie może być zilustrowany tym przykładowym skryptem.

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

Oto kilka wyników.

PS C: \ Users \ JasonAr>. \ ScriptTest.ps1
InvocationName:. \ ScriptTest.ps1
Ścieżka: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Users \ JasonAr>. . \ ScriptTest.ps1
InvocationName:.
Ścieżka: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Users \ JasonAr> & ". \ ScriptTest.ps1"
InvocationName: &
Ścieżka: C: \ Users \ JasonAr \ ScriptTest.ps1

W programie PowerShell 3.0 i nowszych można użyć zmiennej automatycznej $PSScriptRoot:

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C: \ Users \ jarcher>. \ ScriptTest.ps1
Skrypt: C: \ Users \ jarcher \ ScriptTest.ps1
Ścieżka: C: \ Users \ jarcher

Późny dodatek: jeśli martwisz się o wariancję (lub po prostu chcesz „solidnego” kodu), prawdopodobnie chcesz użyć opcji „Write-Output” zamiast „Write-Host”.
KlaymenDK

20
Dobrze byłoby zobaczyć w odpowiedzi przykład użycia Split-Path. Musisz także naprawdę pokazać wywołanie skryptu w innym skrypcie.
Jeremy

37

Bieżąca ścieżka MyScript1.ps1 różni się od myScript2.ps1. Możesz uzyskać ścieżkę do folderu MyScript2.ps1 i połączyć ją z MyScript1.ps1, a następnie wykonać. Oba skrypty muszą znajdować się w tej samej lokalizacji.

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

Jak mam zainicjować zmienną $ MyInvocation?
Nicola Celiento,

Nie, to zmienna automatyczna.
Shay Levy,

Działa, ale przed rzeczywistym wykonaniem wywoływanego skryptu uzyskaj następujący błąd: Split-Path: Nie można powiązać argumentu z parametrem „Path”, ponieważ jest to pusty ciąg. Na linii: 4 char: 25 + $ scriptpath = Split-Path <<<< $ MyInvocation.InvocationName + CategoryInfo: invaliddata: (:) [Split-Path], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed, Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento

utwórz nowy skrypt, umieść w nim: $ MyInvocation.InvocationName i uruchom skrypt. Czy znasz ścieżkę skryptu?
Shay Levy,

@JasonMArcher - Dlaczego zamiast tego? O ile wiem, oba dają ten sam wynik?
manojlds

36

Wywołuję myScript1.ps1 z myScript2.ps1.

Zakładając, że oba skrypty znajdują się w tej samej lokalizacji, najpierw pobierz lokalizację skryptu za pomocą tego polecenia:

$PSScriptRoot

Następnie dodaj nazwę skryptu, który chcesz wywołać w następujący sposób:

& "$PSScriptRoot\myScript1.ps1"

To powinno działać.


3
& "$PSScriptRoot\myScript1.ps1"wystarczy
Weihui Guo

19

Rozwiązanie jednoprzewodowe:

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

To fajne, ale dlaczego by nie tylko, & '.\MyScript1.ps'jeśli skrypt znajduje się w tym samym katalogu?
JoePC

3
To używa bieżącego katalogu, a nie katalogu skryptów. Jasne, często są takie same ... ale nie zawsze!
noelicus

9

To jest tylko dodatkowa informacja do odpowiedzi, aby przekazać argument do innego pliku

Gdzie spodziewasz się kłótni

PrintName.ps1

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


Write-Host $printName

Jak wywołać plik

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


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

Jeśli nie podasz żadnych danych wejściowych, domyślnie będzie to "Joe" i zostanie to przekazane jako argument do argumentu printName w pliku PrintName.ps1 , który z kolei wydrukuje napis "Joe"


4

Być może już znalazłeś na to odpowiedź, ale oto co robię.

Zwykle umieszczam tę linię na początku moich skryptów instalacyjnych:

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

Następnie mogę użyć zmiennej $ PSScriptRoot jako lokalizacji bieżącego skryptu (ścieżki), jak w przykładzie poniżej:

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)

W twoim przypadku możesz wymienić

Rozpocznij proces ... zgodnie z

Invoke-Expression $ PSScriptRoot \ ScriptName.ps1

Więcej informacji na temat automatycznych zmiennych $ MYINVOCATION i $ PSScriptRoot można znaleźć w witrynie Microsoft: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables


4

Aby łatwo wykonać plik skryptu w tym samym folderze (lub podfolderze) co dzwoniący, możesz użyć tego:

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

# Execute script at location:
&"$ScriptRoute"

3

Miałem z tym problem. Nie użyłem jednak żadnych sprytnych $MyInvocationrzeczy, aby to naprawić. Jeśli otworzysz ISE, klikając prawym przyciskiem myszy plik skryptu i wybierając, edita następnie otwórz drugi skrypt z poziomu ISE, możesz wywołać jeden z drugiego, używając zwykłej składni. \ Script.ps1 . Domyślam się, że ISE ma pojęcie bieżącego folderu i otwarcie go w ten sposób ustawia bieżący folder na folder zawierający skrypty. Kiedy wywołuję jeden skrypt z innego w normalnym użyciu, po prostu używam . \ Script.ps1 , IMO, błędem jest modyfikowanie skryptu tylko po to, aby działał poprawnie w ISE ...


2

Miałem podobny problem i rozwiązałem go w ten sposób.

Mój katalog roboczy to ogólny folder skryptów i konkretny folder skryptów na serwerze w tym samym katalogu głównym. Muszę wywołać określony folder skryptów (który wywołuje ogólny skrypt z parametrem konkretnego problemu). Więc katalog roboczy wygląda tak

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

Solutions1 i Solutions2 wywołują PS1 w folderze Scripts ładując parametr przechowywany w ParameterForSolution. Więc w PowerShell ISE uruchamiam to polecenie

.\Nico\Problem1\Solution1.PS1

A kod wewnątrz Solution1.PS1 to:

# 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

Podaję swój przykład do rozważenia. W ten sposób nazywam kod ze skryptu kontrolera w narzędziach, które tworzę. Skrypty, które wykonują tę pracę, również muszą akceptować parametry, więc ten przykład pokazuje, jak je przekazać. Zakłada, że ​​wywoływany skrypt znajduje się w tym samym katalogu co skrypt kontrolera (skrypt wykonujący wywołanie).

[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

Powyższy skrypt to kontroler, który akceptuje 3 parametry. Są one zdefiniowane w bloku parametrów. Następnie skrypt kontrolera wywołuje skrypt o nazwie Get-ZAEventLogData.ps1. Na przykład ten skrypt akceptuje również te same 3 parametry. Kiedy skrypt kontrolera wywołuje skrypt, który wykonuje pracę, musi go wywołać i przekazać parametry. Powyższe pokazuje, jak robię to przez splatting.


1

Jak uruchamiać wbudowane skrypty PowerShell w swoich skryptach?

Jak korzystać z wbudowanych skryptów, takich jak

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

Są one uruchamiane przez Twój komputer, automatycznie sprawdzając ścieżkę do skryptu.

Podobnie mogę uruchamiać własne skrypty, po prostu umieszczając nazwę skryptu w bloku skryptu

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

Przejdź do wiersza poleceń PowerShell i wpisz

> $profile

Spowoduje to zwrócenie ścieżki do pliku, który nasz wiersz poleceń programu PowerShell wykona za każdym razem, gdy otworzysz aplikację.

Będzie to wyglądało tak

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

Przejdź do Dokumentów i sprawdź, czy masz już katalog WindowsPowerShell. Tak nie zrobiłem

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

Stworzyliśmy teraz skrypt, który będzie uruchamiany za każdym razem, gdy otworzymy aplikację PowerShell.

Powodem tego było to, że mogliśmy dodać własny folder zawierający wszystkie nasze niestandardowe skrypty. Utwórzmy ten folder i nadam mu nazwę „Bin” po katalogach, w których Mac / Linux przechowuje swoje skrypty.

> mkdir \Users\jowers\Bin

Teraz chcemy, aby ten katalog był dodawany do naszej $env:pathzmiennej za każdym razem, gdy otwieramy aplikację, więc wróć do WindowsPowerShellkatalogu i

> start Microsoft.PowerShellISE_profile.ps1

Następnie dodaj to

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

Teraz powłoka automatycznie znajdzie twoje polecenia, o ile zapiszesz skrypty w tym katalogu „Bin”.

Uruchom ponownie PowerShell i powinien to być jeden z pierwszych wykonywanych skryptów.

Uruchom to w wierszu poleceń po ponownym załadowaniu, aby zobaczyć nowy katalog w zmiennej ścieżki:

> $env:Path

Teraz możemy wywoływać nasze skrypty z wiersza poleceń lub z poziomu innego skryptu w taki prosty sposób:

$(customScript.ps1 arg1 arg2 ...)

Jak widzisz, musimy wywoływać je z .ps1rozszerzeniem, dopóki nie utworzymy dla nich aliasów. Jeśli chcemy mieć ochotę.


Wow, dzięki za to, jest tu dużo. Ale jest już 9 innych odpowiedzi. Czym się to różni? Jakie dodatkowe informacje dostarcza?
Stephen Rauch,

Dzięki temu możemy używać naszych niestandardowych skryptów w innych skryptach - w taki sam sposób, w jaki wbudowane skrypty są używane w naszych skryptach. Zrób to i tak długo, jak zapiszesz swoje skrypty w katalogu, który umieścisz na swojej ścieżce, komputer automatycznie znajdzie ścieżkę niestandardowego skryptu, gdy użyjesz go w linii poleceń lub w innym skrypcie
Tyler Curtis Jowers
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.