Solved

Problems running powershell from C#

Posted on 2010-09-22
10
3,883 Views
Last Modified: 2013-12-16
I have the following C# code.

When I run my powershell script from a powershell terminal it works fine.

If I try to run that from my C# program I get the following exception:

"Exception setting \"WindowTitle\": \"Cannot invoke this function because the current host does not implement it.\""

Is there to be changed on the script or to the C# code to make it work? I've set the permission to Unrestricted. Also the machine is a Windows 7 box. I have checked that property on the registry and changed to unrestricted too.

Also I've read that could be fixed by adding the following to the ps script which I did but did not work too:

#Global Functions go here

function Set-RegistryValue($Key,$Name,$Value,$type=[Microsoft.win32.registryvaluekind]::DWord) {
 $parent=split-path $key -parent
 $parent=get-item $parent
 $key=get-item $key
 $keyh=$parent.opensubkey($key.name.split("\")[-1],$true)
 $keyh.setvalue($name,$value,$type)
 $keyh.close()
}
function Set-OutputBuffer($width=10000) {
 $key=""
 if ($host.ui.rawui.WindowTitle -eq "taskeng.exe") {
  $key="hkcu:\console\taskeng.exe"
 }
 elseif ($host.ui.rawui.WindowTitle -eq "$($env:windir)\system32\svchost.exe" ) {
  $key="hkcu:\console\%SystemRoot%_system32_svchost.exe"
 }
 # other titles are ignored
 if ($key) {
  $taskeng=$key
  if (!(test-path $taskeng)) {md $taskeng -verbose}
  set-RegistryValue $taskeng FontSize 0x00050000
  set-RegistryValue $taskeng ScreenBufferSize 0x02000200
  set-RegistryValue $taskeng WindowSize 0x00200200
  set-RegistryValue $taskeng FontFamily 0x00000036
  set-RegistryValue $taskeng FontWeight 0x00000190
  set-ItemProperty $taskeng FaceName "Lucida Console"

  $bufferSize=$host.ui.rawui.bufferSize
  $bufferSize.width=$width
  $host.ui.rawui.BufferSize=$BufferSize
  $maxSize=$host.ui.rawui.MaxWindowSize
  $windowSize=$host.ui.rawui.WindowSize
  $windowSize.width=$maxSize.width
  $host.ui.rawui.WindowSize=$windowSize
 }

}

$verbosepreference="continue"
Set-OutputBUffer

The C# code is attached below.

Thanks for the help.
//The additional formatting is how powershell handles spaces in the path

				string command = string.Format("& '{0}' ",invokeProperties.ExecutableName);

				//if (arguments.Length > 0)

				//	command += arguments;



				//RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();



				//using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))

				using (Runspace runspace = RunspaceFactory.CreateRunspace())

				{

					runspace.Open();

					RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);

					scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

					Pipeline pipeline = runspace.CreatePipeline();

					Command scriptCommand = new Command(command,true,true);

					Collection<CommandParameter> commandParameters = new Collection<CommandParameter>();

					string[] args = arguments.Split(' ');

					foreach (string scriptParameter in args)

					{

						CommandParameter commandParm = new CommandParameter(null, scriptParameter);

						commandParameters.Add(commandParm);

						scriptCommand.Parameters.Add(commandParm);

					}

					pipeline.Commands.Add(scriptCommand);

					Collection<PSObject> psObjects;

					psObjects = pipeline.Invoke();



					// convert the script result into a single string

					StringBuilder stringBuilder = new StringBuilder();

					foreach (PSObject obj in psObjects)

					{

						stringBuilder.AppendLine(obj.ToString());

					}

					runspace.Close();

				}

Open in new window

0
Comment
Question by:CarlosScheidecker
  • 7
  • 2
10 Comments
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33742441

Is the first snippet the script you're running?

Your C# snippet doesn't actually contain any PS commands which makes it a tad difficult to know what to suggest.

Chris
0
 
LVL 1

Author Comment

by:CarlosScheidecker
ID: 33743952
Yes, the first is the first part of the script. As on the C# side, it is supposed to execute the script and not an individual PS command.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33744027

Have you tried dropping these bits?

$host.ui.rawui.WindowTitle

Considering you don't have a UI (running under a runspace), you can't really do much with that element.

Chris
0
 
LVL 1

Author Comment

by:CarlosScheidecker
ID: 33745118
Hi Chris,

I had it before without those bits and had the same error. A research online showed that those bits could fix that but setting those values. The problem on the exception, as you can see, is that the WindowTitle is not set.

In either case, with that or without that in the script I still have an error. Hence I wonder if on the C# code I can set something to prevent it. Could not find the solution yet.
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 1

Author Comment

by:CarlosScheidecker
ID: 33745434
It seems to me that you need to implement some functions such as a setter for some host properties like the WindowTitle.

Now, I was trying to set that on the script but it does not work.

Hence the solution must be to implement that on the C# code.

Does anyone have any idea regarding this?
0
 
LVL 1

Author Comment

by:CarlosScheidecker
ID: 33745561
Allow me to add further information.

The script that I am trying to run does a call to VMware script that removes a virtual machine. The VM script has write-host and other commands like that. Hence the problem. I cannot change those scripts.

For the research I have done, it seems that you have to implement your own host to avoid that.

http://msdn.microsoft.com/en-us/library/system.management.automation.host.pshost%28v=VS.85%29.aspx

I am not sure what to do in order to achieve that. Any ideas? Thanks.
0
 
LVL 1

Author Comment

by:CarlosScheidecker
ID: 33749121
Also, I am trying to implement my own host so that I can override the error but I have not yet been successful. There are some examples on MSDN but I could not make them work.

Basically I am trying to wrap the PS execution from the C# app.

0
 
LVL 1

Author Comment

by:CarlosScheidecker
ID: 33749506
Well, I have created my own host implementation as so. Then I am calling it by doing this:

Host01 me = new Host01();
MyHost customHost = new MyHost(me);
Runspace runspace = RunspaceFactory.CreateRunspace(customHost);

I still have the problem even though I have created a property WindowTitle in my PSHost implementation.


internal class Host01

	{

		/// <summary>

		/// Indicator to tell the host application that it should exit.

		/// </summary>

		private bool shouldExit;



		/// <summary>

		/// The exit code that the host application will use to exit.

		/// </summary>

		private int exitCode;



		/// <summary>

		/// Gets or sets a value indicating whether the 

		/// host application should exit.

		/// </summary>

		public bool ShouldExit

		{

			get { return this.shouldExit; }

			set { this.shouldExit = value; }

		}



		/// <summary>

		/// Gets or sets the PSHost implementation that is

		/// used to tell the host application what code to use

		/// when exiting.

		/// </summary>

		public int ExitCode

		{

			get { return this.exitCode; }

			set { this.exitCode = value; }

		}

	}



	internal class MyHost : PSHost

	{

		/// <summary>

		/// A reference to the PSHost implementation.

		/// </summary>

		private Host01 program;



		/// <summary>

		/// The culture information of the thread that created

		/// this object.

		/// </summary>

		private CultureInfo originalCultureInfo =

			 System.Threading.Thread.CurrentThread.CurrentCulture;



		/// <summary>

		/// The UI culture information of the thread that created

		/// this object.

		/// </summary>

		private CultureInfo originalUICultureInfo =

			 System.Threading.Thread.CurrentThread.CurrentUICulture;



		/// <summary>

		/// The identifier of this PSHost implementation.

		/// </summary>

		private Guid myId = Guid.NewGuid();



		/// <summary>

		/// Initializes a new instance of the MyHost class. Keep

		/// a reference to the host application object so that it 

		/// can be informed of when to exit.

		/// </summary>

		/// <param name="program">

		/// A reference to the host application object.

		/// </param>

		public MyHost(Host01 program)

		{

			this.program = program;

		}



		/// <summary>

		/// Return the culture information to use. This implementation 

		/// returns a snapshot of the culture information of the thread 

		/// that created this object.

		/// </summary>

		public override System.Globalization.CultureInfo CurrentCulture

		{

			get { return this.originalCultureInfo; }

		}



		/// <summary>

		/// Return the UI culture information to use. This implementation 

		/// returns a snapshot of the UI culture information of the thread 

		/// that created this object.

		/// </summary>

		public override System.Globalization.CultureInfo CurrentUICulture

		{

			get { return this.originalUICultureInfo; }

		}



		/// <summary>

		/// This implementation always returns the GUID allocated at 

		/// instantiation time.

		/// </summary>

		public override Guid InstanceId

		{

			get { return this.myId; }

		}



		/// <summary>

		/// Return a string that contains the name of the host implementation. 

		/// Keep in mind that this string may be used by script writers to

		/// identify when your host is being used.

		/// </summary>

		public override string Name

		{

			get { return "MySampleConsoleHostImplementation"; }

		}



		/// <summary>

		/// This sample does not implement a PSHostUserInterface component so

		/// this property simply returns null.

		/// </summary>

		public override PSHostUserInterface UI

		{

			get { return null; }

		}



		/// <summary>

		/// Return the version object for this application. Typically this

		/// should match the version resource in the application.

		/// </summary>

		public override Version Version

		{

			get { return new Version(1, 0, 0, 0); }

		}



		/// <summary>

		/// Not implemented by this example class. The call fails with

		/// a NotImplementedException exception.

		/// </summary>

		public override void EnterNestedPrompt()

		{

			throw new NotImplementedException(

				 "The method or operation is not implemented.");

		}



		/// <summary>

		/// Not implemented by this example class. The call fails

		/// with a NotImplementedException exception.

		/// </summary>

		public override void ExitNestedPrompt()

		{

			throw new NotImplementedException(

				 "The method or operation is not implemented.");

		}



		/// <summary>

		/// This API is called before an external application process is 

		/// started. Typically it is used to save state so the parent can 

		/// restore state that has been modified by a child process (after 

		/// the child exits). In this example, this functionality is not  

		/// needed so the method returns nothing.

		/// </summary>

		public override void NotifyBeginApplication()

		{

			return;

		}



		/// <summary>

		/// This API is called after an external application process finishes.

		/// Typically it is used to restore state that a child process may

		/// have altered. In this example, this functionality is not  

		/// needed so the method returns nothing.

		/// </summary>

		public override void NotifyEndApplication()

		{

			return;

		}



		/// <summary>

		/// Indicate to the host application that exit has

		/// been requested. Pass the exit code that the host

		/// application should use when exiting the process.

		/// </summary>

		/// <param name="exitCode">The exit code to use.</param>

		public override void SetShouldExit(int exitCode)

		{

			this.program.ShouldExit = true;

			this.program.ExitCode = exitCode;

		}



		public string WindowTitle { get; set; }

	}

Open in new window

0
 
LVL 1

Accepted Solution

by:
CarlosScheidecker earned 0 total points
ID: 33756858
OK, found the problem and fixed it.

On the PSHost implementation I am calling a PSHostUserInterface implementation.

Now I have this property instead of returning null.

public override PSHostUserInterface UI
            {
                  get { return _ui; }
            }

This property is an instance of MyPSHostUserInterface as follows on the code snipet. It allows me to capture the screen stuff on a StringBuffer and fix all the issues.


internal class MyPSHostUserInterface : PSHostUserInterface

	{

		private StringBuilder _sb;

		public MyPSHostUserInterface() 

		{

        _sb = new StringBuilder();

		}

		 public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value)

    {

        _sb.Append(value);

    }



    public override void Write(string value)

    {

        _sb.Append(value);

    }



    public override void WriteDebugLine(string message)

    {

        _sb.AppendLine("DEBUG: " + message);

    }



    public override void WriteErrorLine(string value)

    {

        _sb.AppendLine("ERROR: " + value);

    }



    public override void WriteLine(string value)

    {

        _sb.AppendLine(value);

    }



    public override void WriteVerboseLine(string message)

    {

        _sb.AppendLine("VERBOSE: " + message);

    }



    public override void WriteWarningLine(string message)

    {

        _sb.AppendLine("WARNING: " + message);

    }



    public override void WriteProgress(long sourceId, ProgressRecord record)

    {

        return;

    }



	 public string Output

	 {

		 get

		 {

			 return _sb.ToString();

		 }

	 }



	 public override Dictionary<string, PSObject> Prompt(string caption, string message, System.Collections.ObjectModel.Collection<FieldDescription> descriptions)

	 {

		 throw new NotImplementedException();

	 }



	 public override int PromptForChoice(string caption, string message, System.Collections.ObjectModel.Collection<ChoiceDescription> choices, int defaultChoice)

	 {

		 //throw new NotImplementedException();

	 	return 0;

	 }



	 public override PSCredential PromptForCredential(string caption, string message, string userName, string targetName, PSCredentialTypes allowedCredentialTypes, PSCredentialUIOptions options)

	 {

		 throw new NotImplementedException();

	 }



	 public override PSCredential PromptForCredential(string caption, string message, string userName, string targetName)

	 {

		 throw new NotImplementedException();

	 }



	 public override PSHostRawUserInterface RawUI

	 {

		 get { return null; }

	 }



	 public override string ReadLine()

	 {

		 throw new NotImplementedException();

	 }



	 public override System.Security.SecureString ReadLineAsSecureString()

	 {

		 throw new NotImplementedException();

	 } 



	}

Open in new window

0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

This is a PowerShell web interface I use to manage some task as a network administrator. Clicking an action button on the left frame will display a form in the middle frame to input some data in textboxes, process this data in PowerShell and display…
How to sign a powershell script so you can prevent tampering, and only allow users to run authorised Powershell scripts
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now