1

我正在尝试将计算属性的哈希表传递给查询,以便与Select-Object. 它在控制台中运行时有效。我可以确认该作业正在读取哈希表,因为它在结果中列出了选定的属性,但它们的所有值都是空的。

注意:我知道我不需要对这些属性进行类型转换。我只是展示我的问题。

如果我运行以下代码(看起来很奇怪,但实际上有一个用例),输出包含我选择的属性(来自$globalConfig.SystemState.Processors.SelectProperties)但计算的属性的值为null,唯一返回正确值的属性是name

$globalConfig = @{
    PingAddress = '8.8.8.8';
    SystemState = @{
        Processors = @{
            Namespace = 'root\cimv2';
            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),它会按预期工作(值112在输出中返回):

$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工作中将计算属性的对象内联传递给?

4

2 回答 2

1

它是一个哈希表,而不是一个 psobject。看起来您无法将脚本块传递给作业。它们变成了字符串。

$globalConfig = @{
  PingAddress = '8.8.8.8'
  SystemState = @{
    Processors = @{
      Namespace = 'root\cimv2'
      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

它适用于线程作业。线程作业不会序列化它们的对象。在 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() 如下所示: 如何将脚本块作为参数之一传递给 start-job

于 2020-03-21T04:00:19.193 回答
0

如果没有@js2010 为我指出正确的方向,我将找不到我的答案,谢谢!

他/她是正确的 - 出于安全原因,您不能将脚本块传递给作业,但与 PowerShell 一样,有一种解决方法。

我可以通过从 切换到Start-Job来使其工作Invoke-Command -asjob,但这需要运行和配置 WinRM,这在生产中不是一个选项。

$globalConfig = @{
    PingAddress = '8.8.8.8';
    SystemState = @{
        Processors = @{
            Namespace = 'root\cimv2';
            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 = 'root\cimv2';
            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
}
于 2020-03-21T11:52:32.093 回答