Hi
I’m running script to update servers and I’m getting errors about non-existing methods EditItem at Start-PoshPAIG.ps1 :449 char48
CommitEdit at Start-PoshPAIG.ps1 :451 char50
EditItelm at Start-PoshPAIG.ps1 :9 char52
and couple of more lines containing this methods
#region Synchronized Collections
$uiHash = [hashtable]::Synchronized(@{})
$runspaceHash = [hashtable]::Synchronized(@{})
$jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
$jobCleanup = [hashtable]::Synchronized(@{})
$Global:updateAudit = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
$Global:installAudit = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
$Global:servicesAudit = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
$Global:installedUpdates = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
#endregion
#region Startup Checks and configurations
#Determine if running from ISE
Write-Verbose "Checking to see if running from console"
If ($Host.name -eq "Windows PowerShell ISE Host") {
Write-Warning "Unable to run this from the PowerShell ISE due to issues with PSexec!`nPlease run from console."
Break
}
#Validate user is an Administrator
Write-Verbose "Checking Administrator credentials"
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
[Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Warning "You are not running this as an Administrator!`nRe-running script and will prompt for administrator credentials."
Start-Process -Verb "Runas" -File PowerShell.exe -Argument "-STA -noprofile -file $($myinvocation.mycommand.definition)"
Break
}
#Ensure that we are running the GUI from the correct location
Set-Location $(Split-Path $MyInvocation.MyCommand.Path)
$Global:Path = $(Split-Path $MyInvocation.MyCommand.Path)
Write-Debug "Current location: $Path"
#Check for PSExec
Write-Verbose "Checking for psexec.exe"
If (-Not (Test-Path psexec.exe)) {
Write-Warning ("Psexec.exe missing from {0}!`n Please place file in the path so UI can work properly" -f (Split-Path $MyInvocation.MyCommand.Path))
Break
}
#Determine if this instance of PowerShell can run WPF
Write-Verbose "Checking the apartment state"
If ($host.Runspace.ApartmentState -ne "STA") {
Write-Warning "This script must be run in PowerShell started using -STA switch!`nScript will attempt to open PowerShell in STA and run re-run script."
Start-Process -File PowerShell.exe -Argument "-STA -noprofile -WindowStyle hidden -file $($myinvocation.mycommand.definition)"
Break
}
#Load Required Assemblies
Add-Type –assemblyName PresentationFramework
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName WindowsBase
Add-Type –assemblyName Microsoft.VisualBasic
Add-Type –assemblyName System.Windows.Forms
#DotSource Help script
. ".\HelpFiles\HelpOverview.ps1"
#DotSource About script
. ".\HelpFiles\About.ps1"
#endregion
Function Set-PoshPAIGOption {
If (Test-Path (Join-Path $Path 'options.xml')) {
$Optionshash = Import-Clixml -Path (Join-Path $Path 'options.xml')
$Global:maxConcurrentJobs = $Optionshash['MaxJobs']
$Global:MaxRebootJobs = $Optionshash['MaxRebootJobs']
If ($Optionshash['ReportPath']) {
$Global:reportpath = $Optionshash['ReportPath']
} Else {
$Optionshash['ReportPath'] = $Global:reportpath = (Join-Path $Home 'Desktop')
}
} Else {
#Default Options
$optionshash = @{
MaxJobs = 5
MaxRebootJobs = 5
ReportPath = (Join-Path $env:USERPROFILE 'Desktop')
}
$Global:maxConcurrentJobs = 5
$Global:MaxRebootJobs = 5
$Global:reportpath = (Join-Path $env:USERPROFILE 'Desktop')
}
$optionshash | Export-Clixml -Path (Join-Path $pwd 'options.xml') -Force
}
#Function for Debug output
Function Global:Show-DebugState {
Write-Debug ("Number of Items: {0}" -f $uiHash.Listview.ItemsSource.count)
Write-Debug ("First Item: {0}" -f $uiHash.Listview.ItemsSource[0].Computer)
Write-Debug ("Last Item: {0}" -f $uiHash.Listview.ItemsSource[$($uiHash.Listview.ItemsSource.count) -1].Computer)
Write-Debug ("Max Progress Bar: {0}" -f $uiHash.ProgressBar.Maximum)
}
#Reboot Warning Message
Function Show-RebootWarning {
$title = "Reboot Server Warning"
$message = "You are about to reboot servers which can affect the environment! `nAre you sure you want to do this?"
$button = [System.Windows.Forms.MessageBoxButtons]::YesNo
$icon = [Windows.Forms.MessageBoxIcon]::Warning
[windows.forms.messagebox]::Show($message,$title,$button,$icon)
}
#Format and display errors
Function Get-Error {
Process {
ForEach ($err in $error) {
Switch ($err) {
{$err -is [System.Management.Automation.ErrorRecord]} {
$hash = @{
Category = $err.categoryinfo.Category
Activity = $err.categoryinfo.Activity
Reason = $err.categoryinfo.Reason
Type = $err.GetType().ToString()
Exception = ($err.exception -split ": ")[1]
QualifiedError = $err.FullyQualifiedErrorId
CharacterNumber = $err.InvocationInfo.OffsetInLine
LineNumber = $err.InvocationInfo.ScriptLineNumber
Line = $err.InvocationInfo.Line
TargetObject = $err.TargetObject
}
}
Default {
$hash = @{
Category = $err.errorrecord.categoryinfo.category
Activity = $err.errorrecord.categoryinfo.Activity
Reason = $err.errorrecord.categoryinfo.Reason
Type = $err.GetType().ToString()
Exception = ($err.errorrecord.exception -split ": ")[1]
QualifiedError = $err.errorrecord.FullyQualifiedErrorId
CharacterNumber = $err.errorrecord.InvocationInfo.OffsetInLine
LineNumber = $err.errorrecord.InvocationInfo.ScriptLineNumber
Line = $err.errorrecord.InvocationInfo.Line
TargetObject = $err.errorrecord.TargetObject
}
}
}
$object = New-Object PSObject -Property $hash
$object.PSTypeNames.Insert(0,'ErrorInformation')
$object
}
}
}
#Add new server to GUI
Function Add-Server {
$computer = [Microsoft.VisualBasic.Interaction]::InputBox("Enter a server name or names. Separate servers with a comma (,) or semi-colon (;).", "Add Server/s")
If (-Not [System.String]::IsNullOrEmpty($computer)) {
[string[]]$computername = $computer -split ",|;"
ForEach ($computer in $computername) {
If (-NOT [System.String]::IsNullOrEmpty($computer)) {
$clientObservable.Add((
New-Object PSObject -Property @{
Computer = ($computer).Trim()
Audited = 0 -as [int]
Installed = 0 -as [int]
InstallErrors = 0 -as [int]
Services = 0 -as [int]
Notes = $Null
}
))
Show-DebugState
}
}
}
}
#Remove server from GUI
Function Remove-Server {
$Servers = @($uiHash.Listview.SelectedItems)
ForEach ($server in $servers) {
$clientObservable.Remove($server)
}
$uiHash.ProgressBar.Maximum = $uiHash.Listview.ItemsSource.count
Show-DebugState
}
#Report Generation function
Function Start-Report {
Write-Debug ("Data: {0}" -f $uiHash.ReportComboBox.SelectedItem.Text)
Switch ($uiHash.ReportComboBox.SelectedItem.Text) {
"Audit CSV Report" {
If ($updateAudit.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path $reportpath "AuditReport.csv"
$updateAudit | Export-Csv $savedreport -NoTypeInformation
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Audit UI Report" {
If ($updateAudit.count -gt 0) {
$updateAudit | Out-GridView -Title 'Audit Report'
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Install CSV Report" {
If ($installAudit.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path $reportpath "InstallReport.csv"
$installAudit | Export-Csv $savedreport -NoTypeInformation
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Install UI Report" {
If ($installAudit.count -gt 0) {
$installAudit | Out-GridView -Title 'Install Report'
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Installed Updates CSV Report" {
If ($installedUpdates.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path $reportpath "InstalledUpdatesReport.csv"
$installedUpdates | Export-Csv $savedreport -NoTypeInformation
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Installed Updates UI Report" {
If ($installedUpdates.count -gt 0) {
$installedUpdates | Out-GridView -Title 'Installed Updates Report'
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Host File List" {
If ($uiHash.Listview.Items.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path $reportpath "hosts.txt"
$uiHash.Listview.DataContext | Select -Expand Computer | Out-File $savedreport
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Computer List Report" {
If ($uiHash.Listview.Items.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path (Join-Path $home Desktop) "serverlist.csv"
$uiHash.Listview.DataContext | Export-Csv -NoTypeInformation $savedreport
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Error UI Report" {Get-Error | Out-GridView -Title 'Error Report'}
"Services UI Report" {
If (@($servicesAudit).count -gt 0) {
$servicesAudit | Select @{L='Computername';E={$_.__Server}},Name,DisplayName,State,StartMode,ExitCode,Status | Out-GridView -Title 'Services Report'
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
"Services CSV Report" {
If (@($servicesAudit).count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path $reportpath "ServicesReport.csv"
$servicesAudit | Select @{L='Computername';E={$_.__Server}},Name,DisplayName,State,StartMode,ExitCode,Status | Export-Csv $savedreport -NoTypeInformation
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
}
}
}
#start-RunJob function
Function Start-RunJob {
Write-Debug ("ComboBox {0}" -f $uiHash.RunOptionComboBox.Text)
$selectedItems = $uiHash.Listview.SelectedItems
If ($selectedItems.Count -gt 0) {
$uiHash.ProgressBar.Maximum = $selectedItems.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
If ($uiHash.RunOptionComboBox.Text -eq 'Install Patches') {
#region Install Patches
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Installing Patches for all servers...Please Wait"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Path,
$Computer,
$installAudit,
$uiHash
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Installing Patches"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $path
. .\Scripts\Install-Patches.ps1
$clientInstall = @(Install-Patches -Computername $computer.computer)
$installAudit.AddRange($clientInstall) | Out-Null
$clientInstalledCount = @($clientInstall | Where {$_.Notes -notmatch "Failed to Install Patch|ERROR"}).Count
$clientInstalledErrorCount = @($clientInstall | Where {$_.Notes -match "Failed to Install Patch|ERROR"}).Count
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($clientInstall[0].Title -eq "NA") {
$Computer.Installed = 0
} Else {
$Computer.Installed = $clientInstalledCount
$Computer.InstallErrors = $clientInstalledErrorCount
}
$Computer.Notes = "Completed"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Normal",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Normal",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Patch Install"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($Path).AddArgument($computer).AddArgument($installAudit).AddArgument($uiHash)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}#endregion
} ElseIf ($uiHash.RunOptionComboBox.Text -eq 'Audit Patches') {
#region Audit Patches
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Auditing Patches for all servers...Please Wait"
$Global:updatelayout = [Windows.Input.InputEventHandler]{ $uiHash.ProgressBar.UpdateLayout() }
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Path,
$Computer,
$updateAudit,
$uiHash
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Auditing Patches"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $path
. .\Scripts\Get-PendingUpdates.ps1
$clientUpdate = @(Get-PendingUpdates -Computer $computer.computer)
$updateAudit.AddRange($clientUpdate) | Out-Null
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($clientUpdate[0].Title -eq "NA") {
$Computer.Audited = 0
$Computer.Notes = "Completed"
} ElseIf ($clientUpdate[0].Title -eq "ERROR") {
$Computer.Audited = 0
$Computer.Notes = "Error with Audit"
} ElseIf ($clientUpdate[0].Title -eq "OFFLINE") {
$Computer.Audited = 0
$Computer.Notes = "Offline"
} Else {
$Computer.Audited = $clientUpdate.Count
$Computer.Notes = "Completed"
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Normal",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Normal",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Patch Audit"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($Path).AddArgument($computer).AddArgument($updateAudit).AddArgument($uiHash)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}#endregion
} ElseIf ($uiHash.RunOptionComboBox.Text -eq 'Reboot Systems') {
#region Reboot
If ((Show-RebootWarning) -eq "Yes") {
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Rebooting Servers..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Rebooting"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
If (Test-Connection -Computer $Computer.computer -count 1 -Quiet) {
Try {
Restart-Computer -ComputerName $Computer.computer -Force -ea stop
Do {
Start-Sleep -Seconds 2
Write-Verbose ("Waiting for {0} to shutdown..." -f $Computer.computer)
}
While ((Test-Connection -ComputerName $Computer.computer -Count 1 -Quiet))
Do {
Start-Sleep -Seconds 5
$i++
Write-Verbose ("{0} down...{1}" -f $Computer.computer, $i)
If($i -eq 60) {
Write-Warning ("{0} did not come back online from reboot!" -f $Computer.computer)
$connection = $False
}
}
While (-NOT(Test-Connection -ComputerName $Computer.computer -Count 1 -Quiet))
Write-Verbose ("{0} is back up" -f $Computer.computer)
$connection = $True
} Catch {
Write-Warning "$($Error[0])"
$connection = $False
}
}
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($Connection) {
$Computer.Notes = "Online"
} ElseIf (-Not $Connection) {
$Computer.Notes = "Offline"
} Else {
$Computer.Notes = "Unknown"
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Normal",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Normal",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxRebootJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Reboot"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}#endregion
} ElseIf ($uiHash.RunOptionComboBox.Text -eq 'Ping Sweep') {
#region PingSweeps
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Checking server connection..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Checking connection"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
$Connection = (Test-Connection -ComputerName $Computer.computer -Count 1 -Quiet)
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($Connection) {
$Computer.Notes = "Online"
} ElseIf (-Not $Connection) {
$Computer.Notes = "Offline"
} Else {
$Computer.Notes = "Unknown"
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Normal",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Normal",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Network Test"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
#endregion
} ElseIf ($uiHash.RunOptionComboBox.Text -eq 'Check Pending Reboot') {
#region Check Pending Reboot
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Checking for servers with a pending reboot..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Checking for pending reboot"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
. .\Scripts\Get-ComputerRebootState.ps1
$clientRebootRequired = Get-ComputerRebootState -Computer $Computer.computer
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($clientRebootRequired.RebootRequired -eq $True) {
$Computer.Notes = "Reboot Required"
} ElseIf ($clientRebootRequired.RebootRequired -eq $False) {
$Computer.Notes = "No Reboot Required"
} ElseIf ($clientRebootRequired.RebootRequired -eq "NA") {
$Computer.Notes = "Unable to determine reboot state"
} ElseIf ($clientRebootRequired.RebootRequired -eq "Offline") {
$Computer.Notes = "Offline"
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Normal",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Normal",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Reboot Check"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}#endregion
} ElseIf ($uiHash.RunOptionComboBox.Text -eq 'Services Check') {
#region Check Services
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Checking for Non-Running Automatic Services..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path,
$servicesAudit
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Checking for non-running services set to Auto"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Clear-Variable queryError -ErrorAction SilentlyContinue
Set-Location $Path
If (Test-Connection -ComputerName $computer.computer -Count 1 -Quiet) {
Try {
$wmi = @{
ErrorAction = 'Stop'
Computername = $computer.computer
Query = "Select __Server,Name,DisplayName,State,StartMode,ExitCode,Status FROM Win32_Service WHERE StartMode='Auto' AND State!='Running'"
}
$services = @(Get-WmiObject @wmi)
} Catch {
$queryError = $_.Exception.Message
}
} Else {
$queryError = "Offline"
}
If ($services.count -gt 0) {
$servicesAudit.AddRange($services) | Out-Null
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$Computer.Services = $services.count
If ($queryError) {
$Computer.notes = $queryError
} Else {
$Computer.notes = 'Completed'
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Normal",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Normal",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Service Check"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path).AddArgument($servicesAudit)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}#endregion
}
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No server/s selected!"
}
}
Function Open-FileDialog {
$dlg = new-object microsoft.win32.OpenFileDialog
$dlg.DefaultExt = "*.txt"
$dlg.Filter = "Text Files |*.txt;*.log"
$dlg.InitialDirectory = $path
[void]$dlg.showdialog()
Write-Output $dlg.FileName
}
Function Open-DomainDialog {
$domain = [Microsoft.VisualBasic.Interaction]::InputBox("Enter the LDAP path for the Domain or press OK to use the default domain.",
"Domain Query", "$(([adsisearcher]'').SearchRoot.distinguishedName)")
If (-Not [string]::IsNullOrEmpty($domain)) {
Write-Output $domain
}
}
#Build the GUI
[xml]$xaml = @"
Audit Patches
Install Patches
Check Pending Reboot
Ping Sweep
Services Check
Reboot Systems
Audit CSV Report
Audit UI Report
Install CSV Report
Install UI Report
Installed Updates CSV Report
Installed Updates UI Report
Services CSV Report
Services UI Report
Host File List
Computer List Report
Error UI Report
Waiting for Action...
"@
#region Load XAML into PowerShell
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$uiHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
#endregion
#region Background runspace to clean up jobs
$jobCleanup.Flag = $True
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("uiHash",$uiHash)
$newRunspace.SessionStateProxy.SetVariable("jobCleanup",$jobCleanup)
$newRunspace.SessionStateProxy.SetVariable("jobs",$jobs)
$jobCleanup.PowerShell = [PowerShell]::Create().AddScript({
#Routine to handle completed runspaces
Do {
Foreach($runspace in $jobs) {
If ($runspace.Runspace.isCompleted) {
$runspace.powershell.EndInvoke($runspace.Runspace) | Out-Null
$runspace.powershell.dispose()
$runspace.Runspace = $null
$runspace.powershell = $null
}
}
#Clean out unused runspace jobs
$temphash = $jobs.clone()
$temphash | Where {
$_.runspace -eq $Null
} | ForEach {
Write-Verbose ("Removing {0}" -f $_.computer)
$jobs.remove($_)
}
Start-Sleep -Seconds 1
} while ($jobCleanup.Flag)
})
$jobCleanup.PowerShell.Runspace = $newRunspace
$jobCleanup.Thread = $jobCleanup.PowerShell.BeginInvoke()
#endregion
#region Connect to all controls
$uiHash.GenerateReportMenu = $uiHash.Window.FindName("GenerateReportMenu")
$uiHash.ClearAuditReportMenu = $uiHash.Window.FindName("ClearAuditReportMenu")
$uiHash.ClearInstallReportMenu = $uiHash.Window.FindName("ClearInstallReportMenu")
$uiHash.SelectAllMenu = $uiHash.Window.FindName("SelectAllMenu")
$uiHash.OptionMenu = $uiHash.Window.FindName("OptionMenu")
$uiHash.WUStopServiceMenu = $uiHash.Window.FindName("WUStopServiceMenu")
$uiHash.WUStartServiceMenu = $uiHash.Window.FindName("WUStartServiceMenu")
$uiHash.WURestartServiceMenu = $uiHash.Window.FindName("WURestartServiceMenu")
$uiHash.WindowsUpdateServiceMenu = $uiHash.Window.FindName("WindowsUpdateServiceMenu")
$uiHash.GenerateReportButton = $uiHash.Window.FindName("GenerateReportButton")
$uiHash.ReportComboBox = $uiHash.Window.FindName("ReportComboBox")
$uiHash.StartImage = $uiHash.Window.FindName("StartImage")
$uiHash.CancelImage = $uiHash.Window.FindName("CancelImage")
$uiHash.RunOptionComboBox = $uiHash.Window.FindName("RunOptionComboBox")
$uiHash.ClearErrorMenu = $uiHash.Window.FindName("ClearErrorMenu")
$uiHash.ViewErrorMenu = $uiHash.Window.FindName("ViewErrorMenu")
$uiHash.EntireLogMenu = $uiHash.Window.FindName("EntireLogMenu")
$uiHash.Last25LogMenu = $uiHash.Window.FindName("Last25LogMenu")
$uiHash.Last50LogMenu = $uiHash.Window.FindName("Last50LogMenu")
$uiHash.Last100LogMenu = $uiHash.Window.FindName("Last100LogMenu")
$uiHash.ResetDataMenu = $uiHash.Window.FindName("ResetDataMenu")
$uiHash.ResetAuthorizationMenu = $uiHash.Window.FindName("ResetAuthorizationMenu")
$uiHash.ClearServerListNotesMenu = $uiHash.Window.FindName("ClearServerListNotesMenu")
$uiHash.ServerListReportMenu = $uiHash.Window.FindName("ServerListReportMenu")
$uiHash.OfflineHostsMenu = $uiHash.Window.FindName("OfflineHostsMenu")
$uiHash.HostListMenu = $uiHash.Window.FindName("HostListMenu")
$uiHash.InstalledUpdatesMenu = $uiHash.Window.FindName("InstalledUpdatesMenu")
$uiHash.DetectNowMenu = $uiHash.Window.FindName("DetectNowMenu")
$uiHash.WindowsUpdateLogMenu = $uiHash.Window.FindName("WindowsUpdateLogMenu")
$uiHash.WUAUCLTMenu = $uiHash.Window.FindName("WUAUCLTMenu")
$uiHash.GUIInstalledUpdatesMenu = $uiHash.Window.FindName("GUIInstalledUpdatesMenu")
$uiHash.AddServerMenu = $uiHash.Window.FindName("AddServerMenu")
$uiHash.RemoveServerMenu = $uiHash.Window.FindName("RemoveServerMenu")
$uiHash.ListviewContextMenu = $uiHash.Window.FindName("ListViewContextMenu")
$uiHash.ExitMenu = $uiHash.Window.FindName("ExitMenu")
$uiHash.ClearInstalledUpdateMenu = $uiHash.Window.FindName("ClearInstalledUpdateMenu")
$uiHash.RunMenu = $uiHash.Window.FindName('RunMenu')
$uiHash.ClearAllMenu = $uiHash.Window.FindName("ClearAllMenu")
$uiHash.ClearServerListMenu = $uiHash.Window.FindName("ClearServerListMenu")
$uiHash.AboutMenu = $uiHash.Window.FindName("AboutMenu")
$uiHash.HelpFileMenu = $uiHash.Window.FindName("HelpFileMenu")
$uiHash.Listview = $uiHash.Window.FindName("Listview")
$uiHash.LoadFileButton = $uiHash.Window.FindName("LoadFileButton")
$uiHash.BrowseFileButton = $uiHash.Window.FindName("BrowseFileButton")
$uiHash.LoadADButton = $uiHash.Window.FindName("LoadADButton")
$uiHash.StatusTextBox = $uiHash.Window.FindName("StatusTextBox")
$uiHash.ProgressBar = $uiHash.Window.FindName("ProgressBar")
$uiHash.RunButton = $uiHash.Window.FindName("RunButton")
$uiHash.CancelButton = $uiHash.Window.FindName("CancelButton")
$uiHash.GridView = $uiHash.Window.FindName("GridView")
#endregion
#region Event Handlers
#Window Load Events
$uiHash.Window.Add_SourceInitialized({
#Configure Options
Write-Verbose 'Updating configuration based on options'
Set-PoshPAIGOption
Write-Debug ("maxConcurrentJobs: {0}" -f $maxConcurrentJobs)
Write-Debug ("MaxRebootJobs: {0}" -f $MaxRebootJobs)
Write-Debug ("reportpath: {0}" -f $reportpath)
#Define hashtable of settings
$Script:SortHash = @{}
#Sort event handler
[System.Windows.RoutedEventHandler]$Global:ColumnSortHandler = {
If ($_.OriginalSource -is [System.Windows.Controls.GridViewColumnHeader]) {
Write-Verbose ("{0}" -f $_.Originalsource.getType().FullName)
If ($_.OriginalSource -AND $_.OriginalSource.Role -ne 'Padding') {
$Column = $_.Originalsource.Column.DisplayMemberBinding.Path.Path
Write-Debug ("Sort: {0}" -f $Column)
If ($SortHash[$Column] -eq 'Ascending') {
Write-Debug "Descending"
$SortHash[$Column] = 'Descending'
} Else {
Write-Debug "Ascending"
$SortHash[$Column] = 'Ascending'
}
Write-Verbose ("Direction: {0}" -f $SortHash[$Column])
$lastColumnsort = $Column
Write-Verbose "Clearing sort descriptions"
$uiHash.Listview.Items.SortDescriptions.clear()
Write-Verbose ("Sorting {0} by {1}" -f $Column, $SortHash[$Column])
$uiHash.Listview.Items.SortDescriptions.Add((New-Object System.ComponentModel.SortDescription $Column, $SortHash[$Column]))
Write-Verbose "Refreshing View"
$uiHash.Listview.Items.Refresh()
}
}
}
$uiHash.Listview.AddHandler([System.Windows.Controls.GridViewColumnHeader]::ClickEvent, $ColumnSortHandler)
#Create and bind the observable collection to the GridView
$Script:clientObservable = New-Object System.Collections.ObjectModel.ObservableCollection[object]
$uiHash.ListView.ItemsSource = $clientObservable
$Global:Clients = $clientObservable | Select -Expand Computer
})
#Window Close Events
$uiHash.Window.Add_Closed({
#Halt job processing
$jobCleanup.Flag = $False
#Stop all runspaces
$jobCleanup.PowerShell.Dispose()
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
})
#Cancel Button Event
$uiHash.CancelButton.Add_Click({
$runspaceHash.runspacepool.Dispose()
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Action cancelled"
[Float]$uiHash.ProgressBar.Value = 0
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
})
#EntireUpdateLog Event
$uiHash.EntireLogMenu.Add_Click({
If ($uiHash.Listview.Items.count -eq 1) {
$selectedItem = $uiHash.Listview.SelectedItem
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Retrieving Windows Update log from Server..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$uiHash.Listview.Items.EditItem($selectedItem)
$selectedItem.Notes = "Retrieving Update Log"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
. .\Scripts\Get-UpdateLog.ps1
Try {
$log = Get-UpdateLog -Computername $selectedItem.computer
If ($log) {
$log | Out-GridView -Title ("{0} Update Log" -f $selectedItem.computer)
$selectedItem.Notes = "Completed"
}
} Catch {
$selectedItem.notes = $_.Exception.Message
}
$uiHash.ProgressBar.value++
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
#Last100UpdateLog Event
$uiHash.Last100LogMenu.Add_Click({
If ($uiHash.Listview.Items.count -eq 1) {
$selectedItem = $uiHash.Listview.SelectedItem
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Retrieving Windows Update log from Server..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$uiHash.Listview.Items.EditItem($selectedItem)
$selectedItem.Notes = "Retrieving Update Log"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
. .\Scripts\Get-UpdateLog.ps1
Try {
$log = Get-UpdateLog -Last 100 -Computername $selectedItem.computer
If ($log) {
$log | Out-GridView -Title ("{0} Update Log" -f $selectedItem.computer)
$selectedItem.Notes = "Completed"
}
} Catch {
$selectedItem.notes = $_.Exception.Message
}
$uiHash.ProgressBar.value++
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
#Last50UpdateLog Event
$uiHash.Last50LogMenu.Add_Click({
If ($uiHash.Listview.Items.count -eq 1) {
$selectedItem = $uiHash.Listview.SelectedItem
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Retrieving Windows Update log from Server..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$uiHash.Listview.Items.EditItem($selectedItem)
$selectedItem.Notes = "Retrieving Update Log"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
. .\Scripts\Get-UpdateLog.ps1
Try {
$log = Get-UpdateLog -Last 50 -Computername $selectedItem.computer
If ($log) {
$log | Out-GridView -Title ("{0} Update Log" -f $selectedItem.computer)
$selectedItem.Notes = "Completed"
}
} Catch {
$selectedItem.notes = $_.Exception.Message
}
$uiHash.ProgressBar.value++
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
#Last25UpdateLog Event
$uiHash.Last25LogMenu.Add_Click({
If ($uiHash.Listview.Items.count -eq 1) {
$selectedItem = $uiHash.Listview.SelectedItem
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Retrieving Windows Update log from Server..."
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$uiHash.Listview.Items.EditItem($selectedItem)
$selectedItem.Notes = "Retrieving Update Log"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
. .\Scripts\Get-UpdateLog.ps1
Try {
$log = Get-UpdateLog -Last 25 -Computername $selectedItem.computer
If ($log) {
$log | Out-GridView -Title ("{0} Update Log" -f $selectedItem.computer)
$selectedItem.Notes = "Completed"
}
} Catch {
$selectedItem.notes = $_.Exception.Message
}
$uiHash.ProgressBar.value++
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
#Offline server removal
$uiHash.OfflineHostsMenu.Add_Click({
Write-Verbose "Removing any server that is shown as offline"
$Offline = @($uiHash.Listview.Items | Where {$_.Notes -eq "Offline"})
$Offline | ForEach {
Write-Verbose ("Removing {0}" -f $_.Computer)
$clientObservable.Remove($_)
}
$uiHash.ProgressBar.Maximum = $uiHash.Listview.ItemsSource.count
})
#ResetAuthorization Event
$uiHash.ResetAuthorizationMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$Servers = $uiHash.Listview.SelectedItems | Select -ExpandProperty Computer
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Forcing Reset Authorization on Servers"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Reset Authorization on Update Client"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
$wmi = @{
Computername = $computer.computer
Class = "Win32_Process"
Name = "Create"
ErrorAction = "Stop"
ArgumentList = "wuauclt /resetauthorization"
}
Try {
If ((Invoke-WmiMethod @wmi).ReturnValue -eq 0) {
$result = $True
} Else {
$result = $False
}
} Catch {
$result = $False
$returnMessage = $_.Exception.Message
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($result) {
$Computer.Notes = "Completed"
} Else {
$computer.notes = ("Issue Occurred: {0}" -f $returnMessage)
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
$uiHash.ProgressBar.value++
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending ResetAuthorization"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}
})
#DetectNow Event
$uiHash.ResetAuthorizationMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$Servers = $uiHash.Listview.SelectedItems | Select -ExpandProperty Computer
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Forcing Re-Detection of Update Client on Servers"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Re-Detect on Update Client"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
$wmi = @{
Computername = $computer.computer
Class = "Win32_Process"
Name = "Create"
ErrorAction = "Stop"
ArgumentList = "wuauclt /detectnow"
}
Try {
If ((Invoke-WmiMethod @wmi).ReturnValue -eq 0) {
$result = $True
} Else {
$result = $False
}
} Catch {
$result = $False
$returnMessage = $_.Exception.Message
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($result) {
$Computer.Notes = "Completed"
} Else {
$computer.notes = ("Issue Occurred: {0}" -f $returnMessage)
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
$uiHash.ProgressBar.value++
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending DetectNow"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}
})
#Rightclick Event
$uiHash.Listview.Add_MouseRightButtonUp({
Write-Debug "$($This.SelectedItem.Row.Computer)"
If ($uiHash.Listview.SelectedItems.count -eq 0) {
$uiHash.RemoveServerMenu.IsEnabled = $False
$uiHash.InstalledUpdatesMenu.IsEnabled = $False
$uiHash.WindowsUpdateLogMenu.IsEnabled = $False
$uiHash.WindowsUpdateServiceMenu.IsEnabled = $False
$uiHash.WUAUCLTMenu.IsEnabled = $False
} ElseIf ($uiHash.Listview.SelectedItems.count -eq 1) {
$uiHash.RemoveServerMenu.IsEnabled = $True
$uiHash.InstalledUpdatesMenu.IsEnabled = $True
$uiHash.WindowsUpdateLogMenu.IsEnabled = $True
$uiHash.WindowsUpdateServiceMenu.IsEnabled = $True
$uiHash.WUAUCLTMenu.IsEnabled = $True
} Else {
$uiHash.RemoveServerMenu.IsEnabled = $True
$uiHash.InstalledUpdatesMenu.IsEnabled = $True
$uiHash.WindowsUpdateLogMenu.IsEnabled = $False
$uiHash.WUAUCLTMenu.IsEnabled = $True
}
})
#ListView drop file Event
$uiHash.Listview.add_Drop({
$content = Get-Content $_.Data.GetFileDropList()
$content | ForEach {
$clientObservable.Add((
New-Object PSObject -Property @{
Computer = $_
Audited = 0 -as [int]
Installed = 0 -as [int]
InstallErrors = 0 -as [int]
Services = 0 -as [int]
Notes = $Null
}
))
}
Show-DebugState
})
#FindFile Button
$uiHash.BrowseFileButton.Add_Click({
$File = Open-FileDialog
If (-Not ([system.string]::IsNullOrEmpty($File))) {
Get-Content $File | Where {$_ -ne ""} | ForEach {
$clientObservable.Add((
New-Object PSObject -Property @{
Computer = $_
Audited = 0 -as [int]
Installed = 0 -as [int]
InstallErrors = 0 -as [int]
Services = 0 -as [int]
Notes = $Null
}
))
}
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Waiting for action..."
Show-DebugState
}
})
#LoadADButton Events
$uiHash.LoadADButton.Add_Click({
$domain = Open-DomainDialog
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Querying Active Directory for Computers..."
$Searcher = [adsisearcher]""
$Searcher.SearchRoot= [adsi]"LDAP://$domain"
$Searcher.Filter = ("(&(objectCategory=computer)(OperatingSystem=*server*))")
$Searcher.PropertiesToLoad.Add('name') | Out-Null
Write-Verbose "Checking for exempt list"
If (Test-Path Exempt.txt) {
Write-Verbose "Collecting systems from exempt list"
[string[]]$exempt = Get-Content Exempt.txt
}
$Results = $Searcher.FindAll()
foreach ($result in $Results) {
[string]$computer = $result.Properties.name
If ($Exempt -notcontains $computer -AND $clients -notcontains $computer) {
$clientObservable.Add((
New-Object PSObject -Property @{
Computer = $computer
Audited = 0 -as [int]
Installed = 0 -as [int]
InstallErrors = 0 -as [int]
Services = 0 -as [int]
Notes = $Null
}
))
} Else {
Write-Verbose "Excluding $computer"
}
}
$uiHash.ProgressBar.Maximum = $uiHash.Listview.ItemsSource.count
$Global:clients = $clientObservable | Select -Expand Computer
Show-DebugState
})
#RunButton Events
$uiHash.RunButton.add_Click({
Start-RunJob
})
#region Client WSUS Service Action
#Stop Service
$uiHash.WUStopServiceMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$Servers = $uiHash.Listview.SelectedItems | Select -ExpandProperty Computer
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Stopping WSUS Client service on selected servers"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Stopping Update Client Service"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
Try {
$updateClient = Get-Service -ComputerName $computer.computer -Name wuauserv -ErrorAction Stop
Stop-Service -inputObject $updateClient -ErrorAction Stop
$result = $True
} Catch {
$updateClient = $_.Exception.Message
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($result) {
$Computer.Notes = "Service Stopped"
} Else {
$computer.notes = ("Issue Occurred: {0}" -f $updateClient)
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Background",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Background",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Stop Service"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}
})
#Start Service
$uiHash.WUStartServiceMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$Servers = $uiHash.Listview.SelectedItems | Select -ExpandProperty Computer
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Starting WSUS Client service on selected servers"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Starting Update Client Service"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
Try {
$updateClient = Get-Service -ComputerName $computer.computer -Name wuauserv -ErrorAction Stop
Start-Service -inputObject $updateClient -ErrorAction Stop
$result = $True
} Catch {
$updateClient = $_.Exception.Message
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($result) {
$Computer.Notes = "Service Started"
} Else {
$computer.notes = ("Issue Occurred: {0}" -f $updateClient)
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Background",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Background",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Start Service"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}
})
#Restart Service
$uiHash.WURestartServiceMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$Servers = $uiHash.Listview.SelectedItems | Select -ExpandProperty Computer
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Restarting WSUS Client service on selected servers"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Restarting Update Client Service"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
Try {
$updateClient = Get-Service -ComputerName $computer.computer -Name wuauserv -ErrorAction Stop
Restart-Service -inputObject $updateClient -ErrorAction Stop
$result = $True
} Catch {
$updateClient = $_.Exception.Message
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($result) {
$Computer.Notes = "Service Restarted"
} Else {
$computer.notes = ("Issue Occurred: {0}" -f $updateClient)
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Background",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Background",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Pending Restart Service"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}
})
#endregion
#View Installed Update Event
$uiHash.GUIInstalledUpdatesMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$selectedItems = $uiHash.Listview.SelectedItems
[Float]$uiHash.ProgressBar.Maximum = $servers.count
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
$uiHash.RunButton.IsEnabled = $False
$uiHash.StartImage.Source = "$pwd\Images\Start_locked.jpg"
$uiHash.CancelButton.IsEnabled = $True
$uiHash.CancelImage.Source = "$pwd\Images\Stop.jpg"
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Gathering all installed patches on Servers"
$uiHash.StartTime = (Get-Date)
[Float]$uiHash.ProgressBar.Value = 0
$scriptBlock = {
Param (
$Computer,
$uiHash,
$Path,
$installedUpdates
)
$uiHash.ListView.Dispatcher.Invoke("Normal",[action]{
$uiHash.Listview.Items.EditItem($Computer)
$computer.Notes = "Querying Installed Updates"
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
Set-Location $Path
Try {
$updates = Get-HotFix -ComputerName $computer.computer -ErrorAction Stop | Where {$_.Description -ne ""}
If ($updates) {
$installedUpdates.AddRange($updates) | Out-Null
}
} Catch {
$result = $_.exception.Message
}
$uiHash.ListView.Dispatcher.Invoke("Background",[action]{
$uiHash.Listview.Items.EditItem($Computer)
If ($result) {
$computer.Notes = $result
} Else {
$computer.Notes = "Completed"
}
$uiHash.Listview.Items.CommitEdit()
$uiHash.Listview.Items.Refresh()
})
$uiHash.ProgressBar.Dispatcher.Invoke("Background",[action]{
$uiHash.ProgressBar.value++
})
$uiHash.Window.Dispatcher.Invoke("Background",[action]{
#Check to see if find job
If ($uiHash.ProgressBar.value -eq $uiHash.ProgressBar.Maximum) {
$End = New-Timespan $uihash.StartTime (Get-Date)
$uiHash.StatusTextBox.Text = ("Completed in {0}" -f $end)
$uiHash.RunButton.IsEnabled = $True
$uiHash.StartImage.Source = "$pwd\Images\Start.jpg"
$uiHash.CancelButton.IsEnabled = $False
$uiHash.CancelImage.Source = "$pwd\Images\Stop_locked.jpg"
}
})
}
Write-Verbose ("Creating runspace pool and session states")
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspaceHash.runspacepool = [runspacefactory]::CreateRunspacePool(1, $maxConcurrentJobs, $sessionstate, $Host)
$runspaceHash.runspacepool.Open()
ForEach ($Computer in $selectedItems) {
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument($computer).AddArgument($uiHash).AddArgument($Path).AddArgument($installedUpdates)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspaceHash.runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer.computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$jobs.Add($temp) | Out-Null
}
}
})
#ClearAuditReportMenu Events
$uiHash.ClearAuditReportMenu.Add_Click({
$updateAudit.Clear()
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Audit Report Cleared!"
})
#ClearInstallReportMenu Events
$uiHash.ClearInstallReportMenu.Add_Click({
Remove-Variable InstallPatchReport -scope Global -force -ea 'silentlycontinue'
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Install Report Cleared!"
})
#ClearInstalledUpdateMenu
$uiHash.ClearInstalledUpdateMenu.Add_Click({
Remove-Variable InstalledPatches -scope Global -force -ea 'silentlycontinue'
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Installed Updates Report Cleared!"
})
#ClearServerListMenu Events
$uiHash.ClearServerListMenu.Add_Click({
$clientObservable.Clear()
$uiHash.StatusTextBox.Foreground = "Black"
$uiHash.StatusTextBox.Text = "Server List Cleared!"
})
#AboutMenu Event
$uiHash.AboutMenu.Add_Click({
Open-PoshPAIGAbout
})
#Options Menu
$uiHash.OptionMenu.Add_Click({
#Launch options window
Write-Verbose "Launching Options Menu"
.\Options.ps1
#Process Updates Options
Set-PoshPAIGOption
})
#Select All
$uiHash.SelectAllMenu.Add_Click({
$uiHash.Listview.SelectAll()
})
#HelpFileMenu Event
$uiHash.HelpFileMenu.Add_Click({
Open-PoshPAIGHelp
})
#KeyDown Event
$uiHash.Window.Add_KeyDown({
$key = $_.Key
If ([System.Windows.Input.Keyboard]::IsKeyDown("RightCtrl") -OR [System.Windows.Input.Keyboard]::IsKeyDown("LeftCtrl")) {
Switch ($Key) {
"E" {$This.Close()}
"A" {$uiHash.Listview.SelectAll()}
"O" {
.\Options.ps1
#Process Updates Options
Set-PoshPAIGOption
}
"S" {Add-Server}
"D" {Remove-Server}
Default {$Null}
}
} ElseIf ([System.Windows.Input.Keyboard]::IsKeyDown("LeftShift") -OR [System.Windows.Input.Keyboard]::IsKeyDown("RightShift")) {
Switch ($Key) {
"RETURN" {Write-Host "Hit Shift+Return"}
}
}
})
#Key Up Event
$uiHash.Window.Add_KeyUp({
$Global:Test = $_
Write-Debug ("Key Pressed: {0}" -f $_.Key)
Switch ($_.Key) {
"F1" {Open-PoshPAIGHelp}
"F5" {Start-RunJob}
"F8" {Start-Report}
Default {$Null}
}
})
#AddServer Menu
$uiHash.AddServerMenu.Add_Click({
Add-Server
})
#RemoveServer Menu
$uiHash.RemoveServerMenu.Add_Click({
Remove-Server
})
#Run Menu
$uiHash.RunMenu.Add_Click({
Start-RunJob
})
#Report Menu
$uiHash.GenerateReportMenu.Add_Click({
Start-Report
})
#Exit Menu
$uiHash.ExitMenu.Add_Click({
$uiHash.Window.Close()
})
#ClearAll Menu
$uiHash.ClearAllMenu.Add_Click({
$clientObservable.Clear()
$content = $Null
[Float]$uiHash.ProgressBar.value = 0
$uiHash.StatusTextBox.Foreground = "Black"
$Global:updateAudit.Clear()
$uiHash.StatusTextBox.Text = "Waiting for action..."
})
#Clear Server List notes
$uiHash.ClearServerListNotesMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null}
}
})
#Save Server List
$uiHash.ServerListReportMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path (Join-Path $home Desktop) "serverlist.csv"
$uiHash.Listview.ItemsSource | Export-Csv -NoTypeInformation $savedreport
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
})
#HostListMenu
$uiHash.HostListMenu.Add_Click({
If ($uiHash.Listview.Items.count -gt 0) {
$uiHash.StatusTextBox.Foreground = "Black"
$savedreport = Join-Path $reportpath "hosts.txt"
$uiHash.Listview.DataContext | Select -Expand Computer | Out-File $savedreport
$uiHash.StatusTextBox.Text = "Report saved to $savedreport"
} Else {
$uiHash.StatusTextBox.Foreground = "Red"
$uiHash.StatusTextBox.Text = "No report to create!"
}
})
#Report Generation
$uiHash.GenerateReportButton.Add_Click({
Start-Report
})
#Clear Error log
$uiHash.ClearErrorMenu.Add_Click({
Write-Verbose "Clearing error log"
$Error.Clear()
})
#View Error Event
$uiHash.ViewErrorMenu.Add_Click({
Get-Error | Out-GridView
})
#ResetServerListData Event
$uiHash.ResetDataMenu.Add_Click({
Write-Verbose "Resetting Server List data"
$uiHash.Listview.ItemsSource | ForEach {$_.Notes = $Null;$_.Audited = 0;$_.Installed = 0;$_.InstallErrors = 0;$_.Services = 0}
})
#endregion
#Start the GUI
$uiHash.Window.ShowDialog() | Out-Null
script can be downloaded here
https://poshpaig.codeplex.com/releases/view/100929