I execute a PowerShell script from C# code. I use System.Management.Automation.dll Nuget package. Although my script has an obvious error, powerShell.Invoke() returns no results, nor error messages.
using (var powerShell = PowerShell.Create())
{
powerShell.AddScript("an erroneous script");
powerShell.Invoke(); // yields an empty PSObject list
}
How can I get a list of errors?
Related
I want to execute the PowerShell script without SDK. In my project, I have to execute the PowerShell script and also want to create an EXE file for the same. But the problem is:
When I remove Microsoft.PowerShell.SDK then the script is not executed and gives an error but creates an exe file. Error is "Cannot load PowerShell snap-in Microsoft.PowerShell.Diagnostics because of the following error: Could not load file or assembly".
When the above package is not removed from the project then the script is working fine but it gives an error while creating an exe file.
Please share your suggestion.
Here is my code:
string readLocationFile = File.ReadAllText(#"gravity_location.ps1");
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript(readLocationFile);
powerShell.AddParameter("name", _locationName.Text);
powerShell.AddParameter("targetPath", filePath);
powerShell.Invoke();
}
You can use System.Management.Automation which is the core of the PowerShell SDK like this
using System.Management.Automation;
using System.Management.Automation.Runspaces;
//...
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
//Here's how you add a new script with arguments
Command myCommand = new Command("your/script/file/path.ps1");
CommandParameter testParam = new CommandParameter("key","value"); //e.g. "-Path" "value"
myCommand.Parameters.Add(testParam);
pipeline.Commands.Add(myCommand);
// Execute PowerShell script
results = pipeline.Invoke();
Detailed information about the packages.
https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/choosing-the-right-nuget-package?view=powershell-7.2
Another post about the topic:
Execute PowerShell Script from C# with Commandline Arguments
I am executing a Powershell script file from C# with the following code:
Runspace _rs = RunspaceFactory.CreateRunspace();
_rs.ApartmentState = ApartmentState.STA;
_rs.Open();
PipeLine _pipeLine = _rs.CreatePipeline();
Command scriptCommand = new Command(filePath);
_pipeLine.Invoke();
In the powershell script file I am referencing libraries:
Add-Type -Path Filepath.dll
In C# i am disposing the runspace and pipeline afterwords trying to unlock the associated libraries.
finally
{
_rs.Dispose();
_pipeLine.Dispose();
}
Unfortunately in a later step when trying to delete the dll files associated in the script, i get a UnauthorizedException. Please note that i dont get the exception if i never run the script from C#. I def should have accss to it.
I'm trying to invoke a Powershell Command Get-DSCLocalConfigurationManager from a windows service project (.net framework 2.0). using System.Management.Automation
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
try
{
runspace.Open();
var ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddCommand("Get-DSCLocalConfigurationManager");
var results = ps.Invoke();
foreach (PSObject result in ps.Invoke())
{
_eventLog.WriteEntry(result.Members["AgentId"].Value.ToString());
}
}
catch (Exception e)
{
_eventLog.WriteEntry($"Powershell Command failed with: {e.Message}", EventLogEntryType.Error);
}
}
Invoking the command in a powershell window works as expected.
The problem is that pretty much every command i try to invoke this way returns an exception:
"The term 'Get-DSCLocalConfigurationManager' is not recognized as the name of a cmdlet,..."
I tried the commands Get-Module -ListAvailable $PSVersionTable.PSVersion with the same result. There are commands that work like Get-Process, so i assume there are missing modules.
Importing the module and invoking the command like this
ps.AddScript(#"Import -Module 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1'; Get-DSCLocalConfigurationManager");
also doesn't work as it returns the following error:
The 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1' module cannot be imported because its manifest contains one or more members that are not valid. The valid manifest members are ('ModuleToProcess', 'NestedModules', 'GUID', 'Author', 'CompanyName', 'Copyright', 'ModuleVersion', 'Description', 'PowerShellVersion', 'PowerShellHostName', 'PowerShellHostVersion', 'CLRVersion', 'DotNetFrameworkVersion', 'ProcessorArchitecture', 'RequiredModules', 'TypesToProcess', 'FormatsToProcess', 'ScriptsToProcess', 'PrivateData', 'RequiredAssemblies', 'ModuleList', 'FileList', 'FunctionsToExport', 'VariablesToExport', 'AliasesToExport', 'CmdletsToExport'). Remove the members that are not valid ('DscResourcesToExport', 'HelpInfoURI'), then try to import the module again.
What Powershell version is used when invoking commands like this? Is it tied to the .net framework version I'm using or is it the installed version of the system? What Modules are loaded? What can i do to invoke this command?
Edit: I created a simple console application and found out, that this is connected with the framework version. With .net framework 4.0 this works as expected, but as soon as i use 3.5 or lower the problem i describe arises.
I had same problem.
It comes from version of Powershell.
When you target project to .Net 2.0/3.5 you using System.Management.Automation.dll version 1.0.0.0, that runs Powershell 2.0, but when your project targets to .Net 4+, using dll version 3.0.0.0 and runs Powershell 3.0.
I pass to my runtime Powershell command to call shell Powershell and execute command, like this:
var results = powerShell.AddScript("powershell Get-AppxPackage -allusers -name 'Microsoft.WindowsStore'").Invoke();
if (powerShell.Streams.Error.Any())
{
foreach (var errorRecord in powerShell.Streams.Error)
throw new Exception();
}
Called Ppowershell redirects streams to runtime Powershell.
var runspace = RunspaceFactory.CreateRunspace()
runspace.Open();
var ps = PowerShell.Create()
ps.Runspace = runspace;
ps.AddCommand(...);
ps.Invoke()
Some cmdlets that exist in a regular shell are missing from the runtime started by C#, e.g. all the commands from the Microsoft.PowerShell.LocalAccounts module :
Error: System.Management.Automation.CommandNotFoundException: The term 'New-LocalUser' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
By comparing the Get-Module -ListAvailable output from a regular shell and a C# started one I noticed multiple modules are missing :
AppBackgroundTask
AssignedAccess
BitLocker
ConfigCI
Defender
Microsoft.PowerShell.LocalAccounts
MMAgent
NetworkSwitchManager
PcsvDevice
PSWorkflow, PSWorkflowUtility
SmbShare, SmbWitness
StartLayout
WindowsSearch
The version ($PSVersionTable) is reported as the same in both shells : 5.1.14393.693
Edit
Seems to be the same issue & solution : Why do powershell modules not import when running powershell via start process in c#?
You can import modules directly on your script instead of trying to do that from C#.
Import-module bitlocker
For example.
Can someone, please, help to understand why the following code inside a Csharp function
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipe = runspace.CreatePipeline();
Command connectToActDir = new Command("connect-QADService");
connectToActDir.Parameters.Add("Service", "'ip:port'");
connectToActDir.Parameters.Add("ConnectionAccount", "'user.local\administrator'");
connectToActDir.Parameters.Add("ConnectionPassword", "'password'");
pipe.Commands.Add(connectToActDir);
pipe.Invoke();
causes the following error
The term 'connect-QADService' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
while ActiveRoles cmdlets are installed and running the equivalent command in power shell succeeds. Do I miss some dll in project references?
Thanks
The Quest ActiveRoles cmdlets are not loaded into a PowerShell session by default, because they're not part of PowerShell.
PowerShell 3 will automatically load modules when needed. I don't know if this holds true when using a RunSpace as I've never used PowerShell this way.
Do you load the Quest snap-in or module in your PowerShell profile? You'll need to do the equivalent in your C# code.