Custom PSHostUserInterface is ignored by Runspace - c#

The Background
I'm writing an application that programatically executes PowerShell scripts. This application has a custom PSHost implementation to allow scripts to output logging statements. Currently, the behavior I'm seeing is that some requests are properly forwarded to my custom PSHost and others are flat out ignored.
Things get even stranger when I started inspecting the $Host variable in my scripts, which seem to suggest that my custom PSHost isn't even being used.
The Code
I have some code that's executing PowerShell within a .NET application:
var state = InitialSessionState.CreateDefault();
state.AuthorizationManager = new AuthorizationManager("dummy"); // Disable execution policy
var host = new CustomPsHost(new CustomPsHostUI());
using (var runspace = RunspaceFactory.CreateRunspace(host, state))
{
runspace.Open();
using (var powershell = PowerShell.Create())
{
powershell.Runspace = runspace;
var command = new Command(filepath);
powershell.Invoke(command);
}
}
The implementation for CustomPsHost is very minimal, only containing what's needed to forward the PSHostUserInterface:
public class CustomPsHost : PSHost
{
private readonly PSHostUserInterface _hostUserInterface;
public CustomPsHost(PSHostUserInterface hostUserInterface)
{
_hostUserInterface = hostUserInterface;
}
public override PSHostUserInterface UI
{
get { return _hostUserInterface; }
}
// Methods omitted for brevity
}
The CustomPsHostUI is used as a wrapper for logging:
public class CustomPsHostUI : PSHostUserInterface
{
public override void Write(string value) { Debug.WriteLine(value); }
public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value){ Debug.WriteLine(value); }
public override void WriteLine(string value) { Debug.WriteLine(value); }
public override void WriteErrorLine(string value) { Debug.WriteLinevalue); }
public override void WriteDebugLine(string message) { Debug.WriteLine(message); }
public override void WriteProgress(long sourceId, ProgressRecord record) {}
public override void WriteVerboseLine(string message) { Debug.WriteLine(message); }
// Other methods omitted for brevity
}
In my PowerShell script, I am trying to write information to the host:
Write-Warning "This gets outputted to my CustomPSHostUI"
Write-Host "This does not get outputted to the CustomPSHostUI"
Write-Warning $Host.GetType().FullName # Says System.Management.Automation.Internal.Host.InternalHost
Write-Warning $Host.UI.GetType().FullName # Says System.Management.Automation.Internal.Host.InternalHostUserInterface
Why am I getting the strange behavior with my CustomPSHostUI?

You need to provide an implementation for PSHostRawUserInterface.
Write-Host ends up calling your version of Write(ConsoleColor, ConsoleColor, string). PowerShell relies on the raw ui implementation for the foreground and background colors.
I have verified this with sample code. Instead of calling out to a ps1 file, I invoked Write-Host directly:
powershell.AddCommand("Write-Host").AddParameter("Testing...")
By running a script, PowerShell was handling the exceptions for you. By invoking the command directly, you can more easily see the exceptions. If you had inspected $error in your original example, you would have seen a helpful error.
Note that the value of $host is never the actual implementation. PowerShell hides the actual implementation by wrapping it. I forget the exact details of why it's wrapped.

For anyone else still struggling after implementing PSHostUserInterface and PSHostRawUserInterface and finding that WriteErrorLine() is being completely ignored when you call Write-Error, even though Warning, Debug, and Verbose make it to the PSHostUserInterface, here's how to get your errors:
Pay close attention to https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx and add these two lines right before your .Invoke() call, like so:
powershell.AddCommand("out-default");
powershell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
powershell.Invoke() // you had this already
This will merge the Errors stream into your console output, otherwise it apparently doesn't go there. I don't have a detailed understanding of why (so perhaps I shouldn't be implementing a custom PSHost to begin with) but there is some further explanation to be had out there:
http://mshforfun.blogspot.com/2006/07/why-there-is-out-default-cmdlet.html
https://msdn.microsoft.com/en-us/library/system.management.automation.runspaces.command.mergemyresults%28v=vs.85%29.aspx
Also, assuming your host is not a console app, and you're not implementing your own cmd-style character-mode display, you'll need to give it a fake buffer size, because it needs to consult this before giving you the Write-Error output. (Don't give it 0,0, otherwise you get a never-ending torrent of blank lines as it struggles to fit the output into a nothing-sized buffer.) I'm using:
class Whatever : PSHostRawUserInterface
{
public override Size BufferSize
{
get { return new Size(300, 5000); }
set { }
}
...
}
If you ARE a console app, just use Console.BufferWidth and Console.BufferHeight.
Update: If you'd rather get your errors in ErrorRecord objects rather than lines of pre-formatted error text going to your WriteErrorLine override, hook the PowerShell.Streams.Error.DataAdding event and get the ItemAdded property on the event args. Way less unruly to work with if you're doing something other than simple line-by-line output in your GUI.

Related

Proper way to set up and use custom event log in .NET service?

I found several topics on this already, but somehow they all managed to avoid the real problem solution/assumed the obvious.
(e.g. here, here, here, here, here)
I am checking for and creating new event log + source during installation, and specifying them to be used during operation, but still somehow "EventSourceName" events end up in Application Log.
Why is that?
Here are snippets out of my code:
Installer:
namespace Service_Name
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
if (!System.Diagnostics.EventLog.SourceExists("EventSourceName"))
{
System.Diagnostics.EventLog.CreateEventSource(
"EventSourceName", "EventLogName");
}
InitializeComponent();
}
private void serviceProcessInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
}
}
}
Service:
public Service_Name()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
ServiceEventLog = new EventLog();
ServiceEventLog.Source = "EventSourceName"; // This is different from Service Name
ServiceEventLog.Log = "EventLogName"; // This is different from Service Name
..
ServiceEventLog.WriteEntry("Service Init");
Worker = new Thread(CodeWorker);
Worker.Start();
}
private void CodeWorker()
{
//.. operational code
while (true)
{
try
{
//.. operational code
ServiceEventLog.WriteEntry("<operational event data here>", (EventLogEntryType)4, 0);
}
catch (Exception Error)
{
ServiceEventLog.WriteEntry(string.Format("<error event data here>", (EventLogEntryType)1, 0);
throw;
}
//.. operational code
}
}
As it turns out, the code works perfectly as is, however there is important thing to remember when working with event log;
EventLog.CreateEventSource Method has an important footnote:
If a source has already been mapped to a log and you remap it to a new
log, you must restart the computer for the changes to take effect.
I had mapped the source prior, to another event log which was named the same as Service itself. Using same name as the service itself caused multiple other issues and I ended up fixing that by using another log name, but did not restart test system prior to doing tests on new code version.
But as Caius Jard pointed out below, parts of the code are redundant:
ServiceEventLog.Log = "EventLogName" does not need to be specified as Source is already registered to Log.
The documentation states "If you change the Log property after the Source property has been set, writing a log entry throws an exception.".
The sample code on MSDN just sets the Source property and then calls WriteEvent, it does not then set the Log beforehand or after setting Source
I recommend you remove the call to setting the Log property; I suspect your call to WriteEvent is crashing, and being in a try catch the call in the catch is also crashing. Perhaps it's not an ideal code structure to "try writing to this log and if it fails, try writing to this log" if it's the "writing to log" that is failing

Is it possible to display VS Output window content in my application?

Long story short: some third party unmanaged dll, which I use in my project, apparently dumps its errors into Visual Studio Output window (shows output from "Debug") during runtime. It looks like this:
*** WARNING ERROR 11 from R3ORP. The degree 0 polynomial fit is a perfect
*** fit within machine precision.
Here is a traceback of subprogram calls in reverse order:
Routine name Error type Error code
------------ ---------- ----------
R3ORP 6 11 (Called internally)
R4ORP 0 0 (Called internally)
R2ORP 0 0 (Called internally)
R2URV 0 0 (Called internally)
RCURV 0 0
USER 0 0
I want to either log these errors or display them in my application.
Is it possible to somehow access the VS output stream from my application? Can I still do it without VS attached to process? I don't need the entire stream, but I want to catch those "warnings" somehow. I've tried adding listeners to Diagnostics.Debug and Diagnostics.Trace, didn't work.
There is! You can implement your own TraceListener-Class.
First write the TraceListener-Class:
class CustomTraceListener : TraceListener
{
public string AllMessages { get; set; }
public override void Write(string message)
{
AllMessages += message;
}
public override void WriteLine(string o)
{
Write(o + '\n');
}
public override string ToString()
{
return AllMessages;
}
}
You can of cause implement custom behavior (like writing to a Textbox etc) in the Write() method.
Then you just have to add an instance of your class to the system's debug trace listeners and you're good:
CustomTraceListener myTraceListener = new CustomTraceListener();
Debug.Listeners.Add(myTraceListener);
Debug.WriteLine("this is a test");
Debug.WriteLine("this is another test");
string result = myTraceListener.ToString();
If this is an unmanaged dll, and the output appears in the Visual Studio output window, that means it is using the OutputDebugString function to write the data.
Because this data is meant for debugging only, there is no guarantee that subsequent versions will still output this info, or stick to the same format.
If that is of no concern to you, a quick google search on 'c# capture debug output' yields this answer.
That's a really fascinating question here.
I found a Solution with the System.Diagnostics.TraceListener class.
sealed class StackOverflowSampleListener : TraceListener
{
// Singleton
public static readonly StackOverflowSampleListener Instance =
new StackOverflowSampleListener();
public void InitializeTracing(bool ReadDebugOutput)
{
if (ReadDebugOutput == true)
Debug.Listeners.Add(this);
else
Trace.Listeners.Add(this);
}
public StringBuilder Buffer = new StringBuilder();
public override void Write(string message)
{
// Do something with your messages!
Buffer.Append(message);
}
public override void WriteLine(string message)
{
// Do something with your messages!
Buffer.Append(message);
}
}
Example in some Form.cs Code:
public Form1()
{
InitializeComponent();
StackOverflowSampleListener.Instance.InitializeTracing(true);
StackOverflowSampleListener.Instance.Buffer.ToString();
}
GuyMontag is absolutly right with his answer, but i prefer a lighter version with an singleton implementation and the possibility collection messages also in the release mode (look at initialize methode).

See parameters of UPDATEs in Fluent NHibernate when outputting statements to Console

Introduction
Following on from How to configure Fluent NHibernate to output queries to Trace or Debug instead of Console? the answer provided there nicely outputs information to the console with the exception that it outputs ? instead of the actual values of parameters.
Additionally using ShowSql() does not output any UPDATE lines.
Question
Is there a way to view the UPDATEs, parameters and all in the debug console?
Details of implementations
Using Interceptor
From How to configure Fluent NHibernate to output queries to Trace or Debug instead of Console?, I have implemented the following:
private class Interceptor : EmptyInterceptor
{
public override SqlString OnPrepareStatement(SqlString sql)
{
var s = base.OnPrepareStatement(sql);
Debug.WriteLine(s.ToString());
return s;
}
}
//...
var factory = Fluently.Configure()
// ...
.ExposeConfiguration(c => c.SetInterceptor(new Interceptor())
// ...
which results in outputs like
UPDATE [User] SET Email = ?, HashedPassword = ?, Name = ? WHERE Id = ?
Using ShowSql()
From this blog I have implemented the following
public class CustomDebugWriter : System.IO.TextWriter
{
public override void WriteLine(string value)
{
Debug.WriteLine(value);
base.WriteLine(value);
}
public override void Write(string value)
{
Debug.Write(value);
base.Write(value);
}
public override System.Text.Encoding Encoding
{
get { return new UTF8Encoding(); }
}
}
// ...
Console.SetOut(new CustomDebugWriter());
var dbConfig = MsSqlConfiguration.MsSql2012.ConnectionString(
c => c.FromConnectionStringWithKey(connectionStringKey));
dbConfig.ShowSql();
which doesn't output UPDATE statements at all.
This is a workaround rather than a true answer.
If you're creating a web-app, you can use the Glimpse and NHibernate.Glimpse Nuget packages to examine what database calls are being made.
This has the parameters shown.
It has to do with ISession's psuedo Unit Of Work and batching.
With Fluent-NHibernate you need to set the AdoNetBatchSize property:
dbConfig.AdoNetBatchSize(0);
dbConfig.ShowSql();
dbConfig.FormatSql();
Then after you do your update, you need to call Flush() to flush the "batch".
entity.Title = "test title";
Session.Update(entity);
Session.Flush();
It really depends on your architecture, where you call this, or if you are using your own Unit Of Work implementation. I only worry about the SQL output in my integration tests project so it's easy, I just call Flush on TearDown. Its probably not something you want to just throw in your App, it's usually best to just let NHibernate handle batch lifecycle and do its thing.

Async write to the PowerShell host

I'm writing some objects that are designed to work (also) with PowerShell.
I would like the possibility to directly write to the PowerShell console in an async way.
By now, I did the following:
Created an IUtilityHost interface which exposes some methods like WriteLine
I implemented the interface in a PSUtilityHost : IUtilityHost class which wraps a PSHost object
Implemented the WriteLine method is implemented calling the WriteLine method on the PSHost.UI object.
The problem is that I have a weird output that mixes the Read-Host messages I need sometimes to block the execution when manual input is needed.
I would like to know if there is a better way to asynchronously send messages to the powershell host.
Thanks
Try to grab the Host object from C# and use its Write* methods to do this e.g.:
public class Poco
{
private PSHostUserInterface _ui;
public Poco()
{
var runspace = Runspace.DefaultRunspace;
Pipeline pipeline = runspace.CreateNestedPipeline("Get-Variable host -ValueOnly", false);
Collection<PSObject> results = pipeline.Invoke();
if (results.Count > 0)
{
var host = results[0].BaseObject as PSHost;
if (host != null)
{
_ui = host.UI;
}
}
}
public void WriteLine(string msg)
{
_ui.WriteLine(msg);
}
}
Note: while you could just use Console.WriteLine to do this for the PowerShell prompt, that doesn't help for other PowerShell hosts like ISE which are not console apps.

How can I add a Trace() to every method call in C#?

I am having a hard time tracking down a lock issue, so I would like to log every method call's entry and exit. I've done this before with C++ without having to add code to every method. Is this possible with C#?
Probably your best bet would be to use an AOP (aspect oriented programming) framework to automatically call tracing code before and after a method execution. A popular choice for AOP and .NET is PostSharp.
If your primary goal is to log function entry/exit points and occasional information in between, I've had good results with an Disposable logging object where the constructor traces the function entry, and Dispose() traces the exit. This allows calling code to simply wrap each method's code inside a single using statement. Methods are also provided for arbitrary logs in between. Here is a complete C# ETW event tracing class along with a function entry/exit wrapper:
using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyExample
{
// This class traces function entry/exit
// Constructor is used to automatically log function entry.
// Dispose is used to automatically log function exit.
// use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing
public class FnTraceWrap : IDisposable
{
string methodName;
string className;
private bool _disposed = false;
public FnTraceWrap()
{
StackFrame frame;
MethodBase method;
frame = new StackFrame(1);
method = frame.GetMethod();
this.methodName = method.Name;
this.className = method.DeclaringType.Name;
MyEventSourceClass.Log.TraceEnter(this.className, this.methodName);
}
public void TraceMessage(string format, params object[] args)
{
string message = String.Format(format, args);
MyEventSourceClass.Log.TraceMessage(message);
}
public void Dispose()
{
if (!this._disposed)
{
this._disposed = true;
MyEventSourceClass.Log.TraceExit(this.className, this.methodName);
}
}
}
[EventSource(Name = "MyEventSource")]
sealed class MyEventSourceClass : EventSource
{
// Global singleton instance
public static MyEventSourceClass Log = new MyEventSourceClass();
private MyEventSourceClass()
{
}
[Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceMessage(string message)
{
WriteEvent(1, message);
}
[Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceCodeLine([CallerFilePath] string filePath = "",
[CallerLineNumber] int line = 0,
[CallerMemberName] string memberName = "", string message = "")
{
WriteEvent(2, filePath, line, memberName, message);
}
// Function-level entry and exit tracing
[Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)]
public void TraceEnter(string className, string methodName)
{
WriteEvent(3, className, methodName);
}
[Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)]
public void TraceExit(string className, string methodName)
{
WriteEvent(4, className, methodName);
}
}
}
Code that uses it will look something like this:
public void DoWork(string foo)
{
using (FnTraceWrap fnTrace = new FnTraceWrap())
{
fnTrace.TraceMessage("Doing work on {0}.", foo);
/*
code ...
*/
}
}
A profiler is great for looking at your running code during development but if you're looking for the ability to do custom traces in production, then, as Denis G. mentionned, PostSharp is the perfect tool: you don't have to change all your code and you can easily switch it on/off.
It's also easy to set-up in a few minutes and Gaƫl Fraiteur, the creator of PostSharp even has videos that shows you how easy it is to add tracing to an existing app.
You will find examples and tutorials in the documentation section.
Use ANTS Profiler from Red Gate would be your best bet. Failing that, look into interceptors in Castle Windsor. That does assume you're loading your types via IoC though.
Reflection is another way, you can use the System.Reflection.Emit methods to "write" code into memory. That code could replace your method's code, and execute it but with appropriate logging. Good luck on that one, though... Easier would be to use an Aspect Oriented Programming framework like Aspect#.
It might be waiting for the lock issue to take hold, doing a memory dump and analysing the call stack on various threads. You can use DebugDiag or the adplus script (hang mode, in this case) that comes with Debugging Tools for Windows.
Tess Ferrandez also has an excellent lab series on learning to debug various issues using .NET memory dumps. I highly recommend it.
How do you know that it's happening? If this is a multithreaded application, i would recommend testing for the condition and calling System.Diagnostics.Debugger.Break() at runtime when it's detected. Then, simply open up the Threads window and step through the call stacks on each relevant thread.

Categories

Resources