Tuesday, September 12, 2017

Query Security Center v4 API for IAVMs across multiple Nessus Scanners (ACAS)

Title:  Query Security Center v4 API for IAVMs across multiple Nessus Scanners (ACAS)
Description:  Remotely poll X number of scanners for IAVM numbers.

A customer had dozens of Nessus Scanners world-wide and needed IAVM data from each of them in a most up-to-date fashion.  Apparently Tenable has some sort of roll-up/replication server or capability but it rarely worked and/or was rarely accurate.  Because of  this, the customer had one person manually logging into the web interface of each Nessus scanner and manually searching for specific IAVMs and then transposing the data to an Excel spreadsheet.  ...On average, they claimed there were anywhere from 15-30 IAVMs they wanted to track.  The Security Center interface only allowed the searcher to query for one IAVM at a time.  This was known to be a full-time job (8 hrs/day) for the person gathering the data.  ...Oh and the report was generated every day.  

After reading up on the Security Center API which covered many of the functions necessary interact with the API in perl/python, I was able to produce a PowerShell script that would poll each server for all of the IAVMs and save them to a CSV.  Not multi-threaded, the script took about 15 minutes to complete.  It's listed below and contains the interactions described above and includes comments that were necessary in the web-page interaction debugging process (e.g. the HTTP POST data) that allowed me to construct the information in the format necessary to interact with the API.

To use:
  1. Copy the script below into a file and save it as whatever-you-want-to-call-it.ps1
    • I named mine Get-NessusV4Report.ps1 but I'm really querying the Security Center and only scanning for IAVMs so call yours something more accurate.
  2. Run the script in the following fashion:
    • PS C:\>whatever-you-want-to-call-it.ps1 -PathToServerList servers.txt -PathToIAVMList iavms.txt
  3. It will prompt for credentials, and assuming you have legitimate nessus scanners in your servers.txt and legitimate IAVMs in your iavms.txt, (and the SecurityCenter version is v4), it will prodcue a CSV to your desktop and let you know when it's done.

Param (
    [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$PathToServerList,
    [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$PathToIAVMList,
    [ValidateNotNullOrEmpty()] [string]$OutputCsv = "$($env:USERPROFILE)\Desktop\NessusSC_VulnerabilitySummary_$(Get-Date -Format 'yyyy-MM-dd').csv"
)


if (-not(Test-Path $PathToIAVMList)) { Write-Warning "File not found, try again:  $($PathToIAVMList)"; break }
if (-not(Test-Path $PathToServerList)) { Write-Warning "File not found, try again:  $($PathToServerList)"; break }
#if (-not(Test-Path $OutputCsv)) { Write-Warning "File not found, try again:  $($OutputCsv)"; break }


#$PathToIAVMList = 'iavms.txt'
#$PathToServerList = 'Servers.txt'

$IAVMList = @([System.IO.File]::ReadAllLines($PathToIAVMList) | Where-Object { $_ -notmatch '^\#' })
$ServerList = @([System.IO.File]::ReadAllLines($PathToServerList) | Where-Object { $_ -notmatch '^\#' })

if ($IAVMList.Count -eq 0) { Write-Warning "IAVMList is empty.  Please populate $($PathToIAVMList) with the IAVM list you want to scan for on each ACAS server."; break }
if ($ServerList.Count -eq 0) { Write-Warning "ServerList is empty.  Please populate $($PathToServerList) with the servers you want to run this query against."; break }


$ValidCred = $false
Do {
    $Username = Read-Host -Prompt "Enter username"
    $Password = Read-Host -Prompt "Enter password" ##The password is provided in plaintext intentionally.  If a SecureString was used, we'd have to convert it back to plaintext to be able to pass to the NESSUS API which would require Administrator elevation.

    if ([System.String]::IsNullOrEmpty($Username) -or [System.String]::IsNullOrEmpty($Password)) { 
        Write-Warning "You must enter a username and password to proceed."; continue
    }

    if ($Credential.UserName -match '\\') {
        Write-Warning "A backslash character was found ('\'), please only supply a username without any domain identification."; continue
    }

    $ValidCred = $true
} Until ($ValidCred)




## These settings are required to successfully establish a connection to an SSL server due to the elevated security posture
## adopted by the org.
[Net.ServicePointManager]::Expect100Continue = $true
[Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Ssl3, [System.Net.SecurityProtocolType]::Tls, [System.Net.SecurityProtocolType]::Tls11, [System.Net.SecurityProtocolType]::Tls12

$Results = @()
#$ServerList = @('acas01')

foreach ($s in $ServerList) {

    Write-Host $s
    if (-not(Test-Connection $s -Count 1 -Quiet)) { Write-Warning "Could not connect to $($s), skipping..."; continue }

    [System.Net.WebRequest]::DefaultWebProxy = $null

    $Login = New-Object PSObject -Property @{
        'username' = $username
        'password' = $password
    
    }

    $ConnectBody = @{
        module = 'auth'
        action = 'login'
        input = (ConvertTo-Json -Compress $Login)
    }
 
    
    try {
        ## Login to the SecurityCenter API -- required by the API
        $ret = Invoke-WebRequest -URI "https://$($s)/request.php" -Method POST -Body $ConnectBody -UseBasicParsing -SessionVariable sv -ErrorAction Stop
    } catch {
        Write-Error $Error[0]
        continue
    }


    if ($ret.StatusCode -ne 200) { 
        Write-Warning "An error occurred with the HTTP request. HTTP Status Code: ($($ret.StatusCode)); HTTP Status Description ($($ret.StatusDescription))"
        continue
    }

    $ApiResponse = $ret.Content | ConvertFrom-Json
    if ($ApiResponse.error_code -ne 0) {
        Write-Warning "The API returned an error trying to authenticate to the server ($($s)).  `r`nAPI Error Code:  ($($ApiResponse.error_code)); `r`nAPI Error Message:  ($($ApiResponse.error_msg)) `r`nConstructed HTTP POST param:  $($ConnectBody.input)"
        continue
    }

 
    # Extract the token
    $resp = (ConvertFrom-Json $ret.Content)
    $token = $resp.response.token
    $sessionid = $resp.response.sessionID


    #$IAVMList = @('2016-B-0036')
    foreach ($IAVMId in $IAVMList) {

        ## Structure the queries into objects that can output JSON compressable format to properly send the query
        $QueryFilters = New-Object PSObject -Property @{
            'filterName' = 'iavmID'
            'operator' = '='
            'value' = $IAVMId
        } 

        $QueryData = @{
            sortDir = 'desc'
            sortField = 'severity'
            endOffset = 29
            tool = 'sumiavm'
            sourceType = 'cumulative'
            filters = '[' + (ConvertTo-Json -Compress $QueryFilters) + ']'
            startOffset = 0
        } 
        
        ## What the filter looks like after compression, if filtering on iavmid 2016-B-0036:
        ## [{"operator":"=","value":"2016-B-0036","filterName":"iavmID"}]


        $QueryBody = @{
            module = 'vuln'
            action = 'query'
            input = (ConvertTo-Json -Compress $QueryData).Replace('\','').Replace('"filters":"', '"filters":').Replace('}]",', '}],')
            token = $token
        }

        ## What the POST data (input property of the QueryBody var) looks like after compression:
        ## {"endOffset":29,"sourceType":"cumulative","filters":"[{\"operator\":\"=\",\"value\":\"2016-B-0036\",\"filterName\":\"iavmID\"}]","sortDir":"desc","sortField":"severity","startOffset":0,"tool":"sumiavm"}

        ## Notice all of the extra encoding of escape characters (\) and quotations in the wrong place.  The replace() filters fixes that.

        ## What the POST data looks like after compression and replacement filters:
        ## {"endOffset":29,"sourceType":"cumulative","filters":[{"operator":"=","value":"2016-B-0036","filterName":"iavmID"}],"sortDir":"desc","sortField":"severity","startOffset":0,"tool":"sumiavm"}

        try {
            $ret = Invoke-WebRequest -URI "https://$($s)/request.php" -Method POST -Headers @{"X-SecurityCenter"="$($token)"} -Body $QueryBody -UseBasicParsing -WebSession $sv -ErrorAction Stop
        } catch {
            Write-Error "An error occurred connecting to server ($($s)), with error:  $($error[0])"
        }
        #$ret

        if ($ret.StatusCode -ne 200) { 
            Write-Warning "An error occurred with the HTTP request. HTTP Status Code: ($($ret.StatusCode)); HTTP Status Description ($($ret.StatusDescription))"; continue
        }

        $ApiResponse = $ret.Content | ConvertFrom-Json
        if ($ApiResponse.error_code -ne 0) {
            Write-Warning "The API returned an error trying to authenticate to the server ($($s)).  API Error Code:  ($($ApiResponse.error_code)); API Error Message:  ($($ApiResponse.error_msg))"; continue
        }

        # Extract data from response.  The response comes back URL Encoded (e.g. single-line) so to convert that back to an object that PowerShell very easily manipulates, JSON works perfectly.
        $data = (ConvertFrom-Json ($ret.Content)).response


        ## Write the results to the output object. The results are empty if 0 are returned so we need a slightly different object to report 0.
        if ($data.totalRecords -eq 0) {
            $Results += New-Object PSObject -Property @{
                'IAVMId' = $IAVMId
                'Severity' = ''
                'Total' = $data.totalRecords
                'HostTotal' = $data.totalRecords
                'Server' = $s
            } | Select-Object IAVMId,Severity,Total,HostTotal,Server
        } else {
            $Results += New-Object PSObject -Property @{
                'IAVMId' = $data.results.iavmId
                'Severity' = $data.results.severity
                'Total' = $data.results.total
                'HostTotal' = $data.results.hostTotal
                'Server' = $s
            } | Select-Object IAVMId,Severity,Total,HostTotal,Server
        }

        ## Manually wipe out variables so we don't get errant data from a previous query added to a query that didn't return correctly.
        $QueryFilters=$QueryBody=$QueryData=$ApiResponse=$data=$ret=$null
    }

    #$ConnectBody = @{
    #    module = 'auth'
    #    action = 'logout'
    #    input = '[]'
    #    token = $token
    #}
 
    # Login to the SecurityCenter
    #$ret = Invoke-WebRequest -URI "https://$($s)/request.php" -Method POST  -Body $ConnectBody -UseBasicParsing -SessionVariable sv
}

$Results | Export-Csv -NoTypeInformation $OutputCsv

Write-Output "Results have been copied to:  $($OutputCsv)"


## Extracted HTTP POST data for Nessus Security Center report generation.
#{"sortDir":"desc","sortField":"severity","endOffset":29,"tool":"sumiavm","sourceType":"cumulative","filters":[{"filterName":"iavmID","operator":"=","value":"2016-B-0036"}],"startOffset":0}

How to Configure a Scheduled Task to run every X Seconds

Title:  How to Configure a Scheduled Task to run every X Seconds
Description:  Windows Task Scheduler only allows for easy configuration of the quickest run-time of every 5 minutes (Trigger Configuration:  Daily occurrence with specified start-time and Task Repeat set to 5 minutes).  The workaround for this problem is to configure X number of TRIGGERS to achieve the desired task-execution frequency.

As an example, I wrote a network polling mechanism for a small/closed-network to determine host uptime.  The customer wanted a frequency greater than every 5 minutes--actually they wanted it to run every 10 seconds.  So, I had to be able to create a mechanism to support this.  I found some posts talking about Microsoft wanting anything < 5 minutes should be a Windows Service--but I shouldn't have to write compiled code with installers just to run a few-line PowerShell script.  So the easy answer is to configure tons of triggers to run with nearly identical configuration:


The key duplicated Trigger configuration parameters can be seen in the image, and are:

  1. Set the schedule setting to Daily.
  2. Ensure the recurrence is set to 1 day.
  3. Check the box to 'Repeat task every' and set it to 5 minutes and for a duration of 1 day.
  4. Ensure the Trigger is Enabled.
For every additional Trigger, increment the Start time from the previous Trigger by X mins or secs, depending on the desired interval.  In my case, the customer wanted my polling script to get metrics every 10 seconds so I had 30 Triggers configured with the following start times:


2017-09-11T00:00:00
2017-09-11T00:00:10
2017-09-11T00:00:20
2017-09-11T00:00:30
2017-09-11T00:00:40
2017-09-11T00:00:50
2017-09-11T00:01:00
2017-09-11T00:01:10
2017-09-11T00:01:20
2017-09-11T00:01:30
2017-09-11T00:01:40
2017-09-11T00:01:50
2017-09-11T00:02:00
2017-09-11T00:02:10
2017-09-11T00:02:20
2017-09-11T00:02:30
2017-09-11T00:02:40
2017-09-11T00:02:50
2017-09-11T00:03:00
2017-09-11T00:03:10
2017-09-11T00:03:20
2017-09-11T00:03:30
2017-09-11T00:03:40
2017-09-11T00:03:50
2017-09-11T00:04:00
2017-09-11T00:04:10
2017-09-11T00:04:20
2017-09-11T00:04:30
2017-09-11T00:04:40
2017-09-11T00:04:50


...which gave me the desired 10 second intervals to run the script.  Also, notice that I set the very first Trigger to start at Midnight.  This was intentional and served two purposes:
  1. It's easier for me to count by 5s/10s, starting from zero.  ;)
  2. I wanted to set this time in the past so that one of the remaining settings would be relevant for testing purposes (see below).
The final settings that are used to test all of this is on the Task itself.  Under Settings, ensure the following two settings are checked:
  1. Allow task to be run on demand
  2. Run task as soon as possible after a scheduled start is missed
In this way, once you click OK to the Task's creation, it should start firing which is what I wanted.

Below is the Task I used to test this configuration before using it in production.  It simply runs at the specified interval and writes the current datetime to a text file on your desktop so you can see the incremental interval.  It might save you a few dozen clicks in the Trigger creation interface.

To import it, simply save it as an .xml file and in Task Scheduler, right-click Import the file.


<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2017-09-11T13:50:23.6011472</Date>
    <Author></Author>
    <URI>\Test</URI>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:00:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:00:10</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:00:20</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:00:30</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:00:40</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:00:50</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:01:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:01:10</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:01:20</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:01:30</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:01:40</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:01:50</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:02:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:02:10</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:02:20</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:02:30</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:02:40</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:02:50</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:03:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:03:10</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:03:20</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:03:30</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:03:40</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:03:50</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:04:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:04:10</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:04:20</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:04:30</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:04:40</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT5M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2017-09-11T00:04:50</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-21-1271409858-1095883707-2794662393-1454529</UserId>
      <LogonType>InteractiveToken</LogonType>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-Command "&amp; { [datetime]::now.ToString() &gt;&gt; $env:UserProfile\Desktop\test_timer.txt } "</Arguments>
    </Exec>
  </Actions>
</Task>