Using a powershell object in C# to retrieve cmdlet get-physicaldisk
Asked Answered
P

2

2

Problem with Powershell object in C#9

I am trying to retrieve physical disks in C# using a system.management.powershell object. When I try using the cmdlet “Get-Process” the powershell object retrieves all processes correctly.

  using (PowerShell PowerShellInstance = PowerShell.Create())
    {
        // this works
        //PowerShellInstance.AddCommand("Get-Process");
        PowerShellInstance.AddScript("Get-PhysicalDisk");
        //PowerShellInstance.AddCommand("Out-String -Width 240 -Stream");
        Collection<PSObject> outlist = PowerShellInstance.Invoke();
    }

When I try using the cmdlet “Get-PhysicalDevice” no data is returned, and no errors are thrown.


I have also tried using a Runspace and a pipeline to execute get-process, and all processes are returned correctly.

Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
Pipeline p = rs.CreatePipeline();
p.Commands.Add("get-process");
// p.Commands.Add("get-physicaldisk");
Collection<PSObject> results = p.Invoke();
rs.Close();

When I try get-physicaldisk with a runspace the program throws a command not found exception. I am transferring a server monitor from VB to C#. The Runspace (get-physicaldisk) works correctly in VB using .net framework 4.1.7.

I am using System Management 5.0, ..Automation 7.1.4, and Powershell SDK 7.1.4.

Penumbra answered 4/9, 2021 at 1:14 Comment(0)
T
2

Set your execution policy to RemoteSigned so that the Storage module can be imported

using (var runspace = RunspaceFactory.CreateRunspace())
{
    runspace.InitialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned;
    runspace.Open();
    using (PowerShell PowerShellInstance = PowerShell.Create(runspace))
    {
        PowerShellInstance.AddScript("Get-PhysicalDisk");
        Collection<PSObject> outlist = PowerShellInstance.Invoke();
    }
}
Trulatrull answered 4/9, 2021 at 2:47 Comment(3)
Nicely done; I was trying to explain in general terms how to diagnose the problem, but the specific cause of a module failing to import hadn't occurred to me.Emanuele
Btw, do you know what inside that module necessitates enabling scripts to run (as an aside: Microsoft.PowerShell.ExecutionPolicy.RemoteSigned should suffice and is probably preferable)? In a pristine PowerShell session, it works for me even with policy Restricted, but in conjunction with loading unrelated format data in my $PROFILE file I do see the symptom.Emanuele
@mklement0, Unfortunately I do not. I just happened to notice the error that the module wasn't loading. I have tested with RemoteSigned and it also works for me so I have updated my answer. I have not been able to get it to work with RestrictedTrulatrull
E
4

Daniel's helpful answer provides an effective solution for the case at hand.

This answer explains how the PowerShell SDK reports errors and how to inspect them:

  • The .AddScript() PowerShell SDK method is for passing one more PowerShell statements for execution; that is, you can pass a snippet of PowerShell source code, as you would find in a .ps1 script file.

  • By contrast, the .AddCommand() method accepts the name or executable path of a single PowerShell command - without arguments; the latter must be added with separate calls, namely via a single .AddParameters() call, or via argument-individual .AddParameter() and .AddArgument() calls.

Choosing one method over the other has implications with respect to error handling, specifically with respect to statement-terminating errors, such as when calling a nonexistent command or, as it turned out to be the case for you, a command whose module failed to import:

  • .AddScript()-added code does not throw a .NET exception when .Invoke() is called and a statement-terminating error occurs - instead, an empty collection is returned, the .HadErrors property returns true, and the error(s) that occurred can be examined via the .Streams.Error collection.

  • .AddCommand()-added code may throw a .NET exception, e.g. of type System.Management.Automation.CommandNotFoundException.

By contrast:

  • Script-terminating errors (those created with a throw statement or via $ErrorActionPreference = 'Stop' / -ErrorAction Stop) always create a .NET exception for the caller.

    • throw, as a PowerShell statement, can only be executed via .AddScript(), but setting $ErrorActionPreference / using -ErrorAction is also possible in connection with .AddCommand().
  • Non-terminating errors (e.g., Get-ChildItem nosuchfile) never create a .NET exception for the caller.

See also:

Emanuele answered 4/9, 2021 at 2:26 Comment(0)
T
2

Set your execution policy to RemoteSigned so that the Storage module can be imported

using (var runspace = RunspaceFactory.CreateRunspace())
{
    runspace.InitialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned;
    runspace.Open();
    using (PowerShell PowerShellInstance = PowerShell.Create(runspace))
    {
        PowerShellInstance.AddScript("Get-PhysicalDisk");
        Collection<PSObject> outlist = PowerShellInstance.Invoke();
    }
}
Trulatrull answered 4/9, 2021 at 2:47 Comment(3)
Nicely done; I was trying to explain in general terms how to diagnose the problem, but the specific cause of a module failing to import hadn't occurred to me.Emanuele
Btw, do you know what inside that module necessitates enabling scripts to run (as an aside: Microsoft.PowerShell.ExecutionPolicy.RemoteSigned should suffice and is probably preferable)? In a pristine PowerShell session, it works for me even with policy Restricted, but in conjunction with loading unrelated format data in my $PROFILE file I do see the symptom.Emanuele
@mklement0, Unfortunately I do not. I just happened to notice the error that the module wasn't loading. I have tested with RemoteSigned and it also works for me so I have updated my answer. I have not been able to get it to work with RestrictedTrulatrull

© 2022 - 2024 — McMap. All rights reserved.