如何在 C# 中获取 PSObject.Properties 的脚本属性值?



我正在尝试使用"GET-PSDrive"命令通过PowerShell 6.0获取服务器的驱动器信息。直接在PowerShell中运行命令,我在输出表中看到了"已使用"和"免费"的值,但是尽管使用Microsoft.Powershell.Sdk在代码中运行相同的命令,但"已使用"和"免费"字段不可用。

我看到这两个项目都列在 PSObject.Properties 数组下,但尝试访问值时我收到异常:

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

以下是我正在使用的 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。这意味着当它被调用时,它会运行一个脚本。我们可以通过调用来查看这一点:

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 *

这是更好的解决方案。

它将返回一个 PS对象的数组,其中的值作为注释而不是脚本

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

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

最新更新