如何在C#中获取PSObject.Properties的ScriptProperty值?

时间:2019-04-20 17:38:56

标签: c# powershell .net-core powershell-sdk

我正在尝试使用“ GET-PSDrive”命令通过PowerShell 6.0获取服务器的驱动器信息。直接在PowerShell中运行命令,我在输出表中看到“ Used”和“ Free”的值,但是使用Microsoft.Powershell.Sdk在代码中运行相同的命令,但“ Used”和“ Free”字段却没有可用。

我在PSObject.Properties数组下看到了两个项目,但是尝试访问该值时会收到异常:

“此线程中没有可用于运行脚本的运行空间。您可以在System.Management.Automation.Runspaces.Runspace类型的DefaultRunspace属性中提供一个。您尝试调用的脚本块是:##” < / p>

以下是我正在使用的POC代码:

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

我期望获得该属性的值,但是每次评估该值时,我都会收到一条错误消息,指出没有可用的运行空间。检查该属性,我确实看到它是一个ScriptProperty,那么您如何获取该生成的值?

1 个答案:

答案 0 :(得分:5)

Used属性称为ScriptProperty。这意味着当它被调用时它将运行一个脚本。我们可以通过调用

看到它
get-PSDrive | get-member -Name Used

这将返回

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

我们可以更深入地研究并查看正在运行的脚本

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

这将返回

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
    };
}

这就是为什么您会收到异常There is no Runspace available to run scripts in this thread的原因。这是因为该信息运行的脚本需要一个运行空间。

要解决此问题,您可以将所有属性变成这样的音符属性

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

或@ mklement0在评论中指出

Get-PSDrive | Select-Object *

哪个是更好的解决方案。

它将返回一个PSobjects数组,其值作为注释而不是脚本

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;
    }
}

*请注意,该值将只是所使用字节的整数。