public PowerShellExecutionResults run_host(ChocolateyConfiguration config, string chocoPowerShellScript, Action <Pipeline> additionalActionsBeforeScript) { // since we control output in the host, always set these true Environment.SetEnvironmentVariable("ChocolateyEnvironmentDebug", "true"); Environment.SetEnvironmentVariable("ChocolateyEnvironmentVerbose", "true"); var result = new PowerShellExecutionResults(); string commandToRun = wrap_script_with_module(chocoPowerShellScript, config); var host = new PoshHost(config); this.Log().Debug(() => "Calling built-in PowerShell host with ['{0}']".format_with(commandToRun.escape_curly_braces())); var initialSessionState = InitialSessionState.CreateDefault(); // override system execution policy without accidentally setting it initialSessionState.AuthorizationManager = new AuthorizationManager("choco"); using (var runspace = RunspaceFactory.CreateRunspace(host, initialSessionState)) { runspace.Open(); // this will affect actual execution policy //RunspaceInvoke invoker = new RunspaceInvoke(runspace); //invoker.Invoke("Set-ExecutionPolicy ByPass"); using (var pipeline = runspace.CreatePipeline()) { // The powershell host itself handles the following items: // * Write-Debug // * Write-Host // * Write-Verbose // * Write-Warning // // the two methods below will pick up Write-Output and Write-Error // Write-Output pipeline.Output.DataReady += (sender, args) => { PipelineReader <PSObject> reader = sender as PipelineReader <PSObject>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteLine(reader.Read().to_string().escape_curly_braces()); } } }; // Write-Error pipeline.Error.DataReady += (sender, args) => { PipelineReader <object> reader = sender as PipelineReader <object>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteErrorLine(reader.Read().to_string().escape_curly_braces()); } } }; var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify); var currentUserCurrentHostProfile = _fileSystem.combine_paths(documentsFolder, "WindowsPowerShell\\Microsoft.PowerShell_profile.ps1"); var recreateProfileScript = @" if ((Test-Path(""{0}"")) -and ($profile -eq $null -or $profile -eq '')) {{ $global:profile = ""{1}"" }} ".format_with(documentsFolder, currentUserCurrentHostProfile); pipeline.Commands.Add(new Command(recreateProfileScript, isScript: true, useLocalScope: false)); // The PowerShell Output Redirection bug affects System.Management.Automation // it appears with v3 more than others. It is already known to affect v2 // this implements the redirection fix from the post below, fixed up with some comments // http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ const string outputRedirectionFixScript = @" try { $bindingFlags = [Reflection.BindingFlags] ""Instance,NonPublic,GetField"" $objectRef = $host.GetType().GetField(""externalHostRef"", $bindingFlags).GetValue($host) $bindingFlags = [Reflection.BindingFlags] ""Instance,NonPublic,GetProperty"" $consoleHost = $objectRef.GetType().GetProperty(""Value"", $bindingFlags).GetValue($objectRef, @()) [void] $consoleHost.GetType().GetProperty(""IsStandardOutputRedirected"", $bindingFlags).GetValue($consoleHost, @()) $bindingFlags = [Reflection.BindingFlags] ""Instance,NonPublic,GetField"" $field = $consoleHost.GetType().GetField(""standardOutputWriter"", $bindingFlags) $field.SetValue($consoleHost, [Console]::Out) [void] $consoleHost.GetType().GetProperty(""IsStandardErrorRedirected"", $bindingFlags).GetValue($consoleHost, @()) $field2 = $consoleHost.GetType().GetField(""standardErrorWriter"", $bindingFlags) $field2.SetValue($consoleHost, [Console]::Error) } catch { Write-Output ""Unable to apply redirection fix"" } "; pipeline.Commands.Add(new Command(outputRedirectionFixScript, isScript: true, useLocalScope: false)); if (additionalActionsBeforeScript != null) { additionalActionsBeforeScript.Invoke(pipeline); } pipeline.Commands.Add(new Command(commandToRun, isScript: true, useLocalScope: false)); try { pipeline.Invoke(); } catch (RuntimeException ex) { var errorStackTrace = ex.StackTrace; var record = ex.ErrorRecord; if (record != null) { // not available in v1 //errorStackTrace = record.ScriptStackTrace; var scriptStackTrace = record.GetType().GetProperty("ScriptStackTrace"); if (scriptStackTrace != null) { var scriptError = scriptStackTrace.GetValue(record, null).to_string(); if (!string.IsNullOrWhiteSpace(scriptError)) { errorStackTrace = scriptError; } } } this.Log().Error("ERROR: {0}{1}".format_with(ex.Message.escape_curly_braces(), !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine, errorStackTrace.escape_curly_braces()))); } catch (Exception ex) { // Unfortunately this doesn't print line number and character. It might be nice to get back to those items unless it involves tons of work. this.Log().Error("ERROR: {0}{1}".format_with(ex.Message.escape_curly_braces(), !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine, ex.StackTrace.escape_curly_braces()))); } if (pipeline.PipelineStateInfo != null) { switch (pipeline.PipelineStateInfo.State) { // disconnected is not available unless the assembly version is at least v3 //case PipelineState.Disconnected: case PipelineState.Running: case PipelineState.NotStarted: case PipelineState.Failed: case PipelineState.Stopping: case PipelineState.Stopped: if (host.ExitCode == 0) { host.SetShouldExit(1); } host.HostException = pipeline.PipelineStateInfo.Reason; break; case PipelineState.Completed: if (host.ExitCode == -1) { host.SetShouldExit(0); } break; } } } } this.Log().Debug("Built-in PowerShell host called with ['{0}'] exited with '{1}'.".format_with(commandToRun.escape_curly_braces(), host.ExitCode)); result.ExitCode = host.ExitCode; result.StandardErrorWritten = host.StandardErrorWritten; return(result); }
private PowerShellExecutionResults run_host(ChocolateyConfiguration config, string chocoPowerShellScript) { var result = new PowerShellExecutionResults(); string commandToRun = wrap_script_with_module(chocoPowerShellScript, config); var host = new PoshHost(config); this.Log().Debug(() => "Calling built-in PowerShell host with ['{0}']".format_with(commandToRun.escape_curly_braces())); var initialSessionState = InitialSessionState.CreateDefault(); // override system execution policy without accidentally setting it initialSessionState.AuthorizationManager = new AuthorizationManager("choco"); using (var runspace = RunspaceFactory.CreateRunspace(host, initialSessionState)) { runspace.Open(); // this will affect actual execution policy //RunspaceInvoke invoker = new RunspaceInvoke(runspace); //invoker.Invoke("Set-ExecutionPolicy ByPass"); using (var pipeline = runspace.CreatePipeline()) { // The powershell host itself handles the following items: // * Write-Debug // * Write-Host // * Write-Verbose // * Write-Warning // // the two methods below will pick up Write-Output and Write-Error // Write-Output pipeline.Output.DataReady += (sender, args) => { PipelineReader<PSObject> reader = sender as PipelineReader<PSObject>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteLine(reader.Read().to_string()); } } }; // Write-Error pipeline.Error.DataReady += (sender, args) => { PipelineReader<object> reader = sender as PipelineReader<object>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteErrorLine(reader.Read().to_string()); } } }; pipeline.Commands.Add(new Command(commandToRun, isScript: true, useLocalScope: false)); try { pipeline.Invoke(); } catch (RuntimeException ex) { var errorStackTrace = ex.StackTrace; var record = ex.ErrorRecord; if (record != null) { // not available in v1 //errorStackTrace = record.ScriptStackTrace; var scriptStackTrace = record.GetType().GetProperty("ScriptStackTrace"); if (scriptStackTrace != null) { var scriptError = scriptStackTrace.GetValue(record, null).to_string(); if (!string.IsNullOrWhiteSpace(scriptError)) errorStackTrace = scriptError; } } this.Log().Error("ERROR: {0}{1}".format_with(ex.Message, !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine,errorStackTrace))); } catch (Exception ex) { // Unfortunately this doesn't print line number and character. It might be nice to get back to those items unless it involves tons of work. this.Log().Error("ERROR: {0}{1}".format_with(ex.Message, !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine,ex.StackTrace))); } if (pipeline.PipelineStateInfo != null) { switch (pipeline.PipelineStateInfo.State) { // disconnected is not available unless the assembly version is at least v3 //case PipelineState.Disconnected: case PipelineState.Running: case PipelineState.NotStarted: case PipelineState.Failed: case PipelineState.Stopping: case PipelineState.Stopped: host.SetShouldExit(1); host.HostException = pipeline.PipelineStateInfo.Reason; break; case PipelineState.Completed: host.SetShouldExit(0); break; } } } } this.Log().Debug("Built-in PowerShell host called with ['{0}'] exited with '{1}'.".format_with(commandToRun.escape_curly_braces(), host.ExitCode)); result.ExitCode = host.ExitCode; result.StandardErrorWritten = host.StandardErrorWritten; return result; }
public PowerShellExecutionResults run_host(ChocolateyConfiguration config, string chocoPowerShellScript, Action<Pipeline> additionalActionsBeforeScript) { // since we control output in the host, always set these true Environment.SetEnvironmentVariable("ChocolateyEnvironmentDebug", "true"); Environment.SetEnvironmentVariable("ChocolateyEnvironmentVerbose", "true"); var result = new PowerShellExecutionResults(); string commandToRun = wrap_script_with_module(chocoPowerShellScript, config); var host = new PoshHost(config); this.Log().Debug(() => "Calling built-in PowerShell host with ['{0}']".format_with(commandToRun.escape_curly_braces())); var initialSessionState = InitialSessionState.CreateDefault(); // override system execution policy without accidentally setting it initialSessionState.AuthorizationManager = new AuthorizationManager("choco"); using (var runspace = RunspaceFactory.CreateRunspace(host, initialSessionState)) { runspace.Open(); // this will affect actual execution policy //RunspaceInvoke invoker = new RunspaceInvoke(runspace); //invoker.Invoke("Set-ExecutionPolicy ByPass"); using (var pipeline = runspace.CreatePipeline()) { // The powershell host itself handles the following items: // * Write-Debug // * Write-Host // * Write-Verbose // * Write-Warning // // the two methods below will pick up Write-Output and Write-Error // Write-Output pipeline.Output.DataReady += (sender, args) => { PipelineReader<PSObject> reader = sender as PipelineReader<PSObject>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteLine(reader.Read().to_string().escape_curly_braces()); } } }; // Write-Error pipeline.Error.DataReady += (sender, args) => { PipelineReader<object> reader = sender as PipelineReader<object>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteErrorLine(reader.Read().to_string().escape_curly_braces()); } } }; var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify); var currentUserCurrentHostProfile = _fileSystem.combine_paths(documentsFolder, "WindowsPowerShell\\Microsoft.PowerShell_profile.ps1"); var recreateProfileScript = @" if ((Test-Path(""{0}"")) -and ($profile -eq $null -or $profile -eq '')) {{ $global:profile = ""{1}"" }} ".format_with(documentsFolder, currentUserCurrentHostProfile); pipeline.Commands.Add(new Command(recreateProfileScript, isScript: true, useLocalScope: false)); // The PowerShell Output Redirection bug affects System.Management.Automation // it appears with v3 more than others. It is already known to affect v2 // this implements the redirection fix from the post below, fixed up with some comments // http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ const string outputRedirectionFixScript = @" try { $bindingFlags = [Reflection.BindingFlags] ""Instance,NonPublic,GetField"" $objectRef = $host.GetType().GetField(""externalHostRef"", $bindingFlags).GetValue($host) $bindingFlags = [Reflection.BindingFlags] ""Instance,NonPublic,GetProperty"" $consoleHost = $objectRef.GetType().GetProperty(""Value"", $bindingFlags).GetValue($objectRef, @()) [void] $consoleHost.GetType().GetProperty(""IsStandardOutputRedirected"", $bindingFlags).GetValue($consoleHost, @()) $bindingFlags = [Reflection.BindingFlags] ""Instance,NonPublic,GetField"" $field = $consoleHost.GetType().GetField(""standardOutputWriter"", $bindingFlags) $field.SetValue($consoleHost, [Console]::Out) [void] $consoleHost.GetType().GetProperty(""IsStandardErrorRedirected"", $bindingFlags).GetValue($consoleHost, @()) $field2 = $consoleHost.GetType().GetField(""standardErrorWriter"", $bindingFlags) $field2.SetValue($consoleHost, [Console]::Error) } catch { Write-Output ""Unable to apply redirection fix"" } "; pipeline.Commands.Add(new Command(outputRedirectionFixScript, isScript: true, useLocalScope: false)); if (additionalActionsBeforeScript != null) additionalActionsBeforeScript.Invoke(pipeline); pipeline.Commands.Add(new Command(commandToRun, isScript: true, useLocalScope: false)); try { pipeline.Invoke(); } catch (RuntimeException ex) { var errorStackTrace = ex.StackTrace; var record = ex.ErrorRecord; if (record != null) { // not available in v1 //errorStackTrace = record.ScriptStackTrace; var scriptStackTrace = record.GetType().GetProperty("ScriptStackTrace"); if (scriptStackTrace != null) { var scriptError = scriptStackTrace.GetValue(record, null).to_string(); if (!string.IsNullOrWhiteSpace(scriptError)) errorStackTrace = scriptError; } } this.Log().Error("ERROR: {0}{1}".format_with(ex.Message.escape_curly_braces(), !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine, errorStackTrace.escape_curly_braces()))); } catch (Exception ex) { // Unfortunately this doesn't print line number and character. It might be nice to get back to those items unless it involves tons of work. this.Log().Error("ERROR: {0}{1}".format_with(ex.Message.escape_curly_braces(), !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine, ex.StackTrace.escape_curly_braces()))); } if (pipeline.PipelineStateInfo != null) { switch (pipeline.PipelineStateInfo.State) { // disconnected is not available unless the assembly version is at least v3 //case PipelineState.Disconnected: case PipelineState.Running: case PipelineState.NotStarted: case PipelineState.Failed: case PipelineState.Stopping: case PipelineState.Stopped: if (host.ExitCode == 0) host.SetShouldExit(1); host.HostException = pipeline.PipelineStateInfo.Reason; break; case PipelineState.Completed: if (host.ExitCode == -1) host.SetShouldExit(0); break; } } } } this.Log().Debug("Built-in PowerShell host called with ['{0}'] exited with '{1}'.".format_with(commandToRun.escape_curly_braces(), host.ExitCode)); result.ExitCode = host.ExitCode; result.StandardErrorWritten = host.StandardErrorWritten; return result; }
private PowerShellExecutionResults run_host(ChocolateyConfiguration config, string chocoPowerShellScript) { var result = new PowerShellExecutionResults(); string commandToRun = wrap_script_with_module(chocoPowerShellScript, config); var host = new PoshHost(config); this.Log().Debug(() => "Calling built-in PowerShell host with ['{0}']".format_with(commandToRun.escape_curly_braces())); var initialSessionState = InitialSessionState.CreateDefault(); // override system execution policy without accidentally setting it initialSessionState.AuthorizationManager = new AuthorizationManager("choco"); using (var runspace = RunspaceFactory.CreateRunspace(host, initialSessionState)) { runspace.Open(); // this will affect actual execution policy //RunspaceInvoke invoker = new RunspaceInvoke(runspace); //invoker.Invoke("Set-ExecutionPolicy ByPass"); using (var pipeline = runspace.CreatePipeline()) { // The powershell host itself handles the following items: // * Write-Debug // * Write-Host // * Write-Verbose // * Write-Warning // // the two methods below will pick up Write-Output and Write-Error // Write-Output pipeline.Output.DataReady += (sender, args) => { PipelineReader <PSObject> reader = sender as PipelineReader <PSObject>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteLine(reader.Read().to_string()); } } }; // Write-Error pipeline.Error.DataReady += (sender, args) => { PipelineReader <object> reader = sender as PipelineReader <object>; if (reader != null) { while (reader.Count > 0) { host.UI.WriteErrorLine(reader.Read().to_string()); } } }; pipeline.Commands.Add(new Command(commandToRun, isScript: true, useLocalScope: false)); try { pipeline.Invoke(); } catch (Exception ex) { // Unfortunately this doesn't print line number and character. It might be nice to get back to those items unless it involves tons of work. this.Log().Error("ERROR: {0}".format_with(ex.Message)); //, !config.Debug ? string.Empty : "{0} {1}".format_with(Environment.NewLine,ex.StackTrace))); } if (pipeline.PipelineStateInfo != null) { switch (pipeline.PipelineStateInfo.State) { // disconnected is not available unless the assembly version is at least v3 //case PipelineState.Disconnected: case PipelineState.Running: case PipelineState.NotStarted: case PipelineState.Failed: case PipelineState.Stopping: case PipelineState.Stopped: host.SetShouldExit(1); host.HostException = pipeline.PipelineStateInfo.Reason; break; case PipelineState.Completed: host.SetShouldExit(0); break; } } } } this.Log().Debug("Built-in PowerShell host called with ['{0}'] exited with '{1}'.".format_with(commandToRun.escape_curly_braces(), host.ExitCode)); result.ExitCode = host.ExitCode; result.StandardErrorWritten = host.StandardErrorWritten; return(result); }