Powershell工作意外地返回' System.Management.Automation.PSObject' object而不是System.Object

时间:2016-02-10 03:17:57

标签: powershell event-log start-job

我运行一个维护Powershell脚本,该脚本远程检查Windows服务器事件日志中的各种条目,然后采取适当的纠正/警报措施。

该脚本每5分钟运行一次,但由于Get-WinEvent调用在尝试查询无法访问/无响应的服务器时出现RPC不可用错误,因此偶尔会运行太长时间。

为了避免这个问题,我正在处理在Jobs中包装Get-WinEvent调用,以便我可以为它们应用可配置的超时。

对于Get-WinEvent作业查找多个事件,Receive-Job正确返回' System.Object []'包含' System.Diagnostics.Eventing.Reader.EventLogRecord'的数组对象。如果只找到一个事件,则Receive-Job返回一个&System; Management.Management.Automation.PSObject'而不是对象。

如果没有与Job相关的代码,发现一个事件的Get-WinEvent调用将返回一个非数组的System.Diagnostics.Eventing.Reader.EventLogRecord'可以很容易地用数组包装以供下游消费的对象。

任何人都有更好的方法来为远程Get-WinEvent调用添加超时或者为System.Management.Automation.PSObject'添加解释/修复。被返回而不是非数组&System; .Diagnostics.Eventing.Reader.EventLogRecord'对象

函数和一些示例调用如下所示:

Function CollectRemoteEvents($the_server,$event_log,$events_to_find,$event_label,$search_start,$search_timeout,$max_event_count){
    Try{
        $job_info = Start-Job -name GetEvents -scriptblock {param($server,$logname,$eventID,$StartTime,$MaxEvents) Get-WinEvent -ComputerName $server -FilterHashtable @{"logname"=$logname;"id"=$eventID;StartTime=$StartTime} -MaxEvents $MaxEvents} -Arg $the_server,$event_log,$events_to_find,$search_start,$max_event_count

        #if the provided timeout value is greater than 0, use it
        if($search_timeout -gt 0){
            #if the job takes a while, tell it to timeout after ## seconds
            $wait_result = Wait-Job -id $job_info.id -timeout $search_timeout
        }Else{
            #if the timeout was specified as 0, let the job run to completion
            $wait_result = Wait-Job -id $job_info.id
        }

        $current_job_state = Get-Job -id ($job_info.id)

        #check if the job has completed before time runs out
        if($current_job_state.State -eq "Completed"){
            #capture the job object
            $job = Get-Job -id ($job_info.id)

            #retrieve the output of the job; if the job raises errors, exceptions will be populated into the $joberror variable
            #NOTE: the $ is *intentionally* left out of the 'joberror' variable name in the command below
            $job_result = $job | Receive-Job -ErrorVariable joberror -ErrorAction Stop
            If($joberror -ne "" -And $joberror -ne $null){
                #if joberror is not empty, the job failed; log it
#               write-host "JobError: '$joberror'"  #used for debugging, this would log to file in a production capacity
            }Else{
#               write-host $job_result.gettype()    #used for debugging
                return ,$job_result
            }
        }else{
            #the search timed out
#           write-host "The event log search timed out." #used for debugging, this would log to file in a production capacity
            return $null
        }
    }Catch [Exception]{
        If($_.FullyQualifiedErrorID -eq "NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand"){
            #No logon timeout events were registered since $search_start
            write-host "$the_server : No $event_label events were found."
            return @()
        }Elseif($_.FullyQualifiedErrorID -eq "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWinEventCommand"){
            #"argument validation error", exit the function with a return value indicating failure
            write-host "$the_server : Event log retrieval failed, can't check for $event_label events (Argument validation error);"
            return $null
        }Elseif($_.FullyQualifiedErrorID -eq "System.Diagnostics.Eventing.Reader.EventLogException,Microsoft.PowerShell.Commands.GetWinEventCommand"){
            #"the RPC server is unavailable", exit the function with a return value indicating failure
            write-host "$the_server : Event log retrieval failed, can't check for $event_label events (RPC server unavailable);"
            return $null
        }Else{
            #if the server logs cannot be retrieved, exit the function with a return value indicating failure
            write-host "$the_server : Event log retrieval failed, can't check for $event_label events (Check access/permissions)($($_.FullyQualifiedErrorID));"
            return $null
        }
    }
}

$server_name = "localhost"
$system_event_ID = @(6013)
$app_event_ID = @(1033)
$timeout_check_timespan = (Get-Date).AddMonths(-2)
$WinEvent_timeout = 10  #how long to let the Job run before timing out

$returns_array = CollectRemoteEvents $server_name 'System' $system_event_ID "Label One" $timeout_check_timespan $WinEvent_timeout 5
$returns_non_array = CollectRemoteEvents $server_name 'Application' $app_event_ID "Label Two" $timeout_check_timespan $WinEvent_timeout 1

write-host ""
write-host $returns_array
write-host $returns_array.count
write-host ""
write-host $returns_non_array
write-host $returns_non_array.count

主回程行上的逗号试图强制返回一个数组(参见:Count property of array in PowerShell with pscustomobjects

我也尝试过实例化一个数组,然后将结果集添加到它:

$var = @()
$var += $results
return $var

将结果集转换为数组:

return [Array]($results)

并将结果集作为数组的一部分返回:

return @($results)

我认为这与Powershell'函数返回值中涵盖的问题不同。提出的解决方案 - 在我的问题中,在函数返回之前存在对象类型的问题。

取消注释以下行以进行调试

#               write-host $job_result.gettype()    #used for debugging

打印以下输出结果:

  

System.Object的[]

     

System.Management.Automation.PSObject

运行Get-WinEvent查询的Job返回System.Object []行,该查询找到多个事件。

System.Management.Automation.PSObject'运行Get-WinEvent查询的作业返回行,该查询找到单个事件

1 个答案:

答案 0 :(得分:0)

根据Reddit用户的建议进行了大量的Google搜索后,您似乎有效地必须对单个对象的返回内容进行双重包装以使其最终成为数组:

#this *does not* work
return @(@($job_result))

#This works
return , @($job_result)