Как получить значения ScriptProperty для PSObject.Properties в C #? - PullRequest
4 голосов
/ 20 апреля 2019

Я пытаюсь получить информацию о диске для сервера через PowerShell 6.0 с помощью команды «GET-PSDrive».Запустив команду непосредственно в PowerShell, я вижу значения «Используется» и «Свободно» в выходной таблице, но выполняю ту же команду в коде, хотя с использованием Microsoft.Powershell.Sdk поля «Используется» и «Бесплатно» не являютсядоступно.

Я вижу оба элемента, перечисленные в массиве PSObject.Properties, но при попытке доступа к значению я получаю исключение:

"Нет пространства для выполнения, доступного для запуска сценариев в этом потоке.Вы можете указать его в свойстве DefaultRunspace типа System.Management.Automation.Runspaces.Runspace. Блок сценария, который вы пытались вызвать, был: ## "

Ниже приведен код 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 Ответ

5 голосов
/ 20 апреля 2019

Используемое свойство называется 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

Это будет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
    };
}

Вот почему вы получаете исключение 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;
    }
}

* Обратите внимание назначением будет только целое число используемых байтов.

...