Invoking PowerShell.exe with "-Command -" (reading input from StdIn) broken in Windows 10 14393?
i have c# app contains embedded powershell script. not matters, external--the important point execute the script invoking powershell.exe "-command -". is, using -command parameter followed hyphen, allows provide body of script execute through stdin.
i technique, and i've been using on year as, among other reasons, script doesn't have single command, can span many lines, declare functions etc, while without ever having script written disk in plain text or base64-encoded.
after having installed anniversary update of windows 10 (1607 aka build 14393), appears broken; captured stderr shows complains missing function bodies, while stdout shows--and find part rather mind-blowing--the script got mangled in such way *all* lines contain function declaration, , following opening *and* closing curly braces, gone. rest of script appears intact. cascade sorts of errors.
i managed write short(-ish) sample demonstrates problem. the same exe demonstrates it's broken on windows 10 14393 (all 3 machines have run version exhibit same behavior), but it works fine on windows 10 10586 as windows 7.
one thing i've discovered if substitute cr/lf characters script single space, error goes away, happens stdout stream capture comes empty--even on other oses otherwise managed handle unmodified script fine--rather containing expected output, comes 1 of script's functions (which write-host).
another thing i've discovered if add "-version 2.0" argument when invoking powershell.exe, reverts normal behavior. while works around immediate problem, obviously i'd to remain version-agnostic, though tend write scripts can run against "lowest common denominator", i'd rather not explicitly restrict myself in fashion, may need write script relies on features have only been introduced in more recent versions. so don't view long-term or permanent solution.
if compiler cares try out, here's sample cut-down c# program. needs built as console exe.
is else getting same results? workaround doesn't require me change script (as won't have knowledge of scripts provided me do, other fact they're expected end single write-host final output value i'm interested in)...
using system; using system.text; using system.diagnostics; namespace pstest { class program { static void main( string[] args ) { string strmyscript = @" function getfunctionvalue() { # comment in getfunctionvalue function return $true } function showvalue( [string] $thevalue ) { # comment in showvalue function write-host $thevalue } # comment @ script level, before function call showvalue( getfunctionvalue ) # comment @ script level, after function call "; //strmyscript = strmyscript.replace( "\n", " " ).replace( "\r", " " ); //strmyscript = strmyscript.replace( environment.newline, " " ); runscript( strmyscript ); } private static string runscript( string strscriptbody ) { var stdoutbuilder = new stringbuilder(); var stderrbuilder = new stringbuilder(); int nexitcode = 0; using ( var p = new process() ) { p.startinfo = new processstartinfo( "powershell.exe" ) { arguments = " -nologo -noninteractive -executionpolicy unrestricted -command -", // following line makes problem go away, on win10 14393, unlike line above //arguments = " -version 2.0 -nologo -noninteractive -executionpolicy unrestricted -command -", createnowindow = true, windowstyle = processwindowstyle.hidden, useshellexecute = false, redirectstandardinput = true, redirectstandardoutput = true, redirectstandarderror = true, verb = "runas" // elevate }; p.outputdatareceived += ( sender, e ) => { if ( !string.isnullorempty( e.data ) ) stdoutbuilder.appendline( e.data ); }; p.errordatareceived += ( sender, e ) => { if ( !string.isnullorempty( e.data ) ) stderrbuilder.appendline( e.data ); }; try { p.start(); } catch ( system.componentmodel.win32exception x ) { console.writeline( "process.start() threw win32exception: " + x.message + environment.newline + x.stacktrace ); return string.empty; } catch ( exception x ) { console.writeline( "process.start() threw exception: " + x.message + environment.newline + x.stacktrace ); return string.empty; } p.beginoutputreadline(); p.beginerrorreadline(); var sw = p.standardinput; sw.writeline( strscriptbody ); sw.close(); p.waitforexit(); nexitcode = p.exitcode; p.close(); } string strerror = stderrbuilder.tostring().trimend(); if ( !string.isnullorempty( strerror ) ) { console.writeline( $"stderr contains following" + environment.newline + ">>>>>" + environment.newline + strerror + environment.newline + "<<<<<" ); console.writeline( environment.newline + environment.newline + environment.newline + environment.newline ); } string stroutput = stdoutbuilder.tostring().trimend(); console.writeline( "stdout contains following" + environment.newline + ">>>>>" + environment.newline + stroutput + environment.newline + "<<<<<" ); return string.empty; } // runscript() } // class }
here's expected output on working machine:
stdout contains following >>>>> true <<<<<
...and here's output on 14393. notice messed script body in stdout, @ end:
stderr contains following >>>>> @ line:1 char:28 + function getfunctionvalue() + ~ missing function body in function declaration. + categoryinfo : parsererror: (:) [], parentcontainserrorrecordexce ption + fullyqualifiederrorid : missingfunctionbody @ line:1 char:41 + function showvalue( [string] $thevalue ) + ~ missing function body in function declaration. + categoryinfo : parsererror: (:) [], parentcontainserrorrecordexce ption + fullyqualifiederrorid : missingfunctionbody getfunctionvalue : term 'getfunctionvalue' not recognized name of cmdlet, function, script file, or operable program. check spelling of name, or if path included, ver ify path correct , try again. @ line:1 char:12 + showvalue( getfunctionvalue ) + ~~~~~~~~~~~~~~~~ + categoryinfo : objectnotfound: (getfunctionvalue:string) [], comm andnotfoundexception + fullyqualifiederrorid : commandnotfoundexception <<<<< stdout contains following >>>>> # comment in getfunctionvalue function return $true # comment in showvalue function write-host $thevalue <<<<<
you have read rest of walk through. script must generate objects pipeline.
you can test code in powershell:
<# test.ps1 co tains 1 line get-childitem #> $ps = [powershell]::create() $p=$ps.addscript('d:\scripts\test.ps1') $ps.invoke()
check $p errors after invoke.
look classes , read how work. if want code in c# absolutely necessary.
here command example:
$ps = [powershell]::create() $ps.addcommand('get-process”' $ps.addparameter('name', 'powershell') $ps.invoke();
one of best uses powershell learning net classes since can browse objects , classes:
[powershell]|gm
for detail on net classes reference msdn library.
start 'http://msdn.microsoft.com/system.management.automation.powershell'
you can add full type name of class , docs prompt.
\_(ツ)_/
Windows Server > Windows PowerShell
Comments
Post a Comment