Featured Quote

In 1913, Henry Ford wrote the following as the directors had been reaping the rewards of profits - "The wages we pay are too small in comparison with our profits. I think we should raise our minimum pay rate".

Friday, September 27, 2013

Programming with VB needs an AutoIT3 helper!

So, I've got this code that goes out and checks on the timestamps of some files that are important to the BMC Bladelogic Client Administration (formerly Marimba) Tuner (aka Agent) on the endpoints.

Checking from a central location out to a couple thousand computers, the Visual Basic .NET (written using Visual Studio Express 2012) can't be trusted to get the latest time stamp.  I wrote the following function and this issue arises specifically when using the Mod.
    Shared Function GetFileInfo(ByVal ComputerName As String, _
                ByVal FiletoFind As String, info As String)        
        Dim Ret As String = ""
        Dim targetfile = "\\" & ComputerName & "\" & FiletoFind
        Dim fi As FileInfo = New FileInfo(targetfile)
        If fi.Exists Then
            fi.Refresh()
            Select Case info
                Case Is = "Exists"
                    Ret = fi.Exists.ToString
                Case Is = "Delete"
                    fi.Delete()
                    Ret = fi.Exists.ToString
                Case Is = "Created"
                    Ret = fi.CreationTime.ToString("MM/dd/yyyy hh:mm:ss tt")
                Case Is = "Access"
                    Ret = fi.LastAccessTime.ToString("MM/dd/yyyy hh:mm:ss tt")
                Case Is = "Mod"
                    Ret = fi.LastWriteTime.ToString("MM/dd/yyyy hh:mm:ss tt")
            End Select
        Else
            Ret = "File Not Found"
        End If

        Ret = Ret.Replace(vbCrLf, "")
        Ret = Ret.Replace(vbCr, "")

        Return Ret

    End Function
So, it should be no problem, right?  Wrong.  Even with the fi.Refresh() in there, it still brings back an outdated time stamp.  You could go to Windows Explorer and UNC to the remote computer, browse to the file and right-click, bring up the properties and see the correct time stamp.  Oddly enough, after you do THAT, the above function gets the right time stamp!  Sometimes the difference between the two can be days!

So, I went to AutoIT3 and ... okay, I already had the code to check the files I wanted...
Func _FileTimeStamp($path)
    Dim $file,$astamp
    $file = $path
    $astamp = FileGetTime($file, 0, 0)
    If IsArray($astamp) Then
        $stamp = $astamp[1] & "/" & $astamp[2] & "/" & $astamp[0] & " " & _
                $astamp[3] & ":" & $astamp[4]
    ElseIf $astamp = 0 Then
        $stamp = "file not Found"
    Else
        $stamp = 0
    EndIf
    Return $stamp
EndFunc   ;==>_FileTimeStamp
The AutoIT3 code gets the right time stamp and makes the VB accessed 'ghost data' update. 

The reason to get the time stamps is to make sure that the Tuner is functioning as expected.  Too often, it is not.  So, WHEN a Tuner has an outdated channel, I wrote a little function to go through a little process that usually fixes the problem.
Private Sub UpdateChannelFix()
        Dim runchannel As String = TunerPath.Replace("Tuner.exe", "Runchannel.exe")
        Dim Procedure(5) As String
        Procedure(0) = "Tuner,-stop http://MyBMCServer.Mycompany.local:5282/Marimba/Current/PatchService"
        Procedure(1) = "Tuner,-stop http://MyBMCServer.Mycompany.local:5282/Marimba/Current/InventoryService"
        Procedure(2) = "Runchannel,-subscribe http://MyBMCServer.Mycompany.local:5282/Marimba/Current/PatchService -reset"
        Procedure(3) = "Runchannel,-subscribe -update http://MyBMCServer.Mycompany.local:5282/Marimba/Current/InfrastructureService"
        Procedure(4) = "Runchannel,-subscribe -update http://MyBMCServer.Mycompany.local:5282/Marimba/Current/InventoryService"
        Procedure(5) = "Runchannel,-subscribe -update http://MyBMCServer.Mycompany.local:5282/Marimba/Current/SubscriptionService"
        For Each pStep As String In Procedure
            Dim rp As Process = New Process
            Dim rpi As ProcessStartInfo = New ProcessStartInfo
            Dim parts = Split(pStep, ",")
            Dim mExe As String = parts(0)
            Dim mCmd As String = parts(1)
            rpi.WindowStyle = ProcessWindowStyle.Hidden
            If mExe = "Tuner" Then
                rpi.FileName = TunerPath
            Else
                rpi.FileName = runchannel
            End If
            rpi.Arguments = mCmd
            rp.StartInfo = rpi
            Try
                rp.Start()
                rp.WaitForExit()
            Catch ex As Exception
                ' oops, nevermind - will catch it in examination
                AlertText = AlertText & vbCrLf & mExe & " " & mCmd & _
                    " <-- Failed to run"
            End Try
        Next
    End Sub
The program finds the path to Tuner.exe by looking in the registry for the Application entry.  Using that, the function uses Tuner.exe to stop the Patch and Inventory channels, which can sometimes get stuck in a running state and cause issues.  Then, it uses the Runchannel.exe program in the same folder to do a reset on the Patch channel.  The -subscribe makes sure that if the channel is not present, it will install it.  Then it updates or subscribes and runs the Infrastructure, Inventory and Subscription channels.  Running the Inventory channel will usually run the Patch channel as well.

Cool, huh?!? :)