I having issues with passing arguments to PowerShell via C#
I am getting the following exception:
"A command that prompts the user failed because the host program or
the command type does not support user interaction. Try a host program
that supports user interaction, such as the Windows PowerShell Console
or Windows PowerShell ISE, and remove prompt-related commands from
command types that do not support user interaction, such as Windows
PowerShell workflows"
cs:
private static void RunPowershellScript(string scriptFile, string scriptParameters)
{
string scriptParameters = "param1 param2";
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
Command scriptCommand = new Command(scriptFile);
Collection<CommandParameter> commandParameters = new Collection<CommandParameter>();
foreach (string scriptParameter in scriptParameters.Split(' '))
{
CommandParameter commandParm = new CommandParameter(null, scriptParameter);
commandParameters.Add(commandParm);
scriptCommand.Parameters.Add(commandParm);
}
pipeline.Commands.Add(scriptCommand);
Collection<PSObject> psObjects;
psObjects = pipeline.Invoke();
}
ps:
Function Foo ($arg1, $arg2)
{
Write-Host $arg1
Write-Host $arg2
}
Foo $args[0] $args[1]
What am i missing here? how can i make this work?
The exception is not about arguments. Either do not use commands that require host UI implemented (Write-Host included) or implement you own custom host (PSHost) and this UI (PSHostUserInterface). Here is the example of a simple host (and there is much more on MSDN about this, if you choose this way):
http://msdn.microsoft.com/en-us/library/windows/desktop/ee706559(v=vs.85).aspx
For simple tasks implementing a host with UI is too much, perhaps. You may consider simply to define a function Write-Host with the same arguments and implement it so that it works in your specific case (e.g. does [Console]::WriteLine(...)). This function should be defined in the script or better made available for it in a different way, e.g. invoke another script with it defined in the global scope.
P.S. And if you have your custom host then use one of the CreateRunspace() overloads that takes a host instance as an argument in order to link the host and the runspace.
Related
I'm using powershell cmdlets in my C# code to interact with Hyper-V virtual machines. I'm specifically trying to get the bootorder of a virtual machine. I have no problem running the Get-Firmware command, but I can't seem to parse the return object and get the boot order info I need.
private void Test()
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
Command command = new Command("Get-VMFirmware");
command.Parameters.Add("VMName", "MachineName");
pipeline.Commands.Add(command);
PSObject result = pipeline.Invoke().First();
var bootorder = result.Properties["BootOrder"].Value;
}
}
Per the documentation (and when I look at the value of result.Properties["BootOrder"].Value in locals) I believe my bootorder variable should be a Microsoft.HyperV.PowerShell.VmBootObject[], but I can't seem to find that namespace so I can't cast it as such. So, bootorder is type object, and I can't get any information out of it. What am I doing wrong here?
I have tried executing RemoteDesktop commandlets in powershell using C#.
The following is my program :
static void Main(string[] args)
{
using (var powershell = PowerShell.Create())
{
powershell.Commands.AddCommand("Import-Module").AddArgument("remotedesktop");
powershell.Invoke();
powershell.Commands.Clear();
powershell.AddCommand(#"Get-RDRemoteApp");
powershell.AddCommand(#"out-string");
foreach (var result in powershell.Invoke())
{
Console.WriteLine(result);
}
}
}
When I invoke command it gives the error System.Management.Automation.CommandNotFoundException: The term 'Get-RDRemoteApp' is not recognized as the name of a cmdlet, function, script file, or operable program.
How can I achieve calling RemoteDesktop commandlets ?
I solved this. I change run mode to x64 from Any CPU.
You need to set a persistent runspace for all of your commands. The way your code is now, each command is being executed in it's own isolated runspace. Adding the following code:
var runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
powershell.Runspace = runspace;
to the beginning of the using block should fix your problem.
I faced the same issue and found your post.
Default InitialSessionState only loads Core commandlets and ExecutionPolicy is set to the most restrictive: Microsoft.PowerShell.ExecutionPolicy.Default.
To work around this, I had to set the ExecutionPolicy as shown below :
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Bypass;
iss.ImportPSModule("RemoteDesktop");
PowerShell powershell = PowerShell.Create(iss);
...
I am trying to use MDT from c# like I can already do with powershell when importing MicrosoftDeploymentToolkit.psd1. For example I can run the command Get-MDTPersistentDrive directly from powershell without problem.
But I can't find a way to do the same thing from c#, I tried to include directly the Microsoft.BDD.PSSnapIn.dll (which was basically what was doing "MicrosoftDeploymentToolkit.psd1") then I could access to the GetPersistent class but an error message informed me that I cannot directly invoke a PSCMDlet.
I then tried to use the PowerShell class
var ps = PowerShell.Create();
ps.AddScript(#"import-module C:\...\MicrosoftDeploymentToolkit.psd1");
ps.Invoke();
ps.AddCommand("Get-MDTPersistentDrive");
var result = ps.Invoke();
But I receive this exception
The term 'Get-MDTPersistentDrive' is not recognized as the name of a
cmdlet, function, script file, or operable program
I then tried to do this
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { #"C:\...\MicrosoftDeploymentToolkit.psd1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.Commands.AddCommand("Get-MDTPersistentDrive");
var result= ps.Invoke();
and I receive the error
Object reference not set to an instance of an object
I'm really lost, I don't get what they mean with this error, If you could show me where I'm wrong, or a way to execute PSCmdlet from c# or even better directly how to control MDT that would be awesome.
Invoke-MyFunction is a commandlet I wrote that takes an input file, changes it, and creates a new output file at a specified location. If I open a PowerShell on my desktop, import MyCommandlet.ps1, and run
Invoke-MyFunction -InputPath path\to\input -OutputPath path\to\output
everything works as expected. But when I try to import and invoke the command from a C# program with the code below, the commandlet doesn't run, doesn't log output, and doesn't produce the output file. It doesn't throw a CommandNotFoundException, so I assume the PowerShell object recognizes my commandlet. But I can't figure out why it doesn't execute it.
//set up the PowerShell object
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { #"C:\path\to\MyCommandlet.ps1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
//have MyFunction take input and create output
ps.AddCommand("Invoke-MyFunction");
ps.AddParameter("OutputPath", #"C:\path\to\output");
ps.AddParameter("InputPath", #"C:\path\to\input");
Collection<PSObject> output = ps.Invoke();
Further, after invoking MyFunction, the PowerShell object ps fails to execute any other commands. Even known ones.
This works for me:
//set up the PowerShell object
var initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { #"C:\Users\Keith\MyModule.ps1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
//have MyFunction take input and create output
ps.AddCommand("Invoke-MyFunction");
ps.AddParameter("OutputPath", #"C:\path\to\output");
ps.AddParameter("InputPath", #"C:\path\to\input");
var output = ps.Invoke();
foreach (var item in output)
{
Console.WriteLine(item);
}
With a MyModule.ps1 of:
function Invoke-MyFunction($InputPath, $OutputPath) {
"InputPath is '$InputPath', OutputPath is '$OutputPath'"
}
One thing that did cause me a failure is that on Visual Studio 2013 (maybe 2012 as well) AnyCPU apps will actually run 32-bit on a 64-bit OS. You have to have set the execution policy for PowerShell x86 to allow script execution. Try opening up a PowerShell x86 shell in admin mode and run Get-ExecutionPolicy. If it is set to Restricted, use Set-ExecutionPolicy RemoteSigned to allows scripts to execute.
I want to use specific command that are provided by the "Active Directory Administration with Windows PowerShell". So I installed this module on my server.
Now, I want to use these commands in my code. My project is in c# - ASP.NET.
Here's the code I use to call traditional "cmdlet" command (New-Mailbox, Set-User, ...) :
string runasUsername = #"Mario";
string runasPassword = "MarioKart";
SecureString ssRunasPassword = new SecureString();
foreach (char x in runasPassword)
ssRunasPassword.AppendChar(x);
PSCredential credentials =
new PSCredential(runasUsername, ssRunasPassword);
// Prepare the connection
var connInfo = new WSManConnectionInfo(new Uri("MarioServer"),
"http://schemas.microsoft.com/powershell/Microsoft.Exchange",credentials);
connInfo.AuthenticationMechanism =
AuthenticationMechanism.Basic;
connInfo.SkipCACheck = true;
connInfo.SkipCNCheck = true;
// Create the runspace where the command will be executed
var runspace = RunspaceFactory.CreateRunspace(connInfo);
//Params
....
// create the PowerShell command
var command = new Command("New-Mailbox");
command.Parameters.Add("Name", name);
....
// Add the command to the runspace's pipeline
runspace.Open();
var pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(command);
// Execute the command
var results = pipeline.Invoke();
if (results.Count > 0)
System.Diagnostics.Debug.WriteLine("SUCCESS");
else
System.Diagnostics.Debug.WriteLine("FAIL");
runspace.Dispose();
This code work perfectly ! Great ! But let say I want to use "Set-ADUser", this command is from ActiveDirectory module (RSAT tools).
Given that all is set on the server (the module is installed), I tried to simply change "New-Mailbox" for "Set-ADUser" :
var command = new Command("Set-ADUser");
When I run the code, I have this error :
The term 'Set-ADUser' is not recognized as the name of a cmdlet, function, script file, or operable program.
So, that's my question :
How can we run command from the ActiveDirectory module (RSAT tools) in c# ? (Im using VS 2010).
As #JPBlanc pointed out in the comments section, you will need to ensure that the ActiveDirectory PowerShell module is loaded. PowerShell version 3.0 and later have module auto-loading enabled by default (it can be disabled), but if you're still targeting PowerShell 2.0, then you must first call:
Import-Module -Name ActiveDirectory;
.. before you can use the commands inside the module.
For the purposes of validation, you can use the Get-Module command, to ensure that the ActiveDirectory module has been imported.
Get-Module -Name ActiveDirectory;
If the above command returns $null, then the module is not imported. To verify that PowerShell can "see" the ActiveDirectory module, without actually importing it, run this command:
Get-Module -Name ActiveDirectory -ListAvailable;