可能有帮助/澄清的 PowerShell 代码

可能有帮助/澄清的 PowerShell 代码

我正在尝试编写一个 PowerShell 脚本来查看特定任务的服务器任务调度程序日志。我想知道是否存在任何错误或任何异常情况。

通常,我会看到事件 ID 、、、、107以及作业成功运行时的情况。我只想知道何时发生其他事情,例如错误、警告等。100129200201102

最后,我想为名为“ ”的任务查找除上述事件 ID 之外的事件 ID Batch001。如果出现任何其他事件 ID,请向我发送电子邮件。

  • 我的电子邮件发送 PowerShell 代码运行良好——如果仅作为部分运行的话。但是我需要弄清楚电子邮件代码的搜索、过滤和触发。

下面的脚本查看特定任务的日志,并将过去 24 小时内相应的全套事件附加到文本文件(一种审计日志)。这部分也正常工作。如果连接服务器时出现问题,那么它应该将一条消息写入错误文本文件并通过 Office 365 将该内容通过电子邮件发送给我。

我无法让此逻辑在发出警告时触发电子邮件。我尝试通过启动批处理作业来模拟失败/错误/警告作业,并在其运行时让计划尝试启动另一个作业,从而对此进行测试。这会导致出现警告,提示无法启动任务,因为有另一个实例正在运行(code 322)。我需要捕获此信息并通过电子邮件发送,但我无法让它工作。

我的 PowerShell 脚本

Start-Transcript -Path "C:\BatchLogs\BatchTranscripts.txt"
$task_name = "Batch001"
$file = "C:\BatchLogs\Batch001.txt"
$file_path = Test-Path $file 
$pc = $_

#If file hasn't been created, create it
If ($file_path -ne $true){
    New-Item C:\BatchLogs\Batch001.txt
}
#Filter xml to pull task scheduler events
 try {
  invoke-command -ComputerName "servername.domain" -ErrorAction Stop -ScriptBlock {
   try {
    $events = @(
     Get-WinEvent  -FilterXml @'
     <QueryList>
      <Query Id="0" Path="Microsoft-Windows-TaskScheduler/Operational">
       <Select Path="Microsoft-Windows-TaskScheduler/Operational">
        *[EventData/Data[@Name='TaskName']='\Batch001'] and *[System[TimeCreated[timediff(@SystemTime) &lt;= 86400000]]]
       </Select>
      </Query>
     </QueryList>
'@  -ErrorAction Stop
   ) 
   } 
   catch {
     Write-Warning -Message "Failed to query $($env:computername) because $($_.Exception.Message)" *> "C:\BatchLogs\errors.txt" 
     Get-Content -Path "C:\BatchLogs\errors.txt" | Add-Content -Path "C:\BatchLogs\Batch001.txt"
     
     [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
     $EmailTo = "[email protected]"
     $EmailFrom = "[email protected]"
     $Subject = "Batch001 Failure"
     $Body = Get-Content -Path "C:\BatchLogs\errors.txt"
     $SMTPServer = "smtp.office365.com"
     $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
     $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
     $SMTPClient.EnableSsl = $true 
     $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "Password123");
     $SMTPClient.Send($SMTPMessage)
   }
   if ($events) {
    $events | Select MachineName,TimeCreated,Id,TaskDisplayName |  Out-File -Append C:\BatchLogs\Batch001.txt 
   }
  } # end of scriptblock
 } catch {
  Write-Warning -Message "Failed to contact $pc because $($_.Exception.Message)" *> "C:\BatchLogs\errors.txt"
  Get-Content -Path "C:\BatchLogs\errors.txt" | Add-Content -Path "C:\BatchLogs\Batch001.txt"
  
  [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
  $EmailTo = "[email protected]"
  $EmailFrom = "[email protected]"
  $Subject = "Batch001 Failure"
  $Body = Get-Content -Path "C:\BatchLogs\errors.txt"
  $SMTPServer = "smtp.office365.com"
  $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
  $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
  $SMTPClient.EnableSsl = $true 
  $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "Password123");
  $SMTPClient.Send($SMTPMessage)
 
 } 

 Stop-Transcript

答案1

可能有帮助/澄清的 PowerShell 代码

首先,你做得非常好将逻辑拼凑在一起,几乎可以得到您所需的一切,干得好。由于您精通 PowerShell,以下逻辑应该可以帮助您 100% 巩固您的首选解决方案。

调整

将非错误/警告事件 ID 数值放入数组中,$notin这些数值不应触发任何电子邮件警告或错误通知。我故意省略了这些数值100,以便可以测试针对该事件 ID 发送电子邮件。

使用命令-ArgumentList的参数Invoke-Command并将$jobName其用作要传递的参数的值(即-ArgumentList $jobName)。

在里面-FilterXml

  • 使用"Microsoft-Windows-TaskScheduler"Path=并省略前面的/Operational值(即<Query Id="0" Path="Microsoft-Windows-TaskScheduler">)。

  • $($args[0])将作为也传入TaskName(即*[EventData/Data[@Name='TaskName']='\$($args[0])'])。

返回脚本块$events内的Invoke-Command(即Return $events)。将Invoke-Command输出设置为$events变量(即$events = Invoke-Command)。

将电子邮件发送逻辑包装在功能只需一次,因此您可以根据需要调用它执行多次,而无需重复相同的代码。

$events将变量数组对象通过管道传输到ForEach-Object循环,但仅输出数组对象中不存在的 ID 号的事件$notin。将这些事件通过管道传输到Format-List并将整个循环保存为$ebody变量。

如果包含数组值$ebody中没有的事件数据事件 ID ,则调用该函数。在函数中,消息变量将被传送到(即),因此必要的数据位于电子邮件正文中。$notinemailemail$body$ebodyOut-String$Body = $ebody | Out-String

电源外壳

$notin = 102, 107, 129, 200, 201;
$jobName = "Batch001";

$events = Invoke-Command -ComputerName "servername.domain" -ScriptBlock {

$events = @(
 Get-WinEvent  -FilterXml @"
 <QueryList>
  <Query Id="0" Path="Microsoft-Windows-TaskScheduler">
   <Select Path="Microsoft-Windows-TaskScheduler/Operational">
    *[EventData/Data[@Name='TaskName']='\$($args[0])'] and *[System[TimeCreated[timediff(@SystemTime) &lt;= 86400000]]]
   </Select>
  </Query>
 </QueryList>
"@  -ErrorAction Stop
);
Return $events;

} -ArgumentList $jobName;

Function email (){
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
    $EmailTo = "[email protected]";
    $EmailFrom = "[email protected]";
    $Subject = "$jobName Failure";
    $Body = $ebody | Out-String;
    $SMTPServer = "smtp.office365.com"
    $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
    $SMTPClient.EnableSsl = $true 
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "Password123");
    $SMTPClient.Send($SMTPMessage)
    };
$ebody = @();
$ebody = $events | % { If ($_.id -notin $notin) {$_ | FL } }

If($ebody){email};

支持资源

答案2

感谢您提供代码帮助...这很棒,我添加了一个 try/catch 来处理前 24 小时内没有发生事件时弹出的错误。

以下是对我有用的最终清理代码:

Start-Transcript -Path "C:\LogPath\TranscriptName.txt"

$jobName = "NameOfTask";
$Date = Get-Date;

$file = "C:\Daily_Batch_Log_Files\$jobName.txt"
$file_path = Test-Path $file 
$pc = $_

#If file hasn't been created, create it
If ($file_path -ne $true){
    New-Item C:\LogPath\$jobName.txt
}


#Filter xml to pull task scheduler events

#Task scheduler common event IDs to ignore (treat as good/success)
$notin = 100, 102, 107, 110, 129, 140, 200, 201;

try {

#Command to connect to remote Server (if needed)
#$events = Invoke-Command -ComputerName "servername.domain" -ScriptBlock {

#Command to execute locally
$events = Invoke-Command  -ScriptBlock {

#Pulls task scheduler, only events with the job (task's) name for events in the last 24 hours
$events = @(
 Get-WinEvent  -FilterXml @"
 <QueryList>
  <Query Id="0" Path="Microsoft-Windows-TaskScheduler">
   <Select Path="Microsoft-Windows-TaskScheduler/Operational">
    *[EventData/Data[@Name='TaskName']='\$($args[0])'] and *[System[TimeCreated[timediff(@SystemTime) &lt;= 86400000]]]
   </Select>
  </Query>
 </QueryList>
"@  -ErrorAction Stop
);
Return $events;

} -ArgumentList $jobName;
}

catch {
    Write-Warning -Message "Failed to query $($env:computername) because $($_.Exception.Message)" *> "C:\LogPath\errors.txt" 
    #If events exist from last 24 hours for this task, append the text (log) file with those events
}

   if ($events) {
    Add-Content C:\LogPath\$jobName.txt "As of $Date :" #-Encoding UTF8
    $events | Select MachineName,TimeCreated,Id,TaskDisplayName |  Out-File -Append C:\LogPath\$jobName.txt #-Encoding UTF8
   }else {
       Add-Content C:\LogPath\$jobName.txt "No files found for last 24 hours as of $Date `r" -Encoding UTF8
   }

#Email function to email us but only email if there are tasks with codes other than the common success ones - only send an email if something is out of the ordinary   
Function email (){
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
    $EmailTo = "[email protected]";
    $EmailFrom = "[email protected]";
    $Subject = "$jobName Failure";
    $Body = $ebody | Out-String;
    $SMTPServer = "smtp.office365.com"
    $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
    $SMTPClient.EnableSsl = $true 
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "Password123");
    $SMTPClient.Send($SMTPMessage)
    };
$ebody = @();
$ebody = $events | % { If ($_.id -notin $notin) {$_ | FL } }

If($ebody){email};

Stop-Transcript

相关内容