我正试图将计算属性的哈希表传递到查询中,以便与Select-Object
一起使用。它在控制台中运行时有效。我可以确认,该作业正在读取哈希表,因为它在结果中列出了选定的属性,但它们的所有值都为null。
注意:我知道我不需要对这些属性进行类型转换。我只是在展示我的问题。
如果我运行以下代码(这看起来很奇怪,但实际上有一个用例(,输出包含我选择的属性(来自$globalConfig.SystemState.Processors.SelectProperties
(,但计算的属性的值为null
,唯一返回正确值的属性是name
:
$globalConfig = @{
PingAddress = '8.8.8.8';
SystemState = @{
Processors = @{
Namespace = 'rootcimv2';
ClassName = 'Win32_Processor';
SelectProperties = 'name', @{ n = 'CpuStatus'; e = { [int]$_.CpuStatus }}, @{ n = 'CurrentVoltage'; e = { [int]$_.CurrentVoltage }};
}
}
}
$job = Start-Job -Name Processors -ArgumentList $globalConfig.SystemState.Processors -ScriptBlock {
Try{
$Response = @{
State = @();
Error = $Null
}
$Response.State = Get-CimInstance -ClassName $Args[0].ClassName | Select-Object $Args[0].SelectProperties -ErrorAction Stop
}Catch{
$Response.Error = @{Id = 2; Message = "$($Args[0].Target) query failed: $($_.Exception.Message)"}
}
Return $Response
}
$job | Wait-Job
$job | Receive-Job | ConvertTo-Json -Depth 3
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
119 Processors BackgroundJob Completed True localhost ...
{
"Error": null,
"State": {
"name": "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",
"CpuStatus": null,
"CurrentVoltage": null
}
}
然而,如果我运行相同的作业,但具有相同的硬编码计算属性(不是使用PSObject传递给Select Object(,它会按预期工作(输出中返回值1
和12
(:
$job = Start-Job -Name Processors -ArgumentList $globalConfig.SystemState.Processors -ScriptBlock {
Try{
$Response = @{
State = @();
Error = $Null
}
$Response.State = Get-CimInstance -ClassName $Args[0].ClassName | Select-Object Name, @{ n = 'CpuStatus'; e = { [int]$_.CpuStatus }},@{ n = 'CurrentVoltage'; e = { [int]$_.CurrentVoltage }}
}Catch{
$Response.Error = @{Id = 2; Message = "$($Args[0].Target) query failed: $($_.Exception.Message)"}
}
Return $Response
}
$job | Wait-Job
$job | Receive-Job | ConvertTo-Json -Depth 3
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
121 Processors BackgroundJob Completed True localhost ...
{
"Error": null,
"State": {
"Name": "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",
"CpuStatus": 1,
"CurrentVoltage": 12
}
}
在作业内部时,如何将具有计算属性的对象内联传递给Select-Object
?
它是一个哈希表,而不是psobject。看起来你无法将脚本块传递到作业中。它们变成了琴弦。
$globalConfig = @{
PingAddress = '8.8.8.8'
SystemState = @{
Processors = @{
Namespace = 'rootcimv2'
ClassName = 'Win32_Processor'
SelectProperties = 'name',
@{ n = 'CpuStatus'; e = { [int]$_.CpuStatus }},
@{ n = 'CurrentVoltage'; e = { [int]$_.CurrentVoltage }}
}
}
}
start-job -args $globalconfig.systemstate.processors {
$list = $args[0].selectproperties
$list[1].e.gettype()
$list[2].e.gettype()
} | receive-job -wait -auto
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
True True String System.Object
它适用于线程作业。线程obs不序列化它们的对象。在ps 5中,您可以从powershell库下载它。https://www.powershellgallery.com/packages/ThreadJob在ps 6&7,它自带。它不会产生新的过程,而且速度更快。(它没有"-args"别名。(
start-threadjob -argumentlist $globalconfig.systemstate.processors {
$list = $args[0].selectproperties
$list[1].e.gettype()
$list[2].e.gettype()
} | receive-job -wait -auto
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ScriptBlock System.Object
True True ScriptBlock System.Object
或者使用静态方法[scriptblock]::create((,如下所示:如何将scriptblock作为启动作业中的参数之一传递
如果没有@js2010为我指明正确的方向,我就不会找到答案,谢谢!
他/她是正确的-出于安全原因,您不能将脚本块传递给作业,但与PowerShell一样,有一个变通方法。
我可以通过从Start-Job
切换到Invoke-Command -asjob
来实现这一点,但这需要运行和配置WinRM,这在生产中不是一个选项。
$globalConfig = @{
PingAddress = '8.8.8.8';
SystemState = @{
Processors = @{
Namespace = 'rootcimv2';
ClassName = 'Win32_Processor';
SelectProperties = 'Name', @{ n = 'CpuStatus'; e = { [int]$_.CpuStatus }};
}
}
}
$ScriptBlock = {
param(
[Parameter(Mandatory=$True, Position=1)]
[hashtable]$hashtable
)
Try{
$Response = @{
State = @();
Error = $Null
}
$Response.State = Get-CimInstance -ClassName $hashtable.ClassName | Select-Object -Property $hashtable.SelectProperties -ErrorAction Stop
}Catch{
$Response.Error = @{Id = 2; Message = "$($data.Target) query failed: $($_.Exception.Message)"}
}
Return $Response
}
Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $globalConfig.SystemState.Processors -ComputerName . -AsJob
Name Value
---- -----
Error
State @{Name=Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz; CpuStatus=1}
这一定是可能的。。。所以我将继续测试解决方案,并将在这里发布我发现的任何内容。
更新
我有这个工作,它有点脏,但它符合项目的需要。我只需使用作业外部的哈希表(作为字符串(构建命令,将命令字符串作为参数传递给作业,然后使用Invoke-Expression
:在作业内部运行命令
$globalConfig = @{
PingAddress = '8.8.8.8';
SystemState = @{
Processors = @{
Target = 'Processors'
Namespace = 'rootcimv2';
ClassName = 'Win32_Processor';
SelectProperties = [string]('"Name", @{ n = "CpuStatus"; e = { [int]$_.CpuStatus }}');
}
}
}
$Args = [PSCustomObject]@{
Target = $globalConfig.SystemState.Processors.Target;
Command = "Get-CimInstance -ClassName $($globalConfig.SystemState.Processors.ClassName) -ErrorAction Stop | Select-Object $($globalConfig.SystemState.Processors.SelectProperties) -ErrorAction Stop";
}
$job = Start-Job -Name Processors -ArgumentList $Args -ScriptBlock {
Try{
$Response = @{
State = @();
Error = $Null
}
$Response.State = Invoke-Expression -Command $args.Command
}Catch{
$Response.Error = @{Id = 2; Message = "$($Args.Target) query failed: $($_.Exception.Message)"}
}
Return $Response
}
$job | Wait-Job
$job | Receive-Job | ConvertTo-Json -Depth 3
{
"Error": null,
"State": {
"Name": "Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz",
"CpuStatus": 1
},
"PSComputerName": "localhost",
"RunspaceId": "89f17de1-98b6-4746-a0ba-3e7c47294c61",
"PSShowComputerName": false
}