Jump to content

Recommended Posts

Posted (edited)

Edit: It's been several years since I first wrote this little tool, and it recently resurfaced due to recent posts.  It got my gears spinning (mostly my obsessive, compulsive tendencies) and motivated me to re-visit the code.  My coding style has improved a lot since then (or at least I feel...I'll let you be the judge.  Below is the "legacy" script with updates as recent as (Sep 2013), and beneath that is my WIP, updated script (with improved coding).  There is still a lot to do (things not working and a lot of code optimizing/cleanup), but I figured I'd share for anyone looking to see how experience and time can changes one's coding style--hopefully for the better.

Legacy Code

At my job we have to double and triple check to see if machines have been patched. I put this together to make checking a little easier. Very basic yes. Supports remote machines you have admin rights on.

Features

  • Query Local or Remote Automatic Updates History
  • Search and Sort and Export History
  • Find Actual Installed Updates
  • Determine Needed Updates
  • Download and Install Needed Updates (Local Machine Only)

Changes

  • Made quick change to scroll listview when searching.
  • Added simple sort to listview and fixed blank record in array.
  • Added tabs to start implementing additional features.
  • Added Needed updates func.
  • Added imagelist to update history listview to easily identify failed events.
  • Changed date format to sort properly.
  • Changed imagelist to ctrl bgcolor.
  • Resize gui method
  • Added Installed Patches tab.
  • Moved search field location and operation.

edit: Fixed bad data @ end of autoit tag and list tags.
edit: llewxam made some nice updates/additions on Post #22

#RequireAdmin
#NoTrayIcon
#include <GuiConstants.au3>
#include <GuiListView.au3>
#Include <GuiImageList.au3>
#include <misc.au3>

If Not _Singleton(@ScriptName) Then Exit

Global $find = -1
Global $items[1][5]
Global $colNeeded
Global $host
$WM_NOTIFY = 0x004E

$host = StringUpper(InputBox("Connect To","Hostname?",@ComputerName,"",200,120))
If $host = "" Then $host = @ComputerName
If Ping($host,100) = 0 Then
    msgbox(16,"Failed to Reach " & $host,"",5)
    Exit
EndIf

$winX = 800
$winY = 600
$gui = GUICreate("Automatic Updates Tool",$winX,$winY,-1,-1,0x00030000)
$hwnd = WinGetHandle("Automatic Updates Tool")
$mnu = GuiCtrlCreateMenu("&File")
$export = GUICtrlCreateMenuItem("&Export History" & @TAB & "Ctrl+Alt+E",$mnu)
$exit = GUICtrlCreateMenuItem("E&xit" & @TAB & "Alt+F4",$mnu)
$input = GUICtrlCreateInput("",$winX * .3,$winY - ($winY * 0.1575),$winX * .275,$winY * 0.04125)
    GuiCtrlSetFont(-1,$winY * 0.0175)
$searchbutton = GUICtrlCreateButton("Search",$winX * .6,$winY - ($winY * .1575),$winX * .1125,$winY * 0.04125)  
    GuiCtrlSetFont(-1,$winX * .01125,$winX * .25)
$tabs = GUICtrlCreateTab(0,0,$winX,$winY)
GUICtrlSetResizing(-1,1)
    $tab1 = GUICtrlCreateTabItem("History")
        $historylistview = GUICtrlCreateListView("Date|Title|Description|Result",0,$winY * 0.0675,$winX-4,$winY-($winY * 0.25))
            GUICtrlSetResizing(-1,4)
            _GUICtrlListView_SetColumnWidth($historylistview,0,$winX * .14275)
    $tab2 = GuiCtrlCreateTabItem("Installed")
        $installedlistview = GUICtrlCreateListView("Title|Description",0,$winY * 0.0675,$winX-4,$winY-($winY * 0.25))
            GUICtrlSetResizing(-1,4)
        $findbutton2 = GUICtrlCreateButton("Find Installed Updates",($winX-($winX * .17725))/2,($winY * 0.01275),$winX * .17725,$winY * 0.04125)
            GuiCtrlSetFont(-1,$winX * .01125)
    $tab3 = GuiCtrlCreateTabItem("Needed")
        $neededlistview = GUICtrlCreateListView("Title|Description|Status",0,$winY * 0.0675,$winX-2,$winY-($winY * 0.25),$LVS_SHOWSELALWAYS)
        $findbutton = GUICtrlCreateButton("Find Needed Updates",($winX-($winX * .17725))/2,($winY * 0.01275),$winX * .17725,$winY * 0.04125)
            GuiCtrlSetFont(-1,$winX * .01125)

$title = "Automatic Updates Tool - " & $host
WinSetTitle("Automatic Updates Tool","",$title)

_PopulateHistory($host)
_ResizeColumns(0)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
Global $B_DESCENDING[_GUICtrlListView_GetColumnCount ($historylistview) ]

GUISetState()

While 1
    If WinActive($title) Then
        HotKeySet("!^e","_Export")
        HotKeySet("{enter}","_Search")
    Else
        HotKeySet("!^e")
        HotKeySet("{enter}")
    EndIf
    sleep(10)
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_MAXIMIZE Then _ResizeColumns(1)
    If $msg = $GUI_EVENT_RESTORE Then _ResizeColumns()
    If $msg = -3 or $msg = $exit Then Exit
    If $msg = $findbutton then _PopulateNeeded($host)
    If $msg = $findbutton2 then _PopulateInstalled($host)
    If $msg = $searchbutton Then _Search()
    If $msg = $export Then _Export()
WEnd

Func _CreateMSUpdateSession($strHost = @ComputerName)
    $objSession = ObjCreate("Microsoft.Update.Session",$strHost)
    If Not IsObj($objSession) Then Return 0
    Return $objSession
EndFunc

Func _CreateSearcher($objSession)
    If Not IsObj($objSession) Then Return -1
    Return $objSession.CreateUpdateSearcher
EndFunc

Func _DateConv($varDate)
    $Year = StringLeft($varDate,4)
    $varDate = StringTrimLeft($varDate,4)
    $Month = Stringleft($varDate,2)
    $varDate = StringTrimLeft($varDate,2)
    $Day = Stringleft($varDate,2)
    $varDate = StringTrimLeft($varDate,2)
    $Hour = Stringleft($varDate,2)
    $varDate = StringTrimLeft($varDate,2)
    $Minute = Stringleft($varDate,2)
    $varDate = StringTrimLeft($varDate,2)
    $Second = Stringleft($varDate,2)
    $varDate = StringTrimLeft($varDate,2)
    Return $Year & "/" & $Month & "/" & $Day & " " & $Hour & ":" & $Minute & ":" & $Second
EndFunc

Func _Export()
    $file = FileSelectFolder("Export to destination folder","",0,@ScriptDir)
    If $file = "" Then Return -6
    $file &= "\" & $host & "-UpdateHistory.csv"
    $wrkfile = FileOpen($file,2)

    $arrHistory = _FetchHistoryData($host)

    For $i = 0 to UBound($arrHistory) -1
        For $x = 0 to 3
            FileWrite($wrkfile,Chr(34) & StringReplace($arrHistory[$i][$x],Chr(34),"'") & Chr(34))
            If $x < 3 Then FileWrite($wrkfile,",")
        Next
        FileWrite($wrkfile,@CRLF)
    Next
    FileClose($wrkfile)
    msgbox(0,"Export Complete","Saved to " & $file)
    Return 1
EndFunc

Func _FetchHistoryData($host)
    $objSearcher = _CreateSearcher(_CreateMSUpdateSession($host))
    $arrHistory = _GetHistory(_GetTotalHistoryCount($objSearcher),$objSearcher)
    $objSearcher = 0

    If Not IsArray($arrHistory) Then
        msgbox(16,"Failed to Fetch History " & $host,"",5)
        Return 0
    EndIf
   
    Return $arrHistory
EndFunc

Func _FetchInstalledData($host)
    $objSearcher = _CreateSearcher(_CreateMSUpdateSession($host))
    $colInstalled = _GetInstalled($objSearcher)
    $objSearcher = 0
    Dim $arrInstalled[1][2]

    For $i = 0 To $colInstalled.Updates.Count-1
        If $i < $colInstalled.Updates.Count-1 Then ReDim $arrInstalled[$i+2][2]
        $update = $colInstalled.Updates.Item($i)
        $arrInstalled[$i][0] = $update.Title
        $arrInstalled[$i][1] = $update.Description
    Next
   
    If Not IsArray($arrInstalled) Then
        msgbox(16,"Failed to Fetch Installed Updates " & $host,"",5)
        Return 0
    EndIf
   
    Return $arrInstalled
EndFunc

Func _FetchNeededData($host)
    $objSearcher = _CreateSearcher(_CreateMSUpdateSession($host))
    $colNeeded = _GetNeededUpdates($objSearcher)
    $objSearcher = 0
    Dim $arrNeeded[1][2]

    For $i = 0 To $colNeeded.Updates.Count-1
        If $i < $colNeeded.Updates.Count-1 Then ReDim $arrNeeded[$i+2][2]
        $update = $colNeeded.Updates.Item($i)
        $arrNeeded[$i][0] = $update.Title
        $arrNeeded[$i][1] = $update.Description
    Next

    If Not IsArray($arrNeeded) Then
        msgbox(16,"Failed to Fetch Needed Updates " & $host,"",5)
        Return 0
    EndIf
   
    Return $arrNeeded
EndFunc

Func _GetHistory($varTotalHistoryCount,$objSearcher)
    If Not $varTotalHistoryCount or Not IsObj($objSearcher) Then Return -3
    Dim $arrHistory[1][4]
    $idx = 0
    $colHistory = $objSearcher.QueryHistory(1, $varTotalHistoryCount)
    For $objEntry in $colHistory
        ReDim $arrHistory[$idx+1][4]
        $arrHistory[$idx][0] = _DateConv($objEntry.Date)
        $arrHistory[$idx][1] = $objEntry.Title
        $arrHistory[$idx][2] = $objEntry.Description
        If $objEntry.ResultCode = 2 Then
            $arrHistory[$idx][3] = "Successful"
        Else
            $arrHistory[$idx][3] = "Failed"
        EndIf
        $idx += 1
    Next
    Return $arrHistory
EndFunc

Func _GetInstalled($objSearcher)
    If Not IsObj($objSearcher) Then Return -4
    $colInstalled = $objSearcher.Search("IsInstalled=1 and Type='Software'")
    Return $colInstalled
EndFunc

Func _GetNeededUpdates($objSearcher)
    If Not IsObj($objSearcher) Then Return -5
    $colNeeded = $objSearcher.Search("IsInstalled=0 and Type='Software'")
    Return $colNeeded
EndFunc

Func _GetTotalHistoryCount($objSearcher)
    If Not IsObj($objSearcher) Then Return -2
    Return $objSearcher.GetTotalHistoryCount
EndFunc

Func _HighlightPatchResults()
    For $i = 0 to UBound($items)-1
        $item = _GUICtrlListView_GetItemText($historylistview,$i,3)
        $find = _ArraySearch($items,$item,0,0,0,0,0,2)
        _GUICtrlListView_SetItemSelected($historylistview,$find,False)
        If $find <> $i And $find <> -1 Then
            For $x = 1 to 4
                $tempval = $items[$i][$x]
                $items[$i][$x] = $items[$find][$x]
                $items[$find][$x] = $tempval
            _ArraySwap($items[$find][$x],$items[$i][$x])
            Next
            msgbox(0,$item,$items[$find][3])
        EndIf
        If _GUICtrlListView_GetItemText($historylistview,$i,3) = "Failed" Then
            GUICtrlSetBkColor($items[$i][0],0xFF0000)
        Else
            GUICtrlSetBkColor($items[$i][0],0xFFFFFF)
        EndIf
    Next
EndFunc

Func _PopulateHistory($host)
    $arrHistory = _FetchHistoryData($host)
   
    For $i = 0 to UBound($arrHistory) -1
        $strItem = $arrHistory[$i][0] & "|" & $arrHistory[$i][1] & "|" & $arrHistory[$i][2] & "|" & $arrHistory[$i][3]
        $items[$i][0] = GUICtrlCreateListViewItem($strItem,$historylistview)
        For $x = 0 to 3
            $items[$i][$x+1] = $arrHistory[$i][$x]
        Next
        If $i < UBound($arrHistory)-1 then ReDim $items[$i+2][5]
    Next

    _HighlightPatchResults()

    $objSearcher = 0
    $arrHistory = 0
EndFunc

Func _PopulateInstalled($host)
    HotKeySet("{enter}")
    GuiCtrlSetState($findbutton2,$GUI_DISABLE)
    _GUICtrlListView_DeleteAllItems(ControlGetHandle($gui,"",$installedlistview))
   
    SplashTextOn("Please Wait.","Finding Installed Updates",200,30,-1,-1,32)
   
    $arrInstalled = _FetchInstalledData($host)
   
    SplashOff()
   
    If IsArray($arrInstalled) and $arrInstalled[0][0]<>"" Then
        For $i = 0 to UBound($arrInstalled) -1
            _GUICtrlListView_AddItem($installedlistview,$arrInstalled[$i][0])
            _GUICtrlListView_AddSubItem($installedlistview,$i,$arrInstalled[$i][1],1)
        Next
    EndIf
   
    GuiCtrlSetData($findbutton2,"Refresh")
    GuiCtrlSetState($findbutton2,$GUI_ENABLE)
   
    $arrInstalled = 0
EndFunc

Func _PopulateNeeded($host)
    HotKeySet("{enter}")
    If StringInstr(GUICtrlRead($findbutton),"Install") then
        _UpdatesDownloadAndInstall()
        Return 0
    EndIf
    GuiCtrlSetState($findbutton,$GUI_DISABLE)
    _GUICtrlListView_DeleteAllItems(ControlGetHandle($gui,"",$neededlistview))
   
    SplashTextOn("Please Wait.","Finding Needed Updates",200,30,-1,-1,32)
   
    $arrNeeded = _FetchNeededData($host)

    SplashOff()

    If IsArray($arrNeeded) and $arrNeeded[0][0]<>"" Then
        For $i = 0 to UBound($arrNeeded) -1
            _GUICtrlListView_AddItem($neededlistview,$arrNeeded[$i][0])
            _GUICtrlListView_AddSubItem($neededlistview,$i,$arrNeeded[$i][1],1)
        Next
        If $host = @ComputerName Then GUICtrlSetData($findbutton,"Download and Install")
    Else
        _GUICtrlListView_AddItem($neededlistview,"No Needed Updates Found")
    EndIf

    GuiCtrlSetState($findbutton,$GUI_ENABLE)
    $objSearcher = 0
    $arrNeeded = 0
EndFunc

Func _ResizeColumns($type = 0)
    $winPos = WinGetPos("Automatic Updates Tool")
    $winX = $winPos[2]
    $winY = $winPos[3]
    If $type = 0 Then
        _GUICtrlListView_SetColumnWidth($historylistview,1,$winX * .35)
        _GUICtrlListView_SetColumnWidth($historylistview,2,$winX * .42)
        _GUICtrlListView_SetColumnWidth($installedlistview,0,$winX * .4125)
    Else
        _GUICtrlListView_SetColumnWidth($historylistview,1,$LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($historylistview,2,$winX * .5)
        _GUICtrlListView_SetColumnWidth($installedlistview,0,$LVSCW_AUTOSIZE)
    EndIf
    _GUICtrlListView_SetColumnWidth($historylistview,3,$LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($neededlistview,0,$winX*.34275)
    _GUICtrlListView_SetColumnWidth($neededlistview,1,$winX*.525)
    _GUICtrlListView_SetColumnWidth($neededlistview,2,$winX*.1125)
    _GUICtrlListView_SetColumnWidth($installedlistview,1,$winX * .575)
EndFunc

Func _Search()
    $strText = GUICtrlRead($input,1)
    If $strText = "" Then Return -6
    $current = _SearchTab()
    Switch $current
        Case 1
            $list = $historylistview
        Case 2
            $list = $installedlistview
    EndSwitch
   
    $find = _GUICtrlListView_FindInText($list,$strText,$find)
    If $find <> -1 Then
        GuiCtrlSetData($searchbutton,"Next")
        _GUICtrlListView_SetItemSelected($list,$find,True)
        _GUICtrlListView_Scroll($list,0,-5000)
        _GUICtrlListView_Scroll($list,0,$find * 7)
    Else
        GuiCtrlSetData($searchbutton,"Search")
        _GUICtrlListView_SetItemSelected($list,0,True)
        _GUICtrlListView_SetItemSelected($list,0,False)
    EndIf
EndFunc

Func _SearchTab()
    $hwnd = WinGetHandle("Automatic Updates Tool")
    $control = ControlGetHandle($hwnd,"",$tabs)
    $current = ControlCommand($hwnd,"",$control,"CurrentTab")
    Return $current
EndFunc

Func _UpdatesDownloadAndInstall()
    HotKeySet("{enter}")
    $selected = _GUICtrlListView_GetSelectedIndices($neededlistview,True)
    If $selected[0] = 0 Then
        Return 0
    EndIf
    GuiCtrlSetState($findbutton,$GUI_DISABLE)
    $objSearcher = _CreateMSUpdateSession($host)
    For $x = 1 To $selected[0]
        $item = _GUICtrlListView_GetItemText($neededlistview,$selected[$x])
        For $i = 0 To $colNeeded.Updates.Count-1
            $update = $colNeeded.Updates.Item($i)
            If $item = $update.Title Then
                _GUICtrlListView_SetItemText($neededlistview,$i,"Downloading...",2)
                $updatesToDownload = ObjCreate("Microsoft.Update.UpdateColl")
                $updatesToDownload.Add ($update)
                $DownloadSession = $objSearcher.CreateUpdateDownloader()
                $DownloadSession.Updates = $updatesToDownload
                $DownloadSession.Download
                _GUICtrlListView_SetItemText($neededlistview,$i,"Downloaded",2)
            EndIf
        Next
    Next
   
    $reboot= 0
    For $x = 1 To $selected[0]
        $item = _GUICtrlListView_GetItemText($neededlistview,$selected[$x])
        For $i = 0 To $colNeeded.Updates.Count-1
            $update = $colNeeded.Updates.Item($i)
            If $item = $update.Title And $update.IsDownloaded Then
                _GUICtrlListView_SetItemText($neededlistview,$i,"Installing...",2)
                $InstallSession = $objSearcher.CreateUpdateInstaller()
                $updatesToInstall = ObjCreate("Microsoft.Update.UpdateColl")
                $updatesToInstall.Add($update)
                $InstallSession.Updates = $updatesToInstall
                $installresult = $InstallSession.Install
                If $installresult.RebootRequired Then $reboot = 1
                _GUICtrlListView_SetItemText($neededlistview,$i,"Complete",2)
            EndIf
        Next
    Next
   
    If $reboot Then Msgbox(0,"Installation Complete","A Reboot is Required.")
   
    GuiCtrlSetState($findbutton,$GUI_ENABLE)
    GUICtrlSetData($findbutton,"Find Needed Updates")
    $DownloadSession = 0
    $updatesToDownload = 0
    Return 0
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
    $hWndListView = GUICtrlGetHandle($historylistview)
    $hWndInstalled = GUICtrlGetHandle($installedlistview)
    $hWndTabs = GUICtrlGetHandle($tabs)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $LVN_COLUMNCLICK ; A column was clicked
                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    _GUICtrlListView_SimpleSort ($hWndListView, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"))
                    _HighlightPatchResults()
            EndSwitch
        Case $hWndInstalled
            Switch $iCode
                Case $LVN_COLUMNCLICK ; A column was clicked
                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    _GUICtrlListView_SimpleSort ($hWndInstalled, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"))
            EndSwitch          
        Case $hWndTabs
            Switch $iCode
                Case -551
                    $current = _SearchTab()
                    If $current = 3 Then
                        GuiCtrlSetState($input,$GUI_DISABLE)
                        GUIctrlSetState($searchbutton,$GUI_DISABLE)
                    Else
                        GuictrlSetState($input,$GUI_ENABLE)
                        GUIctrlSetState($searchbutton,$GUI_ENABLE)
                    EndIf
            EndSwitch
    EndSwitch
    ;Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

New Code

Changes

  • Adopted Best-Coding style practices
  • Consolidated three FetchData functions into one
  • Converted GUI into OnEvent Driven interaction
  • Added comments galore

ToDo

  • More cleanup, more error checking, more comments
  • Fix Row Highlight functionality
#Region - Setup
#RequireAdmin
;#NoTrayIcon

#include <GuiConstants.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <Misc.au3>
;Singleton
If Not _Singleton(@ScriptName) Then Exit
;Define Global Vaiables
Global $iFind = -1, $aItems[1][5], $sHost
Global $aGUI[1] = ["hWnd|id"]    ;Create "Master" Array with GUI/Control IDs/hWnd for easy reference
Global Enum $hGUI = 1, $idMnuFile, $idMnuFileExport, $idMnuFileExit, $idInput, $idBtnSearch, $idTabs, $idTabHistory, $idTabInstalled, $idTabNeeded, $idListViewHistory, $idListViewInstalled, $idListViewNeeded, $idBtnFindInstalled, $idBtnFindNeeded, $iGUILast
ReDim $aGUI[$iGUILast]
Opt("GUIOnEventMode", 1)        ;Enable/Set OnEvent Mode
#EndRegion - Setup

Main()

Func Main()
    If Not _AUTool_HostConnect() Then Exit  ;If Hostname is not valid or not reachable Exit
    _AUTool_CreateGUI() ;Load GUI
    While 1 ;Main Loop
        Sleep(10)
    WEnd
    _Exit()
EndFunc   ;==>Main

#Region - Functions
Func _AUTool_HostConnect()
    $sHost = StringUpper(InputBox("Connect To", "Hostname?", @ComputerName, "", 200, 120))  ;Prompt for Hostname
    If $sHost = "" Then Return SetError(1, 0, 0)    ;If Hostname string not valid
    If Not Ping($sHost, 1000) Then Return SetError(2, 0, 0) ;Attempt to reach host via Ping, Error Our if Fail
    Return SetError(0, 0, 1)        ;Return Success
EndFunc   ;==>_AUTool_HostConnect

Func _AUTool_CreateGUI()
    Local $iWinX = @DesktopWidth * .75  ;Collect Dimensions
    Local $iWinY = @DesktopHeight * .75
    $aGUI[$hGUI] = GUICreate("Automatic Updates Tool", $iWinX, $iWinY, -1, -1, 0x00030000)  ;Create GUI
    $aGUI[$idMnuFile] = GUICtrlCreateMenu("&File")  ;Create File Menu
    $aGUI[$idMnuFileExport] = GUICtrlCreateMenuItem("&Export History" & @TAB & "Ctrl+Alt+E", $aGUI[$idMnuFile])
    GUICtrlSetOnEvent(-1, "_AUTool_Export")
    GUICtrlCreateMenuItem("", $aGUI[$idMnuFile])
    $aGUI[$idMnuFileExit] = GUICtrlCreateMenuItem("E&xit" & @TAB & "Alt+F4", $aGUI[$idMnuFile])
    GUICtrlSetOnEvent(-1, "_Exit")
    $aGUI[$idInput] = GUICtrlCreateInput("", $iWinX * .3, $iWinY - ($iWinY * 0.1575), $iWinX * .275, $iWinY * 0.04125)  ;Create Inputbox
    GUICtrlSetFont(-1, $iWinY * 0.0175)
    $aGUI[$idBtnSearch] = GUICtrlCreateButton("Search", $iWinX * .6, $iWinY - ($iWinY * .1575), $iWinX * .1125, $iWinY * 0.04125)       ;Create Search Button
    GUICtrlSetFont(-1, $iWinX * .01125, $iWinX * .25)
    GUICtrlSetOnEvent(-1, "_AUTool_Search")
    $aGUI[$idTabs] = GUICtrlCreateTab(0, 0, $iWinX, $iWinY)     ;Create Tab Master Control
    GUICtrlSetResizing(-1, 1)
    $aGUI[$idTabHistory] = GUICtrlCreateTabItem("History")      ;Create History Tab
    $aGUI[$idListViewHistory] = GUICtrlCreateListView("Date|Title|Description|Result", 0, $iWinY * 0.0675, $iWinX - 4, $iWinY - ($iWinY * 0.25))
    GUICtrlSetResizing(-1, 4)
    _GUICtrlListView_SetColumnWidth($aGUI[$idListViewHistory], 0, $iWinX * .14275)
    $aGUI[$idTabInstalled] = GUICtrlCreateTabItem("Installed")  ;Create Installed Tab
    $aGUI[$idListViewInstalled] = GUICtrlCreateListView("Title|Description", 0, $iWinY * 0.0675, $iWinX - 4, $iWinY - ($iWinY * 0.25))
    GUICtrlSetResizing(-1, 4)
    $aGUI[$idBtnFindInstalled] = GUICtrlCreateButton("Find Installed Updates", ($iWinX - ($iWinX * .17725)) / 2, ($iWinY * 0.01275), $iWinX * .17725, $iWinY * 0.04125)
    GUICtrlSetFont(-1, $iWinX * .01125)
    GUICtrlSetOnEvent(-1, "_AUTool_PopulateInstalled")
    $aGUI[$idTabNeeded] = GUICtrlCreateTabItem("Needed")        ;Create Needed Tab
    $aGUI[$idListViewNeeded] = GUICtrlCreateListView("Title|Description|Status", 0, $iWinY * 0.0675, $iWinX - 2, $iWinY - ($iWinY * 0.25), $LVS_SHOWSELALWAYS)
    $aGUI[$idBtnFindNeeded] = GUICtrlCreateButton("Find Needed Updates", ($iWinX - ($iWinX * .17725)) / 2, ($iWinY * 0.01275), $iWinX * .17725, $iWinY * 0.04125)
    GUICtrlSetFont(-1, $iWinX * .01125)
    GUICtrlSetOnEvent(-1, "_AUTool_PopulateNeeded")
    GUICtrlCreateTabItem("")
    Local $sTitle = "Automatic Updates Tool - " & $sHost        ;Set Window Title
    WinSetTitle("Automatic Updates Tool", "", $sTitle)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")        ;Set GUI Event Functions
    GUISetOnEvent($GUI_EVENT_MAXIMIZE, "_AUTool_Maximize")
    GUISetOnEvent($GUI_EVENT_RESTORE, "_AUTool_Restore")
    Global $B_DESCENDING[_GUICtrlListView_GetColumnCount ($aGUI[$idListViewHistory]) ]      ;Set Sort Direction Array
    _AUTool_PopulateHistory()       ;Load Patch History
    _AUTool_ResizeColumns()     ;Resize Columns
    GUIRegisterMsg($WM_NOTIFY, "_AUTool_WM_NOTIFY")     ;Register Notify Messages Handler
    GUISetState()   ;Display GUI
EndFunc   ;==>_AUTool_CreateGUI

Func _Exit()
    GUIDelete($aGUI[$hGUI]) ;Delete GUI
    Exit
EndFunc   ;==>_Exit

Func _AUTool_Maximize()
    _AUTool_ResizeColumns(1)    ;Resize Columns after Maximize
EndFunc   ;==>_AUTool_Maximize

Func _AUTool_Restore()
    _AUTool_ResizeColumns() ;Resize Columns after Restore
EndFunc   ;==>_AUTool_Restore

Func _AUTool_CreateMSUpdateSession()
    Local $objSession = ObjCreate("Microsoft.Update.Session", $sHost)   ;Create MS Update Session Object
    Return $objSession  ;Return MS Update Session Object
EndFunc   ;==>_CreateMSUpdateSession

Func _AUTool_CreateSearcher($objSession)
    If Not IsObj($objSession) Then Return -1    ;Verify Session Object
    Return $objSession.CreateUpdateSearcher ;Create Session Update Searcher
EndFunc   ;==>_CreateSearcher

Func _AUTool_DateConv($sDate)
    ;Convert DateTime string into Human Friendly YYYY/MM/DD HH:MM:SS Format
    Local $iYear = StringMid($sDate, 1, 4)
    Local $iMonth = StringMid($sDate, 5, 2)
    Local $iDay = StringMid($sDate, 7, 2)
    Local $iHour = StringMid($sDate, 9, 2)
    Local $iMinute = StringMid($sDate, 11, 2)
    Local $iSecond = StringMid($sDate, 13, 2)
    Local $sDateTime = $iYear & "/" & $iMonth & "/" & $iDay & " " & $iHour & ":" & $iMinute & ":" & $iSecond
    Return $sDateTime
EndFunc   ;==>_DateConv

Func _AUTool_Export()
    Local $sFile = FileSelectFolder("Export to destination folder", "", 0, @ScriptDir)  ;Prompt for Destination Folder
    If $sFile = "" Then Return SetError(1, 0, 0)    ;If Destination is Null Error Out
    $sFile &= "\" & $sHost & "-UpdateHistory.csv"   ;Set Export Filename
    $hFile = FileOpen($sFile, 2)    ;Open Export File I/O Handle
;Local $aHistory = _AUTool_FetchHistoryData()   ;Collect History
    Local $aHistory = _AUTool_FetchData(1)  ;Collect History
    For $iIndxA = 0 To UBound($aHistory) - 1    ;Loop Through History Array
        For $iIndxB = 0 To 3
            FileWrite($hFile, Chr(34) & StringReplace($aHistory[$iIndxA][$iIndxB], Chr(34), "'") & Chr(34)) ;Write CSV Column
            If $iIndxB < 3 Then FileWrite($hFile, ",")  ;Write Column Separator
        Next
        FileWrite($hFile, @CRLF)    ;Write CRLF
    Next
    FileClose($hFile)   ;Close File I/O Handle
    Return MsgBox(0, "Export Complete", "Saved to " & $sFile)   ;Export Complete Message
EndFunc   ;==>_Export

Func _AUTool_FetchData($iMode = 0)
    Local $oSearcher = _AUTool_CreateSearcher(_AUTool_CreateMSUpdateSession())      ;Create MS Update Searcher Object
    Switch $iMode       ;Determine Which Data to Collect Based on $iMode Param
        Case 1  ;Collect Patch History
            Local $aData = _AUTool_GetHistory(_AUTool_GetTotalHistoryCount($oSearcher), $oSearcher)
            $objSearcher = 0    ;Cleanup
            If Not IsArray($aData) Then Return SetError(2, MsgBox(16, "Failed to Fetch History from " & $sHost, "", 5), 0)  ;Validate Array
            Return $aData   ;Return Array
        Case 2  ;Get Installed Patches Collection Object
            Local $oCol = _AUTool_GetInstalled($oSearcher)
        Case 3  ;Get Needed Patches Collection Object
            Local $oCol = _AUTool_GetNeededUpdates($oSearcher)
        Case Else   ;Invalid $iMode Option / Error Out
            $oSearcher = 0
            Return SetError(1, 0, 0)
    EndSwitch
    $oSearcher = 0  ;Cleanup
    Local $iUpdateCount = $oCol.Updates.Count   ;Create Integer of Update Count for MultiReference
    Local $aData[$iUpdateCount][2]  ;Create Data Array to Populate From Collection
    For $iIndx = 0 To $iUpdateCount - 1 ;Loop Through Collection
        Local $oUpdate = $oCol.Updates.Item($iIndx) ;Create Update Object and Collect Info
        $aData[$iIndx][0] = $oUpdate.Title
        $aData[$iIndx][1] = $oUpdate.Description
    Next
    If Not IsArray($aData) Then Return SetError(3, MsgBox(16, "Failed to Fetch Data from " & $sHost, "", 5), 0) ;If No Records Obtained Exit Function
    Return $aData   ;Return Installed Data Array
EndFunc

Func _AUTool_GetHistory($iTotalHistoryCount, $oSearcher)
    If Not $iTotalHistoryCount Or Not IsObj($oSearcher) Then Return SetError(1, 0, 0)   ;Validate History Count and MS Update Session Seasrch Object
    Local $aHistory[$iTotalHistoryCount-1][4]   ;Create Lccal Array and Index Counter
    Local $iIndx = 0
    $oColHistory = $oSearcher.QueryHistory(1, $iTotalHistoryCount)  ;Create Collection Object of Patch History
    For $oEntry In $oColHistory ;Loop Through Collection and Populate History Array
        $aHistory[$iIndx][0] = _AUTool_DateConv($oEntry.Date)
        $aHistory[$iIndx][1] = $oEntry.Title
        $aHistory[$iIndx][2] = $oEntry.Description
        If $oEntry.ResultCode = 2 Then
            $aHistory[$iIndx][3] = "Successful"
        Else
            $aHistory[$iIndx][3] = "Failed"
        EndIf
        $iIndx += 1 ;Increment Index Counter
    Next
    Return $aHistory    ;Return Populated History Array
EndFunc   ;==>_GetHistory

Func _AUTool_GetInstalled(ByRef $oSearcher)
    If Not IsObj($oSearcher) Then Return SetError(1, 0, 0)  ;If not Valid MS Update Session Search Object Return Error
    $oCol = $oSearcher.Search("IsInstalled=1 and Type='Software'")  ;Obtain Collection from Search Object to Collect Installed Patches
    Return $oCol    ;Return Collection
EndFunc   ;==>_GetInstalled

Func _AUTool_GetNeededUpdates(ByRef $oSearcher)
    If Not IsObj($oSearcher) Then Return SetError(1, 0, 0)  ;If not Valid MS Update Session Search Object Return Error
    $oCol = $oSearcher.Search("IsInstalled=0 and Type='Software'")  ;Obtain Collection from Search Object to Collect Needed Patches
    Return $oCol    ;Return Collection
EndFunc   ;==>_GetNeededUpdates

Func _AUTool_GetTotalHistoryCount(ByRef $oSearcher)
    If Not IsObj($oSearcher) Then Return SetError(1, 0, 0)  ;If not Valid MS Update Session Search Object Return Error
    Return $oSearcher.GetTotalHistoryCount  ;Return Search Object History Count Value
EndFunc   ;==>_GetTotalHistoryCount

Func _AUTool_HighlightHistoryPatchResults()
    ;Loop Through Items Array
    For $iIndxA = 0 To UBound($aItems) - 1
;~         $sItem = _GUICtrlListView_GetItemText($aGUI[$idListViewHistory], $iIndxA, 3)
;~         $iFind = _ArraySearch($aItems, $aItems, 0, 0, 0, 0, 0, 2)
;~         _GUICtrlListView_SetItemSelected($aGUI[$idListViewHistory], $iFind, False)
;~         If $iFind <> $iIndxA And $iFind <> -1 Then
;~             For $iIndxB = 1 To 4
;~                 $tempval = $aItems[$iIndxA][$iIndxB]
;~                 $aItems[$iIndxA][$iIndxB] = $aItems[$iFind][$iIndxB]
;~                 $aItems[$iFind][$iIndxB] = $tempval
;~                 _ArraySwap($aItems, $aItems[$iFind][$iIndxB], $aItems[$iIndxA][$iIndxB])
;~             Next
;~         EndIf
        If _GUICtrlListView_GetItemText($aGUI[$idListViewHistory], $iIndxA, 3) = "Failed" Then
            GUICtrlSetBkColor($aItems[$iIndxA][0], 0xFF0000)
        Else
            GUICtrlSetBkColor($aItems[$iIndxA][0], 0xFFFFFF)
        EndIf
    Next
EndFunc   ;==>_HighlightPatchResults

Func _AUTool_PopulateHistory()
;Local $aHistory = _AUTool_FetchHistoryData()
    Local $aHistory = _AUTool_FetchData(1)  ;Collect History Data as Array
    Local $iCount = UBound($aHistory)
    ReDim $aItems[$iCount][5]   ;Redefine Items Array
    ;Loop Through History Data Array and Populate History Listview
    For $iIndxA = 0 To $iCount - 1
        Local $sItem = $aHistory[$iIndxA][0] & "|" & $aHistory[$iIndxA][1] & "|" & $aHistory[$iIndxA][2] & "|" & $aHistory[$iIndxA][3]
        $aItems[$iIndxA][0] = GUICtrlCreateListViewItem($sItem, $aGUI[$idListViewHistory])
        For $iIndxB = 0 To 3
            $aItems[$iIndxA][$iIndxB + 1] = $aHistory[$iIndxA][$iIndxB]
        Next
        ;If $iIndxA < UBound($aHistory) - 1 Then ReDim $aItems[$iIndxA + 2][5]
    Next
    ;Highlight Patch History Results
;_AUTool_HighlightHistoryPatchResults()
    $aHistory = 0   ;Cleanup
    Return 1
EndFunc   ;==>_PopulateHistory

Func _AUTool_PopulateInstalled()
    GUICtrlSetState($aGUI[$idBtnFindInstalled], $GUI_DISABLE)   ;Disable Button to Prevent Multiple Clicks / Stacked Commands/Executions
    _GUICtrlListView_DeleteAllItems(ControlGetHandle($aGUI[$hGUI], "", $aGUI[$idListViewInstalled]))    ;Clear Installed ListView
    SplashTextOn("Please Wait.", "Finding Installed Updates", 300, 30, -1, -1, 32)  ;Display Wait Window
;Local $aInstalled = _AUTool_FetchInstalledData()
    Local $aInstalled = _AUTool_FetchData(2)    ;Create Local Array with Installed Patch Info
    SplashOff() ;Turn Off Wait Window
    If IsArray($aInstalled) And $aInstalled[0][0] <> "" Then    ;Loop Through Installed Patches Array
        For $iIndxA = 0 To UBound($aInstalled) - 1
            _GUICtrlListView_AddItem($aGUI[$idListViewInstalled], $aInstalled[$iIndxA][0])
            _GUICtrlListView_AddSubItem($aGUI[$idListViewInstalled], $iIndxA, $aInstalled[$iIndxA][1], 1)
        Next
    EndIf
    GUICtrlSetData($aGUI[$idBtnFindInstalled], "Refresh")   ;Enable and Set GUI Button Text
    GUICtrlSetState($aGUI[$idBtnFindInstalled], $GUI_ENABLE)
    $aInstalled = 0 ;Cleanup
EndFunc   ;==>_PopulateInstalled

Func _AUTool_PopulateNeeded()
    If StringInStr(GUICtrlRead($aGUI[$idBtnFindNeeded]), "Install") Then    ;If Button says Install and is Clicked Then Do It
        _AUTool_UpdatesDownloadAndInstall()
        Return 0
    EndIf
    GUICtrlSetState($aGUI[$idBtnFindNeeded], $GUI_DISABLE)  ;Disable Button to Prevent Multiple Clicks / Stacked Commands/Executions
    _GUICtrlListView_DeleteAllItems(ControlGetHandle($aGUI[$hGUI], "", $aGUI[$idListViewNeeded]))   ;Clear Installed ListView
    SplashTextOn("Please Wait.", "Finding Needed Updates", 300, 30, -1, -1, 32) ;Display Wait Window
;Local $aNeeded = _AUTool_FetchNeededData()
    Local $aNeeded = _AUTool_FetchData(3)   ;Create Local Array with Needed Patch Info
    SplashOff() ;Turn Off Wait Window
    If IsArray($aNeeded) And $aNeeded[0][0] <> "" Then      ;Loop Through Needed Patches Array
        For $iIndxA = 0 To UBound($aNeeded) - 1
            _GUICtrlListView_AddItem($aGUI[$idListViewNeeded], $aNeeded[$iIndxA][0])
            _GUICtrlListView_AddSubItem($aGUI[$idListViewNeeded], $iIndxA, $aNeeded[$iIndxA][1], 1)
        Next
        If $sHost = @ComputerName Then GUICtrlSetData($aGUI[$idBtnFindNeeded], "Download and Install")
    Else
        _GUICtrlListView_AddItem($aGUI[$idListViewNeeded], "No Needed Updates Found")
    EndIf
    GUICtrlSetState($aGUI[$idBtnFindNeeded], $GUI_ENABLE)   ;Enable GUI Button
    $aNeeded = 0    ;Cleanup
    Return 1
EndFunc   ;==>_PopulateNeeded

Func _AUTool_ResizeColumns($type = 0)
    _GUICtrlListView_BeginUpdate($aGUI[$idListViewHistory]) ;Block ListView Control Updates While Resizing
    _GUICtrlListView_BeginUpdate($aGUI[$idListViewInstalled])
    _GUICtrlListView_BeginUpdate($aGUI[$idListViewNeeded])
    Local $winPos = WinGetPos("Automatic Updates Tool") ;Get Window Size
    $iWinX = $winPos[2]
    $iWinY = $winPos[3]
    If $type = 0 Then   ;Set Column Widths on Maximize
        _GUICtrlListView_SetColumnWidth($aGUI[$idListViewHistory], 1, $iWinX * .35)
        _GUICtrlListView_SetColumnWidth($aGUI[$idListViewHistory], 2, $iWinX * .42)
        _GUICtrlListView_SetColumnWidth($aGUI[$idListViewInstalled], 0, $iWinX * .4125)
    Else    ;Set Column Widths on MRestore
        _GUICtrlListView_SetColumnWidth($aGUI[$idListViewHistory], 1, $LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($aGUI[$idListViewHistory], 2, $iWinX * .5)
        _GUICtrlListView_SetColumnWidth($aGUI[$idListViewInstalled], 0, $LVSCW_AUTOSIZE)
    EndIf
    _GUICtrlListView_SetColumnWidth($aGUI[$idListViewHistory], 3, $LVSCW_AUTOSIZE)
    _GUICtrlListView_SetColumnWidth($aGUI[$idListViewNeeded], 0, $iWinX * .34275)
    _GUICtrlListView_SetColumnWidth($aGUI[$idListViewNeeded], 1, $iWinX * .525)
    _GUICtrlListView_SetColumnWidth($aGUI[$idListViewNeeded], 2, $iWinX * .1125)
    _GUICtrlListView_SetColumnWidth($aGUI[$idListViewInstalled], 1, $iWinX * .575)
    _GUICtrlListView_EndUpdate($aGUI[$idListViewHistory])   ;UnBlock ListView Control Updates
    _GUICtrlListView_EndUpdate($aGUI[$idListViewInstalled])
    _GUICtrlListView_EndUpdate($aGUI[$idListViewNeeded])
EndFunc   ;==>_ResizeColumns

Func _AUTool_Search()
    Local $sText = GUICtrlRead($aGUI[$idInput], 1)  ;Read Search Inputbox
    If $sText = "" Then Return SetError(1, 0, 0)    ;If Search is Null Error Out
    Local $iCurrentTab = _AUTool_GetTab()   ;Enum Active Tab
    Local $idList = 0
    Switch $iCurrentTab
        Case 1
            $idList = $aGUI[$idListViewHistory]
        Case 2
            $idList = $aGUI[$idListViewInstalled]
    EndSwitch
    _GUICtrlListView_BeginUpdate($idList)   ;Block ListView Control Updates While Searching
    $iFind = _GUICtrlListView_FindInText($idList, $sText, $iFind)   ;Search for Item
    If $iFind <> -1 Then    ;If Item Found, Select and Display it
        _GUICtrlListView_SetItemSelected($idList, $iFind, True)
        _GUICtrlListView_EnsureVisible($idList, $iFind)
    Else    ;Else Select & Deselect first Item
        _GUICtrlListView_SetItemSelected($idList, 0, True)
        _GUICtrlListView_SetItemSelected($idList, 0, False)
    EndIf
    _GUICtrlListView_EndUpdate($idList) ;Block ListView Control Updates
EndFunc   ;==>_Search

Func _AUTool_GetTab()
    Return ControlCommand($aGUI[$hGUI], "", $aGUI[$idTabs], "CurrentTab")   ;Return Current / Active Tab
EndFunc   ;==>_SearchTab

Func _AUTool_UpdatesDownloadAndInstall()
    Local $aSelected = _GUICtrlListView_GetSelectedIndices($aGUI[$idListViewNeeded], True)  ;Collect Selected Patches
    If $aSelected[0] = 0 Then   ;If No Patches are Selected, Abort
        MsgBox(0,"No Patches Selected","Please select one or more patches to downlaod and install.")
        Return 0
    EndIf
    GUICtrlSetState($aGUI[$idBtnFindNeeded], $GUI_DISABLE)  ;Disable Button to Prevent MultiClicks/Execution
    Local $oMSUpdater = _AUTool_CreateMSUpdateSession() ;Create Update Session Object and Search Object
    Local $oSearch = _AUTool_CreateSearcher($oMSUpdater)
    Local $oCol = _AUTool_GetNeededUpdates($oSearch)    ;Collect Needed Patches as Object Collection
    For $iIndxA = 1 To $aSelected[0]    ;Loop Through Selected Patches
        Local $sItem = _GUICtrlListView_GetItemText($aGUI[$idListViewNeeded], $aSelected[$iIndxA])
        For $iIndxB = 0 To $oCol.Updates.Count - 1
            Local $oUpdate = $oCol.Updates.Item($iIndxB)
            If $sItem = $oUpdate.Title Then
                _GUICtrlListView_SetItemText($aGUI[$idListViewNeeded], $iIndxB, "Downloading...", 2)    ;Update ListView to Indicate Patch is Downloading
                Local $oUpdatesToDownload = ObjCreate("Microsoft.Update.UpdateColl")    ;Download Patch
                $oUpdatesToDownload.Add($oUpdate)
                Local $oDownloadSession = $oMSUpdater.CreateUpdateDownloader()
                $oDownloadSession.Updates = $oUpdatesToDownload
                $oDownloadSession.Download
                _GUICtrlListView_SetItemText($aGUI[$idListViewNeeded], $iIndxB, "Downloaded", 2)    ;Update ListView to Indicate Patch Download is Complete
            EndIf
        Next
    Next
    Local $iReboot = 0  ;Create Reboot Required Flag
    For $iIndxA = 1 To $aSelected[0]    ;Loop Through Selected Patches
        $sItem = _GUICtrlListView_GetItemText($aGUI[$idListViewNeeded], $aSelected[$iIndxA])
        For $iIndxB = 0 To $oCol.Updates.Count - 1
            $oUpdate = $oCol.Updates.Item($iIndxB)
            If $sItem = $oUpdate.Title And $oUpdate.IsDownloaded Then
                _GUICtrlListView_SetItemText($aGUI[$idListViewNeeded], $iIndxB, "Installing...", 2) ;Update ListView to Indicate Patch is Installing
                Local $oInstallSession = $oMSUpdater.CreateUpdateInstaller()
                Local $oUpdatesToInstall = ObjCreate("Microsoft.Update.UpdateColl")
                $oUpdatesToInstall.Add($oUpdate)
                $oInstallSession.Updates = $oUpdatesToInstall
                Local $oInstallResult = $oInstallSession.Install
                If $oInstallResult.RebootRequired Then $iReboot = 1 ;If Reboot Required Set Flag
                _GUICtrlListView_SetItemText($aGUI[$idListViewNeeded], $iIndxB, "Complete", 2)  ;Update ListView to Indicate Patch is Install is Complete
            EndIf
        Next
    Next
    If $iReboot Then MsgBox(0, "Installation Complete", "A Reboot is Required.")    ;Warn User if Reboot is Required
    GUICtrlSetState($aGUI[$idBtnFindInstalled], $GUI_ENABLE)    ;Enable GUI Button and Reset Text
    GUICtrlSetData($aGUI[$idBtnFindInstalled], "Find Needed Updates")
    Return 1    ;Return Success
EndFunc   ;==>_UpdatesDownloadAndInstall

Func _AUTool_WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListViewHistory, $hWndListViewInstalled, $hWndTabs
    $hWndListViewHistory = GUICtrlGetHandle($aGUI[$idListViewHistory])
    $hWndListViewInstalled = GUICtrlGetHandle($aGUI[$idListViewInstalled])
    $hWndTabs = GUICtrlGetHandle($aGUI[$idTabs])
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom    ;Switch Notifcation Handle Source
        Case $hWndListViewHistory
            Switch $iCode
                Case $LVN_COLUMNCLICK ; A column was clicked
                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    _GUICtrlListView_SimpleSort($hWndListViewHistory, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"))
;_AUTool_HighlightHistoryPatchResults()
            EndSwitch
        Case $hWndListViewInstalled
            Switch $iCode
                Case $LVN_COLUMNCLICK ; A column was clicked
                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    _GUICtrlListView_SimpleSort($hWndListViewInstalled, $B_DESCENDING, DllStructGetData($tInfo, "SubItem"))
            EndSwitch
        Case $hWndTabs
            Switch $iCode
                Case $TCN_SELCHANGE ;Tab Selection Changed
                    Local $iCurrent = _AUTool_GetTab()
                    If $iCurrent = 3 Then   ;Disable Searching on Needed Tab
                        GUICtrlSetState($aGUI[$idInput], $GUI_DISABLE)
                        GUICtrlSetState($aGUI[$idBtnSearch], $GUI_DISABLE)
                    Else    ;Enable Searching on History and Installed Tabs
                        GUICtrlSetState($aGUI[$idInput], $GUI_ENABLE)
                        GUICtrlSetState($aGUI[$idBtnSearch], $GUI_ENABLE)
                    EndIf
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
#EndRegion - Functions

 

Edited by spudw2k
Posted

Looks good and seems to work OK on my machine (XP SP3). Is there anyway of knowing what patches haven't been installed yet or what ones need to be installed (I'm assuming that the result field is simply the success or failure of already downloaded patches, not what needs to be downloaded)?

Posted (edited)

Funny you should ask. ;) There is a function in the script that is not used by the gui. It connects to Windows Update (or WSUS server if you run one) and returns an array of Patch Titles not installed but required by the system. This does take a few minutes (depending on the speed of your computer and the last time it was updated). Example code using the functions in the script above.

$objSearcher = _CreateSearcher(_CreateMSUpdateSession($host))
$arrUpdates = _GetNeededUpdates($objSearcher)

I was considering adding the func to do this and download the updates and install them and such, but I really just needed the ability to easily check if a machine has a patch installed or not.

edit: Have implemented features. :D

Edited by spudw2k
  • 3 weeks later...
Posted (edited)

Added tabs to start implementing additional features. Added Needed updates func.

edit: added imagelist to update history listview to easily identify failed events. Changes date format to sort properly.

edit: Changes reflected in Original Post

Edited by spudw2k
Posted (edited)

This is very useful.

Thanks. :) There's a weird bug though. When you click an item in the list (usually 4,5,6) it triggers the if $msg= logic. Not sure why..... Edited by spudw2k
Posted (edited)

I removed some of the _GUICtrlListView funcs and this bug went away...Not sure what was causing it. I updated the source on the first post and fixed any bugs I ran into. The listview highlights the events red if they are failures.

Edited by spudw2k
Posted (edited)

Does it require a particular version of AutoIT? I've gotten several errors running in v3.2.10.0.

Tested with latest ver. 3.2.12.1

What errors you getting?

edit: I found a few bugs with the listview selection behavior. Will fix when I get a chance.

edit: Fixed the selection bug and added download and install updates func.

edit: Fixed spelling ^ (sleection) (yes, I'm a dork)

Edited by spudw2k
  • 6 months later...
Posted

This is nice , will work on it to include more information. actually i would like these functionality added:

1) If user asks for, then The KB article home page should be displayed as a link

2) If user asks for, then the remote file sizes should be populated and displayed.

3) Filterable search results would be very nice.

Posted

Don't know if anyone has heard of this site:

http://www.windowsupdatesdownloader.com/

(WUD) essentially downloads updates and stores them locally on your machine. It does not install them, though. It's kind of a poor man's WSUS. What would be really cool is to be able to incorporate this script with a cache of updates already downloaded. Could cut system building times in half. I know - if you want it go build it. I'm already pulling the script apart to see if that could be done. Excellent work and kudos to original poster.

Posted

Don't know if anyone has heard of this site:

http://www.windowsupdatesdownloader.com/

I had not; looks interesting though. I'll have to see if I can incorporate, or make a new script. Thanks for the kudos.

... i would like these functionality added:

1) If user asks for, then The KB article home page should be displayed as a link

2) If user asks for, then the remote file sizes should be populated and displayed.

3) Filterable search results would be very nice.

I think those are reasonable feature requests. I'll see what I can do in my spare time. Thanks for testing/using.
Posted (edited)

Don't know if anyone has heard of this site:

http://www.windowsupdatesdownloader.com/

(WUD) essentially downloads updates and stores them locally on your machine. It does not install them, though. It's kind of a poor man's WSUS. What would be really cool is to be able to incorporate this script with a cache of updates already downloaded. Could cut system building times in half. I know - if you want it go build it. I'm already pulling the script apart to see if that could be done. Excellent work and kudos to original poster.

I like this one: http://www.heise.de/ct/projekte/offlineupd...wnload_uk.shtml

And the GUIs are programmed in AutoIt too!

Edit: Main article in English: http://www.h-online.com/security/Do-it-you.../features/80682

Edited by ResNullius
  • 7 months later...
Posted (edited)

I copied your script but haven't tried it yet. I was wondering, what is with all the scrambled info at the bottom of the script?

Oh, and for offline windows updates, I don't know if anyone included AutoPatcher. It seems to work ok for many people. I have some odd issues with it but maybe only because I am tinkering with the .apm files. I have used the option to force particular updates to install (if they aren't) using the command file and that has worked well.

Edited by LostUser

Be open minded but not gullible.A hammer sees everything as a nail ... so don't be A tool ... be many tools.

Posted

...I was wondering, what is with all the scrambled info at the bottom of the script?

This is an artifact sometimes caused by issues with the autoit tags. I've corrected the issue.
  • 1 year later...
Posted (edited)

Hi

Has anyone updated this to work for windows 7 32bit and 64bit?

jamie

I tested it on Windows Server 2008. Seems like the History part works, but not the rest.

Edited by spudw2k
Posted

I tested it on Windows Server 2008. Seems like the History part works, but not the rest.

Nothing seems to work for me im on win 7 64bit

Drunken Frat-Boy Monkey Garbage

Posted
Posted

Worked for me on Win7 64. Did you run with Admin Rights?

I appended #RequireAdmin to the script.

Works like a charm thanks

Drunken Frat-Boy Monkey Garbage

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...