Panggil skrip PowerShell PS1 dari skrip PS1 lain di dalam Powershell ISE

138

Saya ingin eksekusi panggilan untuk skrip myScript1.ps1 di dalam skrip myScript2.ps1 kedua di dalam Powershell ISE.

Kode berikut di dalam MyScript2.ps1, berfungsi dengan baik dari Powershell Administration, tetapi tidak berfungsi di dalam PowerShell ISE:

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

Saya mendapatkan kesalahan berikut ketika saya menjalankan MyScript2.ps1 dari PowerShell ISE:

Istilah '. \ MyScript1.ps1' tidak dikenali sebagai nama cmdlet, fungsi, file skrip, atau program yang dapat dioperasikan. Periksa ejaan nama, atau jika jalur disertakan, verifikasi jalur itu benar dan coba lagi.

Nicola Celiento
sumber

Jawaban:

83

Untuk menemukan lokasi skrip, gunakan Split-Path $MyInvocation.MyCommand.Path(pastikan Anda menggunakan ini dalam konteks skrip).

Alasan Anda harus menggunakannya dan bukan hal lain yang dapat diilustrasikan dengan skrip contoh ini.

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

Inilah beberapa hasil.

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

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

PS C: \ Users \ JasonAr> & ". \ ScriptTest.ps1"
Nama Invokasi: &
Path: C: \ Users \ JasonAr \ ScriptTest.ps1

Di PowerShell 3.0 dan yang lebih baru, Anda dapat menggunakan variabel otomatis $PSScriptRoot:

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C: \ Users \ jarcher>. \ ScriptTest.ps1
Script: C: \ Users \ jarcher \ ScriptTest.ps1
Path: C: \ Users \ jarcher
JasonMArcher
sumber
Tambahan tambahan: Jika Anda khawatir variasi abot (atau, sebenarnya, hanya ingin kode "solid") Anda mungkin ingin menggunakan "Write-Output" daripada "Write-Host".
KlaymenDK
20
Akan lebih baik untuk melihat contoh penggunaan Split-Path dalam jawabannya. Anda juga harus menunjukkan pemanggilan skrip di dalam skrip lain dengan benar.
Jeremy
37

Jalur MyScript1.ps1 saat ini tidak sama dengan myScript2.ps1. Anda bisa mendapatkan path folder MyScript2.ps1 dan menggabungkannya ke MyScript1.ps1 dan kemudian jalankan. Kedua skrip harus berada di lokasi yang sama.

## MyScript2.ps1 ##
$ScriptPath = Split-Path $MyInvocation.InvocationName
& "$ScriptPath\MyScript1.ps1"
Shay Levy
sumber
Bagaimana saya harus menginisialisasi variabel $ MyInvocation?
Nicola Celiento
Anda tidak, ini adalah variabel otomatis.
Shay Levy
Ini berfungsi, tetapi dapatkan kesalahan berikut sebelum benar-benar mengeksekusi skrip yang disebut: Split-Path: Tidak dapat mengikat argumen ke parameter 'Path' karena ini adalah string kosong. Pada baris: 4 Char: 25 + $ ScriptPath = Split-jalan <<<< $ MyInvocation.InvocationName + CategoryInfo: InvalidData: (:) [Split-jalan], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed, Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento
buat skrip baru: $ MyInvocation.InvocationName di dalamnya dan jalankan skrip. Apakah Anda mendapatkan jalur skrip?
Shay Levy
@JasonMArcher - Kenapa sebaliknya? Sejauh yang saya tahu keduanya memberikan output yang sama?
manojlds
36

Saya memanggil myScript1.ps1 dari myScript2.ps1.

Dengan asumsi kedua skrip berada di lokasi yang sama, pertama-tama dapatkan lokasi skrip dengan menggunakan perintah ini:

$PSScriptRoot

Dan, kemudian, tambahkan nama skrip yang ingin Anda panggil seperti ini:

& "$PSScriptRoot\myScript1.ps1"

Ini seharusnya bekerja.

Srijani Ghosh
sumber
3
& "$PSScriptRoot\myScript1.ps1"sudah cukup
Weihui Guo
19

Solusi satu baris:

& ((Split-Path $MyInvocation.InvocationName) + "\MyScript1.ps1")
Noelicus
sumber
Ini bagus, tetapi mengapa tidak hanya & '.\MyScript1.ps'jika skrip berada di direktori yang sama?
JoePC
3
Itu menggunakan direktori saat ini bukan direktori skrip. Tentu mereka sering sama ... tetapi tidak selalu!
noelicus
9

Ini hanyalah info tambahan untuk jawaban agar dapat meneruskan argumen ke file lain

Di mana Anda mengharapkan pertengkaran

PrintName.ps1

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


Write-Host $printName

Cara memanggil file

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


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

Jika Anda tidak memberikan input apa pun, maka defaultnya adalah "Joe" dan ini akan diteruskan sebagai argumen ke argumen printName dalam file PrintName.ps1 yang pada gilirannya akan mencetak string "Joe"

cpoDesign
sumber
4

Anda mungkin sudah menemukan jawabannya, tetapi inilah yang saya lakukan.

Saya biasanya menempatkan baris ini di awal skrip instalasi saya:

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

Maka saya dapat menggunakan variabel $ PSScriptRoot sebagai lokasi skrip saat ini (path), seperti dalam contoh di bawah ini:

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)

Dalam kasus Anda, Anda dapat mengganti

Mulai proses ... sejalan dengan

Invoke-Expression $ PSScriptRoot \ ScriptName.ps1

Anda dapat membaca lebih lanjut tentang $ MYINVOCATION dan $ PSScriptRoot variabel otomatis di situs Microsoft: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_about_automatic_variables

Emil Bogopolskiy
sumber
4

Untuk menjalankan dengan mudah file skrip dalam folder yang sama (atau subfolder dari) sebagai pemanggil Anda dapat menggunakan ini:

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

# Execute script at location:
&"$ScriptRoute"
Rrr
sumber
3

Saya punya masalah dengan ini. Saya tidak menggunakan $MyInvocationbarang pintar untuk memperbaikinya. Jika Anda membuka ISE dengan mengklik kanan file skrip dan memilih editlalu buka skrip kedua dari dalam ISE, Anda dapat memohon satu dari yang lain dengan hanya menggunakan sintaks normal . \ Script.ps1 . Dugaan saya adalah bahwa ISE memiliki gagasan tentang folder saat ini dan membukanya seperti ini menetapkan folder saat ini ke folder yang berisi skrip. Ketika saya memohon satu skrip dari yang lain dalam penggunaan normal saya hanya menggunakan . \ Script.ps1 , IMO salah untuk memodifikasi skrip hanya untuk membuatnya bekerja di ISE dengan benar ...

Sabroni
sumber
2

Saya memiliki masalah yang sama dan menyelesaikannya dengan cara ini.

Direktori kerja saya adalah folder skrip umum dan folder skrip serveral tertentu di root yang sama, saya perlu memanggil folder skrip tertentu (yang memanggil skrip umum dengan parameter masalah tertentu). Jadi direktori yang berfungsi seperti ini

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

Solutions1 dan Solutions2 memanggil folder PS1 dalam Script memuat parameter yang disimpan di ParameterForSolution. Jadi di PowerShell ISE saya menjalankan perintah ini

.\Nico\Problem1\Solution1.PS1

Dan kode di dalam Solution1.PS1 adalah:

# 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"
Nico Osorio
sumber
2

Saya mengirimkan contoh saya untuk dipertimbangkan. Ini adalah bagaimana saya memanggil beberapa kode dari skrip pengontrol di alat yang saya buat. Script yang melakukan pekerjaan juga perlu menerima parameter juga, jadi contoh ini menunjukkan cara untuk melewatinya. Itu mengasumsikan skrip yang dipanggil berada di direktori yang sama dengan skrip controller (skrip membuat panggilan).

[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

Di atas adalah skrip pengontrol yang menerima 3 parameter. Ini didefinisikan di blok param. Script controller kemudian memanggil script bernama Get-ZAEventLogData.ps1. Sebagai contoh, skrip ini juga menerima 3 parameter yang sama. Ketika skrip pengontrol memanggil skrip yang berfungsi, skrip perlu memanggilnya dan meneruskan parameternya. Di atas menunjukkan bagaimana saya melakukannya dengan menepuk.

Zack A
sumber
1

Bagaimana Anda menjalankan skrip internal PowerShell di dalam skrip Anda?

Bagaimana Anda menggunakan skrip bawaan

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

Itu dijalankan oleh komputer Anda, secara otomatis memeriksa jalur skrip.

Demikian pula, saya dapat menjalankan skrip khusus saya dengan hanya memasukkan nama skrip di blok skrip

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

Lanjutkan ke baris perintah dan ketik powershell

> $profile

Ini akan mengembalikan jalur ke file yang akan dieksekusi baris perintah PowerShell kami setiap kali Anda membuka aplikasi.

Ini akan terlihat seperti ini

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

Pergi ke Dokumen dan lihat apakah Anda sudah memiliki direktori WindowsPowerShell. Saya tidak, jadi

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

Kami sekarang telah membuat skrip yang akan diluncurkan setiap kali kami membuka Aplikasi PowerShell.

Alasan kami melakukannya adalah agar kami dapat menambahkan folder kami sendiri yang menampung semua skrip khusus kami. Mari kita buat folder itu dan saya akan beri nama "Bin" setelah direktori tempat Mac / Linux menyimpan skripnya.

> mkdir \Users\jowers\Bin

Sekarang kami ingin direktori itu ditambahkan ke $env:pathvariabel kami setiap kali kami membuka aplikasi jadi kembali ke WindowsPowerShellDirektori dan

> start Microsoft.PowerShellISE_profile.ps1

Kemudian tambahkan ini

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

Sekarang shell akan secara otomatis menemukan perintah Anda, selama Anda menyimpan skrip Anda di direktori "Bin".

Luncurkan kembali PowerShell dan itu harus menjadi salah satu skrip pertama yang mengeksekusi.

Jalankan ini pada baris perintah setelah reload untuk melihat direktori baru Anda di variabel path Anda:

> $env:Path

Sekarang kita dapat memanggil skrip kita dari baris perintah atau dari dalam skrip lain sesederhana ini:

$(customScript.ps1 arg1 arg2 ...)

Seperti yang Anda lihat, kita harus memanggil mereka dengan .ps1ekstensi sampai kita membuat alias untuk mereka. Jika kita ingin menjadi mewah.

Tyler Curtis Jowers
sumber
Wow, terima kasih untuk ini, ada banyak hal di sini. Tetapi sudah ada 9 jawaban lain di sini. Apa bedanya? Apa informasi tambahan yang disediakannya?
Stephen Rauch
Dengan melakukan ini, kami dapat menggunakan skrip khusus kami di dalam skrip lain — dengan cara yang sama seperti skrip bawaan digunakan di dalam skrip kami. Lakukan ini dan selama Anda menyimpan skrip Anda di direktori yang Anda letakkan di jalur Anda, komputer akan secara otomatis menemukan lintasan skrip kustom ketika Anda menggunakannya di baris perintah atau di skrip lain
Tyler Curtis Jowers