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

Posted

技术标签:

【中文标题】如何在 C# 中获取 PSObject.Properties 的 ScriptProperty 值?【英文标题】:How to get ScriptProperty Values of PSObject.Properties in C#? 【发布时间】:2019-04-20 17:38:56 【问题描述】:

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

我看到 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,那么你如何获取生成的值?

【问题讨论】:

【参考方案1】:

使用的属性是一个称为 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 在 cmets 中指出的那样

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;
    

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

【讨论】:

感谢您的澄清。深入研究它,我确实找到了它试图运行的脚本,但被困在如何让它执行上。不过,将其切换为便笺即可。 可靠答案(+1); Get-PSDrive | Select-Object * 是一种更简单(而且可能更快)的解决方案。 你刚刚教会了我一些新东西@mklement0

以上是关于如何在 C# 中获取 PSObject.Properties 的 ScriptProperty 值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中获取调用方法 [重复]

如何在 C# 中获取文件大小?

如何在 C# 中获取本地机器名称?

如何在 C# 中获取当前的区域设置?

如何在 C# 代码中获取 IP 地址 [重复]

如何在 C# 中获取字符串的 ASCII 值