This is a script that I wrote which uses the WSUS APIs in windows (COM) and presents the user with a GUI to select and install updates. I was very happy to learn how to use a listview .NET control in this exercise.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
#####################
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
function Show-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
#5 show
[Console.Window]::ShowWindow($consolePtr, 5)
}
function Hide-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
#0 hide
[Console.Window]::ShowWindow($consolePtr, 0)
}
#####################
#uncomment next line to hide console window to make things prettier if run from SCCM application/package for instance
#Hide-Console
Start-Process -FilePath "wuauclt.exe" -ArgumentList "/a /resetauthorization /detectnow"
#Alternate detection than wuauclt, not sure if it does the resetauthorization switch
#$AutoUpdate = New-Object -ComObject Microsoft.Update.AutoUpdate
#$AutoUpdate.DetectNow()
$UpdateCollection = New-Object -ComObject "Microsoft.Update.UpdateColl"
$Searcher = New-Object -ComObject "Microsoft.Update.Searcher"
$Session = New-Object -ComObject "Microsoft.Update.Session"
$Downloader = $Session.CreateUpdateDownloader()
$Installer = New-Object -ComObject "Microsoft.Update.Installer"
#May be necessary to specify other parameters to use a WSUS server
#$Searcher.ServerSelection = 0 #Default
#$Searcher.Online = $False
$LoadingForm = New-Object System.Windows.Forms.Form
$LoadingForm.Size = [System.Drawing.Point]"300,300"
$LoadingForm.FormBorderStyle = "None"
$LoadingForm.TopMost = $true
$LoadingForm.BackColor = [System.Drawing.Color]::PaleTurquoise
$LoadingForm.StartPosition = "CenterScreen"
$LoadingLabel = New-Object System.Windows.Forms.Label
$LoadingLabel.Text = "Loading updates, please wait..."
$LoadingLabel.Location = [System.Drawing.Point]"25,100"
$LoadingLabel.Font = "Calibri, 25"
$LoadingLabel.Size = [System.Drawing.Point]"300,200"
$LoadingForm.Controls.Add($LoadingLabel)
$LoadingForm.Show()
#Allow update scan time to work
Start-Sleep -Seconds 30
$NotInstalled = $Searcher.Search("IsInstalled=0")
$LoadingForm.Close()
#>
########Begin Form
Function New-Button($Text,$X,$Y,$ScriptBlock){
$Button = New-Object System.Windows.Forms.Button
$Button.Size = [System.Drawing.Point]"200,50"
$Button.Location = [System.Drawing.Point]"$x,$y"
$Button.Text = $Text
$Button.Add_Click($ScriptBlock)
$Button
}
########Begin Form
$Form = New-Object System.Windows.Forms.Form
$Form.Size = [System.Drawing.Point]"800,600"
$Form.StartPosition = "CenterScreen"
$Form.FormBorderStyle = "FixedSingle"
$Form.TopMost = $true
$Form.MinimizeBox = $false
$Form.MaximizeBox = $false
$ListView = New-Object System.Windows.Forms.ListView
$ListView.Size = [System.Drawing.Point]"400,400"
$ListView.Location = [System.Drawing.Point]"50,50"
$ListView.CheckBoxes = $true
$ListView.View = [System.Windows.Forms.View]::Details
$ListView.Width = $Form.ClientRectangle.Width - 100
$ListView.Height = $Form.ClientRectangle.Height - 150
$ListView.Anchor = "Top, Left, Right, Bottom"
$ListView.Columns.Add("Title",-2) | Out-Null
$ListView.Columns.Add("GUID",0) | Out-Null
$ListView.Columns.Add("Needs Reboot",-2) | Out-Null
$ListView.add_ItemChecked({if(.$EvalChecks){$OKButton.Enabled = $true}else{$OKButton.Enabled = $false}})
Foreach($Update in $NotInstalled.Updates){
if($Update.InstallationBehavior.CanRequestUserInput -eq $false){
$ListViewItem = New-Object System.Windows.Forms.ListViewItem($Update.Title)
#$ListViewItem.SubItems.Add($Update.KBArticleIDs.Item(0)) | Out-Null
#$ListViewItem.SubItems.Add([int]($Update.MaxDownloadSize / 1MB)) | Out-Null
#$ListViewItem.SubItems.Add($Update.LastDeploymentChangeTime.ToString()) | Out-Null
$ListViewItem.SubItems.Add($Update.Identity.UpdateID) | Out-Null
$ListViewItem.SubItems.Add($Update.RebootRequired.ToString()) | Out-Null
$ListView.Items.Add($ListViewItem) | Out-Null
}
}
$EvalChecks = {
($ListView.Items | select -ExpandProperty checked | ?{$_ -eq $true} | Measure-Object | select -ExpandProperty count) -gt 0
}
$InstallUpdates = {
$Form.Hide()
$CheckedUpdates = $ListView.Items | where{$_.Checked} | select -ExpandProperty SubItems | Where{$_.Text -match "\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b"} | select -ExpandProperty Text
$Installer = New-Object -ComObject "Microsoft.Update.Installer"
$UpdateCollection = New-Object -ComObject "Microsoft.Update.UpdateColl"
$DownloadCollection = New-Object -ComObject "Microsoft.Update.UpdateColl"
Foreach($Selected_Update in $CheckedUpdates){
$UpdateToInstall = $NotInstalled.Updates | Where{$_.Identity.UpdateID -in $Selected_Update}
#Check if already downloaded, no need to duplicate effort
if(!$UpdateToInstall.IsDownloaded){
$DownloadCollection.Add($UpdateToInstall)
}
$UpdateCollection.Add($UpdateToInstall)
if($Installer.RebootRequiredBeforeInstallation){[System.Windows.Forms.MessageBox]::Show("A reboot is required before the remaining updates can be installed.");$Form.Close();break}
}
$Downloader.Updates = $DownloadCollection
$Downloader.Download()
$Installer.Updates = $UpdateCollection
$Installer.Install()
$Form.Close()
}
$CancelButton = New-Button -Text "Cancel" -X 425 -Y 485 -ScriptBlock {$ListView.Items | %{$_.Checked = $false};$Form.Close()}
$OKButton = New-Button -Text "Install Selection" -X 175 -Y 485 -ScriptBlock $InstallUpdates
$CheckBox_Select_All = New-Object System.Windows.Forms.CheckBox
$CheckBox_Select_All.Size = [System.Drawing.Point]"100,20"
$CheckBox_Select_All.Location = [System.Drawing.Point]"55,25"
$CheckBox_Select_All.Text = "Select All"
$CheckBox_Select_All.Add_CheckedChanged({
If($CheckBox_Select_All.Checked){
$ListView.Items | %{$_.Checked = $true}
}
elseif(! $CheckBox_Select_All.Checked){
$ListView.Items | %{$_.Checked = $false}
}
})
$Form.Controls.Add($CheckBox_Select_All)
$Title = New-Object System.Windows.Forms.Label
$Title.Text = "The Chicoine Patching Tool"
$Title.Font = "Calibri,20"
$Title.Location = [System.Drawing.Point]"250,10"
$Title.Size = [System.Drawing.Point]"500,40"
$Form.Controls.Add($Title)
$Form.Controls.Add($ListView) | Out-Null
$Form.Controls.Add($OKButton)
$Form.Controls.Add($CancelButton)
$Form.Add_Shown({if(.$EvalChecks){$OKButton.Enabled = $true}else{$OKButton.Enabled = $false}})
#[System.Windows.Forms.Application]::Run($Form)
$Form.ShowDialog()
No comments:
Post a Comment