誤った更新を排除して、クライアントマシンへの更新のインストールを自動化する

1年に1回、更新により通常の作業が中断されます。 Windowsは3回インストールを試み、3回ロールバックされた場合、インストールせずにロードします。 朝のユーザーが電話をかけ始めます。 何もしなければ、翌朝、状況は繰り返されます。



これはすべて不便であるため、管理者はほとんど同じことを行います。問題のマシンの更新を無効にします。 そして、1、2年後、彼はローリングアップデートを開始し、同じ問題に直面します。



なぜなら 更新の不具合により緊急モードが発生し、まったく意味のないごみを扱うスタッフに信じられないほどの時間がかかり、 スマートインフラストラクチャに到達するために、このプロセスを自動化することが決定されました。 途中で、自動モードで新しくインストールしたマシンにすべての更新をインストールできるスクリプトを受け取りました。



すぐに予約する必要があります-このスクリプトは、まったくロードしないシステムの修復方法を知らず、更新プログラムのインストール方法を認識し、周期的な再起動を引き起こす更新プログラムを自動的にスローし、リストに不正な更新プログラムを手動で追加し、インストールに関する問題を管理者に通知することができます。





すべてを開始する方法、クイックスタート



1つのファイル内の記事のソース

0.システムでスクリプトを許可します。 Set-ExecitionPolicy Unrestrictedまたは証明書でスクリプトに署名します。

1. WUErrorreportingスクリプトを制御対象マシンのディスクにコピーし、午後12:30などにタスクスケジューラに追加します。 スケジュールされたタスクの作成方法がわからない場合は、ここをクリックしてください

WUErrorreporting.ps1
<# 2016.05.23 Windows Update Error reporter      .           20   . Pak NV #> ############# # Variables # ############# #        [int]$DaysBefore = 5 #         $SaveLog = $false $LogPath = 'c:\WUError.txt' #   HTML [boolean]$SaveReport = $False [string]$ReportPath = 'C:\WUErrorReport.html' #  HTML  [boolean]$SendReport = $true [string]$ReportMail1 = 'admin@test.local' [string]$from = 'bot_abormot@test.local' [string]$SMTPServer = 'mail.test.local' ############################################################################# #      $Events = Get-EventLog -LogName System -EntryType Error -After (Get-Date).AddDays(-$DaysBefore) -InstanceId 20 -ErrorAction SilentlyContinue #          if ($Events.Count -eq 0) { Write-Host '   ,  ' -ForegroundColor Green Exit } #    $Log = @() #          foreach ($Event in $Events) { $regex = $Event.Message -match "KB\d+" $KB = $matches[0] $params = [ordered]@{ 'KB'=$KB #'EntryType'=$Event.EntryType 'Index'=$Event.Index 'MachineName'=$Event.MachineName 'Message'=$Event.Message 'Source'=$Event.Source 'TimeGenerated'=$Event.TimeGenerated 'TimeWritten'=$Event.TimeWritten 'UserName'=$Event.UserName } $obj = New-Object -TypeName PSObject -Property $params $Log += $obj } if ($SaveLog -eq $true) { #      Add-Content -Path $LogPath -Value '' $Log | select -ExpandProperty KB | Add-Content -Path $LogPath } #,    #################################   ##################################### Write-Verbose 'HTML fragment producing' $ClientName = $env:COMPUTERNAME $TotalErrors = $log.Count $frag1 = $Log | ConvertTo-Html -As table -Fragment -PreContent "<h2>Windows Update error report. $ClientName </h2><br><h3>Total $TotalErrors errors.</h3>" | Out-String Write-Verbose 'definiting CSS' $head = @' <style> body { background-color:#ffffff; font-family:Tahoma; font-size:12pt; } td, th { border:1px solid black; border-collapse:collapse; } th { color:white; background-color:black; } table, tr, td, th { padding: 2px; margin: 0px } table { font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif; font-size: 14px; border-radius: 10px; border-spacing: 0; text-align: center; } th { background: #BCEBDD; color: white; text-shadow: 0 1px 1px #2D2020; padding: 10px 20px; } th, td { border-style: solid; border-width: 0 1px 1px 0; border-color: white; } th:first-child, td:first-child { text-align: left; } th:first-child { border-top-left-radius: 10px; } th:last-child { border-top-right-radius: 10px; border-right: none; } td { padding: 10px 20px; background: #F8E391; } tr:last-child td:first-child { border-radius: 0 0 0 10px; } tr:last-child td:last-child { border-radius: 0 0 10px 0; } tr td:last-child { border-right: none; } </style> '@ $Date = Get-Date if ($SendReport -eq $true) { Write-Verbose 'SendEmail' $encoding = [System.Text.Encoding]::UTF8 $body = ConvertTo-HTML -head $head -PostContent $frag1 -PreContent "<h1>Windows Update error report. Client $ClientName. Date:$Date</h1>" | Out-String $params = @{'To'=$ReportMail1 'From'=$from 'Subject'="$ClientName. Windows Update error $Date" 'Body'=$Body 'BodyAsHTML'=$True 'SMTPServer'=$SMTPServer} Send-MailMessage @params -Encoding $encoding }
      
      





2.更新エラー通知パラメーターを設定します。これにより、パラメーターを変更します

$ ReportMail1 = 'admin@test.local'をメールに

$ SMTPServer = 'mail.test.local'からメールサーバーへ。



3.構成リセットスクリプトを目的のマシンにコピーして実行します。 初期設定でディレクトリを作成します。ディレクトリがある場合は、初期状態にリセットします。

Rearm_Install-ClientUpdate.ps1
 <#       #> #         $Path = Split-Path ($MyInvocation.MyCommand.Path) -Parent if ((Test-Path -Path "$Path\BadUpdates") -eq $false) { New-Item -Path "$Path\BadUpdates" -ItemType Directory -Force } #    $LastInstalledUpdatesFile = "$Path\BadUpdates\LastInstalledUpdates.txt" #     $BadUpdatesFile = "$Path\BadUpdates\BadUpdates.txt" # FastInstaller $KAFUFile = "$Path\BadUpdates\KAFU.txt" #      $KAFUDeltaFile = "$Path\BadUpdates\KAFUDelta.txt" # Fastinstaller watchdog $KAFUWatchDogFile = "$Path\BadUpdates\KAFUWatchDog.txt" # Fastinstaller update installer watchdog $KAFUWatchDog2File = "$Path\BadUpdates\KAFUWatchDog2.txt" # SlowInstaller $KASUFile = "$Path\BadUpdates\KASU.txt" #   $WorkLogFile = "$Path\BadUpdates\log.txt" #   $KAFile = "$Path\BadUpdates\KA.txt" Set-Content $LastInstalledUpdatesFile -Value '' Set-Content $KAFUFile -Value 0 Set-Content $KAFUDeltaFile -Value 5 Set-Content $KAFUWatchDogFile -Value 0 Set-Content $KAFUWatchDog2File -Value 0 Set-Content $KASUFile -Value 0 Set-Content $KAFile -Value 99 Set-Content $BadUpdatesFile -Value ''
      
      







4.更新スクリプトを前のスクリプト(注、以下は大きなスクリプト、85kb)を含むディレクトリにコピーします。コピーしないように、ここからダウンロードします



Install-ClientUpdate.ps1
 <# 2016.06.14 ver 2            .        .       (FastUpdate)       30%  ,      25%,      5  .    ,             ,                                 ,   ,         1.      2.    "\BadUpdates\KA.txt"   9,  11 3.            -  ,  6   -   powershell.exe -file "   \Install-ClientUpdate.ps1" 4.       5.       $RebootEnabled = $False                    1.      2.    "\BadUpdates\KA.txt"   9,  11 3.            -   (  ),   10   -   powershell.exe -file "   \Install-ClientUpdate.ps1" 4.       5.       $RebootEnabled = $true              :       SoftwareDistribution.                  Plugins.           .           ,          .        "    "      .          .      IsHidden=1            .        "4.      ".    .    win 7       .             : powershell 2.0 Pak Nikolay GEOM, Aqtobe   win 8.1/2012R2; win 7; win 2008R2 #> ############# # Variables # ############# # Allow reboot.        .      #    .       10 ,   .    #    . #$RebootEnabled = $true $RebootEnabled = $False # Fast install          $FastInstallLimit = 45 #         $Path = Split-Path ($MyInvocation.MyCommand.Path) -Parent #    $LastInstalledUpdatesFile = "$Path\BadUpdates\LastInstalledUpdates.txt" #     $BadUpdatesFile = "$Path\BadUpdates\BadUpdates.txt" # FastInstaller $KAFUFile = "$Path\BadUpdates\KAFU.txt" #      $KAFUDeltaFile = "$Path\BadUpdates\KAFUDelta.txt" # Fastinstaller watchdog $KAFUWatchDogFile = "$Path\BadUpdates\KAFUWatchDog.txt" # Fastinstaller update installer watchdog $KAFUWatchDog2File = "$Path\BadUpdates\KAFUWatchDog2.txt" # SlowInstaller $KASUFile = "$Path\BadUpdates\KASU.txt" #   $WorkLogFile = "$Path\BadUpdates\log.txt" #   $KAFile = "$Path\BadUpdates\KA.txt" ########################## Report params ################################### [boolean]$SaveReport = $true [string]$ReportPath = 'C:\Report-InstallUpdates.html' [boolean]$SendReport = $true [string]$From = 'bot_abormot@test.local' [string]$SMTP = 'mail.test.local' [string]$ReportMail1 = 'admin1@test.local' [string]$ReportMail2 = 'admin2@test.local' [string]$ReportMail3 = 'admin3@test.local' function report { Param ( [string]$Text = 'test' ) $Date = Get-Date if ($SaveReport = $true) { $Text | Out-File $ReportPath } if ($SendReport = $true) { $encoding = [System.Text.Encoding]::UTF8 $body = $Text $Subj = "install-updates script report $Date" $params = @{'To'=$ReportMail1 'From'=$From 'Subject'=$Subj 'Body'=$Body 'BodyAsHTML'=$True 'SMTPServer'=$SMTP} Send-MailMessage @params -Encoding $encoding $params = @{'To'=$ReportMail2 'From'=$From 'Subject'=$Subj 'Body'=$Body 'BodyAsHTML'=$True 'SMTPServer'=$SMTP} Send-MailMessage @params -Encoding $encoding $params = @{'To'=$ReportMail3 'From'=$From 'Subject'=$Subj 'Body'=$Body 'BodyAsHTML'=$True 'SMTPServer'=$SMTP} Send-MailMessage @params -Encoding $encoding } } ########################## Report params ################################### function Log { PARAM ( [parameter(Mandatory = $true)] [string]$Message ) $Date = Get-Date -Format "yyyy.MM.dd HH:mm:ss" [string]$Msg = $Date + "`t" + $Message Out-File -FilePath $WorkLogFile -InputObject $Msg -Append # -encoding unicode } function Clear-Log { $Date = Get-Date -Format "yyyy.MM.dd HH:mm:ss" $Msg = $Date + "`t" + '   Clear-Log' Set-Content -Path $WorkLogFile -Value $Msg } function Trim-Log { #    5    if ( (Get-Item -Path $WorkLogFile).Length -gt 5mb ) { Clear-Log } } <#   SoftwareDistribution      ,  ,       WUAUSRV       .       #> function ResetSoftwareDistribution { $WUServices = 'BITS','wuauserv' $windows = 0x24 Log 'call ResetSoftwareDistribution' Log 'stopping WU services' Write-Host " SoftwareDistribution" -ForegroundColor Green Write-Host "-------------------------------" -ForegroundColor Green Write-Host " " -ForegroundColor Green $WUServices | Stop-Service -Verbose Start-Sleep -Seconds 20 #      if ( ((Get-Service 'BITS').Status -eq 'stopped' ) -and ((Get-Service 'wuauserv').Status -eq 'stopped') ) { Log 'services stopped sucsessful' Write-Host '  ' -ForegroundColor Green $Folders = Get-ChildItem ( (New-Object -ComObject Shell.Application).Namespace( $windows ).Self.Path) -Directory | where { $_.Name -like '*SoftwareDistribution*' } Write-Host "   WU" -ForegroundColor Green $Folders Write-Host " ..." $Folders | Remove-Item -Recurse -Force -Verbose -Confirm:$false #   $Folders = Get-ChildItem ( (New-Object -ComObject Shell.Application).Namespace( $windows ).Self.Path) -Directory | where { $_.Name -like '*SoftwareDistribution*' } if ($Folders -eq $null) { Log 'SoftwareDistribution folder deleted successful' Write-Host " SoftwareDistribution  " -ForegroundColor Green } else { Log 'SoftwareDistribution folder deleted NOT successful' Write-Host "SoftwareDistribution   !" -ForegroundColor Red #              Softwaredistrib #Exit } } Log 'starting WU services' Write-Host " " -ForegroundColor Green $WUServices | Start-Service -Verbose } <#            KB      IsHidden  0,    Softwaredistribution    Hidden .         IsHidden = 1             '2976978', '3156418' | install-updates -Verbose #> function install-updates { [CmdletBinding()] PARAM ( [Parameter( Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true) ] [string[]]$KB ) BEGIN { Log 'call install-updates' $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $Updates = $searcher.Search("IsInstalled=0 and Type='Software' and ISHidden=0") #     if ($Updates.Updates.Count -eq 0) { $NoUpdates = $true } else { $NoUpdates = $false } #   Write-Verbose '---------------------------------------------------------------------' Write-Verbose "install-updates:   NoUpdates = $NoUpdates" if ($NoUpdates -eq $false) { Write-Verbose "   " $temp1 = $Updates.updates | select Title $temp1 | Write-Verbose $Count = $Updates.Updates.Count Write-Verbose "$Count   " Log "$Count   " foreach ( $temp in $temp1 ) { Log " $temp" } } else { Log "install-updates:      " Write-Verbose "install-updates:      " } Write-Verbose '---------------------------------------------------------------------' } PROCESS { Write-Verbose "install-updates:     process $KB" if ($NoUpdates -eq $true) { break } if ($KB -match ' ' ) { break } $HotFix = $Updates.Updates | where { $_.Title -like "*$KB*" } if ($HotFix -eq $null) { Write-Verbose "     " Log "     " break } else { $Title = $HotFix.Title Write-Verbose "    $Title" Log "    $Title" } #   $downloads = New-Object -ComObject Microsoft.Update.UpdateColl $downloads.Add( $HotFix ) #      80070005.        SYSTEM #                  #      Write-Verbose ' ' Log 'download update' $downloader = $session.CreateUpdateDownLoader() $downloader.Updates = $downloads $downloader.Download() if ($HotFix.IsDownloaded) { Log 'download successfull' Write-Verbose ' . (   downloads)' } $installs = New-Object -ComObject Microsoft.Update.UpdateColl if ($HotFix.IsDownloaded) { $installs.Add( $HotFix ) | Out-Null } log 'start instal' #      80070005.        SYSTEM #                  #      $installer = $session.CreateUpdateInstaller() $installer.Updates = $installs $installresult = $installer.Install() $installresult log 'installing successfull' } END { Write-Verbose 'install-updates:   ' log 'install-updates:   ' log '--------------------------------------------------------------' } } <#         20-30     .    .               .            , ..  10-20                .      ,             .       $KAFUWatchDog     0       1/3          1       1/4          2       5         #> #  [int]$KAFU = Get-Content $KAFUFile #      [int]$KAFUDelta = Get-Content $KAFUDeltaFile function Fast-Update { function Write-KAFU { PARAM ( $State ) Set-Content $KAFUFile -Value $State } Log "--- Fast-Update ---------------------------------------------------------" Log "Fast-Update    " switch ($KAFU) { 0 { Log "   0" #        $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Count = $temp.Updates.Count #   ,              $KAFUWatchDog = Get-Content $KAFUWatchDogFile log "KAFUWatchDog = $KAFUWatchDog" switch ($KAFUWatchDog) { 0 { #  ,     2      $KAFUDelta = [Math]::Truncate( $Count / 3 ) Log " ,   1/3     $KAFUDelta" } 1 { #     4      $KAFUDelta = [Math]::Truncate( $Count / 4 ) Log " ,   1/4     $KAFUDelta" } 2 { #     -          #   5    $KAFUDelta = 5 log '    -            5' } default { Log '   ,   ' $KAFUWatchDog = 0 $KAFUDelta = [Math]::Truncate( $Count / 3 ) Set-Content $KAFUWatchDogFile -Value $KAFUWatchDog } } #     Set-Content $LastInstalledUpdatesFile -Value '' Set-Content $KAFUDeltaFile -Value $KAFUDelta Set-Content $KAFUWatchDog2File -Value 0 Write-KAFU 1 break } 1 { Log "enter in state 1" $LastInstalled = Get-Content $LastInstalledUpdatesFile $BadUpdates = Get-Content $BadUpdatesFile log '     ' $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Updates = $temp.Updates | select title #        [string[]]$HotFixs = '' foreach ($temp in $Updates) { $regex = $temp.Title -match "KB\d+" $KB = $matches[0] $HotFixs += $KB Log "   : $KB" } $Count = $HotFixs.Count Log "    $Count" log ' ' $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $Upd #         if ($BadUpdates.Count -ne 0) { $temp = Compare-Object -ReferenceObject $HotFixs -DifferenceObject $BadUpdates $temp = $temp | where { $_.Sideindicator -like '<=' } | select -ExpandProperty InputObject $HotFixs = $temp $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd $temp = $HotFixs Log "    :" foreach ( $temp1 in $temp ) { Log "    : $temp1" } $Count = $temp.Count Log ": $Count " } else { Log "   " } if ($LastInstalled.Count -ne 0) { $temp = Compare-Object -ReferenceObject $HotFixs -DifferenceObject $LastInstalled $temp = $temp | where { $_.Sideindicator -like '<=' } | select -ExpandProperty InputObject $HotFixs = $temp Log "     :" $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd $temp = $HotFixs foreach ( $temp1 in $temp ) { Log "     : $temp1" } $Count = $temp.Count Log ": $Count " } else { Log "     " } #     [int]$KAFUWatchDog2 = Get-Content $KAFUWatchDog2File if ($KAFUWatchDog2 -gt 20) { Log "   ,      1,  : $KAFUWatchDog2" Write-KAFU 2 Set-Content $KAFUWatchDog2File -Value 0 break } if ($HotFixs.Count -eq 0) { #   log ' ,   .    2' Write-KAFU 2 break } else { #     $temp = $HotFixs | select -First $KAFUDelta $Count = $temp.Count if ($Count -eq 0) { log '  .    2' Write-KAFU 2 break } foreach ( $temp1 in $temp ) { Log "   : $temp1" } Log ": $Count " $HotFixs = $temp #   Add-Content -Path $LastInstalledUpdatesFile -Value '' Add-Content -Path $LastInstalledUpdatesFile -Value $HotFixs @(Get-Content $LastInstalledUpdatesFile) -match '\S' | out-file $LastInstalledUpdatesFile LOG "    " #    log '  ' $HotFixs | install-updates } Set-Content $KAFUWatchDog2File -Value ($KAFUWatchDog2 + 1) break } 2 { #           Log '   2.' $KAFUWatchDog = Get-Content $KAFUWatchDogFile $KAFUDelta = Get-Content $KAFUDeltaFile $LastInstalled = Get-Content $LastInstalledUpdatesFile log "KAFUWatchDog = $KAFUWatchDog" switch ($KAFUWatchDog) { 0 { #   .   ?      $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Updates = $temp.Updates #       * 3 - 2 $Count1 = $Updates.Count if ($KAFUDelta -eq 0) { $KAFUDelta = 5 } $Count2 = $KAFUDelta * 3 - 2 if ($Count2 -lt $Count1) { #     .     $KAFUWatchDog = 1 Set-Content $KAFUWatchDogFile -Value 1 Write-KAFU 0 Log '    .   = 1.    0' break } else { log '    WatchDog = 0' log '   3' Write-KAFU 3 break } } 1 { #     $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Updates = $temp.Updates | select title #       * 3 - 2 $Count1 = $Updates.Count $Count2 = $KAFUDelta * 4 - 2 if ($Count2 -gt $Count1) { #     - 4        25%  #      5 $KAFUWatchDog = 2 Set-Content $KAFUWatchDogFile -Value 2 Write-KAFU 0 Log '    .  = 2.    0' break } else { log '    WatchDog = 1' log '   3' Write-KAFU 3 break } } 2 { #     5    log '    WatchDog = 2' log '   3' Write-KAFU 3 break } default { Log '     0' Set-Content $KAFUWatchDogFile -Value 0 Write-KAFU 0 break } } } 3 { # ,  Write-KAFU 3 break } default { Set-Content $KAFUWatchDogFile -Value 0 Write-KAFU 0 Log "warning!!!   ,   0. KAFU = $KAFU" break } } Log "--- Fast-Update -- -------------------------------------------------------" } <################################################################################################      .       .     ,      .    48      24   2  ,   1 .       3-6   ,      30-40    . ################################################################################################> <#                           #> #  [int]$KASU = Get-Content $KASUFile function Slow-update { function Write-KASU { PARAM ( $State ) Set-Content $KASUFile -Value $State } Log "--- Slow Update ---------------------------------------------------------" Log "Slow Update " switch ($KASU) { 0 { #    log "   0,   " #     Set-Content $LastInstalledUpdatesFile -Value '' Set-Content $KAFUWatchDog2File -Value 0 Set-Content $KAFUWatchDog2File -Value 0 Write-KASU 1 break } 1 { log "   1" $LastInstalled = Get-Content $LastInstalledUpdatesFile $BadUpdates = Get-Content $BadUpdatesFile log '     ' $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Updates = $temp.Updates | select title #        [string[]]$HotFixs = '' foreach ($temp in $Updates) { $regex = $temp.Title -match "KB\d+" $KB = $matches[0] $HotFixs += $KB Log "   : $KB" } $Count = $HotFixs.Count Log "    $Count" $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $PotentialBad = $Upd #         if ($BadUpdates.Count -ne 0) { $temp = Compare-Object -ReferenceObject $HotFixs -DifferenceObject $BadUpdates $temp = $temp | where { $_.Sideindicator -like '<=' } | select -ExpandProperty InputObject $HotFixs = $temp Log "    :" $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd $temp = $HotFixs foreach ( $temp1 in $temp ) { Log "    : $temp1" } $Count = $temp.Count Log ": $Count " } else { Log "   " } $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd if ($LastInstalled.Count -ne 0) { $temp = Compare-Object -ReferenceObject $HotFixs -DifferenceObject $LastInstalled $temp = $temp | where { $_.Sideindicator -like '<=' } | select -ExpandProperty InputObject $HotFixs = $temp Log "     :" $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd $temp = $HotFixs foreach ( $temp1 in $temp ) { Log "     : $temp1" } $Count = $temp.Count Log ": $Count " } else { Log "     " } $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd if ($HotFixs.Count -eq 0) { #   log ' ,   .     ' if ($PotentialBad -ne 0 ) { foreach ( $Bad in $PotentialBad ) { log "   : $Bad" } #   ..   ,         #Add-Content -Path $BadUpdatesFile -Value '' #Add-Content -Path $BadUpdatesFile -Value $LastInstalled } Write-KASU 2 break } else { #     $temp = $HotFixs | select -First 1 $Count = $temp.Count if ( $Count -eq 0 ) { log '   2' Write-KASU 2 break } foreach ( $temp1 in $temp ) { Log "   : $temp1" } Log ": $Count " $HotFixs = $temp #   Add-Content -Path $LastInstalledUpdatesFile -Value '' Add-Content -Path $LastInstalledUpdatesFile -Value $HotFixs @(Get-Content $LastInstalledUpdatesFile) -match '\S' | out-file $LastInstalledUpdatesFile LOG "    " #    log '  ' Write-Host $HotFixs -ForegroundColor Green $HotFixs | install-updates } Set-Content $KAFUWatchDog2File -Value ($KAFUWatchDog2 + 1) break } 2 { #  ,  Write-KASU 2 break } default { #   log " " Write-KASU 0 } } Log "--- Slow-Update -- -------------------------------------------------------" } [int]$KA = Get-Content $KAFile function Write-KA { PARAM ( $State ) Set-Content $KAFile -Value $State } Log ' ' Log " " Log ' ' Log ' ' Log ' ' Log '##############################' Log "### ---   --- ###" Log '##############################' switch ($KA) { 0 { #   log( ' = 0.         ' ) Set-Content $LastInstalledUpdatesFile -Value '' Set-Content $KAFUWatchDogFile -Value 0 Set-Content $KASUFile -Value 0 Set-Content $KAFUFile -Value 0 Write-KA 9 break } 1 { #   Log '  1.    ' [int]$KAFU = Get-Content $KAFUFile if ($KAFU -eq 3) { #    log '  ,    ' Write-KA 2 Set-Content $KASUFile -Value 0 break } else { log '  ' ResetSoftwareDistribution Fast-Update Trim-Log break } } 2 { #  log ' 2,  ' [int]$KASU = Get-Content $KASUFile if ($KASU -eq 2) { #    #                 Trim-Log ResetSoftwareDistribution log( ' = 2.    ' ) $BadUpdates = Get-Content $BadUpdatesFile $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Updates = $temp.Updates | select title #        [string[]]$HotFixs = '' foreach ($temp in $Updates) { $regex = $temp.Title -match "KB\d+" $KB = $matches[0] $HotFixs += $KB Log "   : $KB" } $Count = $HotFixs.Count Log "    $Count" $PotentialBad = $HotFixs #    if ($BadUpdates.Count -ne 0) { $temp = Compare-Object -ReferenceObject $HotFixs -DifferenceObject $BadUpdates $temp = $temp | where { $_.Sideindicator -like '<=' } | select -ExpandProperty InputObject $HotFixs = $temp Log "    :" foreach ( $temp1 in $temp ) { Log "    : $temp1" } $Count = $temp.Count Log ": $Count " } else { Log "   " } $Updates = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Updates += $temp } } if ($Updates.Count -ne 0) { #    log '        ' Add-Content -Path $BadUpdatesFile -Value '' Add-Content -Path $BadUpdatesFile -Value $Updates $Date = Get-Date $CompName = $env:COMPUTERNAME $body = "<H1>     $CompName,<br><br>   </H1><h3>" foreach ($upd in $updates) { $body += "<br> $upd<br>" } $body += "<br>         .   ,        " report -text $body } Write-KA 9 break } else { log '        ' ResetSoftwareDistribution Trim-Log Slow-update break } } 9 { #     log( ' = 9.     ' ) Trim-Log ResetSoftwareDistribution $BadUpdates = Get-Content $BadUpdatesFile log '    ' $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Updates = $temp.Updates | select title #        [string[]]$HotFixs = '' foreach ($temp in $Updates) { $regex = $temp.Title -match "KB\d+" $KB = $matches[0] $HotFixs += $KB Log "   : $KB" } $Count = $HotFixs.Count Log "    $Count" $PotentialBad = $HotFixs #    if ($BadUpdates.Count -ne 0) { $temp = Compare-Object -ReferenceObject $HotFixs -DifferenceObject $BadUpdates $temp = $temp | where { $_.Sideindicator -like '<=' } | select -ExpandProperty InputObject $HotFixs = $temp Log "    :" $Upd = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Upd += $temp } } $HotFixs = $Upd $temp = $HotFixs foreach ( $temp1 in $temp ) { Log "    : $temp1" } $Count = $temp.Count Log ": $Count " } else { Log "   " } log ' ' $Updates = @() foreach ($temp in $HotFixs) { if ($temp -ne '') { $Updates += $temp } } $Count = $Updates.Count Log "  $Count  " #     $FastInstallLimit    if ($Updates.Count -gt $FastInstallLimit) { #    log "updates more than $FastInstallLimit. Go to FastInstall" Write-KA 1 break } if ($Updates.Count -gt 0) { log "Go to Slow Install" Write-KA 2 Set-Content $KASUFile -Value 0 break } if ($Updates.Count -eq 0) { log '    ' Write-KA 9 break } } default { #   log( '   .    0' ) Write-KA 0 } } #ResetSoftwareDistribution #Fast-Update #Trim-Log #Slow-update Log '##############################' Log "### ---   --- ###" Log '##############################' if ( $RebootEnabled -eq $true ) { Restart-Computer -Force Log ' >>>' } <# schtasks /run /tn "\My_Tasks\PSWindowsUpdate" [Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding("cp866") #>
      
      







5. SYSTEM特権を使用してスケジューラでタスクを作成し、1日に1回実行します。既知の問題は、アップデートのインストールがSYSTEM権限でのみ開始できることです。 (ちなみに、このメソッドを使用してアクティベーターと最高の特権で動作するすべてのものを起動することができます)





6時間の起動後遅延はうまくいき





ました。



最初の3回は、検証のために手動で実行できます。スケジューラからタスクを実行し、ファイル\ BadUpdates \ log.txtの内容を確認します。スクリプトのログが含まれている必要があります。空の場合は、スクリプト実行ポリシーが有効になっているかどうかを確認し、更新サーバーが利用可能な場合は、更新を手動で検索してみてください。



45を超える更新がある場合(この値は変更できます)、スクリプトは更新をバッチでインストールしようとします。この場合、最初に一度に1 \ 3をインストールしようとします。3パックの更新プログラムのいずれもインストールされていない場合、ステップは1/4に変更されます。 1つのマシンに6つの不適切な更新が均等に分散されていたが、一度に1つずつほぼ90の更新をインストールすることはオプションではありません(1つの更新で90日)。



:

1. WUErrorreporting 20, .

2. SoftwareDistribution

3. . :

4. 45 «»

  • , , 1/3 , 1/4 , 5
  • ,
  • BadUpdates\LastInstalledUpdates.txt


5. 45

6.

  • 更新のリストは、あなたが試したものと間違いなく悪いものなしで受信されます。更新が残っていない場合、インストールされていない更新は、正確に悪いもののリストに追加され、電子メールアラートによって修正されます。まだある場合、インストールが開始されます


7.ワークアウト後、マシンは更新待ち状態になります


SoftwareDistributionフォルダーが削除されていないことがログに示されている場合はSoftwareDistribution \ Pluginsフォルダーを確認してください。一部のプログラムはそれを保持し、クリーニングを許可しません。

新しくインストールしたシステムを更新する必要がある場合は、次の手順を実行します。

  • パラメーター$ RebootEnabled = $ trueを設定します。これにより、スクリプトの実行後すぐに再起動できます
  • システムの起動後、10分間トリガーを設定します
  • スクリプトを保存して実行します
  • その後、彼は自分で更新プログラムをインストールしようとし、コンピューターを自分で再起動するか、別のユーザーを作成するか、自分の仕事のために特別にログインする必要はありません。
  • 一定時間後、ログファイルを見て制御します
  • すべてを入れて状態9(更新待ち)になったとき$ RebootEnabled = $ falseを設定します
  • 更新する必要がなくなったらトリガーを無効にします




仕事を分析しましょう



Wuerrorreporting



1.変数を設定します

最も重要なのは、$ DaysBefore変数-ログがスキャンされる日数、デフォルトでは5日です。更新プログラムのインストール中にエラーが発生した場合、同じエラーに関する連続した5日間の管理通知を受け取ります。原則として、1日か2日を置くのは普通です。意味がありません。週末に誰かが仕事に出かけた場合、レポートをスキップできます。



変数はSAVELOG $ディスクに現在の実行ログを維持する責任。便利なのは、クライアントマシンにアクセスしたり、クライアントマシンに接続したり、操作中にどのアップデートが配信されなかったかを見たりすることです。



最後の4つの変数は、レポートの送信先を管理します。$ SendReport = $ trueのままにする必要があります通知をメールで送信する場合は、管理メール$ ReportMail1 = 'admin@test.local'指定し、どのサーバーに$ SMTPServer = 'mail.test.local'を送信するかを指定します認証が必要な場合は、156行目に追加します



変数のセクション
 ############# # Variables # ############# #        [int]$DaysBefore = 5 #         $SaveLog = $false $LogPath = 'c:\WUError.txt' #   HTML [boolean]$SaveReport = $False [string]$ReportPath = 'C:\WUErrorReport.html' #  HTML  [boolean]$SendReport = $true [string]$ReportMail1 = 'admin@test.local' $from = 'bot_abormot@test.local' [string]$SMTPServer = 'mail.test.local'
      
      









2.操作の原理は非常に単純です。



システムログからID20のエラーのみアップロードします。

 $Events = Get-EventLog -LogName System -EntryType Error -After (Get-Date).AddDays(-$DaysBefore) -InstanceId 20 -ErrorAction SilentlyContinue
      
      







エラーがある場合は、レポートオブジェクトを生成します



 #    $Log = @() #          foreach ($Event in $Events) { $regex = $Event.Message -match "KB\d+" $KB = $matches[0] $params = [ordered]@{ 'KB'=$KB #'EntryType'=$Event.EntryType 'Index'=$Event.Index 'MachineName'=$Event.MachineName 'Message'=$Event.Message 'Source'=$Event.Source 'TimeGenerated'=$Event.TimeGenerated 'TimeWritten'=$Event.TimeWritten 'UserName'=$Event.UserName } $obj = New-Object -TypeName PSObject -Property $params $Log += $obj }
      
      





そしてそれらを「正しい」方法で送ります

  $encoding = [System.Text.Encoding]::UTF8 $body = ConvertTo-HTML -head $head -PostContent $frag1 -PreContent "<h1>Windows Update error report. Client $ClientName. Date:$Date</h1>" | Out-String $params = @{'To'=$ReportMail1 'From'=$from 'Subject'="$ClientName. Windows Update error $Date" 'Body'=$Body 'BodyAsHTML'=$True 'SMTPServer'=$SMTPServer} Send-MailMessage @params -Encoding $encoding
      
      





適用されるCSSスタイルはOutlook向けにシャープ化され、WordをHTMLエンジンとして使用するため、標準のサポートが不完全になります。誰かがOutlookで機能する別の美しいスタイルを選んだら、私も捨ててください。

CSSスタイルレポート
 $head = @' <style> body { background-color:#ffffff; font-family:Tahoma; font-size:12pt; } td, th { border:1px solid black; border-collapse:collapse; } th { color:white; background-color:black; } table, tr, td, th { padding: 2px; margin: 0px } table { font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif; font-size: 14px; border-radius: 10px; border-spacing: 0; text-align: center; } th { background: #BCEBDD; color: white; text-shadow: 0 1px 1px #2D2020; padding: 10px 20px; } th, td { border-style: solid; border-width: 0 1px 1px 0; border-color: white; } th:first-child, td:first-child { text-align: left; } th:first-child { border-top-left-radius: 10px; } th:last-child { border-top-right-radius: 10px; border-right: none; } td { padding: 10px 20px; background: #F8E391; } tr:last-child td:first-child { border-radius: 0 0 0 10px; } tr:last-child td:last-child { border-radius: 0 0 10px 0; } tr td:last-child { border-right: none; } </style> '@
      
      









Install-ClientUpdate.ps1



3つの有限状態マシンがスクリプトに実装されています。単純な管理者にとっては、スクリプトを理解するのは非常に複雑です。



必要な変数を設定します。

$ FastInstallLimitがこのしきい値を超えると、クイックインストールがオンになり、更新をこのしきい値よりも1つずつ少なくします。

$ RebootEnabledは、スクリプトの各パスの後に再起動を許可します。車をアップグレードする必要がある場合に使用されます。このパラメーターを$ trueに設定し、開始時間を10分に設定して、朝までそのままにします。



以下はメール設定です

 ########################## Report params ################################### [boolean]$SaveReport = $true [string]$ReportPath = 'C:\Report-InstallUpdates.html' [boolean]$SendReport = $true [string]$From = 'bot_abormot@test.local' [string]$SMTP = 'mail.test.local' [string]$ReportMail1 = 'admin1@test.local' [string]$ReportMail2 = 'admin2@test.local' [string]$ReportMail3 = 'admin3@test.local'
      
      





リモートマシンまたはローカルマシンに更新があるかどうかを確認する必要がある場合は、次のコードを使用します。コピーしてコンソールに貼り付けるだけです

 $session = New-Object -ComObject Microsoft.Update.Session $searcher = $session.CreateUpdateSearcher() $temp = $searcher.Search("IsInstalled=0 and Type='Software'" ) $Count = $temp.Updates.Count $Count ''
      
      







一般的な推奨事項:最初の段階では、次のようにユーザーと連絡をとることをお勧めします。更新プログラムの長期インストールとその後のロールバックを恐れています。

また、コンピュータの電源を切ったばかりで、「更新して作業を完了する」をクリックしなかったと説明することをお勧めします。そうしないと、すべての更新がインストールされ、作業のロジックに違反します。



このスクリプトはwin 8.1でテストされました。2012R2; win 7 x64



アドオン2016.08.03:既知の明らかに

悪い更新がある場合KB121212の形式でファイル\ BadUpdates \ BadUpdates.txt手動で書き込みます。作業中に、スクリプトはインストールオプションからこの更新を自動的に削除します



All Articles