Microsoft deployment toolkit from c# - c#

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.

Related

How to get the result of a Powershell cmdlet in C# unit method

I have below PowerShell cmnd which runs fine in PowerShell and I am also able to call and execute it from a unit test in C# as described below. But my problem is in PowerShell window I write $rec.Categories.Count and then I get result. How can I write this in PowerShell script which I call in C# and get the value in there to test?
In PowerShell window:
$inv = Get-Inventory -Project 'TestDemo'
$inv.Categories.Count
4
Same script I have in C# and I am calling it by below method and it runs successfully but I don't know the way to get "4" in my result variable.
[Fact]
public void VerifyGetInventoriesOfaProject()
{
string path = Path.Combine( Root, #"TestData\GetInventory.ps1" );
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript( path );
var results = pipeline.Invoke();
runspace.Close();
// Assert.Equal( 5, results );
}
If you just search c# get output from powershell the first result is a stackoverflow post about this with a pretty clear and easy answer ...
Get Powershell command's output when invoked through code

Error while running RemoteDesktop commandlets in powershell from C#

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);
...

Get-RDUserSession not executing in PSScript when called

I have a PSScript that I call from C#. The problem that I am encountering, is that even though script has loaded, the Get-RDUserSession is not being executed. The function which contains this cmdlet is being called, because if I include the Get-Process, I am getting results.
Therefore, I am at a loss as to why and how I get this particular cmdlet to execute from C# - it works in Powershell directly.
My code is:
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = rs;
ps.AddScript(myscript);
ps.Invoke();
ps.AddCommand("MyFunction");
Collection<PSObject> output = ps.Invoke();
}
Does anyone have any ideas?
Make sure your C# Object is set correctly to either 64bit or 32bit depending upon your environment.

PowerShell commandlet getting invoked but not responding

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.

Invoking C# powershell cmdlets from another powershell cmdlet

Here is my scenario : I have add-data and add-bulkdata cmdlets, both are written in C# deriving from pscmdlet, add-bulkdata takes a csv file and each line is fed to add-data cmdlet. Add-data cmdlet might throw terminating exceptions, if it does I dont know how to receive it in the add-bulkdata cmdlet, in bulkdata cmdlet I get a commandinvocationexception but it does not have the ErrorRecord that the underlying add-data had set. Also if I query pipeline.errors it gives me no information.
What is the best way to handle such scenario?
My Add-Bulkdata ProcessRecord() function looks something like this :
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new[] { #"C:\mybinary.dll" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(cmd); //cmd is add-data cmdlet
pipeline.Commands.Add("out-string"); // I have tried with and without this
Collection<PSObject> results = pipeline.Invoke();
Collection<object> errors = pipeline.Error.ReadToEnd();

Categories

Resources