【问题标题】:powershell to report when a server uptime is above threshold当服务器正常运行时间高于阈值时,powershell 报告
【发布时间】:2018-01-29 21:00:56
【问题描述】:

我想创建一个 powershell 脚本来检查域上的所有服务器(Windows 2012 R2),如果服务器正常运行时间超过您在脚本中设置的阈值(这种情况是30天)。但我有一个问题,看起来函数不适用于我的 ForEach 循环。

到目前为止我的代码:

# Variables for sending the report
$sender = "serviceaccount@domain.com"
$receiver = "administrator@domain.no"

# Find all the servers in the domain that need to be checked
Get-ADComputer -filter * -properties operatingsystem | where {$_.operatingsystem -match "server"} | select name | export-csv c:\script\serverlist.csv -NotypeInformation

$computer = import-csv .\serverlist.csv

# Set the Threshold Limit and Deadline
$Threshold = -30
$Deadline = (Get-Date).AddDays($Threshold)

# Function that checks the uptime
function Get-Uptime {
   $os = Get-WmiObject win32_operatingsystem
   $uptime = (Get-Date) - ($os.ConvertToDateTime($os.lastbootuptime))
   $display = "Uptime: " + $Uptime.Days + " days" 
   Write-Output $display
}

# Then run a check on all the servers to see if the uptime is longer than the threshold
ForEach ($computer in $computer) 
    {
    If ($uptime -ge $Deadline) 
      {
      Send-MailMessage -From $sender -To $receiver -Subject "Server $computer need to be rebooted" -Body "Server has been up for more than $Threshold days" -Priority High -dno onSuccess, onFailure -SmtpServer "mailserver.domain.com"
      }
    }

# End of script

【问题讨论】:

  • 现在我没有得到脚本的结果,所以任何关于如何完成这项工作的提示都非常感谢
  • 你不要在循环中执行函数 Get-Uptime .. 所以变量 $uptime = $0 = $false
  • 好吧,我不是程序员,我只是想学习powershell的服务器管理员。那么我应该如何在循环中使用该函数呢?
  • 等我把它写成答案
  • 您的函数将返回一个字符串,因此您不能在与$Deadline 的比较中使用它。此外,它会从本地计算机而不是 $computer 查询上次启动时间,并计算自上次重启以来的天数,而不是返回实际日期。

标签: windows powershell server active-directory windows-server-2012-r2


【解决方案1】:

您忘记在循环中执行函数Get-Uptime,还必须在计算机上远程运行命令。

# Variables for sending the report
$sender = "serviceaccount@domain.com"
$receiver = "administrator@domain.no"

$computers = Get-ADComputer -filter * -properties operatingsystem | where {$_.operatingsystem -match "server"} | select name

# Set the Threshold Limit and Deadline
$Threshold = -30
$Deadline = (Get-Date).AddDays($Threshold)

$Remote_Credentials = Get-Credentials
#Run a check on all the servers to see if the uptime is longer than the threshold
    ForEach ($computer in $computers) 
    {
        #Remotly invoke the Commands to check uptime
        $uptime = (Get-Date) - ((Get-WmiObject win32_operatingsystem).ConvertToDateTime((Get-WmiObject win32_operatingsystem -ComputerName $computer -Credential $Remote_Credentials).lastbootuptime))

        If ($uptime -ge $Deadline) 
        {
          Send-MailMessage -From $sender -To $receiver -Subject "Server $computer need to be rebooted" -Body "Server has been up for more than $Threshold days" -Priority High -dno onSuccess, onFailure -SmtpServer "mailserver.domain.com"a
        }
    }

如果您不想为超过限制的每台计算机发送一封电子邮件,而是只为这些计算机写一封电子邮件,您可以更改最后一部分:

If ($uptime -ge $Deadline) 
            {
              $subject += "Server $computer need to be rebooted" -Body "Server has been up for more than $Threshold days"
            }

并在 Foreach 循环之后发送邮件:

Send-MailMessage -From $sender -To $receiver -Subject $Subject -Priority High -dno onSuccess, onFailure -SmtpServer "mailserver.domain.com"
#Dont forget to reset $subject afterwards: $subject = $0

【讨论】:

  • 你可能不需要使用Invoke-Command; Get-WMIObject(以及现在首选的Get-CIMInstance)采用-ComputerName 参数,如果用户的当前凭据也对指定的计算机有效,它将成功检索类实例。
  • 我尝试按照您的建议更改脚本。但我收到此错误消息:Get-WmiObject:RPC 服务器不可用。 (HRESULT 异常:0x800706BA)
  • @Tomas 您必须在要使用 get-wmi 命令检查的计算机上启用 powershell 远程处理。请确保它已启用,然后重试。
  • @Tomas 好吧,我调查了异常,似乎它不是基于 PS-Remote 的启用,也许看看这个:stackoverflow.com/questions/48516735/… 您可能必须使用 Invoke-Command 而不是 Get- WmiObject.
【解决方案2】:

您的 ForEach 循环结构不正确;您正在尝试将包含您正在迭代的集合的相同变量 ($computer) 用作“索引变量”($computer)。把$computer = Import-CSV ...改成$computers = ...,把ForEach改成ForEach ($Computer in $Computers) ...

此外,正如其他人所指出的(我最初忽略了这一点),您永远不会调用您的 Get-Uptime 函数。由于Get-WMIObject 采用-ComputerName 参数,我将重写它:

function Get-Uptime {
    param (
        [string]$ComputerName = "localhost"
    )
    $os = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem
    $uptime = (Get-Date) - ($os.ConvertToDateTime($os.lastbootuptime))
    return $uptime
}

并在您的 ForEach 循环中调用它:

ForEach ($Computer in $Computers) {
    if ((Get-Uptime -ComputerName $Computer) -ge $Deadline) {
        Send-MailMessage ...
    } #ENDIF
} #END-ForEach

【讨论】:

  • 提问者编写的自定义函数 (Get-Uptime) 从未在 foreach 循环中实际调用,因此此代码将永远不会运行(除了不正确的结构化循环)。
  • @bluuf - 你是对的;我专注于他对他的ForEach 不起作用的抱怨,并忽略了所提供的代码基本上无法用于声明的目的。
猜你喜欢
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多