updates controlled by script

This topic contains 1 reply, has 2 voices, and was last updated by  Richard Diphoorn 2 years, 4 months ago.

  • Author
    Posts
  • #26366

    Martin Manonym
    Participant

    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

  • #26368

    Richard Diphoorn
    Participant

    Aaaa Boe Prox' script. If you read this post, there's a comment saying that you need to run this script in PowerShell v3. Then the errors will go away.

    SOLUTION

You must be logged in to reply to this topic.