This is the second half of the configuration of maintenance windows in Tanium described in Patch Like You Mean It. You can reference Setting Tanium Maintenance Windows with TanREST – Part I for the first half of the story.
Disclaimer: Any code made available on this site is free to use at your own discretion but it is provided without any explicit or implied guarantees of support, reliability, or functionality. I accept no responsibility in the event that the code, in its original form or any derivative versions thereafter, malfunctions or causes problems . Anything from this site that you decide to work with should be tested thoroughly in development environments in collaboration with your Technical Account Manager (TAM) until such time that you, the responsible party, decides that you are satisfied with its outcomes.
switch ("$Mode") { All { $taniumDeployMaintenanceWindows = Get-TaniumDeployMaintenanceWindow -WebSession $session | Where-Object {$_.Name -like "windowName*"} $taniumPatchMaintenanceWindows = Get-TaniumPatchMaintenanceWindow -WebSession $session | Where-Object {$_.Name -like "windowName*"} } Patch { $taniumPatchMaintenanceWindows = Get-TaniumPatchMaintenanceWindow -WebSession $session | Where-Object {$_.Name -like "windowName*"} } Deploy { $taniumDeployMaintenanceWindows = Get-TaniumDeployMaintenanceWindow -WebSession $session | Where-Object {$_.Name -like "windowName*"} } }
This lovely little mechanism above is called a switch statement. Where an if statement could accomplish the same thing, I prefer to use switch statements when I’ve got to evaluate the value of a variable that could have 3 or more values. In the above block, the $Mode variable could have three potential values. Each value will lead the function down a different path of operation. For example, the Patch section will be the only portion executed if the $Mode value is set to Patch when the Set-TaniumMaintenanceWindows function is executed.
Depending on your mode of execution, the function will execute one of the short blocks you see here. The functionality is relatively straightforward: each block has a variable to store the maintenance windows for Patch, Deploy, or both by invoking the Get-TaniumDeployMaintenanceWindow / Get-TaniumPatchMaintenanceWindow functions that are part of TanREST.
For more information about the switch statement, input the following command into a PowerShell session: Get-Help about_Switch and the included help file will give you the full breakdown of the mechanism along with examples of how to use it.
if ($Mode -eq 'All' -or $Mode -eq 'Patch') { foreach ($item in $maintenanceWindows) { if ($item.hoursDuration.Length -eq 4) { $item.hoursDuration = -join ('0',$item.hoursDuration) } $id = $taniumPatchMaintenanceWindows | Where-Object {$_.Name -eq "$($item.windowName)"} | Select-Object -ExpandProperty id $startDate = $($patchTuesday.AddDays($($item.patchTuesdayOffset))).ToString("yyyy-MM-dd") $hoursDuration = $item.hoursDuration $stopDate = ($(Get-Date "$startDate $hoursDuration").AddHours($item.HoursDuration)).ToString('yyyy-MM-dd') $stopTime = (Get-Date ($(Get-Date "$startDate $hoursDuration").AddHours($item.HoursDuration)) -UFormat %R) $configInfo = [PSCustomObject]@{ 'Name'="$($item.windowName)"; 'Module'='Patch'; 'Start Date'="$startDate"; 'Start Time (24hr)'="$hoursDuration"; 'Stop Date'="$stopDate"; 'Stop Time (24hr)'="$stopTime"; 'Duration'="$($item.HoursDuration)"; 'TaniumhoursDuration'="$null"; 'TaniumEndTime'="$null" } if ($Historical -eq $false) { $data = @{name="$($item.windowName)";repeatEvery=1;useTaniumClientTimeZone='true';` hoursDuration="$(-join ($startDate,'T',$hoursDuration,':00.00Z'))";` endTime="$(-join ($stopDate,'T',$stopTime,':00.00Z'))";osType='windows'} } else { $data = @{name="$($item.windowName)";repeatEvery=1;useTaniumClientTimeZone='true';` hoursDuration="2019-01-01T23:30:00.000Z";endTime="2019-01-02T23:30:00.000Z";osType='windows'} } if ($null -ne $id) { Set-TaniumPatchMaintenanceWindow -WebSession $session -ID $id -Data $data $currentMaintenanceWindow = Get-TaniumPatchMaintenanceWindow -ID $id -WebSession $session $configInfo.'TaniumhoursDuration' = $currentMaintenanceWindow | Select-Object -ExpandProperty hoursDuration $configInfo.'TaniumEndTime' = $currentMaintenanceWindow | Select-Object -ExpandProperty endTime $configurations.Add($configInfo) | Out-Null } else { $currentMaintenanceWindow = 'NoWindowFound' $configInfo.'TaniumhoursDuration' = 'NoWindowFound' $configInfo.'TaniumEndTime' = 'NoWindowFound' $configurations.Add($configInfo) | Out-Null } } }
This is where it gets real.
On Line 1, we’re making the determination about whether or not this block should run by evaluating the parameter value of $Mode. On Line 2, we’re creating a loop structure (Get-Help about_foreach in PowerShell for more detail) and instructing the function of our intention to repeat the nested, subsequent logic to take place for every row of values that was imported into the $maintenanceWindows variable from the CSV detailed in Part I. The current row being worked on by the function is represented by $item, meaning $item.hoursDuration or $item.patchTuesdayOffset will represent the specific value of one of the rows from the maintenance window source CSV.
On Line 7, we’re identifying the id of the maintenance window object that was pulled into an array variable by the API call made in the switch statement above. We’re doing so by comparing the name of the maintenance window from the CSV to the names of the maintenance window objects pulled in from Tanium. We will need the id later in order to update its configuration.
Line 8 serves to determine the start date for the current maintenance window in the foreach loop by calling the AddDays method of the $patchTuesday variable, adding the patchTuesdayOffset value to the Patch Tuesday date, and then formatting it in a way that we’ll be able to leverage later for TanREST. The following 3 lines are largely following the same pattern.
Lines 13-22 are populating a hash table that will be fed into the $configInfo variable which will itself be fed into the $configurations array created in the first post. If the information wasn’t passed from this loop to a variable outside of the loop, the data would be discarded and we would have nothing to pass to Send-HTMLEmail for the purposes of confirmation.
Lines 25-33 serve to construct the $data variable which will hold the JSON (JavaScript Object Notation) data. This data contains the information that will be passed to the API via the TanREST functions. Lines 25 and 30 represent the same data structure with different values that will take you in a different direction depending on whether you executed the function with the Historical switch or not.
Lines 35-41 are where the heaviest interactions with the API take place. Set-TaniumPatchMaintenanceWindow takes all the structured data we’ve created and passes it to the API to set those values on the Tanium maintenance window object. In order to confirm that value was set properly, the Get-TaniumPatchMaintenanceWindow is then called to pull those values back. The $configInfo properties are set on Lines 38-39 and then the $configInfo object for this iteration of the loop is passed outside of the loop to the $configurations array. If the $id had turned out to be null, Lines 42-46 would’ve foregone the call to the API and instead fed data into the $configurations array indicating that it couldn’t find a maintenance window in Tanium for that particular row in the CSV.
The block specifically tailored for Deploy is identical to the one detailed above except that it uses Set-TaniumDeployMaintenanceWindow and Get-TaniumDeployMaintenanceWindow instead.
$configurations = $configurations | Sort-Object -Property Name if ($Notify -eq $true) { if ($Mode -eq 'All') { Send-HTMLEmail -InputObject $configurations -To 'somebody@somewhere.com' -Subject ("Maintenance window configurations made for Patch and Deploy modules") -SmtpServer "someSmtoServer.com" } else { Send-HTMLEmail -InputObject $configurations -To 'somebody@somewhere.com' -Subject ("Maintenance window configurations made for $Mode module") -SmtpServer "someSmtoServer.com" } } else { if ($Mode -eq 'All') { Send-HTMLEmail -InputObject $configurations -To 'somebody@somewhere.com' -Subject ("Maintenance window configurations made for Patch and Deploy modules") -SmtpServer "someSmtoServer.com" } else { Send-HTMLEmail -InputObject $maintenanceWindows -To 'somebody@somewhere.com' -Subject ("Maintenance window configurations made for $Mode module") -SmtpServer "someSmtoServer.com" } }
Compared to the previous block, this one is fairly straightforward. Line 1 is simply an attempt to make the email easier to follow by reordering the $configurations variable to be in alphabetical order by the maintenance window name. Following that, there are some if statements that will take unique actions depending on whether you used the Notify switch when you executed the function.
The email that will be generated from the $configurations variable passed to the Send-HTMLEmail function can be seen below. The names have been redacted.
Disclaimer: Any code made available on this site is free to use at your own discretion but it is provided without any explicit or implied guarantees of support, reliability, or functionality. I accept no responsibility in the event that the code, in its original form or any derivative versions thereafter, malfunctions or causes problems . Anything from this site that you decide to work with should be tested thoroughly in development environments in collaboration with your Technical Account Manager (TAM) until such time that you, the responsible party, decides that you are satisfied with its outcomes.
One reply on “Setting Tanium Maintenance Windows with TanREST – Part II”
[…] explored in greater detail with the Setting Tanium Maintenance Windows with TanREST – Part I and Setting Tanium Maintenance Windows with TanREST – Part II posts, was the ability to ingest all our maintenance window settings from a CSV, enforce them […]