问题
I am trying to get drive information for a server through PowerShell 6.0 using the 'GET-PSDrive' command. Running the command directly in PowerShell, I see the values for 'Used' and 'Free' within the output table, but running the same command in code though using the Microsoft.Powershell.Sdk the 'Used' and 'Free' fields are not available.
I see both items listed under the PSObject.Properties array, but trying to access the value I receive the exception:
"There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: ##"
The following is the POC code that I am working with:
using (var psCon = PowerShell.Create())
{
psCon.AddCommand("GET-PSDrive");
var psReturn = psCon.Invoke();
foreach (var psObj in psReturn)
{
var driveUsedValue = psObj.Properties["Used"].Value;
}
}
I am expecting to get the value of that property, but each time the value is evaluated I get an error saying that no runspace is available. Inspecting the property I do see that its a ScriptProperty, so how do you go about getting that generated value?
回答1:
The property Used is a called a ScriptProperty. It means when it is called it runs a script. We can see this by calling :
get-PSDrive | get-member -Name Used
This returns
Name MemberType Definition
---- ---------- ----------
Used ScriptProperty System.Object Used {get=## Ensure that this is a FileSystem drive...
We can dig deeper and see the script that is running also
get-PSDrive | get-member -Name Used | select -ExpandProperty Definition
This will 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
};
}
This is why you get the exception There is no Runspace available to run scripts in this thread
. It is because that info runs a script which needs a runspace.
to work around this you can turn all the properties into note properties like this
Get-PSDrive | %{
$drive = $_
$obj = new-object psobject
$_.psobject.Properties.GetEnumerator() | %{
$obj | Add-Member -MemberType NoteProperty -name $_.Name -Value $drive."$($_.name)"
}
$obj
}
OR as @mklement0 pointed out in the comments
Get-PSDrive | Select-Object *
Which is much better solution.
It will return an array of PSobjects with the values as notes instead of script
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;
}
}
*Note the value will just the integer of bytes used.
来源:https://stackoverflow.com/questions/55776105/how-to-get-scriptproperty-values-of-psobject-properties-in-c