Я пытаюсь получить информацию о диске для сервера через 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, так как же получить это сгенерированное значение?





Используемое свойство называется 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;
}
}
*Обратите внимание, что значение будет просто целым числом используемых байтов.
Твердый ответ (+1); Get-PSDrive | Select-Object * — более простое (и, предположительно, более быстрое) решение.
Ты только что научил меня чему-то новому @mklement0
Спасибо за разъяснения. Покопавшись в нем, я нашел скрипт, который он пытался запустить, но не знал, как его выполнить. Однако переключение на заметку помогло.