How to get ScriptProperty Values of PSObject.Properties in C#?

天涯浪子 提交于 2019-12-10 17:13:25

问题


I am trying to get drive information for a server through PowerShell 6.0 using the 'GET-PSDrive' command. Running the command directly in PowerShell, I see the values for 'Used' and 'Free' within the output table, but running the same command in code though using the Microsoft.Powershell.Sdk the 'Used' and 'Free' fields are not available.

I see both items listed under the PSObject.Properties array, but trying to access the value I receive the exception:

"There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: ##"

The following is the POC code that I am working with:

using (var psCon = PowerShell.Create())
{
     psCon.AddCommand("GET-PSDrive");
     var psReturn = psCon.Invoke();
     foreach (var psObj in psReturn)
     {
          var driveUsedValue = psObj.Properties["Used"].Value;
     }
}

I am expecting to get the value of that property, but each time the value is evaluated I get an error saying that no runspace is available. Inspecting the property I do see that its a ScriptProperty, so how do you go about getting that generated value?


回答1:


The property Used is a called a ScriptProperty. It means when it is called it runs a script. We can see this by calling :

get-PSDrive | get-member -Name Used

This returns

Name MemberType     Definition
---- ----------     ----------
Used ScriptProperty System.Object Used {get=## Ensure that this is a FileSystem drive...

We can dig deeper and see the script that is running also

get-PSDrive  | get-member -Name Used | select -ExpandProperty Definition

This will return

System.Object Used {
    get=## Ensure that this is a FileSystem drive
    if($this.Provider.ImplementingType -eq [Microsoft.PowerShell.Commands.FileSystemProvider]){
        $driveRoot = ([System.IO.DirectoryInfo] $this.Root).Name.Replace('\','')
        $drive = Get-CimInstance Win32_LogicalDisk -Filter "DeviceId='$driveRoot'"
        $drive.Size - $drive.FreeSpace
    };
}

This is why you get the exception There is no Runspace available to run scripts in this thread. It is because that info runs a script which needs a runspace.

to work around this you can turn all the properties into note properties like this

Get-PSDrive | %{
    $drive = $_
    $obj = new-object psobject
    $_.psobject.Properties.GetEnumerator() | %{
        $obj | Add-Member -MemberType NoteProperty -name $_.Name -Value $drive."$($_.name)" 
    }
    $obj
}

OR as @mklement0 pointed out in the comments

Get-PSDrive | Select-Object *

Which is much better solution.

It will return an array of PSobjects with the values as notes instead of script

using (var psCon = PowerShell.Create()){
    psCon.AddScript(@"
        Get-PSDrive | Select-Object *
    ");


    var psReturn = psCon.Invoke();
    foreach (var psObj in psReturn)
    {
        var driveUsedValue = psObj.Properties["Used"].Value;
    }
}

*Note the value will just the integer of bytes used.



来源:https://stackoverflow.com/questions/55776105/how-to-get-scriptproperty-values-of-psobject-properties-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!