2012-10-02 35 views
7

Tôi muốn tạo một chức năng PowerShell liệt kê một số dữ liệu và kích hoạt một khối tập lệnh trên tất cả các lần xuất hiện.Chức năng PowerShell với khối tập lệnh tham số

Bởi bây giờ tôi có (điều này không phải là mã thực tế, nhưng nó cho thấy vấn đề của tôi):

function Invoke-TenTimes 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Mandatory=$true, Position=0)] 
     [ScriptBlock]$Action 
    ) 
    process 
    { 
     $digits = 0..10 
     $digits | % { 
      $Action.Invoke($_); 
     } 
    } 
} 

tôi đặt chức năng này trong mô-đun của tôi. Tuy nhiên, tôi không nhận được bất kỳ kết quả nào khi tôi gọi:

Invoke-TenTimes { $_ } 

Đầu ra trống (không có gì được hiển thị).

Nếu tôi gọi

Invoke-TenTimes { $_ -eq $null } 

tôi được mười true. Trong thực tế, tôi thấy rằng $_ là null.

Cách thích hợp để điền $_ là gì?

gì là lái xe cho tôi điên, là nếu tôi đặt chức năng này và các cuộc gọi trong file ps1 cùng, nó hoạt động (nhưng tôi muốn vượt qua khối kịch bản theo yêu cầu):

function Invoke-TenTimes 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Mandatory=$true, Position=0)] 
     [ScriptBlock]$Action 
    ) 
    process 
    { 
     $digits = 0..10 
     $digits | % { 
      $Action.Invoke($_); 
     } 
    } 
} 


Invoke-TenTimes { $_ } 

Trả lời

2

đây là một vấn đề Phạm vi với thông qua vào scriptblock thuộc về một phạm vi khác với nơi nó được thực hiện. Nếu thông qua trong scriptblock sẽ không phải tham chiếu đến các biến từ ngữ cảnh của nó, bạn có thể đơn giản sao chép tập lệnh chặn để buộc nó nằm trong phạm vi bạn đang chạy nó. với

$action = [scriptblock]::Create($action) 

điều thú vị là nó chỉ hoạt động ngay từ đầu bởi ACCIDENT. nó đã nhận được $ _ từ phạm vi cha mẹ của nơi mà các scriptblock thuộc mà xảy ra được bên trong bạn foreach-đối tượng đó là tốt.

tuy nhiên lấy phiên bản ban đầu của bạn, và sau đó chạy này

"gotcha" | % { 
Invoke-TenTimes { $_ } 
} 

và bạn sẽ thấy bạn sẽ nhận được Gotcha 10 lần, vì $ _ không phải là null trong phạm vi người gọi của bạn, nhưng là một cái gì đó.

+0

Cảm ơn! điều này đã giải quyết được vấn đề của tôi và bây giờ tôi có thể sử dụng một khối tập lệnh với $ _ :). –

3

Vấn đề là được biết và nó là cụ thể cho các mô-đun. Có lẽ đây thậm chí là một lỗi. Xin hãy nhìn vào câu hỏi này: Strange behavior with Powershell scriptblock variable scope and modules, any suggestions?

Đối với trường hợp cụ thể của bạn, hãy gọi chức năng của bạn như thế này:

Invoke-TenTimes { $args[0] } 

Bằng cách này nó sẽ làm việc như mong đợi.

+0

Điều này đã giải quyết được sự cố của tôi. Nhưng tôi sẽ đợi một vài ngày để xem ai đó có một giải pháp thực tế để đề xuất hay không. –

5

Ở đây chúng ta đi:

$scriptblock = {param($number) Write-Host "Current Number is $number"} 

function Invoke-TenTimes 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Mandatory=$true, Position=0)] 
     [ScriptBlock]$Action 
    ) 
    $digits = 1..10 
    $digits | ForEach-Object{Invoke-Command -ScriptBlock $Action -Args $_} 
} 

Sử dụng:

Invoke-TenTimes $scriptblock 
0

Nó dễ dàng hơn mọi người cho phép.

Xem xét $ A và $ B được xác định ở cấp độ toàn cầu và chỉ $ B được xác định ở cấp mô-đun. Khối tập lệnh của bạn là phạm vi thứ 3. Trong đó, bạn tham khảo $ A và nhận giá trị toàn cầu.Tương tự như vậy nếu bạn tham khảo $ B, bạn nhận được giá trị cấp mô-đun vì nó vượt quá thể hiện toàn cục.

VẤN ĐỀ: Nếu bạn cố ghi vào một trong hai - một cá thể cục bộ được tạo.

Trả lời:

([ref]$A).value = 'Something malicious' 

Lưu ý rằng "([ref] $ {name})" là một đối tượng tài liệu tham khảo như vậy ".Value" là cần thiết để đạt được các biến thực tế. Vì vậy,

([ref]$B).value.Length 

cũng giống như

$B.Length 

Trong cả hai trường hợp bạn không có kiểm soát trực tiếp trên phạm vi. Bạn nhận được ví dụ bạn sẽ đọc từ. Vì vậy, ví dụ đầu tiên sửa đổi Global $ A và ví dụ thứ hai tham chiếu đến thể hiện mức mô đun của $ B.

Các vấn đề liên quan