Skip to content

Instantly share code, notes, and snippets.

@levi-turner
Created November 6, 2020 18:36
Show Gist options
  • Save levi-turner/18f2c4db12c948ae8709d3cca34aecfd to your computer and use it in GitHub Desktop.
Save levi-turner/18f2c4db12c948ae8709d3cca34aecfd to your computer and use it in GitHub Desktop.
#--------------------------------------------------------------------------------------------------------------------------------
#
# Script Name: qs-qrs-telemetry_task_fix.ps1
# Description: A PowerShell script to fix & schedule tasks for Telemetry Dashboard project
# Dependency: None
#
# Version Date Author Change Notes
# 0.1 2020-04-27 Levi Turner Initial Version
# Many thanks to:
# https://stackoverflow.com/questions/19741716/how-do-i-get-date-1-formatted-as-mm-dd-yyyy-using-powershell
# http://webofwood.com/2010/08/13/get-a-midnight-datetime-value-in-powershell/
# Known Issues:
# Handling of different time zones. You will need to adjust values to get them to align with what you want at the current time.
# Unknown Issues:
# Different regional settings for the Windows Server
#--------------------------------------------------------------------------------------------------------------------------------
# Mandatory Variables
$createSchedule = 'Y' # Define whether the Telemetry Tasks will be scheduled
$scheduleCadence = 'Daily' # Define what cadence. Accepted Values: Daily / Weekly
$weeklyDay = 'Saturday' # Define what day the task will run if Weekly is chosen for $scheduleCadence. Accepted Values: Monday / Tuesday / Wednesday / Thursday / Friday / Saturday / Sunday
$hour = '4' # Hour for task to execute. Accepted Values: 0-23 (Midnight - 11PM / 2300)
# Build out headers for QRS API Calls
$hdrs = @{}
$hdrs.Add("X-Qlik-Xrfkey","examplexrfkey123")
$hdrs.Add("X-Qlik-User", "UserDirectory=INTERNAL; UserId=sa_api")
# Get the certificate
$cert = Get-ChildItem -Path "Cert:\CurrentUser\My" | Where {$_.Subject -like '*QlikClient*'}
# Check for the cert
if (!$cert) {
Write-Host "Client certificate not found" -ForegroundColor Red
Exit
}
# Construct the host to call
$Data = Get-Content C:\ProgramData\Qlik\Sense\Host.cfg
$FQDN = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($($Data)))
if (!$Data) {
Write-Host "Host.cfg file not found. Ensure script is run on a Qlik Sense node" -ForegroundColor Red
Exit
} else {
Write-Host "Attempting to connect to $FQDN" -ForegroundColor Green
}
# Handle TLS 1.2 exclusive environments
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
# Test call /qrs/about to ensure connectivity
$about = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/about?xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if (!$about) {
Write-Host "Unable to contact QRS at $($FQDN)" -ForegroundColor Red
Exit
} else {
Write-Host "Connected to $FQDN" -ForegroundColor Green
}
# Check for whether the app exists
$app = 'Telemetry Dashboard'
$telemetryapp = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/app/full?filter=(name eq '$app')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if (!$telemetryapp) {
Write-Host "Telemetry App: [ ]" -ForegroundColor Red
Write-Host "Rename / Import app" -ForegroundColor Red
Exit
}
elseif ($telemetryapp.count -gt 1) {
Write-Host "Duplicate copies of apps named Telemetry Dashboard found" -ForegroundColor Red
Write-Host "Ensure only 1 app is named Telemetry Dashboard for task fix" -ForegroundColor Red
Exit
}
else {
Write-Host "Telemetry App: [x]" -ForegroundColor Green
}
$telemetryapp = $telemetryapp.id
# Check for App Metadata Fetch Task
$task1 = 'TelemetryDashboard-1-Generate-Metadata'
$fetchtask = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/task/full?filter=(name eq '$task1')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if (!$fetchtask) {
Write-Host "Metadata Fetch: [ ]" -ForegroundColor Red
Write-Host "Creating Metadata Fetch Task ..." -ForegroundColor Green
$sharepath = (Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/servicecluster/full?xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert).settings.sharedPersistenceProperties.rootFolder
$sharepath = $sharepath.Replace('\', '\\')
$parampath = $sharepath
$parampath += '\\TelemetryDashboard\\TelemetryDashboard.exe\" -fetchmetadata -tasktriggered'
$body = '{
"path": "cmd.exe",'
$body += '"parameters": "/C \"'
$body += $parampath
$body += '"'
$body += ','
$body += '"name": "TelemetryDashboard-1-Generate-Metadata",
"taskType": 1,
"enabled": true,
"taskSessionTimeout": 1440,
"maxRetries": 0,
"impactSecurityAccess": false,
"schemaPath": "ExternalProgramTask"
}'
$body
$null = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/externalprogramtask?xrfkey=examplexrfkey123" -Method Post -Body $body -Headers $hdrs -ContentType 'application/json' -Certificate $cert
$fetchtask = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/task/full?filter=(name eq '$task1')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if ($fetchtask.count -eq '1') {
Write-Host "Metadata Fetch: [x]" -ForegroundColor Green
}
$trigger = 'telemetry-metadata-trigger'
$triggerevent = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/compositeevent/full?filter=(name eq '$trigger')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
$null = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/compositeevent/$($triggerevent.id)?xrfkey=examplexrfkey123" -Method Delete -Headers $hdrs -ContentType 'application/json' -Certificate $cert
}
elseif ($fetchtask.count -gt 1) {
Write-Host "Multiple tasks found named TelemetryDashboard-1-Generate-Metadata" -ForegroundColor Red
Write-Host "Ensure only 1 task is named TelemetryDashboard-1-Generate-Metadata" -ForegroundColor Red
Exit
}
else {
Write-Host "Metadata Fetch: [x]" -ForegroundColor Green
}
# Check for App Reload Task
$task2 = 'TelemetryDashboard-2-Reload-Dashboard'
$apptask = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/task/full?filter=(name eq '$task2')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if (!$apptask) {
Write-Host "App Reload Task: [ ]" -ForegroundColor Red
Write-Host "Creating Reload Task ..." -ForegroundColor Green
$reloadtaskbody = '{"task": {
"app": {
"id": "'
$reloadtaskbody += $telemetryapp
$reloadtaskbody += '",'
$reloadtaskbody += '
"name": "Telemetry Dashboard"
},
"enabled": true,
"isManuallyTriggered": false,
"maxRetries": 0,
"name": "TelemetryDashboard-2-Reload-Dashboard",
"taskSessionTimeout": 1440,
"taskType": 0
}
}'
$null = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/reloadtask/create?xrfkey=examplexrfkey123" -Method Post -Body $reloadtaskbody -Headers $hdrs -ContentType 'application/json' -Certificate $cert
$apptask = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/task/full?filter=(name eq '$task2')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if ($apptask.count -eq '1') {
Write-Host "App Reload Task: [x]" -ForegroundColor Green
}
}
elseif ($apptask.count -gt 1) {
Write-Host "Multiple tasks found for app named Telemetry Dashboard" -ForegroundColor Red
Write-Host "Ensure only 1 task is named TelemetryDashboard-1-Generate-Metadata" -ForegroundColor Red
Exit
}
else {
Write-Host "App Reload Task: [x]" -ForegroundColor Green
}
# Check for the trigger
$trigger = 'telemetry-metadata-trigger'
$triggerevent = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/compositeevent/full?filter=(name eq '$trigger')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if (!$triggerevent) {
Write-Host "Tasks linked: [ ]" -ForegroundColor Red
Write-Host "Creating link ..." -ForegroundColor Green
$triggerbody = '
{
"compositeEvents":[
{
"timeConstraint":{
"seconds":0,
"minutes":360,
"hours":0,
"days":0
},
"name":"telemetry-metadata-trigger",
"enabled":true,
"eventType":1,
"reloadTask":{
"id":"'
$triggerbody += $apptask.id
$triggerbody +='"
},
"compositeRules":[
{
"ruleState":1,
"externalProgramTask":{
"id":"'
$triggerbody += $fetchtask.id
$triggerbody +='"
}
}
],
"privileges":[
"read",
"update",
"create",
"delete"
]
}
]
}'
$null = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/reloadtask/update?xrfkey=examplexrfkey123" -Method Post -Body $triggerbody -Headers $hdrs -ContentType 'application/json' -Certificate $cert
$triggerevent = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/compositeevent/full?filter=(name eq '$trigger')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
if ($triggerevent.count -eq '1') {
Write-Host "Tasks linked: [x]" -ForegroundColor Green
}
}
elseif ($triggerevent.count -gt 1) {
Write-Host "Multiple chains are found." -ForegroundColor Red
Write-Host "Trigger is named telemetry-metadata-trigger" -ForegroundColor Red
Write-Host "Ensure only 1 trigger is named telemetry-metadata-trigger" -ForegroundColor Red
Exit
}
else {
Write-Host "Tasks linked: [x]" -ForegroundColor Green
}
# validate variables
if ($createSchedule -eq 'Y') {
Write-Host "Metadata Fetch Will be Scheduled [x]" -ForegroundColor Green
} elseif ($schedule -eq 'N') {
Write-Host "Metadata Fetch Will Not be Scheduled [x]" -ForegroundColor Green
} else {
Write-Host "Invalid Value for createSchedule variable" -ForegroundColor Red
Exit
}
if ($scheduleCadence -eq 'Daily') {
Write-Host "Daily Reload Specified" -ForegroundColor Green
} elseif ($scheduleCadence -eq 'Weekly') {
Write-Host "Weekly Reload Specified [x]" -ForegroundColor Green
} else {
Write-Host "Invalid Value for scheduleCadence variable" -ForegroundColor Red
Exit
}
if ($scheduleCadence -eq 'Weekly') {
if ($weeklyDay -eq 'Monday') {
Write-Host "Configure Reload for Mon [x]" -ForegroundColor Green
}
elseif ($weeklyDay -eq 'Tuesday') {Write-Host "Configure Reload for Tue [x]" -ForegroundColor Green}
elseif ($weeklyDay -eq 'Wednesday') {Write-Host "Configure Reload for Wed [x]" -ForegroundColor Green}
elseif ($weeklyDay -eq 'Thursday') {Write-Host "Configure Reload for Thu [x]" -ForegroundColor Green}
elseif ($weeklyDay -eq 'Friday') {Write-Host "Configure Reload for Fri [x]" -ForegroundColor Green}
elseif ($weeklyDay -eq 'Saturday') {Write-Host "Configure Reload for Sat [x]" -ForegroundColor Green}
elseif ($weeklyDay -eq 'Sunday') {Write-Host "Configure Reload for Sun [x]" -ForegroundColor Green}
else {
Write-Host "Invalid Value for weeklyDay variable" -ForegroundColor Red
Exit
}
}
# Look to see if currently scheduled, if scheduled, delete operational
$task1 = 'TelemetryDashboard-1-Generate-Metadata'
# Get TaskID
$fetchtask = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/task/full?filter=(name eq '$task1')&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
# Get ExternalProgramTaskID
$fetchtask = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/externalprogramtask/$($fetchtask.id)?xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
# Check for previously defined Schedule for the ExternalProgramTask
$fetchSchema = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/schemaevent/full?filter=(externalProgramTask.id eq $($fetchtask.id))&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
# if previously scheduled, delete the Schema
if (!$fetchSchema) {
Write-Host "Metadata Fetch currently unscheduled" -ForegroundColor Green
} else {
Write-Host "Metadata Fetch Scheduled ..." -ForegroundColor Green
Write-Host "... deleting schedule [x]" -ForegroundColor Green
Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/schemaevent/$($fetchSchema.id)?xrfkey=examplexrfkey123" -Method Delete -Headers $hdrs -ContentType 'application/json' -Certificate $cert | Out-Null
}
# Schedule bit
if ($scheduleCadence -eq 'Daily') {
$date = Get-Date
if ($date.Hour -gt $hour) {
# Schedule for tomorrow @ time
$dateQRS = (Get-Date -Hour $hour -Minute 00 -Second 00).AddDays(1).ToString('yyyy-MM-ddTHH:mm:ssZ')
$operationalBody = ' {
"nextExecution": "'
$operationalBody += $dateQRS
$operationalBody += '",
"schemaPath": "SchemaEventOperational"
}'
} else {
# Schedule for today
$dateQRS = (Get-Date -Hour $hour -Minute 00 -Second 00).ToString('yyyy-MM-ddTHH:mm:ssZ')
$operationalBody = ' {
"nextExecution": "'
$operationalBody += $dateQRS
$operationalBody += '",
"schemaPath": "SchemaEventOperational"
}'
}
# Post in the Schedule
$operational = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/schemaeventoperational?xrfkey=examplexrfkey123" -Method Post -body $operationalBody -Headers $hdrs -ContentType 'application/json' -Certificate $cert
$eventBody = '{
"timeZone": "America/New_York",
"daylightSavingTime": 0,
"startDate": "'
$eventBody += $dateQRS
$eventBody +='",
"expirationDate": "9999-12-31T00:00:00",
"schemaFilterDescription": [
"* * - * * * * *"
],
"incrementDescription": "0 0 1 0",
"incrementOption": 2,
"operational": {
"id": "'
$eventBody += $($operational.id)
$eventBody += '", "createdDate" : "'
$eventBody += $($operational.createdDate)
$eventBody += '","modifiedDate" : "'
$eventBody += $($operational.modifiedDate)
$eventBody += '", "modifiedByUserName" : "INTERNAL\\sa_api'
$eventBody += '", "lastEventDate" : "'
$eventBody += $($operational.lastEventDate)
$eventBody += '", "nextExecution" : "'
$eventBody += $($operational.nextExecution)
$eventBody += '", "timesTriggered" : 0,
"schemaPath": "SchemaEventOperational"
},
"name": "Reload fetchmetadata.js",
"enabled": true,
"eventType": 0,
"externalProgramTask": {
"id": "'
$eventBody += $($fetchtask.id)
$eventBody += '",
"operational": {
"id": "'
$eventBody += $fetchtask.operational.id
$eventBody += '"},
"name": "TelemetryDashboard-1-Generate-Metadata",
"taskType": 1,
"enabled": true,
"taskSessionTimeout": 1440,
"maxRetries": 0,
"privileges": null
},
"userSyncTask": null,
"reloadTask": null,
"privileges": null,
"schemaPath": "SchemaEvent"
}'
} else {
$date = Get-Date
# if current date, schedule
if ($weeklyDay -eq 'Monday') {
$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Monday'}
} elseif ($weeklyDay -eq 'Tuesday') {$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Tuesday'}}
elseif ($weeklyDay -eq 'Wednesday') {$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Wednesday'}}
elseif ($weeklyDay -eq 'Thursday') {$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Thursday'}}
elseif ($weeklyDay -eq 'Friday') {$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Friday'}}
elseif ($weeklyDay -eq 'Saturday') {$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Saturday'}}
else {$scheduleDate = 1..7 | % {$(Get-Date).AddDays($_)} | ? {$_.DayOfWeek -eq 'Sunday'}}
# build schedule
$dateQRS = $scheduleDate.ToString('yyyy-MM-ddTHH:mm:ssZ')
$dateQRS = (Get-Date -Hour $hour -Minute 00 -Second 00).ToString('yyyy-MM-ddTHH:mm:ssZ')
$operationalBody = ' {
"nextExecution": "'
$operationalBody += $dateQRS
$operationalBody += '",
"schemaPath": "SchemaEventOperational"
}'
# Post in the Schedule
$operational = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/schemaeventoperational?xrfkey=examplexrfkey123" -Method Post -body $operationalBody -Headers $hdrs -ContentType 'application/json' -Certificate $cert
$eventBody = '{
"timeZone": "America/New_York",
"daylightSavingTime": 0,
"startDate": "'
$eventBody += $dateQRS
$eventBody +='",
"expirationDate": "9999-12-31T00:00:00",
"schemaFilterDescription": [
"* * - '
switch ($weeklyDay) {
"Sunday" {$weeklyDay = 0}
"Monday" {$weeklyDay = 1}
"Tuesday" {$weeklyDay = 2}
"Wednesday" {$weeklyDay = 3}
"Thursday" {$weeklyDay = 4}
"Friday" {$weeklyDay = 5}
"Saturday" {$weeklyDay = 6}
}
$eventBody += $weeklyDay
$eventBody += ' 1 * * *"
],
"incrementDescription": "0 0 1 0",
"incrementOption": 3,
"operational": {
"id": "'
$eventBody += $($operational.id)
$eventBody += '", "createdDate" : "'
$eventBody += $($operational.createdDate)
$eventBody += '","modifiedDate" : "'
$eventBody += $($operational.modifiedDate)
$eventBody += '", "modifiedByUserName" : "INTERNAL\\sa_api'
$eventBody += '", "lastEventDate" : "'
$eventBody += $($operational.lastEventDate)
$eventBody += '", "nextExecution" : "'
$eventBody += $($operational.nextExecution)
$eventBody += '", "timesTriggered" : 0,
"schemaPath": "SchemaEventOperational"
},
"name": "Reload fetchmetadata.js",
"enabled": true,
"eventType": 0,
"externalProgramTask": {
"id": "'
$eventBody += $($fetchtask.id)
$eventBody += '",
"operational": {
"id": "'
$eventBody += $fetchtask.operational.id
$eventBody += '"},
"name": "TelemetryDashboard-1-Generate-Metadata",
"taskType": 1,
"enabled": true,
"taskSessionTimeout": 1440,
"maxRetries": 0,
"privileges": null
},
"userSyncTask": null,
"reloadTask": null,
"privileges": null,
"schemaPath": "SchemaEvent"
}'
}
# Post in the Schedule
Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/schemaevent?xrfkey=examplexrfkey123" -Method Post -body $eventBody -Headers $hdrs -ContentType 'application/json' -Certificate $cert | Out-Null
# Ensure schemaEvent exists
$fetchSchema = ''
$fetchSchema = Invoke-RestMethod -Uri "https://$($FQDN):4242/qrs/schemaevent/full?filter=(externalProgramTask.id eq $($fetchtask.id))&xrfkey=examplexrfkey123" -Method Get -Headers $hdrs -ContentType 'application/json' -Certificate $cert
# if previously scheduled, delete the Schema
if (!$fetchSchema) {
Write-Host "Metadata Fetch currently unscheduled" -ForegroundColor Red
} else {
Write-Host "Metadata Fetch Scheduled [x]" -ForegroundColor Green
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment