watch-vox - in powershell...

I'm ever so sorry :/        but I couldn't stop myself Smiley Tongue

...if you want to run it, then :

1) save the code somewhere as "watch-vox.ps1"

2) run it using :

powershell -file watch-vox.ps1

...anyway, here's the script :

#############################################################################################################
# File:     watch-vox.ps1
# Purpose:  Script to watch VOX forum(s) for updates.
#
# Vers    Date          Who   Description
# ----    ----          ---   -----------
# v0.01   12-Jan-2017   sdo   Initial draft.
# v0.02   12-Jan-2017   sdo   Only log when something has changed.
# v0.03   12-Jan-2017   sdo   Log every 100 iterations.
# v0.04   13-Jan-2017   sdo   Append the diff to the log.  Diff -y and suppress.
# v0.05   13-Jan-2017   sdo   Place all temporary working files in script path.
# v0.06   14-Jan-2017   sdo   Check status of curl web page fetch.
# v0.07   15-Jan-2017   sdo   Only move file if curl web page fetch is successful.
# v0.08   21-Jan-2017   sdo   Test status of initial search to handle successful page fetch which is empty.
# v0.09   21-Jan-2017   sdo   More capture of stderr to the log file.
# v0.10   21-Jan-2017   sdo   Store the data files in a sub-folder.
# v0.11   21-Jan-2017   sdo   Test size of page/file retrieved by curl.
# v0.12   22-Jan-2017   sdo   Also able to monitor the Article and Downloads by searching for match3.
# v0.13   16-Sep-2019   sdo   Convert from bash to PowerShell, and so some comments above are now irrelevant.
# v0.14   19-Sep-2019   sdo   Match "*p*ge-link*" to also pull out names of contributors to topics.
# v0.15   19-Sep-2019   sdo   Remove last five entries in the topics list, which are top kudo'ed names.
# v0.16   19-Sep-2019   sdo   Check for minimum of 40 topic entries.
# v0.17   19-Sep-2019   sdo   Added more detail to comments are core of functionality.
#############################################################################################################
$myScriptVersion = "v0.17"

$ErrorActionPreference = "Stop"

$Debug = $False



#############################################################################################################
# Script functions...
#

Function dt {
    [System.DateTime]::Now.ToString( "yyyy-MM-dd HH:mm:ss" )
}

Function Log( $myText ) {
    If ( $Null -eq $myText ) {
        Write-Host "$(dt)"
    } Else {
        Write-Host "$(dt)  $myText"
    }

    If ( $myScriptLog -ne "" ) {
        If ( $Null -eq $myText ) {
            Add-Content -Path $myScriptLog -Value "$(dt)" -Force
        } Else {
            Add-Content -Path $myScriptLog -Value "$(dt)  $myText" -Force
        }
    }
}

Function Abort( $myText ) {
    Log $myText
    Log "script aborting..."
    Exit 1
}



#############################################################################################################
# Where am I ?  Who am I ?
#

$myScriptSpec  = [System.IO.FileInfo]$PSCommandPath
$myScriptPath  = $myScriptSpec.Directory
$myScriptName  = $myScriptSpec.BaseName
$myScriptLog   = Join-Path -Path $myScriptPath -ChildPath "$myScriptName.log"
$myScriptStart = Get-Date

If ( Test-Path -Path $myScriptLog -PathType Leaf ) { Remove-Item -Path $myScriptLog -Force }

$myUsername       = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$myComputerDomain = ( Get-WmiObject Win32_ComputerSystem ).Domain
$myComputerName   = ( Get-WmiObject Win32_ComputerSystem ).Name

Log ""
Log ""
Log "#############################################################################"
Log "Script details..."
Log "...script spec:      $myScriptSpec"
Log "...script path:      $myScriptPath"
Log "...script name:      $myScriptName"
Log "...script log:       $myScriptLog"
Log "...script version:   $myScriptVersion"
Log "...user:             $myUsername"
Log "...computer name:    $myComputerName"
Log "...computer domain:  $myComputerDomain"
Log "...done..."

$myScriptData = Join-Path -Path $myScriptPath -ChildPath "DATA\"



#############################################################################################################
# Start main engines...
#

Log ""
Log "Initialisation..."

If ( -not ( Test-Path -Path $myScriptData -PathType Container ) ) {
    Log "...creating data folder..."
    Try {
        New-Item -Path $myScriptData -ItemType Directory -Force
    } Catch {
        Log "...failed to create DATA folder..."
        Log $_
        Abort "...script cannot continue..."
    }
    Log "...created ok..."
}

Log "...the URLs to monitor are:"

$URLS = @(
     "https://vox.veritas.com/t5/NetBackup/bd-p/netbackup"
    ,"https://vox.veritas.com/t5/NetBackup-Appliance/bd-p/netbackup-appliance"
    ,"https://vox.veritas.com/t5/OpsCenter/bd-p/opscenter"
    ,"https://vox.veritas.com/t5/Articles/tkb-p/Articles-Backup-and-Recovery"
    ,"https://vox.veritas.com/t5/Downloads/tkb-p/Downloads-Backup-and-Recovery"
)

$Count = 0
ForEach ( $URL In $URLS ) {
    $Count++
    Log "...num:  $Count  $URL"
    $OldFile = "$myScriptData\old$Count.txt"
    $NewFile = "$myScriptData\new$Count.txt"
    $DifFile = "$myScriptData\dif$Count.txt"
    If ( -not ( Test-Path -Path $OldFile ) ) { Set-Content -Path $OldFile -Value "" -Force }
    If ( -not ( Test-Path -Path $NewFile ) ) { Set-Content -Path $NewFile -Value "" -Force }
    If (      ( Test-Path -Path $DifFile ) ) { Remove-Item -Path $DifFile           -Force }
}

$Speech = $True
Try {
    Add-Type -AssemblyName System.Speech
    $Say = New-Object System.Speech.Synthesis.SpeechSynthesizer
    Log "...speech is possible..."
} Catch {
    $Speech = $False
    Log "...speech is NOT possible..."
}

Log "...done..."



#############################################################################################################
# Lift off...
# ...but let's only monitor until midnight...
#

Log ""
Log "Begin monitoring..."

$DateStarted = ( Get-Date ).ToString( "dd-MMM-yyyy" )

# ...this turns off the PowerShell progress bar which speeds up the fetch of the web page...
$ProgressPreference = "SilentlyContinue"

# ...to match the security level of the Veritas VOX web-site...
[Net.ServicePointManager]::SecurityProtocol = "tls12"

# ...now we begin looping until midnight...
$Loop = 0

Do {
    $Loop++

    # ...just a little to show that we are still working...
    If ( ( $Loop % 100 ) -eq 0 ) { Log "...loop: $Loop" }

    $Count = 0
    ForEach ( $URL In $URLS ) {
        $Count++

        # ...our data files are number based...
        $OldFile = "$myScriptData\old$Count.txt"
        $NewFile = "$myScriptData\new$Count.txt"
        $DifFile = "$myScriptData\dif$Count.txt"

        # ...pull out the main topic section name from the URL...
        $Section = $URL.Split( "/" )[4]

        If ( $Debug ) { Log "...checking:  $Count  $Section" }

        Try {
            $Page = Invoke-WebRequest $URL -Method Get -Erroraction Stop
            $Sts = $Page.StatusCode
        } Catch {
            $Sts = $_.Exception.Page.StatusCode.value__
        }

        If ( $Sts -ne 200 ) {
            Log "...failed to fetch:  $URL     status:  $Sts"
        
        } Else {
            If ( $Page.RawContentLength -lt 150000 ) {
                Log "...page too small:  $($Page.RawContentLength)    for:  $Section"

            } Else {
                # ...here we select/extract the "InnerText" content of the appropriate page links from the web page content...
                # ...which generates a list of topic headings...
                # ...plus the original poster/contributor name...
                # ...plus the most recent responder/replier/contributor name...
                # ...plus at the very end of the list the top kudo'ed or top authors (which we do not need, we remove these later)...
                $Topics = $Page.Links | Where-Object { $_.Class -like "*p*ge-link*" } | Select-Object InnerText

                If ( $Topics.Count -lt 40 ) {
                    Log "...low topic count:  $($Topics.Count)    for:  $Section"

                } Else {
                    # ...now we come to the crux of it...

                    # ...first, strip off the trailing five entries which are the names of the top five kudo'ed or top four...
                    # ...authors - yes, this does mean that we loose the name of the author of the last topic in Articles...
                    # ...and Downloads, but that doesn't matter for our purposes, because the changes/updates that we want...
                    # ...to detect occur at the head/top of the list...
                    $Topics = $Topics | Select-Object -First ( $Topics.Count - 5 )

                    # ...it's time to rotate stock...
                    If ( Test-Path -Path $OldFile ) { Remove-Item -Path $OldFile -Force }

                    # ...but we need to be able to tolerate Brexit (so sad!), i.e. the rug being pulled from underneath us...
                    If ( Test-Path -Path $NewFile ) {
                        Move-Item  -Path $NewFile -Destination $OldFile -Force
                    } Else {
                        Set-Content -Path $NewFile -Value "" -Force
                    }

                    # ...if we are still missing an old file, then we still need an empty old file to diff against...
                    If ( -not ( Test-Path -Path $OldFile ) ) { Set-Content -Path $OldFile -Value "" -Force }

                    # ...let's save the current list of topics, in the order that they appear on the web page...
                    $Topics | Set-Content -Path $NewFile -Force

                    # ...let's compare / diff the lists of topics...
                    fc.exe /L /U "$NewFile" "$OldFile" >"$DifFile"

                    # ...check if there was a change/update in the list of topics and/or contributors...
                    If ( $LastExitCode -eq 1 ) {
                        # ...yes, there was a change in the list of topics and/or contributors...
                        [console]::beep(500,300)
                        [console]::beep(500,300)
                        [console]::beep(500,300)
                        Log "...updated:  $Section"
                        If ( $Speech ) { $Say.Speak( "VOX $Section updated." ) }
                    }
                }
            }
        }
    }

    If ( $Debug ) { Log "...sleeping..." }
    Start-Sleep -Seconds 300

    $DateNow = ( Get-Date ).ToString( "dd-MMM-yyyy" )
} Until ( $DateNow -ne $DateStarted )

Log "...monitoring is done for the day..."



#############################################################################################################
# Our day's work is done...
#

Log "...script exiting..."
Exit
Tags (1)