2010-02-17 9 views
12

टेस्ट स्क्रिप्ट:पावरहेल स्क्रिप्टिंग: फ़ंक्शन कॉल के दौरान कन्फ्रोसिस को लागू करने के लिए अनुशंसित तरीका घोंसला है?

function outer 
{ 
    [cmdletbinding(supportsshouldprocess=$true)] 
    param($s) 

    process 
    {   
     $pscmdlet.shouldprocess("outer $s", "ShouldProcess") | out-null 
     "" | out-file "outer $s" 

     inner ImplicitPassthru 
     inner VerbosePassthru -Verbose:$Verbose 
     inner WhatifPassthru -WhatIf:$WhatIf 
    } 
} 

function inner 
{ 
    [cmdletbinding(supportsshouldprocess=$true)] 
    param($s) 

    process 
    { 
     $pscmdlet.shouldprocess("inner $s", "ShouldProcess") | out-null 
     "" | out-file "inner $s" 
    } 
} 

"`n** NORMAL **" 
outer normal 
"`n** VERBOSE **" 
outer verbose -Verbose 
"`n** WHATIF **" 
outer whatif -WhatIf 

आउटपुट:

** NORMAL ** 
VERBOSE: Performing operation "ShouldProcess" on Target "inner VerbosePassthru". 
What if: Performing operation "ShouldProcess" on Target "inner WhatifPassthru". 
What if: Performing operation "Output to File" on Target "inner WhatifPassthru". 

** VERBOSE ** 
VERBOSE: Performing operation "ShouldProcess" on Target "outer verbose". 
VERBOSE: Performing operation "ShouldProcess" on Target "inner VerbosePassthru". 
What if: Performing operation "ShouldProcess" on Target "inner WhatifPassthru". 
What if: Performing operation "Output to File" on Target "inner WhatifPassthru". 

** WHATIF ** 
What if: Performing operation "ShouldProcess" on Target "outer whatif". 
What if: Performing operation "Output to File" on Target "outer whatif". 
What if: Performing operation "ShouldProcess" on Target "inner ImplicitPassthru". 
What if: Performing operation "Output to File" on Target "inner ImplicitPassthru". 
What if: Performing operation "ShouldProcess" on Target "inner VerbosePassthru". 
What if: Performing operation "Output to File" on Target "inner VerbosePassthru". 
What if: Performing operation "ShouldProcess" on Target "inner WhatifPassthru". 
What if: Performing operation "Output to File" on Target "inner WhatifPassthru". 

मेरी आँख करने के लिए वहाँ कई विषमताएं यहां हैं:

  • -WhatIf निर्दिष्ट करना: $ foo होगा हमेशा $ WhatIf पर बारी कैली (और इसकी कॉलियों) में, कोई फर्क नहीं पड़ता कि $ foo क्या है।
  • जब आप निर्दिष्ट करते हैं- क्या "असली के लिए" (मौजूदा चर में इसे बाधित किए बिना), यह स्पष्ट रूप से कॉलियों का प्रचार करता है। पासस्ट्रू या स्पैटिंग के लिए कोई ज़रूरत नहीं है।
  • विपरीत नहीं - क्या स्पष्ट है, स्पष्ट-वर्बोज़ पूरी तरह से कॉलियों को कैस्केड नहीं करता है।
  • जब आप मैन्युअल रूप से passthru -Verbose: $ foo करने का प्रयास करते हैं, तो आप देखते हैं कि व्यवहार समान है -क्या: $ foo। लेकिन यह केवल उन स्क्रिप्ट को प्रभावित करता है जो मैन्युअल रूप से $ psCmdlet का परीक्षण करते हैं। ShouldProcess() - cmdlets में निर्मित प्रभावित नहीं हैं।

एनबी।: पुष्टि करें कि क्या होता है। मैंने इसे संक्षिप्तता के लिए छोड़ दिया।

वेब खोजना और कनेक्ट करना, मुझे उन्नत कार्यों के संबंध में कंधप्रचार व्यवहार (प्रो या कॉन) की गहराई से चर्चा नहीं दिखती है। निकटतम बात a post from James O'Neill है जो पूरे कॉल स्टैक में $ pscmdlet का एक उदाहरण पास करने की अनुशंसा करता है। हालांकि, वह एक पूरी तरह से अलग समस्या (एकाधिक-कॉन्फर्म संकेतों से परहेज) से काम करने के लिए ऐसा करता है। इस बीच, जब आप प्रत्येक समारोह में प्रदान किए गए मानक $ psCmdlet के साथ चिपके रहते हैं, तो मुझे उम्मीद नहीं है कि क्या अपेक्षा की जा सकती है ... बहुत कम डिज़ाइन पैटर्न, सर्वोत्तम प्रथाओं, आदि ...

उत्तर

11

आप वास्तव में $ क्या होगा यदि $ Verbose इनके लिए संश्लेषित किया गया है यानी ये चर आपके फ़ंक्शन में मौजूद नहीं हैं। यदि उपयोगकर्ता उन्हें निर्दिष्ट करता है तो आप उन्हें $ PSBoundParameters के माध्यम से प्राप्त कर सकते हैं, लेकिन यदि उपयोगकर्ता निर्दिष्ट नहीं करता है तो जाहिर है कि वे इस हैशटेबल में नहीं होंगे।

जब आप स्विच के लिए मान पास करते हैं तो PowerShell निर्दिष्ट मूल्य को एक बूल में बदलने का प्रयास करने के लिए सामान्य जबरन प्रक्रिया करेगा। चूंकि $ whatif परिभाषित नहीं किया गया है, यह $ null के लिए evals है जिसके परिणामस्वरूप स्विच मान $ true पर सेट किया जा रहा है। यह अनुमानतः है क्योंकि यह देखता है कि स्विच स्पष्ट रूप से प्रभावी रूप से कोई मूल्य नहीं है जो केवल निर्दिष्ट करने के बराबर है - बिना किसी मूल्य के। आप यह देख सकते हैं जब आप पैरामीटर बाध्यकारी का पता लगाने:

function Foo 
{ 
    [CmdletBinding(SupportsShouldProcess=1)] 
    param() 

    Process 
    { 
     $PSBoundParameters 
    } 
} 

Trace-Command -name ParameterBinding -expr {Foo -whatif:$xyzzy} -PSHost 
DEBUG: BIND NAMED cmd line args [Foo] 
DEBUG: BIND arg [] to parameter [WhatIf] 
DEBUG:  COERCE arg to [System.Management.Automation.SwitchParameter] 
DEBUG:  Arg is null or not present, type is SWITCHPARAMTER, value is true. 
DEBUG:   BIND arg [True] to param [WhatIf] SUCCESSFUL 
DEBUG: BIND POSITIONAL cmd line args [Foo] 
DEBUG: MANDATORY PARAMETER CHECK on cmdlet [Foo] 
DEBUG: CALLING BeginProcessing 
DEBUG: CALLING EndProcessing 

$ WhatIfPreference और $ VerbosePreference पर कि क्या बाहरी -verbose या -whatif साथ बुलाया गया था आधारित बाहरी में उचित रूप से सेट हो जाता है। मैं देख सकता हूं कि वे मान आंतरिक रूप से ठीक से प्रचारित होते हैं। ऐसा लगता है कि $ pscmdlet.ShouldProcess के साथ एक PowerShell बग है। ऐसा लगता है कि इस मामले में $ VerbosePreference के मूल्य का सम्मान नहीं किया जा रहा है। तुम इतनी तरह भीतरी करने -verbose के माध्यम से गुजर आज़मा सकते हैं:

function Outer 
{ 
    [CmdletBinding(SupportsShouldProcess=1)] 
    param() 

    Process 
    { 
     $pscmdlet.ShouldProcess("Outer process", '') > $null 
     inner 
     #inner -Verbose:($VerbosePreference -eq 'Continue') 
    } 
} 

function Inner 
{ 
    [CmdletBinding(SupportsShouldProcess=1)] 
    param() 

    Process 
    { 
     $pscmdlet = (Get-Variable -Scope 1 -Name PSCmdlet).Value 
     $pscmdlet.ShouldProcess("Inner process", '') > $null 
     "Inner $VerbosePreference" 
    } 
} 

Outer -Verbose 

मुझे यकीन है कि मुझे यह पसंद है क्योंकि यह तात्पर्य नहीं कर रहा हूँ:

inner VerbosePassthru -Verbose:($VerbosePreference -eq 'Continue') 

एक अन्य विकल्प तो जैसे Get-चर -Scope उपयोग करने के लिए है कि आप जानते हैं बाहरी बाहरी से 1 स्तर ऊपर है।आप अगले पीएससीएमडलेट चर के लिए देख रहे स्कोप स्टैक को "चल सकते हैं"। यह प्रभावी ढंग से पीएससीएमडलेट (जो सकल है) में पास होने से छुटकारा पाता है लेकिन यह अभी भी एक हैक है। आपको इसके बारे में एमएस कनेक्ट पर एक बग दर्ज करने पर विचार करना चाहिए।

+0

बग दायर: https://connect.microsoft.com/PowerShell/feedback/details/535559/shouldprocess-cmdlets-the-verbose-preference-is-not-evaluated-in-callees अशक्त मजबूर - > ट्रू भी एक बग आईएमओ है, क्योंकि यह सामान्य स्विच पैरामीटर के साथ नहीं होता है। अलग से दायर @ https://connect.microsoft.com/PowerShell/feedback/details/535557/shouldprocess- सिंथेटिक-parameters-should-not-coerce-null-true –

+0

वोट दिया गया। उनको दाखिल करने के लिए धन्यवाद। –

+0

अच्छा काम लोग। – JasonMArcher

0

मैं बिल्कुल वही प्रश्न लिखना चाहता था, और मैं इसे लगभग 7 साल बाद लिख रहा हूं। मुझे हैरान है कि माइक्रोसॉफ्ट की पावरशेल टीम ने अभी तक इसे ठीक नहीं किया है। मैंने इस मुद्दे को पावरशेल संस्करण 6 पूर्वावलोकन (नवीनतम संस्करण) के साथ पुन: उत्पन्न किया है।

मैं एक सरल समाधान का साथ आए हैं, वह है, Inner समारोह के अंदर, हम बना सकते हैं और एक scriptblock चलाने के लिए, $VerbosePreference जाँच जो सही ढंग से Continue के लिए सेट है, भले ही यह ShouldProcess द्वारा सम्मानित नहीं किया गया है द्वारा -Verbose ध्वज की स्थापना :


Function Outer { 
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] 
    param([string]$Name) 

    Process { 
     Write-Host "Outer called"; 
     Inner $Name 
    } 
} 

Function Inner { 
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] 
    param([string]$Name) 

    Process { 
     if (-not ($PSBoundParameters.ContainsKey('Verbose'))) { 
      $PSBoundParameters.Add('Verbose', [bool]$VerbosePreference -eq 'Continue'); 
     } 

     & { 
      [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] 

      param([string]$Name) 

      if ($PSCmdlet.ShouldProcess($Name, "Inner")) { 
       Write-Host "Inner called"; 
      } 
     } @PSBoundParameters; 
    } 
} 

Export-ModuleMember * 
+0

यह काम कर सकता है। हालांकि, इस सूक्ष्म प्रभाव को प्राप्त करने के लिए बॉयलरप्लेट कोड आवश्यक है (प्रत्येक फ़ंक्शन में!) काफी भारी है। आप एक अलग व्यवहार प्राप्त करने की कोशिश कर रहे हैं, लेकिन सभी PowerShell कोड इसका पालन नहीं करेंगे। इसका मतलब है कि आप भ्रम में जोड़ रहे हैं जब यह आपके कोडबेस में subtly diffrent काम करता है। –

संबंधित मुद्दे

 संबंधित मुद्दे