2012-01-05 15 views
10

PowerShell v2 में, निम्न पंक्ति:चुनिंदा ऑब्जेक्ट पावरशेल v3 में पाइपलाइन को कैसे रोकता है?

1..3| foreach { Write-Host "Value : $_"; $_ }| select -First 1 

चाहेंगे प्रदर्शन:

Value : 1 
1 
Value : 2 
Value : 3 

के बाद से सभी तत्वों को नीचे पाइप लाइन धकेल दिया गया। हालांकि, v3 में उपरोक्त पंक्ति केवल प्रदर्शित करता है: इससे पहले कि 2 और 3 को Foreach-Object भेजा जाता है

Value : 1 
1 

पाइप लाइन बंद कर दिया है (ध्यान दें: Select-Object के लिए -Wait स्विच सभी तत्वों foreach ब्लॉक तक पहुँचने के लिए अनुमति देता है)।

कैसे Select-Object पाइपलाइन रोक होता है, और अब मैं एक foreach से या अपने खुद के समारोह से पाइप लाइन बंद कर सकते हैं?

संपादित करें: मैं जानता हूँ कि मैं एक करते हैं में एक पाइप लाइन लपेट कर सकते हैं ... जबकि पाश और पाइप लाइन से बाहर जारी है। मैंने यह भी पाया है v3 में मैं (यह वी 2 में काम नहीं करता) कुछ इस तरह कर सकते हैं कि:

function Start-Enumerate ($array) { 
    do{ $array } while($false) 
} 

Start-Enumerate (1..3)| foreach {if($_ -ge 2){break};$_}; 'V2 Will Not Get Here' 

लेकिन Select-Object इन तकनीकों इसलिए मुझे उम्मीद थी के लिए एक रास्ता था कि दोनों में से किसी की आवश्यकता नहीं है पाइपलाइन में एक बिंदु से पाइपलाइन को रोकें।

+1

तो तुम StopUpstreamCommandsException लिए देख रहे हैं, लेकिन आप कर सकते हैं इसका उपयोग नहीं करते क्योंकि यह आंतरिक है। यहां इसके लिए एक एमएस कनेक्ट सुझाव है: https://connect.microsoft.com/PowerShell/feedback/details/768650/enable-users-to-stop-pipeline-making-stopupstreamcommandsexception-public –

+1

धन्यवाद, @LarsTruijens मुझे इंगित करने के लिए उस से; मैंने इसे वोट दिया। – Rynant

उत्तर

3

चेक आप एक पाइप लाइन कैसे रद्द कर सकते हैं पर इस पोस्ट:
http://powershell.com/cs/blogs/tobias/archive/2010/01/01/cancelling-a-pipeline.aspx

PowerShell 3.0 में यह एक इंजन सुधार है। CTP1 नमूने फ़ोल्डर ('\ इंजन प्रदर्शन \ विविध \ ConnectBugFixes.ps1') से:

# Connect Bug 332685 
# Select-Object optimization 
# Submitted by Shay Levi 
# Connect Suggestion 286219 
# PSV2: Lazy pipeline - ability for cmdlets to say "NO MORE" 
# Submitted by Karl Prosser 

# Stop the pipeline once the objects have been selected 
# Useful for commands that return a lot of objects, like dealing with the event log 

# In PS 2.0, this took a long time even though we only wanted the first 10 events 
Start-Process powershell.exe -Args '-Version 2 -NoExit -Command Get-WinEvent | Select-Object -First 10' 

# In PS 3.0, the pipeline stops after retrieving the first 10 objects 
Get-WinEvent | Select-Object -First 10 
+0

हां, मैंने इन दोनों को देखा है। मैंने अपना प्रश्न अपडेट कर लिया है। – Rynant

+0

जहां तक ​​मैं यह कह सकता हूं कि यह एक StopUpstreamCommandsException अपवाद फेंकता है, जो कि मैंने उल्लेख किए गए पोस्ट में टोबीस क्या कर रहा है उससे बहुत समान है। –

+1

लेकिन पाइपलाइनस्टॉप अपवाद के विपरीत, 'चयन-ऑब्जेक्ट' डाउनस्ट्रीम कमांड को पूरा करने से नहीं रोकता है। मैं उपयोगकर्ता को यह जानने के बिना पाइपलाइन को रोकने में सक्षम होना चाहूंगा कि उन्हें कुछ समय-समय पर पाइपलाइन लपेटनी पड़ेगी, लेकिन मुझे लगता है कि यह StopUpstreamCommandsException का उपयोग नहीं कर सकता क्योंकि यह एक निजी प्रकार है। – Rynant

1

मुझे पता है कि एक PipelineStoppedException फेंकने पाइप लाइन बंद हो जाता है। निम्न उदाहरण अनुकरण करेंगे v3.0 में Select -first 1 साथ क्या देखते हैं, v2.0 में:

filter Select-Improved($first) { 
    begin{ 
     $count = 0 
    } 
    process{ 
     $_ 
     $count++ 
     if($count -ge $first){throw (new-object System.Management.Automation.PipelineStoppedException)} 
    } 
} 

trap{continue} 
1..3| foreach { Write-Host "Value : $_"; $_ }| Select-Improved -first 1 
write-host "after" 
+0

आपके पास एक टाइपो है: $ मुट्ठी> $ पहले। और 'नया' नया ऑब्जेक्ट होना चाहिए। –

+0

@ShayLevy - धन्यवाद, सही :) – manojlds

+1

मेरे पास एक पाइपलाइन स्टॉपप्डएक्सप्शन फेंकने की समस्या यह है कि पाइपलाइन के नीचे दिए गए आदेश प्रसंस्करण को समाप्त नहीं करते हैं। यह काम करता है: '1..5 | चुनें- पहले 3 | माप ', लेकिन यह नहीं है: '1..5 | चुनें-बेहतर-पहले 3 | माप – Rynant

3

StopUpstreamCommandsException, ActionPreferenceStopException, और PipelineClosedException फेंक, $ PSCmdlet.ThrowTerminatingError बुला और $ ExecutionContext सहित कई तरीकों, की कोशिश के बाद। Host.Runspace.GetCurrentlyRunningPipeline()। Stopper.set_IsStopping ($ true) मुझे अंत में पता चला कि केवल चयन-ऑब्जेक्ट का उपयोग करना एकमात्र चीज थी जिसने पूरी स्क्रिप्ट को रद्द नहीं किया (केवल पाइपलाइन बनाम)। [ध्यान दें कि ऊपर उल्लेख किया आइटम में से कुछ निजी सदस्यों, जो मैं प्रतिबिंब के माध्यम से एक्सेस करने के लिए उपयोग की आवश्यकता है।]

# This looks like it should put a zero in the pipeline but on PS 3.0 it doesn't 
function stop-pipeline { 
    $sp = {select-object -f 1}.GetSteppablePipeline($MyInvocation.CommandOrigin) 
    $sp.Begin($true) 
    $x = $sp.Process(0) # this call doesn't return 
    $sp.End() 
} 

नई विधि ओपी से टिप्पणी के आधार पर इस प्रकार। दुर्भाग्य से यह विधि बहुत जटिल है और निजी सदस्यों का उपयोग करती है। इसके अलावा मुझे नहीं पता कि यह कितना मजबूत है - मुझे अभी काम करने के लिए ओपी का उदाहरण मिला और वहां रुक गया।तो FWIW: प्रतिबिंब के माध्यम से विधि आह्वान करने के लिए

$t_cmdRun = $pscmdlet.CommandRuntime.gettype() 
# Get pipelineprocessor value ($pipor) 
$bindFlags = [Reflection.BindingFlags]"NonPublic,Instance" 
$piporProp = $t_cmdRun.getproperty("PipelineProcessor", $bindFlags) 
$pipor=$piporProp.GetValue($PSCmdlet.CommandRuntime,$null) 

Powershell कोड:

# wh is alias for write-host 
# sel is alias for select-object 

# The following two use reflection to access private members: 
# invoke-method invokes private methods 
# select-properties is similar to select-object, but it gets private properties 

# Get the system.management.automation assembly 
$smaa=[appdomain]::currentdomain.getassemblies()| 
     ? location -like "*system.management.automation*" 

# Get the StopUpstreamCommandsException class 
$upcet=$smaa.gettypes()| ? name -like "*upstream*" 

filter x { 
    [CmdletBinding()] 
    param(
    [parameter(ValueFromPipeline=$true)] 
    [object] $inputObject 
) 
    process { 
    if ($inputObject -ge 5) { 
     # Create a StopUpstreamCommandsException 
     $upce = [activator]::CreateInstance($upcet,@($pscmdlet)) 

     $PipelineProcessor=$pscmdlet.CommandRuntime|select-properties PipelineProcessor 
     $commands = $PipelineProcessor|select-properties commands 
     $commandProcessor= $commands[0] 

     $null = $upce.RequestingCommandProcessor|select-properties * 

     $upce.RequestingCommandProcessor.commandinfo = 
      $commandProcessor|select-properties commandinfo 

     $upce.RequestingCommandProcessor.Commandruntime = 
      $commandProcessor|select-properties commandruntime 

     $null = $PipelineProcessor| 
      invoke-method recordfailure @($upce, $commandProcessor.command) 

     1..($commands.count-1) | % { 
     $commands[$_] | invoke-method DoComplete 
     } 

     wh throwing 
     throw $upce 
    } 
    wh "< $inputObject >" 

    $inputObject 
    } # end process 
    end { 
    wh in x end 
    } 
} # end filter x 

filter y { 
    [CmdletBinding()] 
    param(
    [parameter(ValueFromPipeline=$true)] 
    [object] $inputObject 
) 
    process { 
    $inputObject 
    } 
    end { 
    wh in y end 
    } 
} 

1..5| x | y | measure -Sum 

PowerShell कोड प्रतिबिंब के माध्यम से PipelineProcessor मान प्राप्त करने के लिए

$proc = (gps)[12] # semi-random process 
$methinfo = $proc.gettype().getmethod("GetComIUnknown", $bindFlags) 
# Return ComIUnknown as an IntPtr 
$comIUnknown = $methinfo.Invoke($proc, @($true)) 
+0

स्वरूपण में सुधार, कृपया। –

+0

यह वह नहीं करता जो मैं ढूंढ रहा हूं। '1..5 | चयन करें - पहले 3 | उपाय -सम 'परिणाम देता है, लेकिन '1..5 | % {अगर ($ _ -ge 4) {स्टॉप-पाइपलाइन}} | उपाय -सम 'नहीं है। मैं नई वस्तुओं को पाइपलाइन के माध्यम से भेजने से रोकना चाहता हूं, लेकिन पाइपलाइन को प्रसंस्करण खत्म करने की अनुमति देता हूं। – Rynant

+1

क्या आप 'invoke-method' और' select-Properties' फ़ंक्शंस 'के लिए कोड शामिल कर सकते हैं? आपूर्ति कोड उन कार्यों के बिना काम नहीं करेगा। – Rynant