2012-03-26 18 views
11

मैं एक ऐसा फ़ंक्शन लिखने की कोशिश कर रहा हूं जो एकाधिक तर्क लेता है, जो कमांड लाइन से या पाइपलाइन से आ सकता है। तर्क तार या निर्देशिका वस्तुओं हो सकता है।मैं एक फ़ंक्शन कैसे बना सकता हूं जो पाइपलाइन और कमांड लाइन से एकाधिक तर्क प्रकार स्वीकार करता है?

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

निम्नलिखित कोड लगभग काम करता है:

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

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

यह दोनों पाइप लाइन और आदेश तर्क से तार संभालती है, और निर्देशिका वस्तुओं संभालती विचार है कि निम्नलिखित आमंत्रण के किसी भी काम करना चाहिए है पाइपलाइन से (ValueFromPipelineByPropertyName और FullName उपनाम के माध्यम से)। लेकिन यह कमांड लाइन पर निर्देशिका वस्तुओं संभाल नहीं करता, इसलिए

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

विफल रहता है, के रूप में यह तार करने के लिए निर्देशिका वस्तुओं, जो FullName के बजाय नाम संपत्ति का उपयोग करता है बदल देता है, और बाद में कोड विफल रहता है।

क्या कोई मुझे बता सकता है कि मैं क्या हासिल करना चाहता हूं?

मुझे पता है कि अगर मैं इसे काम करने के लिए भी प्राप्त कर सकता हूं, तो यह विशेष रूप से अच्छा डिज़ाइन नहीं हो सकता है। लेकिन जहां तक ​​मैं कह सकता हूं, यह है कि टेस्ट-पथ में निर्मित कैसे काम करता है, इसलिए मैं अपने स्वयं के आविष्कार से पहले मानक व्यवहार का पालन करना चाहता हूं ...

उत्तर

9

चूंकि आपका पैरामीटर प्रकार string है, यह फ़ाइल सिस्टम जानकारी को जोड़ रहा है जब आप पाइपलाइन { Test-VEnv $_ } का उपयोग नहीं कर रहे हैं तो स्ट्रिंग में ऑब्जेक्ट करें। यदि आप या तो System.IO.FileInfo या System.IO.DirectoryInfo ऑब्जेक्ट की विधि को कॉल करते हैं तो आप इसे देखेंगे। जब आप पाइपलाइन का उपयोग करते हैं तो यह पूर्ण नाम उपनाम देता है जो आपको पूरा पथ देता है।

आप देख सकते हैं कि PowerShell Trace-Command का उपयोग कर इनपुट ऑब्जेक्ट को बाध्य करने के लिए क्या कर रहा है।

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

यहाँ उत्पादन का महत्वपूर्ण हिस्सा है::

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 एक ही बात करता है इसका इस्तेमाल करने का एक उदाहरण है। इन तीन उदाहरण पर एक नज़र डालें:

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. मेरी पीडब्ल्यूडी के बाद से C:\ नहीं है मैं गलत मिलता है क्योंकि DirectoryInfo वस्तु स्ट्रिंग (ToString()) जो केवल फ़ोल्डर नाम देता है में बदल जाती है। ऐसा इसलिए है क्योंकि पाइपलाइन का उपयोग नहीं किया गया था।

  2. के बाद से पाइपलाइन यह काम करता है क्योंकि यह इस पैरामीटर के साथ PsPath के लिए बाध्य किया जाता है प्रयोग किया जाता है:

    [Parameter(ParameterSetName='LiteralPath', Mandatory=$true, ValueFromPipelineByPropertyName=$true)] 
    [Alias('PSPath')] 
    [string[]] 
    ${LiteralPath}, 
    
  3. के बाद से निर्देशिका फ़ोल्डर फ़ोल्डर के नाम से मौजूद है शामिल हैं।

आप अपने बंधन के लिए उर्फ ​​PsPath कोशिश कर सकते हैं।यह वही है Test-Path का उपयोग करता है:

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

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

कुछ परीक्षण:

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 

आउटपुट:

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

ठीक है, तो आप जो कह रहे हैं वह यह है कि मेरा कार्य परीक्षण पथ की तरह व्यवहार करता है। मेरी माफ़ी, मुझे लगता है कि मेरा परीक्षण थोड़ा उलझ गया है - मेरे लिए स्पष्टीकरण के लिए धन्यवाद। तो क्या इसका मतलब यह है कि परिणाम प्राप्त करना संभव नहीं है? (कोड में कम से कम गंदे स्पष्ट प्रकार के चेक के बिना नहीं) –

+0

@PaulMoore क्या आप पाइपलाइन का उपयोग करते हैं या नहीं, भले ही स्ट्रिंग के रूप में पूर्ण पथ को '$ पथ' तक सीमित कर रहे हों? –

+0

@PaulMoore 'PsPath' का उपयोग करने का प्रयास करें, यह' टेस्ट-पथ 'का उपयोग करता है। मैंने कुछ उदाहरणों के साथ अपना जवाब अपडेट किया। –

0

अगर आप [] करने के लिए स्ट्रिंग से $ पथ का प्रकार बदलने के काम करता है [सिस्टम .IO.DirectoryInfo []]?

+0

यह स्पष्ट नहीं है कि ओपी FileInfos और DirectoryInfos दोनों को संसाधित करना चाहता है या नहीं। चूंकि उदाहरण पथ का उपयोग कर रहा है, मेरा अनुमान है कि दोनों का उपयोग किया जा रहा है। –

+0

आप शायद सही हैं। मैंने इसे इस पर आधारित किया: 'तर्क स्ट्रिंग या निर्देशिका ऑब्जेक्ट्स हो सकते हैं'। –

+0

यदि 'test-VEnv' केवल निर्देशिकाओं पर काम करना है, तो मैं यही करूँगा। –

7

@ एंडी कुछ अच्छी जानकारी देता है जो विशेष रूप से आपके प्रश्न में अंक संबोधित करता है। यहां मेरा जवाब व्यापक प्रभावों पर विचार करने के पूरक के अधिक है। यह शायद केवल एक टिप्पणी होने का हकदार है, लेकिन लंबाई और मेरी शामिल छवि मुझे इसे केवल एक टिप्पणी के रूप में पोस्ट करने से रोकती है ...

मैंने हाल ही में पावरहेल बनाम सीधे इनपुट के सवाल को एक विशिष्ट लक्ष्य के साथ जांच लिया इनपुट के सभी वर्गों के संबंध में और डिफ़ॉल्ट रूप से लागू किए जाने के संबंध में इन इनपुट धाराओं को सममित बनाते हैं। कर रहे हैं, मेरी गणना द्वारा, इनपुट के छह तुल्यता कक्षाओं विचार करने के लिए:

  • कोई इनपुट
  • अशक्त
  • खाली
  • अदिश
  • सामान्य मूल्यों
  • की सूची की सूची मिश्रित मान (यानी कुछ शून्य या खाली)

एक आम तौर पर जब इन इनपुट में से प्रत्येक के एक समारोह के लिए भेजा जाता है इस इसी सूची होगा उम्मीद करेंगे क्या:

  • डिफ़ॉल्ट मान
  • अशक्त
  • खाली
  • अदिश
  • की सूची सामान्य मूल्य
  • मिश्रित मूल्यों (यानी कुछ शून्य या खाली)

यह है कि, डिफ़ॉल्ट इनपुट की आपूर्ति की गई कोई इनपुट नहीं है; अन्यथा दिए गए मान का उपयोग किया जाता है। यह लगभग मामूली लगता है, व्यावहारिक रूप से एक tautology, लेकिन कुछ subtleties हैं। उदाहरण के लिए, पाइपलाइन के माध्यम से कोई इनपुट आपूर्ति करने का क्या अर्थ है? क्या यह शून्य या खाली संग्रह है? मैं बाद में अन्य कारणों के लिए संघर्ष करता हूं, यह उपरोक्त वर्णित धाराओं के बीच समरूपता की अनुमति देता है। इसके अलावा, आप दोनों कैसे लिखते हैं आपके फ़ंक्शन हस्ताक्षर और आपका फ़ंक्शन बॉडी किसी एक या अन्य इनपुट स्ट्रीम के साथ इनमें से कुछ या सभी इनपुट कक्षाओं पर कभी-कभी आश्चर्यजनक प्रभाव डालता है। इस प्रकार, मैं आगे तर्क देता हूं कि पहली नज़र में आंखों की तुलना में इस "तुच्छ" विचार के लिए बहुत कुछ है। इतना आसान है कि मैंने आलेख Down the Rabbit Hole- A Study in PowerShell Pipelines, Functions, and Parameters, पर सरल-Talk.com पर प्रकाशित किया।लेख के साथ शामिल एक वालचार्ट है जो छः समकक्ष इनपुट कक्षाओं की एक तालिका दिखाता है और आप प्रत्येक के लिए अलग-अलग फ़ंक्शन टेम्पलेट्स के साथ क्या प्राप्त करते हैं। यहाँ 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 

यह कैसे काम करता:
1) एक परिवर्तन पैरामीटर मूल्य पर कार्रवाई करने के गुण बनाएँ।
2) परिवर्तन के दौरान, यदि मान फ़ाइल सिस्टम सिस्टम या पथइन्फो है, तो हम मान लेते हैं, यदि हम मूल्य को स्ट्रिंग में परिवर्तित नहीं करते हैं और सुनिश्चित करते हैं कि "पथ" मान्य है (और आवश्यक होने पर पथ को हल करें)।
3) लागू होने पर, परिवर्तन का परिणाम हमेशा स्ट्रिंग होता है।