Gọi tập lệnh PowerShell PS1 từ tập lệnh PS1 khác bên trong Powershell ISE


137

Tôi muốn thực thi cuộc gọi cho tập lệnh myScript1.ps1 bên trong tập lệnh myScript2.ps1 thứ hai bên trong Powershell ISE.

Đoạn mã sau trong MyScript2.ps1, hoạt động tốt từ Quản trị Powershell, nhưng không hoạt động trong PowerShell ISE:

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

Tôi gặp lỗi sau khi thực thi MyScript2.ps1 từ PowerShell ISE:

Thuật ngữ '. \ MyScript1.ps1' không được nhận dạng là tên của một lệnh ghép ngắn, hàm, tệp tập lệnh hoặc chương trình có thể hoạt động. Kiểm tra chính tả của tên hoặc nếu một đường dẫn được bao gồm, xác minh rằng đường dẫn đó là chính xác và thử lại.

Câu trả lời:


83

Để tìm vị trí của tập lệnh, hãy sử dụng Split-Path $MyInvocation.MyCommand.Path(đảm bảo bạn sử dụng vị trí này trong ngữ cảnh tập lệnh).

Lý do bạn nên sử dụng điều đó và không phải bất cứ điều gì khác có thể được minh họa bằng kịch bản ví dụ này.

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

Dưới đây là một số kết quả.

PS C: \ Người dùng \ JasonAr>. \ ScriptTest.ps1
Tên gọi :. \ ScriptTest.ps1
Đường dẫn: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Người dùng \ JasonAr>. . \ ScriptTest.ps1
Tên gọi :.
Đường dẫn: C: \ Users \ JasonAr \ ScriptTest.ps1

PS C: \ Người dùng \ JasonAr> & ". \ ScriptTest.ps1"
Tên gọi: &
Đường dẫn: C: \ Users \ JasonAr \ ScriptTest.ps1

Trong PowerShell 3.0 trở lên, bạn có thể sử dụng biến tự động $PSScriptRoot:

## ScriptTest.ps1
Write-Host "Script:" $PSCommandPath
Write-Host "Path:" $PSScriptRoot
PS C: \ Users \ jarcher>. \ ScriptTest.ps1
Tập lệnh: C: \ Users \ jarcher \ ScriptTest.ps1
Đường dẫn: C: \ Users \ jarcher

Một bổ sung muộn: Nếu bạn lo lắng về phương sai abot (hoặc thực tế, chỉ muốn mã "rắn"), bạn có thể muốn sử dụng "Đầu ra ghi" thay vì "Máy chủ ghi".
KlaymenDK

20
Sẽ rất tốt khi thấy một ví dụ sử dụng Split-Path trong câu trả lời. Bạn cũng cần hiển thị việc gọi một kịch bản bên trong một kịch bản khác thực sự.
Jeremy

37

Đường dẫn hiện tại của MyScript1.ps1 không giống với myScript2.ps1. Bạn có thể lấy đường dẫn thư mục của MyScript2.ps1 và nối nó với MyScript1.ps1 và sau đó thực thi nó. Cả hai tập lệnh phải ở cùng một vị trí.

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

Làm cách nào để tôi khởi tạo biến $ MyInvocation?
Nicola Celiento

Bạn không, đó là một biến tự động.
Shay Levy

Nó hoạt động, nhưng có được lỗi sau trước khi thực sự thực thi tập lệnh được gọi: Split-Path: Không thể liên kết đối số với tham số 'Đường dẫn' vì đây là một chuỗi rỗng. Tại dòng: 4 char: 25 + $ ScriptPath = Split-Đường dẫn <<<< $ MyInvocation.InvocationName + CategoryInfo: InvalidData: (:) [Chia-Path], ParameterBindingValidationException + FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed, Microsoft.PowerShell.Commands.SplitPathCommand
Nicola Celiento

tạo một tập lệnh mới đặt: $ MyInvocation.InvocationName trong đó và chạy tập lệnh. Bạn có nhận được đường dẫn của kịch bản không?
Shay Levy

@JasonMArcher - Tại sao thay thế? Theo tôi biết cả hai cho cùng một đầu ra?
manojlds

35

Tôi đang gọi myScript1.ps1 từ myScript2.ps1.

Giả sử cả hai tập lệnh đều ở cùng một vị trí, trước tiên hãy lấy vị trí của tập lệnh bằng cách sử dụng lệnh này:

$PSScriptRoot

Và sau đó, nối thêm tên tập lệnh mà bạn muốn gọi như thế này:

& "$PSScriptRoot\myScript1.ps1"

Điều này nên làm việc.


3
& "$PSScriptRoot\myScript1.ps1"là đủ
Weihui Guo

19

Giải pháp một dòng:

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

Điều này là tốt, nhưng tại sao không chỉ là & '.\MyScript1.ps'nếu tập lệnh nằm trong cùng một thư mục?
JoePC

3
Đó là sử dụng thư mục hiện tại không phải thư mục script. Chắc chắn chúng thường giống nhau ... nhưng không phải lúc nào cũng vậy!
noelicus

9

Đây chỉ là thông tin bổ sung cho câu trả lời để truyền đối số vào tệp khác

Nơi bạn mong đợi tranh luận

Tên in.ps1

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


Write-Host $printName

Cách gọi tập tin

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


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

Nếu bạn không cung cấp bất kỳ đầu vào nào, nó sẽ mặc định là "Joe" và điều này sẽ được chuyển thành đối số thành đối số printName trong tệp PrintName.ps1 sẽ lần lượt in ra chuỗi "Joe"


4

Bạn có thể đã tìm thấy câu trả lời cho nó rồi, nhưng đây là những gì tôi làm.

Tôi thường đặt dòng này ở đầu tập lệnh cài đặt của mình:

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

Sau đó, tôi có thể sử dụng biến $ PSScriptRoot làm vị trí của tập lệnh hiện tại (đường dẫn), như trong ví dụ dưới đây:

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)

Trong trường hợp của bạn, bạn có thể thay thế

Bắt đầu quá trình ... phù hợp với

Gọi biểu thức $ PSScriptRoot \ ScriptName.ps1

Bạn có thể đọc thêm về các biến tự động $ MYINVOCATION và $ PSScriptRoot trên trang web của Microsoft: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables


4

Để thực hiện dễ dàng một tệp tập lệnh trong cùng một thư mục (hoặc thư mục con) như người gọi, bạn có thể sử dụng tệp này:

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

# Execute script at location:
&"$ScriptRoute"

3

Tôi đã có một vấn đề với điều này. Tôi đã không sử dụng bất kỳ $MyInvocationcông cụ thông minh để sửa chữa nó mặc dù. Nếu bạn mở ISE bằng cách nhấp chuột phải vào tệp tập lệnh và chọn editrồi mở tập lệnh thứ hai từ bên trong ISE, bạn có thể gọi cái này từ cái kia bằng cách sử dụng cú pháp. \ Script.ps1 bình thường . Tôi đoán là ISE có khái niệm về một thư mục hiện tại và việc mở nó như thế này sẽ đặt thư mục hiện tại vào thư mục chứa các tập lệnh. Khi tôi gọi một tập lệnh từ một tập lệnh khác trong sử dụng bình thường, tôi chỉ sử dụng . \ Script.ps1 , IMO đã sai khi sửa đổi tập lệnh chỉ để làm cho nó hoạt động đúng trong ISE ...


2

Tôi đã có một vấn đề tương tự và giải quyết nó theo cách này.

Thư mục làm việc của tôi là một thư mục script chung và thư mục script cụ thể của máy chủ trong cùng một root, tôi cần gọi thư mục script cụ thể (gọi script chung với tham số của vấn đề cụ thể). Vì vậy, thư mục làm việc là như thế này

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

Solutions1 và Solutions2 gọi PS1 trong thư mục ScScript đang tải tham số được lưu trong ParameterForSolution. Vì vậy, trong powershell ISE, tôi chạy lệnh này

.\Nico\Problem1\Solution1.PS1

Và mã bên trong Solution1.PS1 là:

# 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

Tôi gửi ví dụ của tôi để xem xét. Đây là cách tôi gọi một số mã từ tập lệnh điều khiển trong các công cụ tôi tạo. Các tập lệnh thực hiện công việc cũng cần phải chấp nhận các tham số, vì vậy ví dụ này cho thấy cách vượt qua chúng. Nó không cho rằng tập lệnh đang được gọi nằm trong cùng thư mục với tập lệnh điều khiển (tập lệnh thực hiện cuộc gọi).

[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

Trên đây là một kịch bản điều khiển chấp nhận 3 tham số. Chúng được định nghĩa trong khối param. Tập lệnh điều khiển sau đó gọi tập lệnh có tên Get-ZAEventLogData.ps1. Vì lợi ích của ví dụ, tập lệnh này cũng chấp nhận 3 tham số tương tự. Khi tập lệnh điều khiển gọi đến tập lệnh thực hiện công việc, nó cần gọi nó và truyền các tham số. Ở trên cho thấy cách tôi làm điều đó bằng cách bắn.


1

Làm thế nào để bạn chạy tập lệnh tích hợp PowerShell bên trong tập lệnh của bạn?

Làm thế nào để bạn sử dụng các tập lệnh tích hợp như

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

Chúng được điều hành bởi máy tính của bạn, tự động kiểm tra đường dẫn của tập lệnh.

Tương tự, tôi có thể chạy các tập lệnh tùy chỉnh của mình bằng cách chỉ cần đặt tên của tập lệnh trong khối tập lệnh

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

Đi đến dòng lệnh powershell và gõ

> $profile

Điều này sẽ trả về đường dẫn đến một tệp mà dòng lệnh PowerShell của chúng tôi sẽ thực thi mỗi khi bạn mở ứng dụng.

Nó sẽ trông giống thế này

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

Chuyển đến Documents và xem bạn đã có thư mục WindowsPowerShell chưa. Tôi đã không làm vậy

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

Bây giờ chúng tôi đã tạo tập lệnh sẽ khởi chạy mỗi khi chúng tôi mở Ứng dụng PowerShell.

Lý do chúng tôi đã làm điều đó là để chúng tôi có thể thêm thư mục riêng chứa tất cả các tập lệnh tùy chỉnh của chúng tôi. Hãy tạo thư mục đó và tôi sẽ đặt tên là "Bin" sau các thư mục mà Mac / Linux giữ các tập lệnh của nó.

> mkdir \Users\jowers\Bin

Bây giờ chúng tôi muốn thư mục đó được thêm vào $env:pathbiến của chúng tôi mỗi khi chúng tôi mở ứng dụng để quay lại WindowsPowerShellThư mục và

> start Microsoft.PowerShellISE_profile.ps1

Sau đó thêm cái này

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

Bây giờ, shell sẽ tự động tìm các lệnh của bạn, miễn là bạn lưu tập lệnh của mình trong thư mục "Bin" đó.

Khởi chạy lại quyền hạn và nó phải là một trong những tập lệnh đầu tiên thực thi.

Chạy nó trên dòng lệnh sau khi tải lại để xem thư mục mới của bạn trong biến đường dẫn của bạn:

> $env:Path

Bây giờ chúng ta có thể gọi các tập lệnh của mình từ dòng lệnh hoặc từ bên trong một tập lệnh khác đơn giản như sau:

$(customScript.ps1 arg1 arg2 ...)

Như bạn thấy, chúng ta phải gọi chúng bằng .ps1phần mở rộng cho đến khi chúng ta tạo bí danh cho chúng. Nếu chúng ta muốn có được ưa thích.


Wow, cảm ơn vì điều này, có rất nhiều ở đây. Nhưng có 9 câu trả lời khác đã ở đây. Điều này khác nhau như thế nào? Nó cung cấp thêm thông tin gì?
Stephen Rauch

Việc này cho phép chúng tôi sử dụng các tập lệnh tùy chỉnh bên trong các tập lệnh khác, giống như cách các tập lệnh tích hợp được sử dụng bên trong tập lệnh của chúng tôi. Thực hiện việc này và miễn là bạn lưu tập lệnh của mình vào thư mục bạn đặt trong đường dẫn, máy tính sẽ tự động tìm đường dẫn của tập lệnh tùy chỉnh khi bạn sử dụng tập lệnh trên dòng lệnh hoặc trong tập lệnh khác
Tyler Curtis Jowers
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.