स्टार्ट-प्रोसेस के साथ मानक आउट और त्रुटि कैप्चर करना


112

क्या पॉवरशेल की Start-Processकमान में एक बग है StandardErrorऔर StandardOutputसंपत्तियों तक पहुंच है ?

यदि मैं निम्नलिखित चलाता हूं तो मुझे कोई आउटपुट नहीं मिलता है:

$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

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

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

जवाबों:


128

कि कैसे 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

7
मैं आपके उत्तर को स्वीकार कर रहा हूं। काश, उन्होंने ऐसी प्रॉपर्टी नहीं बनाई होती, जिनका इस्तेमाल नहीं किया गया हो, यह बहुत भ्रामक है।
jzbruno

6
यदि आपको इस तरह से एक प्रक्रिया चलाने में परेशानी होती है, तो यहां स्वीकृत उत्तर देखें stackoverflow.com/questions/11531068/… , जिसमें WaitForExit और StandardOutput.ReadToEnd
Ralph.goss

3
जब u -verb रनवे का उपयोग करता है, तो वह -NoNewWindow या पुनर्निर्देशन विकल्प की अनुमति नहीं देता है
Maverick

15
यह कोड StdErr और StdOut दोनों के अंत में पढ़े जाने के कारण कुछ शर्तों के तहत गतिरोध होगा। msdn.microsoft.com/en-us/library/...
codepoke

8
@codepoke - यह उससे थोड़ा खराब है - चूंकि यह WaitForExit कॉल पहले करता है, भले ही यह उनमें से केवल एक को पुनर्निर्देशित करता हो, अगर धारा बफर भर जाती है तो यह गतिरोध कर सकता है (क्योंकि यह प्रक्रिया से इसे पढ़ने का प्रयास नहीं करता है से बाहर हो गया है)
जेम्स मैनिंग

20

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

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

ध्यान दें कि (आपके उदाहरण के अनुसार) आपको पैरामीटर -PassThruऔर -Waitपैरामीटर जोड़ने की आवश्यकता है (यह मुझे थोड़ी देर के लिए पकड़ा गया)।


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

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

कैसे पॉवरशेल विंडो में आउटपुट दिखाने के साथ-साथ उसे लॉग फाइल में लॉग करें? क्या यह संभव है?
मुरली धर दर्शन

-NoNewWindow-Verb runAs
बजे

11

मेरे पास यह मुद्दा भी था और एंडी के कोड का उपयोग करके चीजों को साफ करने के लिए एक फ़ंक्शन बनाने के लिए समाप्त हुआ जब कई कमांड चलाने की आवश्यकता होती है।

यह ऑब्जेक्ट के रूप में 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
    }
}

इसका उपयोग कैसे करें:

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

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

के बारे में "नोट करने के लिए एक बात है: समारोह को स्वीकार नहीं करेगा \ रास्ते में, पूर्ण पथ इस्तेमाल किया जाना चाहिए।।": आप इस्तेमाल कर सकते हैं:> $ pinfo.FileName = हल-पथ $ commandPath
Lupuz

9

जरूरी:

हम एलपीजी द्वारा उपरोक्त प्रदान किए गए फ़ंक्शन का उपयोग कर रहे हैं ।

हालाँकि, इसमें एक बग हो सकता है जब आप एक प्रक्रिया शुरू करते हैं जो बहुत अधिक आउटपुट उत्पन्न करता है। इसके कारण आप इस फ़ंक्शन का उपयोग करते समय एक गतिरोध के साथ समाप्त हो सकते हैं। इसके बजाय नीचे दिए गए अनुकूलित संस्करण का उपयोग करें:

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
  }
}

इस मुद्दे पर अधिक जानकारी MSDN पर पाई जा सकती है :

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


3
यह कोड अभी भी ReadToEnd () के लिए तुल्यकालिक कॉल के कारण गतिरोध है, जो आपके MSDN के लिंक के रूप में अच्छी तरह से वर्णन करता है।
बरगमेस्टर

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

8

मुझे वास्तव में एंडी अरिस्मेंडी और एलपीजी से उन उदाहरणों से परेशानी थी । आपको हमेशा उपयोग करना चाहिए:

$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

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

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

@CJBS: "सिर्फ इसलिए कि बफर अंत तक पढ़ा जाता है, इसका मतलब यह नहीं है कि प्रक्रिया पूरी हो गई है" - इसका मतलब यह है कि। वास्तव में, यही कारण है कि यह गतिरोध कर सकता है। "अंत तक" पढ़ने का मतलब यह नहीं है कि "जो कुछ भी है उसे अभी पढ़ें "। इसका मतलब यह है कि पढ़ना शुरू करें, और तब तक न रुके जब तक कि धारा बंद न हो जाए, जो कि प्रक्रिया को समाप्त करने के समान है।
पीटर डनिहो

0

यहाँ फ़ंक्शन का मेरा संस्करण है जो मानक System.Diagnostics को लौटा रहा है। 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.WindowStyle = 'Hidden'
        $pinfo.CreateNoWindow = $True
        $pinfo.Arguments = $commandArguments
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null
        $stdout = $p.StandardOutput.ReadToEnd()
        $stderr = $p.StandardError.ReadToEnd()
        $p.WaitForExit()
        $p | Add-Member "commandTitle" $commandTitle
        $p | Add-Member "stdout" $stdout
        $p | Add-Member "stderr" $stderr
    }
    Catch {
    }
    $p
}

0

यहां एक अन्य शक्तियुक्त प्रक्रिया से आउटपुट प्राप्त करने का एक कठिन तरीका है:

start-process -wait -nonewwindow powershell 'ps | Export-Clixml out.xml'; import-clixml out.xml
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.