您好,脚本专家 ! 备份您的 Windows PowerShell 脚本的事件日志

The Microsoft Scripting Guys

热! 首先 Jason 和注意到我们时停留在机场中吉隆坡,马来西亚 sweltering 粘滞、 呼吸记录潮湿热。 我们已到达该路缘之前,必须我们袋树干和我们的门打开一个友好的 CAB 驱动程序。 掌上 tree–lined 道路的引导到吉隆坡城市中心 (KLCC) 通过 brisk 旅行。 只要我们输入了该高速公路,我们可以看到 glistening 英里出每个方向从标记 KLCC 在 Patronus 塔的顶部。 我们城镇的 Microsoft 员工组教 Microsoft 操作框架 (MOF) 类。

MOF 类的突出显示的机场模拟的绝对没有一个不断获得右侧第一次尝试。 但这是类的点的一部分 — 处理改进。 我们必须让类知道超过 20 个时间,没有人过上的成功第一天。 某些类仅它通过进行模拟的类的最后一天。 直到现在。

末尾的第一天是模拟的圆形之一的时间。 Jason 和交换知道 glances,为我们提供指示。 学生坐 rapt 关注,然后时钟启动 ticking,而不是在通常喧闹运行周围中编码的混淆学生安静地获得一起到一个小 huddle。 它们介绍了快速为大约 5 分钟一个学生他的便携式计算机上打开并开始进行说明。 然后它们 calmly 周围打开并赢得该游戏在第一轮中的继续。

如何在做它? 它们只被定向所有方案的重要元素其关注。 它们将忽略所有不必要的信息,并创建新的进程,解决了问题。 由于它们专注于核心问题,它们是免费的任何复杂的工作的规则,并且它们是能够将其精力关注手头的任务。

过于复杂的工作的规则可以影响工作效率。 今天的脚本增长出情况下一个客户的面对它们已在其中花费几个小时备份事件日志,从各种网络服务器,并将它们复制到一个中央存储位置,它们是更高版本的一天备份到磁带。 我们收到过它们复杂的工作的规则后,我们能够创建自定义脚本的完全什么需要它们。 此脚本保存在他们以前已花费管理事件日志的人工客户每周和每年的 500 小时的 10 小时。

当我们从复杂的工作的规则的超时时间时,我们可以集中更多的关注和提供 IT 服务的能源手头,在任务上。 让我们看一看一个脚本,可用于备份、 存档,和清除在网络上的事件日志。 整个 BackUpAndClearEventLogs.ps1 脚本如 图 1 所示。

图 1 BackUpAndClearEventLogs.ps1

Param(
       $LogsArchive = "c:\logarchive", 
       $List,
       $computers,
       [switch]$AD, 
       [switch]$Localhost,
       [switch]$clear,
       [switch]$Help
     )
Function Get-ADComputers
{
 $ds = New-Object DirectoryServices.DirectorySearcher
 $ds.Filter = "ObjectCategory=Computer"
 $ds.FindAll() | 
     ForEach-Object { $_.Properties['dnshostname']}
} #end Get-AdComputers

Function Test-ComputerConnection
{
 ForEach($Computer in $Computers)
 {
  $Result = Get-WmiObject -Class win32_pingstatus -Filter "address='$computer'"
  If($Result.Statuscode -eq 0)
   {
     if($computer.length -ge 1) 
        { 
         Write-Host "+ Processing $Computer"
         Get-BackUpFolder 
        }
   } #end if
   else { "Skipping $computer .. not accessible" }
 } #end Foreach
} #end Test-ComputerConnection



Function Get-BackUpFolder
{
 $Folder = "{1}-Logs-{0:MMddyymm}" -f [DateTime]::now,$computer
  New-Item "$LogsArchive\$folder" -type Directory -force  | out-Null
  If(!(Test-Path "\\$computer\c$\LogFolder\$folder"))
    {
      New-Item "\\$computer\c$\LogFolder\$folder" -type Directory -force | out-Null
    } #end if
 Backup-EventLogs($Folder)
} #end Get-BackUpFolder

Function Backup-EventLogs
{
 $Eventlogs = Get-WmiObject -Class Win32_NTEventLogFile -ComputerName $computer
 Foreach($log in $EventLogs)
        {
            $path = "\\{0}\c$\LogFolder\$folder\{1}.evt" -f $Computer,$log.LogFileName
            $ErrBackup = ($log.BackupEventLog($path)).ReturnValue
            if($clear)
               {
                if($ErrBackup -eq 0)
                  {
                   $errClear = ($log.ClearEventLog()).ReturnValue
                  } #end if
                else
                  { 
                    "Unable to clear event log because backup failed" 
                    "Backup Error was " + $ErrBackup
                  } #end else
               } #end if clear
            Copy-EventLogsToArchive -path $path -Folder $Folder
        } #end foreach log
} #end Backup-EventLogs

Function Copy-EventLogsToArchive($path, $folder)
{
 Copy-Item -path $path -dest "$LogsArchive\$folder" -force
} # end Copy-EventLogsToArchive

Function Get-HelpText
{
 $helpText= `
@"
 DESCRIPTION:
 NAME: BackUpAndClearEventLogs.ps1
 This script will backup, archive, and clear the event logs on 
 both local and remote computers. It will accept a computer name,
 query AD, or read a text file for the list of computers. 

 PARAMETERS: 
 -LogsArchive local or remote collection of all computers event logs
 -List path to a list of computer names to process
 -Computers one or more computer names typed in
 -AD switch that causes script to query AD for all computer accounts
 -Localhost switch that runs script against local computer only
 -Clear switch that causes script to empty the event log if the back succeeds
 -Help displays this help topic

 SYNTAX:
 BackUpAndClearEventLogs.ps1 -LocalHost 

 Backs up all event logs on local computer. Archives them to C:\logarchive.

 BackUpAndClearEventLogs.ps1 -AD -Clear

 Searches AD for all computers. Connects to these computers, and backs up all event 
 logs. Archives all event logs to C:\logarchive. It then clears all event logs 
 if the backup operation was successful. 

 BackUpAndClearEventLogs.ps1 -List C:\fso\ListOfComputers.txt

 Reads the ListOfComputers.txt file to obtain a list of computer. Connects to these 
 computers, and backs up all event logs. Archives all event logs to C:\logarchive. 

 BackUpAndClearEventLogs.ps1 -Computers "Berlin,Vista" -LogsArchive "\\berlin\C$\fso\Logs"

 Connects to a remote computers named Berlin and Vista, and backs up    all event 
 logs. Archives all event logs from all computers to the path c:\fso\Logs directory on 
   a remote computer named Berlin. 

BackUpAndClearEventLogs.ps1 -help

Prints the help topic for the script
"@ #end helpText
  $helpText
}

# *** Entry Point To Script ***

If($AD) { $Computers = Get-ADComputers; Test-ComputerConnection; exit }
If($List) { $Computers = Get-Content -path $list; Test-ComputerConnection; exit }
If($LocalHost) { $computers = $env:computerName; Test-ComputerConnection; exit }
If($Computers) 
  { 
   if($Computers.Contains(",")) {$Computers = $Computers.Split(",")} 
   Test-ComputerConnection; exit 
  }
If($help) { Get-HelpText; exit }
"Missing parameters" ; Get-HelpText

首先我们做脚本是在 BackUpAndClearEventLogs.ps1 中使用参数语句来创建在的脚本的一些命令行参数如下所示:

Param(
       $LogsArchive = "c:\logarchive", 
       $List,
       $Computers,
       [switch]$AD, 
       [switch]$Localhost,
       [switch]$Clear,
       [switch]$Help
     )

为了给更大的灵活性,脚本很多,我们使用几个参数。 -LogsArchive 参数用来定义事件日志存档的位置。 我们将设置此为默认位置 C: \ 椹卞姩鍣 ㄤ 笂但使用 LogsArchive,您可以选择适合您的计算环境的任何位置。

的列表参数使您可以提供的脚本通过鏂囨湰鏂囦欢计算机列表。 此参数需要一个包含计算机名称的文本文件,完整路径。 文本文件的语法很简单 ; 您只需放置您要使用其自己单独的行上的每个计算机的名称。

参数允许您提供的计算机从命令行的列表,当您运行脚本时的计算机。 若要将此参数您放置在引号计算机名称由逗号分隔的一组内。 理想情况下,则应该使用此参数,如果您想检查只需少量的计算机。

下一步是四个交换的参数。 在酷之一是交换的参数调用 –AD,使您可以查询 Active Directory 的计算机列表。 最好使用此开关,如果您要检查大量的网络上所有计算机上的事件日志。 当然,在大型网络上这可能需要很长时间。 如果您想要对您的本地计算机运行该脚本,使用-Localhost 开关,它指示要对本地计算机执行该脚本。 besides 备份事件日志,并且存档到一个中心位置的这些,可以也为空的使用,-清除事件日志内容切换参数。 获取帮助信息,运行该脚本使用-帮助。 我们现在转至第一个函数在我们的脚本。 获取的 ADComputers 函数是查询用于检索的所有计算机帐户在 Active Directory 中的列表。 此函数不需要任何输入的参数。 当调用该函数时,将使用新建对象-cmdlet 从 Microsoft.NET 框架创建 DirectoryServices.DirectorySearcher 类的一个实例。 我们不传递任何信息要在新建的对象 cmdlet 以便使用默认构造函数创建 DirectoryServices.DirectorySearcher 类。 新 DirectorySearcher 类存储在 $ ds 变量,如下所示:

Function Get-ADComputers
{
$ds = New-Object DirectoryServices.DirectorySearcher

我们 DirectorySearcher 类的一个实例后,我们可以使用 Filter 属性创建搜索筛选器以减少检索到的项目数。 LDAP 搜索筛选器记录在" 搜索筛选器语法." 我们想要的属性中称为 ObjectCategory,我们在寻找值为"计算机"。 我们创建我们的筛选器之后,我们使用 FindAll 方法从 DirectorySearcher 对象:

 $ds.Filter = "ObjectCategory=Computer"
$ds.FindAll() | 

从 FindAll 方法结果的管道到 ForEach-对象 cmdlet 用于循环访问跺 FindAll 返回的对象的集合。 由大括号中,标记,在脚本块内我们使用自动 $ _ 变量来引用在管道上当前项。 我们访问跺对象的属性,并返回该 dnshostname:

     ForEach-Object {$_.Properties['dnshostname']}
} #end Get-ADComputers

现在,我们将创建以确保计算机在网络上并运行测试的 ComputerConnection 函数。 这将防止超时问题,并使脚本更有效。 然后,我们开始使用该函数关键字指定函数的名称和打开脚本块:

Function Test-ComputerConnection
{

下一步,我们需要遍历集合存储在 $ 计算机变量,我们将执行中的计算机的枚举数为 $ 计算机变量使用 ForEach 语句。 然后,我们打开脚本块使用一个左大括号:

 ForEach($Computer in $Computers)
{

我们需要使用 WMI 类 Win32_PingStatus ping 远程计算机。 涓烘  我们使用 WmiObject 获取的 cmdlet 和在指定类 Win32_PingStatus 并创建检查地址属性,以查看其是否符合 $ 计算机变量中存储值的筛选器。 我们在变量命名 $ 结果存储此 WMI 查询的结果,如下所示:

  $Result = Get-WmiObject -Class Win32_PingStatus -Filter "address='$computer'"

现在,我们计算从 WMI 查询返回状态代码。 如果状态代码是等于零,没有错误,计算机启动并正在运行:

  If($Result.Statuscode -eq 0)
   {

奇怪由于某种原因,我的计算机上查询返回它的计算结果的虚拟计算机为存在但没有一个名称。 若要删除的虚拟计算机,添加以确保计算机的名称是至少一个字符长的代码行:

     if($computer.length -ge 1) 
        { 

下一步我们的反馈信息向用户提供通过显示一状态消息,指出我们处理的计算机。 我们使用 cmdlet 写入的主机提供此反馈:

         Write-Host "+t Processing $Computer"

现在我们调用 BackupFolder 获取的函数,以查找要用于备份的文件夹:

         Get-BackUpFolder 
        }
   } #end if

如果计算机是可访问,没有在尝试备份事件日志,因为我们能够到达该点。 我们将显示一个状态消息,表明我们将跳过计算机并退出该函数:

   else { "Skipping $computer .. not accessible" }
 } #end Foreach
} #end Test-ComputerConnection

评估计算机的可访问性后, 就可以创建 BackupFolder 获取的函数:

Function Get-BackupFolder
{

下的一行代码是有点 odd-looking 因此有点混乱:

$Folder = "{1}-Logs-{0:MMddyymm}" -f [DateTime]::now,$computer

我们将使用格式运算符 (-f) 执行文件夹的名称将用于在字符串中的某些值替换。 该字符串包含在一对大括号,用短划线,和另一对大括号封闭数字 0 的一组字母后跟单词日志将数字 1。

一次我们这一步。 –f 运算符执行一个替换的字符串中包含的值。 只与数组中,第一个元素开始 0,1 第二个。 –f 运算符的右侧各项是放在左侧相应插槽中的替代值。

之前得到主的脚本,让我们花一点时间考虑示例,说明如何在脚本中实现替换。 请注意我们如何替换一个 {0} 部分单词和一词两个 {1} 部分在下面的代码中:

PS C:\Users\edwilson> $test = "{0}-first-{1}-second" -f "one","two"
PS C:\Users\edwilson> $test
one-first-two-second

我们可能应该有重排我们的代码,以使第一个元素的第一个位置。 而是,我们编写了它的第二个元素是在第一个的位置,并且第一个元素是第二个位置。 如果我们有移动将事情有点,代码行的周围有将如下所示查找:

PS C:\Users\edwilson> $computer = "localhost"
PS C:\Users\edwilson> $Folder = "{0}-Logs-{1:MMddyymm}" -f $computer, [DateTime]::now
PS C:\Users\edwilson> $Folder
localhost-Logs-04070938

在上面的命令 {1:MMddyymm} 用于提供当前日期和时间。 我们不希望 DateTime 对象,因为它太长,并且有一个文件夹名不允许的字符在此处显示的正常显示。 2009,4 月 7 日,星期二 6:45:37 PM DateTime 对象的默认显示。

字母模式的冒号字符在我们的脚本中用来控制日期时间值将会显示的方式。 在我们的示例月后跟一天、 一年和分钟数。 在记录这些 DateTime 格式字符串 自定义 DateTime 格式字符串. 它们是还讨论了在最近的文章中在 Microsoft 脚本中心" 如何是否可以检查我的事件日志的大小,然后备份并将其存档如果它是多个半完整?"

接下来我们将创建事件日志的存档文件夹。 若要创建文件夹中,,我们使用新建项目 cmdlet,并为目录中指定类型。 我们将使用该变量 $ LogsArchive 和我们 $ 文件夹来创建到存档路径变量中存储模式。 我们使用-强制参数启用的完整路径,创建,如果需要。 因为我们不感兴趣反馈此命令,我们管道将结果在 Out-Null cmdlet,如下所示:

New-Item "$LogsArchive\$folder" -type Directory -force | Out-Null

我们还需要确定计算机上是否存在日志文件夹。 为此,我们使用该测试的路径 cmdlet 像下面这样:

  If(!(Test-Path "\\$computer\c$\LogFolder\$folder"))
    {

测试的路径 cmdlet 返回 $ true 或 false $ 的布尔值。 它在要求,"日志文件夹有吗? 将放置在不感兴趣只当文件夹不存在我们前面的测试的路径 cmdlet 运算符 (!) 指示。

如果在远程计算机上不存在日志文件夹,我们用于新建项目 cmdlet 创建它。 我们的硬编码值 LogFolder,但您可以更改此。 在以前的新建项目 cmdlet,为我们使用的强制参数,以创建完整路径和管道将结果在 Out-Null cmdlet:

      New-Item "\\$computer\c$\LogFolder\$folder" -type Directory -force | out-Null
    } #end if

我们现在想要调用的备份 EventLogs 函数执行实际的事件日志的备份。 我们传递我们调用函数时,$ 文件夹变量中存储路径:

 Backup-EventLogs($folder)
} #end Get-BackUpFolder

下一步中,我们创建备份的 EventLogs 函数:

Function Backup-EventLogs
{

我们可以使用 Win32_NTEventLogFile WMI 类来执行实际的备份。 涓烘  我们给 WmiObject 获取的 cmdlet 并它 Win32_NTEventLogFile 的类名称,以及计算机名称包含 $ 计算机变量中。 我们 $ Eventlogs 变量中存储了生成 WMI 对象:

$Eventlogs = Get-WmiObject -Class Win32_NTEventLogFile -ComputerName $computer

通过一个通用的、 未筛选 WMI 查询返回表示计算机上的每个事件日志的事件日志对象。 这些是典型的事件日志 图 2 所示。

为了使用这些事件日志,需要使用 ForEach 语句完成的 WMI 对象的集合。 我们使用我们的枚举数为变量 $ 日志来帮助我们遍历该集合保持我们的位置:

fig02.gif

图 2 Win32_NTEventLogFile 经典事件日志检索

 ForEach($log in $EventLogs)
        {

我们现在需要创建路径。 再一次我们使用格式运算符来执行某些模式替换。 在 {0} 是占位符,路径将用于为事件日志中计算机的名称。 在 {1} 是用于保存备份事件日志时将使用日志文件名称的占位符:

            $path = "\\{0}\c$\LogFolder\$folder\{1}.evt" -f $Computer,$log.LogFileName

现在,我们从 Win32_NTEventLogFile WMI 类调用 BackupEventLog 方法。 我们将路径传递给 BackupEventLog 方法,并从方法调用中检索返回值。 我们在此处看到 $ ErrBackup 变量中存储返回值:

            $ErrBackup = ($log.BackupEventLog($path)).ReturnValue

如果使用 –clear 开关运行该脚本,$ 清除变量会存在,而且我们将在这种情况下需要清除事件日志。 因此,我们使用 if 语句,以确定是否存在 $ 清除变量:

            if($clear)
               {

我们为空的事件日志之前,我们希望确保事件日志已成功备份。 涓烘  我们检查 $ ErrBackup 变量中存储值。 如果是等于零我们知道在备份操作过程中出现没有错误,并且是安全地继续清空事件日志:

                if($ErrBackup -eq 0)
                  {

我们从 Win32_NTEventLogFile WMI 类调用 ClearEventLog 方法,并从方法调用中检索该 ReturnValue。 我们存储在 ReturnValue $ errClear 变量如下所示:

                   $errClear = ($log.ClearEventLog()).ReturnValue
                  } #end if

如果在 $ ErrBackup 变量的值不等于 0,我们做不清除了解事件日志。 而,我们显示状态消息指出我们无法清除事件日志,因为备份操作失败。 提供其他疑难解答信息,介绍在备份操作中检索到的状态代码:

                else
                  { 
                    "Unable to clear event log because backup failed" 
                    "Backup Error was " + $ErrBackup
                  } #end else
               } #end if clear

下一步中,我们将在事件日志复制到存档位置。 涓烘  我们调用复制-EventLogsToArchive 函数然后交给路径事件日志和文件夹的目标:

            Copy-EventLogsToArchive -path $path -Folder $Folder
        } #end foreach log
} #end Backup-EventLogs

复制-EventLogsToArchive 使用复制的项目 cmdlet 将事件日志复制到存档位置。 我们再一次使用-强制参数创建该文件夹,如果它不存在:

Function Copy-EventLogsToArchive($path, $folder)
{
 Copy-Item -path $path -dest "$LogsArchive\$folder" -force
} # end Copy-EventLogsToArchive

现在,我们需要创建一些帮助文本的脚本。 涓烘  我们创建了获取-HelpText 函数存储在单个变量中的帮助信息: $ helpText。 作为一个此处的字符串可以设置文本格式我们想要其不与自己有关的转义引号的情况下出现在屏幕上的写入帮助文本。 这使得我们键入一个较大的字符串,如 图 3 中容易得多。

图 3 HelpText 获取的函数

Function Get-HelpText
{ 
 $helpText= `
@"
 DESCRIPTION:
 NAME: BackUpAndClearEventLogs.ps1
 This script will backup, archive, and clear the event logs on 
 both local and remote computers. It will accept a computer name,
 query AD, or read a text file for the list of computers. 
 PARAMETERS: 
 -LogsArchive local or remote collection of all computers event logs
 -List path to a list of computer names to process
 -Computers one or more computer names typed in
 -AD switch that causes script to query AD for all computer accounts
 -Localhost switch that runs script against local computer only
 -Clear switch that causes script to empty the event log if the back succeeds
 -Help displays this help topic
 SYNTAX:
 BackUpAndClearEventLogs.ps1 -LocalHost 
Backs up all event logs on local computer. Archives them to C:\logarchive.
 BackUpAndClearEventLogs.ps1 -AD -Clear
 Searches AD for all computers. Connects to these computers, and backs up all event 
 logs. Archives all event logs to C:\logarchive. It then clears all event logs if the
 backup operation was successful. 
 BackUpAndClearEventLogs.ps1 -List C:\fso\ListOfComputers.txt
 Reads the ListOfComputers.txt file to obtain a list of computer. Connects to these 
 computers, and backs up all event logs. Archives all event logs to C:\logarchive. 
 BackUpAndClearEventLogs.ps1 -Computers "Berlin,Vista" -LogsArchive "\\berlin\C$\fso\Logs"
 Connects to a remote computers named Berlin and Vista, and backs up all event 
 logs. Archives all event logs from all computers to the path c:\fso\Logs directory on 
 a remote computer named Berlin. 
 BackUpAndClearEventLogs.ps1 -help
 Prints the help topic for the script
 "@ #end helpText

若要显示在帮助文字,我们按名称调用变量:

  $helpText
}

下一步中,我们分析命令行输入如下所示:

If($AD) { $Computers = Get-ADComputers; Test-ComputerConnection; exit }
If($List) { $Computers = Get-Content -path $list; Test-ComputerConnection; exit }
If($LocalHost) { $computers = $env:computerName; Test-ComputerConnection; exit }

如果 $ AD 变量存在,运行脚本-AD 的开关和我们因此填充 $ 计算机变量 ADComputers 获取的函数中获取信息。 然后我们调用测试-ComputerConnection 函数将确定计算机是否联机并再次设置事件日志。 然后,我们退出脚本。 如果 $ 列表变量存在,我们用于获取内容的 cmdlet 读取文本文件和填充 $ 计算机变量。 然后我们调用 ComputerConnection 测试的函数,并退出脚本。 如果 $ 本地主机变量存在,我们通过读取直接从计算机名环境变量的值填充 $ 计算机变量。 然后我们调用 ComputerConnection 测试的函数,并退出脚本。

如果 $ 计算机变量存在,则表示脚本已运行,且从命令行提供的计算机名称。 我们需要将分为一个数组,这些计算机的名称。 涓烘  我们将使用拆分方法的字符串对象:

If($Computers) 
  { 
   if($Computers.Contains(",")) {$Computers = $Computers.Split(",")} 
   Test-ComputerConnection; exit 
  }

如果使用-帮助开关运行脚本,本我们调用 HelpText 获取的函数,显示帮助,然后退出脚本:

If($help) { Get-HelpText; exit }

存在没有参数时我们将显示消息状态我们所缺少的参数,然后调用的获取帮助测试函数:

"Missing parameters" ; Get-HelpText

BackupAndClearEventLogs.ps1 脚本可以轻松地适用您的网络上提供您的需要。 渚嬪的方式  您可以修改 Active Directory 查询,以便它将返回从特定的组织单位仅服务器或您可以添加的其他 WMI 查询,以进一步筛选出处理的计算机。 我们希望您喜欢该脚本可以使用它的工作。 请访问我们和社区的脚本编写者, 脚本中心在位置也可以捕获我们每日嗨脚本专家 ! 文章。

Ed 孙 ,一已知的脚本专家是八个包括 Windows PowerShell Scripting Guide Microsoft Press (2008) 的图书和 Microsoft Windows PowerShell Step by Step Microsoft 的作者 (2007)。 Ed 拥有超过 20 个包括 Microsoft 认证系统工程师 (MCSE) 和认证信息系统安全专家 (CISSP) 的行业证书。 在他的业余时间他喜欢 woodworking underwater 摄影,scuba 跳水。 和茶。

Craig Liebendorfer 是 wordsmith 和 longtime Microsoft Web 编辑器。 Craig 仍不能相信还有支付他使用单词的每一天的作业。 他的最爱之一就是 irreverent 幽默,因此他应该符合下面中的权限。 他认为他是他 magnificent 女儿生活中的最大 accomplishment。