2012-01-06 7 views
61

के साथ मानक आउट और त्रुटि को कैप्चर करना StandardError और StandardOutput गुणों तक पहुंचने पर पावरहेल के Start-Process कमांड में कोई बग है?स्टार्ट-प्रोसेस

अगर मैं निम्नलिखित चलाने मुझे कोई उत्पादन

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait 
$process.StandardOutput 
$process.StandardError 

मिल लेकिन अगर मैं एक फाइल करने के लिए उत्पादन अनुप्रेषित मैं अपेक्षित परिणाम

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait -RedirectStandardOutput stdout.txt -RedirectStandardError stderr.txt 
+4

इस विशिष्ट मामले में आपको वास्तव में स्टार्ट-प्रोसेस की आवश्यकता है? ...'$ process = ping localhost' # प्रक्रिया चर में आउटपुट को सहेज लेगा। – mjsr

+1

सच है। मैं वापसी और तर्कों को संभालने के लिए एक क्लीनर तरीका ढूंढ रहा था। मैंने आपके द्वारा दिखाए गए स्क्रिप्ट को लिखना समाप्त कर दिया। – jzbruno

उत्तर

84

है कि कैसे Start-Process किसी कारण से डिजाइन किया गया था मिलता है। यहाँ एक तरह से फाइल करने के लिए भेजने के बिना इसे पाने के लिए है:

$pinfo = New-Object System.Diagnostics.ProcessStartInfo 
$pinfo.FileName = "ping.exe" 
$pinfo.RedirectStandardError = $true 
$pinfo.RedirectStandardOutput = $true 
$pinfo.UseShellExecute = $false 
$pinfo.Arguments = "localhost" 
$p = New-Object System.Diagnostics.Process 
$p.StartInfo = $pinfo 
$p.Start() | Out-Null 
$p.WaitForExit() 
$stdout = $p.StandardOutput.ReadToEnd() 
$stderr = $p.StandardError.ReadToEnd() 
Write-Host "stdout: $stdout" 
Write-Host "stderr: $stderr" 
Write-Host "exit code: " + $p.ExitCode 
+6

मैं आपका उत्तर स्वीकार कर रहा हूं। काश वे उन गुणों को नहीं बनाएंगे जो उपयोग नहीं किए जाते हैं, यह बहुत भ्रमित है। – jzbruno

+1

@jzbruno PowerShell टीम ने मानक आउटपुट/मानक त्रुटि गुण नहीं बनाए ... वे अंतर्निहित [System.Diagnostics.Process] (http://msdn.microsoft.com/en-us/library/system] का हिस्सा हैं। diagnostics.process.aspx) ऑब्जेक्ट। हालांकि वे केवल तभी उपलब्ध होते हैं जब 'UseShellExecute' प्रॉपर्टी को गलत पर सेट किया जाता है। तो यह इस बात पर निर्भर करता है कि पावरशेल टीम ने दृश्यों के पीछे 'स्टार्ट-प्रोसेस' को कैसे लागू किया ... दुर्भाग्यवश मैं स्रोत कोड को नहीं देख सकता :-( –

+2

यदि आपको इस तरह की प्रक्रिया चलाने में परेशानी है, तो यहां स्वीकृत उत्तर देखें http: //stackoverflow.com/questions/11531068/powershell-capturing- मानक-out-and-error-with-process-object, जिसमें WaitForExit और StandardOutput में थोड़ा सा संशोधन है। ReadToEnd –

13

प्रश्न में दिए गए कोड में, मुझे लगता है कि दीक्षा चर के ExitCode संपत्ति पढ़ने काम करना चाहिए।

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait 
$process.ExitCode 

नोट (अपने उदाहरण के रूप में) आप -PassThru और रुको पैरामीटर जोड़ने की जरूरत है

+0

क्या होगा यदि तर्कसूची में एक चर है? यह विस्तार प्रतीत नहीं होता है। –

+1

आप उद्धरण में तर्क सूची डाल देंगे। क्या इससे काम हो जायेगा ? ... $ प्रक्रिया = स्टार्ट-प्रोसेस -फाइलपैथ पिंग -अर्ग्यूमेंटलिस्ट "-t localhost -n 1" -नवीन न्यूविंडो -पास-थ्रू -Wait – JJones

8

मैं भी इस मुद्दे था और Andys कोड का उपयोग कर समाप्त हो गया (यह मेरे थोड़ी देर के लिए बाहर पकड़ लिया) कि कई आदेशों को चलाने की आवश्यकता होने पर चीजों को साफ करने के लिए एक फ़ंक्शन बनाने के लिए, यह ऑब्जेक्ट्स के रूप में stderr, stdout और निकास कोड वापस कर देगा। फ़ंक्शन को नोट करने की एक बात स्वीकार नहीं होगी। पथ में, पूर्ण पथ का उपयोग किया जाना चाहिए।

Function Execute-Command ($commandTitle, $commandPath, $commandArguments) 
{ 
    $pinfo = New-Object System.Diagnostics.ProcessStartInfo 
    $pinfo.FileName = $commandPath 
    $pinfo.RedirectStandardError = $true 
    $pinfo.RedirectStandardOutput = $true 
    $pinfo.UseShellExecute = $false 
    $pinfo.Arguments = $commandArguments 
    $p = New-Object System.Diagnostics.Process 
    $p.StartInfo = $pinfo 
    $p.Start() | Out-Null 
    $p.WaitForExit() 
    [pscustomobject]@{ 
     commandTitle = $commandTitle 
     stdout = $p.StandardOutput.ReadToEnd() 
     stderr = $p.StandardError.ReadToEnd() 
     ExitCode = $p.ExitCode 
    } 
} 

यहाँ कैसे @Andy Arismendi और @LPG से अधिक आयु वालों के उदाहरणों से

$DisableACMonitorTimeOut = Execute-Command -commandTitle "Disable Monitor Timeout" -commandPath "C:\Windows\System32\powercfg.exe" -commandArguments " -x monitor-timeout-ac 0" 
+0

अच्छा विचार है, लेकिन ऐसा लगता है कि वाक्यविन्यास मेरे लिए काम नहीं कर रहा है। पैरामीटर सूची पैरामीटर ([प्रकार] $ ArgumentName) वाक्यविन्यास का उपयोग नहीं करना चाहिए? क्या आप इस फ़ंक्शन में एक उदाहरण कॉल जोड़ सकते हैं? – Lockszmith

4

मैं वास्तव में था मुसीबतों उपयोग करने के लिए है। तुम हमेशा उपयोग करना चाहिए:

$stdout = $p.StandardOutput.ReadToEnd() 

बुला

$p.WaitForExit() 

पूर्ण उदाहरण से पहले है:

$pinfo = New-Object System.Diagnostics.ProcessStartInfo 
$pinfo.FileName = "ping.exe" 
$pinfo.RedirectStandardError = $true 
$pinfo.RedirectStandardOutput = $true 
$pinfo.UseShellExecute = $false 
$pinfo.Arguments = "localhost" 
$p = New-Object System.Diagnostics.Process 
$p.StartInfo = $pinfo 
$p.Start() | Out-Null 
$stdout = $p.StandardOutput.ReadToEnd() 
$stderr = $p.StandardError.ReadToEnd() 
$p.WaitForExit() 
Write-Host "stdout: $stdout" 
Write-Host "stderr: $stderr" 
Write-Host "exit code: " + $p.ExitCode 
+0

क्या यह डेडलॉक समस्या को हल करता है? –

+0

आपने यह कहां पढ़ा था "आपको हमेशा $ p.StandardOutput.ReadToEnd() $ p.WaitForExit()" से पहले उपयोग करना चाहिए? " यदि बफर पर आउटपुट समाप्त हो गया है, तो बाद में अधिक आउटपुट के बाद, अगर चूक की लाइन WaitForExit पर है और प्रक्रिया समाप्त नहीं हुई है (और बाद में अधिक stderr या stdout आउटपुट) है तो यह चूक जाएगा .... – CJBS

+0

ऊपर मेरी टिप्पणी के बारे में, मैंने बाद में बड़े आउटपुट के मामलों में डेडलॉकिंग और बफर ओवरफ्लो के संबंध में स्वीकृत उत्तर पर टिप्पणियां देखीं, लेकिन एक तरफ, मैं उम्मीद करता हूं कि बफर को अंत तक पढ़ा जाए, इसका मतलब यह नहीं है कि इसका मतलब यह नहीं है प्रक्रिया पूरी हो गई है, और इस तरह से अधिक उत्पादन हो सकता है जो चूक गया है। क्या मैं कुछ भूल रहा हूँ? – CJBS

3

महत्वपूर्ण:

हम समारोह के रूप में रसोई गैस से ऊपर दी गई उपयोग किया गया है। हालांकि इसमें एक ऐसी बग है जो आपको तब मिल सकती है जब आप ऐसी प्रक्रिया शुरू करते हैं जो बहुत अधिक उत्पादन उत्पन्न करती है। इस फ़ंक्शन का उपयोग करते समय आप एक डेडलॉक के साथ समाप्त हो सकते हैं।

Function Execute-Command ($commandTitle, $commandPath, $commandArguments) 
{ 
    Try { 
    $pinfo = New-Object System.Diagnostics.ProcessStartInfo 
    $pinfo.FileName = $commandPath 
    $pinfo.RedirectStandardError = $true 
    $pinfo.RedirectStandardOutput = $true 
    $pinfo.UseShellExecute = $false 
    $pinfo.Arguments = $commandArguments 
    $p = New-Object System.Diagnostics.Process 
    $p.StartInfo = $pinfo 
    $p.Start() | Out-Null 
    [pscustomobject]@{ 
     commandTitle = $commandTitle 
     stdout = $p.StandardOutput.ReadToEnd() 
     stderr = $p.StandardError.ReadToEnd() 
     ExitCode = $p.ExitCode 
    } 
    $p.WaitForExit() 
    } 
    Catch { 
    exit 
    } 
} 

इस मुद्दे पर आगे की जानकारी पाया जा सकता है at MSDN:

एक गतिरोध हालत अगर माता पिता प्रक्रिया p.StandardError.ReadToEnd से पहले p.WaitForExit कॉल करता है और परिणाम कर सकते हैं इसके बजाय नीचे अनुकूलित संस्करण का उपयोग बाल प्रक्रिया पुनर्निर्देशित स्ट्रीम को भरने के लिए पर्याप्त पाठ लिखती है। बाल प्रक्रिया से बाहर निकलने के लिए मूल प्रक्रिया अनिश्चित काल तक प्रतीक्षा करेगी। माता-पिता को पूर्ण मानक एरर स्ट्रीम से पढ़ने के लिए बाल प्रक्रिया अनिश्चित काल तक प्रतीक्षा करेगी।

संपादित करें: कोशिश ब्लॉक के अंत में एक लापता घुंघराले ब्रेस जोड़ा गया।

+1

यह कोड अभी भी ReadToEnd() के सिंक्रोनस कॉल के कारण deadlocks है, जो एमएसडीएन के लिए आपका लिंक भी वर्णन करता है। – bergmeister

+0

अब यह मेरी समस्या हल हो गया है। मुझे यह स्वीकार करना होगा कि मैं पूरी तरह समझ नहीं पा रहा हूं कि यह क्यों लटका हुआ है, लेकिन ऐसा लगता है कि खाली stderr प्रक्रिया को खत्म करने के लिए अवरुद्ध कर दिया। अजीब चीज़, क्योंकि यह लंबे समय तक काम करता था, लेकिन क्रिसमस से पहले अचानक यह असफल हो गया, जिससे जावा-प्रक्रियाओं को लटका दिया गया। – rhellem