当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 运行空间、远程处理和工作流程,天哪!

作者:精品下载站 日期:2024-12-14 07:40:03 浏览:13 分类:玩电脑

运行空间、远程处理和工作流程,天哪!


[玩转系统] 运行空间、远程处理和工作流程,天哪!

当我看到这样的脚本时,我担心的是,刚接触 PowerShell 的人会看到它并跑到山上,认为他们永远无法使用 PowerShell,但事实绝对不是这样。因此,我决定看看我能想出什么,使用更 IT 专业人士友好的基于 cmdlet 的方法。我想写一些你们大多数人都能想到的东西。

我的第一次尝试是使用 Invoke-Command 在远程会话中运行 Get-Eventlog cmdlet 的函数。在函数中,我定义了一个脚本块,用于获取所有带有记录的事件日志,然后从昨天午夜以来发生的这些日志中获取所有非信息或 SuccessAudit 事件。我的函数支持凭据并利用 Invoke-Command 的一些其他功能。

Function Get-RecentEventLog {

[CmdletBinding()]
[OutputType([System.Diagnostics.EventLogEntry])]

Param(
[Parameter(Position=0,HelpMessage="Enter the name of a computer")]
[ValidateNotNullorEmpty()]
[Alias("cn","pscomputername","name")]
[string[]]$Computername=$env:COMPUTERNAME,
[ValidateScript({$_ -ge 1})]
[int]$Days=1,
[Alias("RunAs")]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
[ValidateScript({$_ -ge 1})]
[int]$ThrottleLimit=32,
[switch]$Asjob,
[string]$JobName
)

Begin {
    Write-Verbose -Message "Starting $($MyInvocation.Mycommand)"     
} #begin

Process {

#define a scriptblock to search event logs that will run remotely via Invoke-Command
$sb = {

$logs = Get-Eventlog -List | where {$_.entries.count -gt 0}

if ($logs) {   
    #construct a filter hashtable    
    $filterParams= @{
        Logname= $Null
        After= (Get-Date).AddDays(-$using:Days).Date
        EntryType= "error","warning","failureaudit"
        ErrorAction="stop"
     }

    foreach ($log in $logs) {
        $filterParams.Logname = $log.log
        #add the log name to each entry
        Write-Verbose "Processing $($log.log) on $env:computername"
        Try {
        Get-Eventlog @filterParams | 
        Add-Member -MemberType NoteProperty -Name Logname -value $log -PassThru
        }
        Catch {
            #ignore errors because they are probably for no matching records
        }
    } #foreach log

} #if $logs

} #close scriptblock

    #create a hashtable of parameters for Invoke-Command
    #use the bound parameters as a starting point
    $icmParam=$PSBoundParameters

    if ($icmParam.ContainsKey("Days")) {
      #remove Days since it isn't used by Invoke-Command
       $icmParam.Remove("Days")
    }
    #add the other parameters
    $icmParam.Add("Scriptblock",$sb)
    $icmParam.Add("ErrorAction","Stop")
    $icmParam.Add("ErrorVariable","myErr")

     Try {
        Write-Verbose "Initiating Invoke-Command"
        Write-Verbose "Getting event logs from the past $days day(s)"
        Invoke-Command @icmParam
     }
     Catch {
        Write-Warning "Failed to run Invoke-Command"
        Write-Warning $myErr.ErrorRecord
     }
    
} #process

End {
    Write-Verbose -Message "Ending $($MyInvocation.Mycommand)"
} #end


} #close function Get-RecentEventLog

该函数运行正常,在我的虚拟测试环境中查询 8 台机器花费了大约 1 1/2 分钟。使用 Invoke-Command 时肯定会产生一些开销,但代价是脚本更容易开发和维护。

然后我想,工作流程怎么样?我正在查询事件日志,但我没有理由不能同时查询所有事件日志。这是我的工作流程,其功能与我的功能基本相同。

WorkFlow Get-RecentEventLog {

Param(
[int]$Days=1
)

Write-Verbose -Message "$(Get-Date) Starting $workflowcommandname"

#get event logs that have values
$logs = Get-Eventlog -List | Where-Object -filter {$_.entries.count -gt 0}

#search each log in parallel
foreach -parallel ($log in $logs) {
  Write-Verbose -message "Processing $($log.log)"
  Sequence {
   $After= InlineScript { (Get-Date).AddDays(-$using:Days).Date}
   $EntryType= "error","warning","failureaudit"  
   Try {
    Get-Eventlog -LogName $log.log -After $After -EntryType $EntryType -ErrorAction Stop |
    Add-Member -MemberType NoteProperty -Name Logname -value $log -PassThru
   }
   Catch {
    Write-Verbose -Message "No matching entries found in $($log.log)"
   }
  } #sequence
} #foreach parallel

Write-Verbose -Message "$(Get-Date) Ending $workflowcommandname"

}

有趣的是,在我的测试中,工作流程的运行时间大约相同。但这是一个较短的开发脚本,因为远程处理、凭据和作业等所有功能都会自动成为工作流程的一部分。一个潜在的缺点是所有远程计算机都必须运行 PowerShell 3.0。这个工作流程也是一个很好的例子,因为工作流程并不总是答案。除了可能使用并行性之外,实际上没有什么可以使它成为比我的函数更好的选择。

我对画廊脚本的最后一个担忧是,所有事件日志都汇总在每台计算机的属性中,我不知道这是否会对其性能产生影响。这意味着您必须采取一些进一步的步骤来扩展和格式化结果。我的功能和工作流程,因为它们依赖于 Get-Eventlog,已格式化并准备就绪。

我还没有尝试过如何使用 Get-WinEvent 或 Get-CimInstance 来完成同样的任务。后者有助于避免 WMI 的一些问题并且可能性能更好。如果我有时间,我会告诉你我的结果。但与此同时,您对这一切有何看法?

在 PowerShell 中使用运行空间有一席之地,但绝对需要高级技能,并且愿意接受更复杂的脚本来开发和维护(特别是如果其他人必须这样做的话)以提高性能。我可以看出,当您拥有数千台计算机时,使用运行空间方法是有意义的。但我也可能会说,如果这就是您的环境,您可能拥有成熟的管理套件。是的,我知道总会有例外。但对于大多数人来说,您是否乐意编写使用现有 cmdlet 的脚本,或者您是否觉得有必要在使用 PowerShell 之前学习 .NET?

更新:
我使用 Get-CIMInstance 尝试过此操作。是的,这需要远程使用 PowerShell 3(除非您采取额外的步骤来设置 DCOM CIM 会话)并使用 WSMan 协议,但这执行得非常好,并且只需要几行 PowerShell。

#convert date time to WMI format
$after = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime((Get-Date).AddDays(-1).date)

#get all non information and success entries
$filter = "TimeGenerated >= ""$after"" AND (Type <> 'Information' AND type <> 'Audit Success')"

$computers = "chi-dc01","chi-dc04","chi-hvr2","chi-core01","chi-win81","chi-fp02"
Get-CimInstance win32_ntlogevent -filter $filter -ComputerName $computers

我在测试环境中运行此命令,大约需要 30 秒才能返回 188 个事件日志条目。因为我们使用 WSMAN,所以我们避免了 RPC 和 DCOM 的一些问题。因此,这里有一个解决方案,至少在这种情况下,它与使用运行空间一样快,但只需几分钟即可编写,并且易于遵循。

作为 IT 专业人员,我们所做的一切都是平衡权衡并在一系列限制内工作的问题。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯