2012-03-26 24 views
11

Tôi đang cố gắng viết một hàm lấy nhiều đối số, có thể đến từ dòng lệnh hoặc từ đường dẫn. Các đối số có thể là các chuỗi hoặc các đối tượng thư mục. Ý tưởng là bất kỳ lời gọi sau đây nên làm việc:Làm cách nào để tạo một hàm chấp nhận nhiều loại đối số từ đường ống và dòng lệnh?

Test-VEnv '.\MyPath', '.\AnotherPath' 
Test-VEnv (dir) 
'MyPath', 'AnotherPath' | Test-VEnv 
dir | Test-VEnv 

Các mã sau đây gần công trình:

function Test-VEnv { 
    [CmdletBinding()] 
    param (
     [Parameter(Mandatory=$true, Position=0, 
      ValueFromPipeline=$True, 
      ValueFromPipelineByPropertyName=$true)] 
     [Alias('FullName')] 
     [String[]]$Path 
    ) 

    process { 
     foreach ($P in $Path) { 
      ... 
     } 
    } 
} 

Nó xử lý chuỗi cả từ các đường ống dẫn và các tham số lệnh, và xử lý các đối tượng thư mục từ đường ống (thông qua ValueFromPipelineByPropertyName và bí danh FullName). Nhưng nó không xử lý các đối tượng thư mục trên dòng lệnh, do đó,

dir | Where-Object { Test-VEnv $_ } 

không thành công.

Có ai có thể cho tôi biết cách đạt được những gì tôi muốn không?

Tôi biết rằng ngay cả khi tôi có thể làm việc này, nó có thể không phải là một thiết kế đặc biệt tốt. Nhưng theo như tôi có thể nói, đó là cách xây dựng trong Test-Path hoạt động, vì vậy tôi muốn thử theo hành vi tiêu chuẩn trước khi tôi phát minh ra ...

Trả lời

9

Vì loại tham số của bạn là string nó là thông tin hệ thống tập tin đối tượng thành chuỗi khi bạn không sử dụng đường ống { Test-VEnv $_ }. Nếu bạn gọi phương thức ToString() của đối tượng System.IO.FileInfo hoặc System.IO.DirectoryInfo, bạn sẽ thấy điều này. Khi bạn sử dụng đường ống, nó liên kết bí danh fullname cho bạn đường dẫn đầy đủ.

Bạn có thể xem PowerShell đang làm gì để ràng buộc đối tượng đầu vào bằng cách sử dụng Trace-Command. Dưới đây là một ví dụ về cách sử dụng nó:

trace-command -name parameterbinding -expression {(dir C:\)[0] | ? {Test-VEnv $_}} -pshost 

đây là phần quan trọng của kết quả:

BIND arg [PerfLogs] to parameter [Path] 
    Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute] 
     result returned from DATA GENERATION: System.String[] 
    COERCE arg to [System.String[]] 
     Parameter and arg types the same, no coercion is needed. 
    BIND arg [System.String[]] to param [Path] SUCCESSFUL 

Test-Path làm điều tương tự. Hãy xem ba ví dụ sau:

PS C:\Users\Andy> Test-Path (dir C:\)[0] 
False 
PS C:\Users\Andy> (dir C:\)[0] | Test-Path 
True 
PS C:\> Test-Path (dir C:\)[0] 
True 
  1. Kể từ PWD tôi không phải là C:\ tôi nhận FALSE vì đối tượng DirectoryInfo được chuyển thành chuỗi (ToString()) mà chỉ cung cấp cho các tên thư mục. Điều này là do đường ống không được sử dụng.

  2. Kể từ khi đường ống được sử dụng nó hoạt động bởi vì nó được gắn vào PsPath với tham số này:

    [Parameter(ParameterSetName='LiteralPath', Mandatory=$true, ValueFromPipelineByPropertyName=$true)] 
    [Alias('PSPath')] 
    [string[]] 
    ${LiteralPath}, 
    
  3. Kể từ khi thư mục chứa thư mục tên của thư mục tồn tại.

Bạn có thể thử bí danh PsPath để ràng buộc.Đây là những gì Test-Path sử dụng:

param (
    [Parameter(Mandatory=$true, Position=0, 
     ValueFromPipeline=$True, 
     ValueFromPipelineByPropertyName=$true)] 
    [Alias('PsPath')] 
    [String[]] $Path 
) 

process { 
    foreach ($P in $Path) { 
     Get-Item $p 
    } 
} 

Một số xét nghiệm:

Set-Location C:\ 
Write-Host 1 
    Test-VEnv '.\Windows', '.\Program Files' 
Write-Host 2 
    Test-VEnv (dir) 
Write-Host 3 
    'Windows', 'Program Files' | Test-VEnv 
Write-Host 4 
    dir | Test-VEnv 

Output:

1 
    Directory: C:\ 
Mode    LastWriteTime  Length Name              
----    -------------  ------ ----              
d----   3/14/2012 3:41 AM   Windows              
d-r--   3/24/2012 7:46 PM   Program Files            

2 
d----   2/18/2012 4:32 AM   PerfLogs             
d-r--   3/24/2012 7:46 PM   Program Files            
d-r--   3/25/2012 4:49 PM   Program Files (x86)           
d----   3/9/2012 9:57 PM   Python27             
d-r--   3/4/2012 8:11 PM   Users              
d----   3/14/2012 3:41 AM   Windows              
-a---   3/4/2012 8:45 PM  1024 .rnd              

3 
d----   3/14/2012 3:41 AM   Windows              
d-r--   3/24/2012 7:46 PM   Program Files            

4 
d----   2/18/2012 4:32 AM   PerfLogs             
d-r--   3/24/2012 7:46 PM   Program Files            
d-r--   3/25/2012 4:49 PM   Program Files (x86)           
d----   3/9/2012 9:57 PM   Python27             
d-r--   3/4/2012 8:11 PM   Users              
d----   3/14/2012 3:41 AM   Windows              
-a---   3/4/2012 8:45 PM  1024 .rnd 
+0

OK, vậy điều bạn đang nói là chức năng của tôi hoạt động như đường dẫn kiểm tra. Lời xin lỗi của tôi, tôi dường như đã thử nghiệm của tôi một chút lộn xộn - cảm ơn vì đã làm rõ cho tôi. Vậy điều đó có nghĩa là không thể đạt được kết quả tôi muốn? (Ít nhất không phải không có kiểm tra loại rõ ràng lộn xộn trong mã) –

+0

@PaulMoore Bạn đang mong đợi đường dẫn đầy đủ bị ràng buộc như là một chuỗi để '$ Path' bất kể đường ống được sử dụng hay không? –

+0

@PaulMoore Hãy thử sử dụng 'PsPath' đây là những gì' Test-Path' sử dụng. Tôi đã cập nhật câu trả lời của mình với một số ví dụ. –

0

Liệu nó có tác dụng nếu bạn thay đổi kiểu của $ path từ String [] tới [Hệ thống .IO.DirectoryInfo []]?

+0

Nó không rõ ràng nếu OP muốn xử lý cả FileInfos và DirectoryInfos hay không. Vì ví dụ này sử dụng đường dẫn mà tôi đoán cả hai đều đang được sử dụng. –

+0

Có lẽ bạn đang đúng. Tôi đã thêm điều này dựa trên: 'Các đối số có thể là chuỗi hoặc đối tượng thư mục'. –

+0

Nếu 'Test-VEnv' chỉ hoạt động trên các thư mục thì đây là những gì tôi muốn làm. –

7

@Andy cung cấp một số thông tin tuyệt vời cụ thể giải quyết các điểm trong câu hỏi của bạn. Câu trả lời của tôi ở đây là nhiều hơn một bổ sung xem xét các tác động rộng lớn hơn. Nó có lẽ chỉ xứng đáng là một nhận xét nhưng độ dài và hình ảnh được bao gồm của tôi ngăn tôi đăng bài này chỉ là một bình luận ...

Gần đây tôi đã xem xét câu hỏi về đường ống so với đầu vào trực tiếp trong Powershell với mục tiêu cụ thể hướng tới làm cho các luồng đầu vào này đối xứng đối với tất cả các lớp đầu vào và đối với các giá trị mặc định được áp dụng. Có, bởi phán xét tôi, sáu lớp tương đương đầu vào cần cân nhắc:

  • không có đầu vào
  • rỗng
  • trống
  • vô hướng
  • danh sách giá trị bình thường
  • danh sách các giá trị hỗn hợp (ví dụ: một số giá trị rỗng hoặc trống)

gì người ta thường mong chờ khi mỗi một trong các yếu tố đầu vào sẽ được gửi đến một chức năng sẽ là danh sách tương ứng này:

  • giá trị mặc định
  • rỗng
  • trống
  • vô hướng
  • danh sách bình thường giá trị
  • danh sách giá trị hỗn hợp (ví dụ: một số rỗng hoặc trống)

Tức là, không có đầu vào nào được cung cấp giá trị mặc định được sử dụng; nếu không thì giá trị đã cho sẽ được sử dụng. Điều này nghe có vẻ gần như tầm thường, thực tế là tautology, nhưng có một số tinh tế. Ví dụ: xem xét việc cung cấp không có đầu vào qua đường ống là gì? Nó là một bộ sưu tập rỗng hay không? Tôi cho rằng cái thứ hai, trong số các lý do khác, nó cho phép đối xứng giữa các luồng tôi đã đề cập ở trên. Hơn nữa, cách bạn viết cả hai chữ ký chức năng cơ quan chức năng của bạn đôi khi gây ra những tác động đáng ngạc nhiên đối với một số hoặc tất cả các lớp nhập này bằng một hoặc các luồng đầu vào khác. Vì vậy, tôi tiếp tục tranh luận rằng có nhiều hơn nữa để xem xét "tầm thường" này hơn đáp ứng mắt ở cái nhìn đầu tiên. Vì vậy, nhiều như vậy mà tôi đã viết rộng rãi về nó trong bài viết Down the Rabbit Hole- A Study in PowerShell Pipelines, Functions, and Parameters, được xuất bản trên Simple-Talk.com.Bao gồm với bài viết là một wallchart cho thấy một bảng của sáu lớp đầu vào tương đương và những gì bạn nhận được cho mỗi với các mẫu chức năng khác nhau. Đây là một hình ảnh thu nhỏ của wallchart:

enter image description here

0
function Install-PathTransformation 
{ 
    [CmdletBinding()] 
    param() 

    if (-not $script:my_pathtransformation_types) { 
     $script:my_pathtransformation_types = Add-Type -TypeDefinition @" 
     using System; 
     using System.IO; 
     using System.Management.Automation; 

     public class ValidPathTransformationAttribute : ArgumentTransformationAttribute { 
      public bool Resolve { 
       get; 
       set; 
      } 

      public override Object Transform(EngineIntrinsics engineIntrinsics, Object inputObject) { 
       PSObject psobj = inputObject as PSObject; 
       if (psobj != null) 
        inputObject = psobj.BaseObject; 
       if (inputObject == null) 
        return inputObject; 

       FileSystemInfo test1 = inputObject as FileSystemInfo; 
       if (test1 != null) 
        return test1.FullName; // no need for further checks, path shoul de qualified! 

       PathInfo test2 = inputObject as PathInfo; 
       if (test2 != null) 
        return test2.Path;  // no need for further checks, path shoul de qualified! 

       string test3 = inputObject as string; 
       if (test3 == null) 
        test3 = (string)LanguagePrimitives.ConvertTo(inputObject, typeof(string)); 
       if (Resolve) 
        test3 = engineIntrinsics.SessionState.Path.GetUnresolvedProviderPathFromPSPath(test3); 
       else if (!engineIntrinsics.SessionState.Path.IsValid(test3)) 
        throw new ArgumentTransformationMetadataException("Invalid path value: " + test3); 
       return test3; 
      } 
     } 
"@ 
    } 
    return $script:my_pathtransformation_types 
} 


Install-PathTransformation 

function A(
    [parameter(Mandatory=$false, ValueFromPipeline=$true)] 
    [ValidPathTransformation(Resolve=$true)] 
    [string] # optional, transformation returns always string 
    $z) { 
    Process { 
    Write-Host $("{0}: {1}" -f $z.GetType().FullName, $z) 
    } 
} 

& { 
    'mumu', 10, 10.5, "" 
    dir $env:Temp | select -First 5 
} | A 

Cách hoạt động:
1) Tạo một chuyển đổi thuộc tính để xử lý các giá trị thông số. Trong khi chuyển đổi, nếu Value là FileSystemInfo hoặc PathInfo chúng ta lấy giá trị bên trong, nếu không chúng ta chuyển đổi giá trị thành chuỗi và đảm bảo rằng "path" là hợp lệ (và phân giải đường dẫn nếu cần).
3) Khi được áp dụng, kết quả của Phép biến đổi luôn luôn là chuỗi.

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