我运行一个维护 Powershell 脚本,它远程检查 Windows 服务器事件日志中的各种条目,然后采取适当的纠正/警报措施。
该脚本每 5 分钟运行一次,但由于在尝试查询无法访问/无响应的服务器时 Get-WinEvent 调用超时并出现 RPC 不可用错误,该脚本有时会运行太长时间。
为了避免这个问题,我正在努力将 Get-WinEvent 调用包装在 Jobs 中,以便我可以对它们应用可配置的超时。
对于查找多个事件的 Get-WinEvent 作业,Receive-Job 正确返回包含“System.Diagnostics.Eventing.Reader.EventLogRecord”对象的“System.Object[]”数组。如果只找到一个事件,则 Receive-Job 会改为返回“System.Management.Automation.PSObject”对象。
如果没有与作业相关的代码,查找一个事件的 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
主返回行上的逗号试图强制返回一个数组(请参阅:PowerShell 中数组的计数属性与 pscustomobjects)
我也尝试过实例化一个数组,然后将结果集添加到其中:
$var = @()
$var += $results
return $var
将结果集转换为数组:
return [Array]($results)
并将结果集作为数组的一部分返回:
return @($results)
我认为这与“Powershell 中的函数返回值”提出的解决方案中所涵盖的问题不同——在我的问题中,对象类型的问题在函数返回之前就存在了。
出于调试目的取消注释以下行
# write-host $job_result.gettype() #used for debugging
结果打印以下输出:
系统对象[]
System.Management.Automation.PSObject
System.Object[] 行由运行 Get-WinEvent 查询以查找多个事件的作业返回。
“System.Management.Automation.PSObject”行由运行 Get-WinEvent 查询的作业返回,该查询找到单个事件