Как получить значения ScriptProperty для PSObject.Properties в C#?
Я пытаюсь получить информацию о диске для сервера через 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 ответ
Используемое свойство называется 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;
}
}
* Обратите внимание, что значением будет только целое число байтов.