4

I have code for a C# test app that queries system info using PowerShell, and in it I have a few simple functions like the following:

public void GetSystemInfo()
{
    using (PowerShell ps = PowerShell.Create())
    {
        ps.AddCommand("Get-Disk");      // Get-Disk is an example; this varies
        foreach (PSObject result in ps.Invoke())
        {
            // ...
            // Do work here. Process results, etc...
            // ...
        }
    }
}

This is straightforward and mostly taken from MSDN examples, like here: https://msdn.microsoft.com/en-us/library/dd182449(v=vs.85).aspx

The problem is that each time this function is called, I can see the app's memory footprint grow. The footprint grows right at the call to ps.Invoke() and never shrinks. It doesn't matter how I process the data; I can even comment the body of the foreach loop out completely and the memory is never garbage collected.

As far as I can tell from looking at the PowerShell class interface, there doesn't seem to be a way to force it to clean itself up, and Dispose() clearly doesn't work since the resources remain leaking in memory after the using block exits.

Is this a known bug in the C# PowerShell class implementation or PowerShell itself? Is anyone aware of a solution, or an alternative if possible?


EDIT

I've also tried the follow now, with the same results:

public void GetSystemInfo()
{
    Runspace rs = RunspaceFactory.CreateRunspace();
    rs.Open();

    PowerShell ps = PowerShell.Create();
    ps.Runspace = rs;
    ps.AddCommand("Get-Disk");      // Get-Disk is an example; this varies
    foreach (PSObject result in ps.Invoke())
    {
        // ...
        // Do work here. Process results, etc...
        // ...
    }

    rs.Close();
}

Again, super straightforward. Taken from the sample here.

I'm wondering if this is a know bug in the Powershell module. Perhaps I'll start looking into alternatives to the Powershell interface (WMI, etc) since I need to call these PS queries periodically over an indeterminately long duration.

8bitcartridge
  • 1,629
  • 6
  • 25
  • 38
  • 1
    I'm not certain about this so I'm not adding it as an answer, but maybe the memory is in the runspace and not the PowerShell object. What if you manage your own runspace or runspacepool with RunspaceFactory, and then try to clean up those objects when you're done? – briantist Feb 25 '16 at 23:39
  • Thanks for the suggestion. I'll try it and report back into the post. – 8bitcartridge Feb 25 '16 at 23:48

1 Answers1

0

There does indeed appear to be an issue with the Powershell API in the C# library. Even forcing a garbage collect doesn't seem to free up the memory.

Replacing everything with WMI calls instead of Powershell eliminates the problem.

8bitcartridge
  • 1,629
  • 6
  • 25
  • 38
  • 1
    Weird. Possibly raise this on Microsoft User Voice/MSDN User Voice or something. In the meantime you could write an interface along the lines of `ISystemManagment` (or a better name according to what you're making) which provides the methods you need. Then have two classes, both of which implement `ISystemManagment`, but one class does it with WMI and the other the Powershell way. You can then much more easily swap functionality should the Powershell problem be resolved. So for example `GetSystemInfo` in both classes but one is with WMI and the other with Powershell. Just a suggestion anyway. – user9993 Mar 03 '16 at 10:14