Advertisement
syntek

Process KnowBe4 Users with Past Due Training as High Risk in Entra Conditional Access

May 3rd, 2024
11
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. This script is intended to run hourly via a scheduled task, to sync users with past due training in knowbe4
  3. to an active directory security group. Separately, Azure AD Connect/Entra ID Connect/Cloud Connect will then
  4. sync this group up to Microsoft Entra, where a conditional access policy can be assigned to increase MFA prompts
  5. or however you would like to treat these users as 'high risk'. Once they complete their past due training, they
  6. will be removed from the group the next time the script is ran.
  7. #>
  8.  
  9. $EAP = $ErrorActionPreference
  10. $ErrorActionPreference = 'SilentlyContinue' # Because possibly dealing with converting a null value to 'datetime', below.
  11. $AccessToken = '---enter-knowbe4-reporting-api-token-here---'
  12. $GroupName = 'High Risk Users' # AD Group name
  13. $EmailDomainSuffix = '@contoso.com' # cheap hack to convert knowbe4 email addresses to AD sAMAccountName. must include the @ symbol!
  14.  
  15. #Force PowerShell to use TLS 1.2
  16. [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12
  17. #Set Required Headers
  18. $auth = @{
  19.     "ContentType" = 'application/json'
  20.     "Method"      = 'GET'
  21.     "Headers"     = @{
  22.         "Authorization" = "Bearer $AccessToken"
  23.         "Accept"        = "application/json"
  24.     }
  25. }
  26.  
  27. $URL = 'https://us.api.knowbe4.com/v1/training/campaigns/'
  28.  
  29. $campaigns = $null
  30. $campaigns = Invoke-RestMethod -Uri $URL @auth
  31. $campaigns | ForEach-Object {
  32.     if ($_.start_date -ne $null) { $_.start_date = [datetime]"$($_.start_date)" }
  33.     if ($_.start_date -eq $null) { $_.start_date = [nullable[datetime]]$null }
  34.     if ($_.end_date -ne $null) { $_.end_date = [datetime]"$($_.end_date)" }
  35.     if ($_.end_date -eq $null) { $_.end_date = [nullable[datetime]]$null }
  36. }
  37.  
  38. $PastDue = @()
  39.  
  40. $campaigns | Where-Object { $_.Status -ne "closed" -and $_.Status -ne "created" -and $_.completion_percentage -lt '100' } | Sort-Object name | ForEach-Object {
  41.     # Write-Host $_.campaign_id -ForegroundColor Yellow -NoNewline
  42.     # Write-Host " - "$_.name -ForegroundColor Cyan -NoNewline
  43.     if ($_.relative_duration) {
  44.         $_relative_duration = $_.relative_duration
  45.         #Write-Host " - Rel. Dur.:"$_.relative_duration -NoNewline
  46.     }
  47.     if ($_.end_date -ne $null) {
  48.         $_relative_duration = "$(New-TimeSpan -Start $($_.start_date) -End $($_.end_date)).Days days"
  49.         #Write-Host " (End date: $($_.end_date))" -ForegroundColor Green
  50.     }
  51.     if ($_.end_date -eq $null) {
  52.         #Write-Host " (No End date)"
  53.     }
  54. #>
  55.     $URL = "https://us.api.knowbe4.com/v1/training/enrollments?campaign_id=$($_.campaign_id)?per_page=500"
  56.  
  57.     $enrollments = $null
  58.  
  59.     $enrollments = Invoke-RestMethod -Uri $URL @auth
  60.     $enrollments = $enrollments | Select-Object campaign_name, completion_date, content_type, enrollment_date, enrollment_id, module_name, policy_acknowledged, start_date, status, user_status, user, id, first_name, last_name, email
  61.     $enrollments | ForEach-Object {
  62.         $_.id = $_.user.id
  63.         $_.first_name = $_.user.first_name
  64.         $_.last_name = $_.user.last_name
  65.         $_.email = $_.user.email
  66.     }
  67.     if ($_.relative_duration -eq $null) {}
  68.     $PastDue += $enrollments | Where-Object { $_.status -eq "past due" } | Select-Object campaign_name, enrollment_date, @{ Name = 'duration'; Expression = { $_relative_duration } }, days_late, module_name, status, user_status, id, first_name, last_name, email
  69. }
  70.  
  71. $ErrorActionPreference = $EAP
  72.  
  73. $PastDue | Sort-Object campaign_name, email  | ForEach-Object {
  74.     $duration_period = (($_.duration).Trim()).Split(' ')
  75.     if ($duration_period[1] -match "weeks") { $_days = ((Get-Date).AddDays( - ([int]$duration_period[0] * 7)) - [Datetime]"$($_.enrollment_date)").Days }
  76.     if ($duration_period[1] -match "months") { $_days = ((Get-Date).AddMonths( - ([int]$duration_period[0])) - [Datetime]"$($_.enrollment_date)").Days }
  77.     if ($duration_period[1] -match "days") { $_days = $duration_period[0] }
  78.     $_.days_late = "  $_days "
  79.     $_.enrollment_date = [datetime]"$($_.enrollment_date)"
  80. }
  81. # Is the user 'Active' or 'Archived'?
  82. $PastDue | ForEach-Object {
  83.     $StatusURL = "https://us.api.knowbe4.com/v1/users/$($_.id)"
  84.     $_.user_status = (Invoke-RestMethod -Uri $StatusURL @auth).Status
  85. }
  86.  
  87. $PastDue = $PastDue | Where-Object { $_.user_status -eq "Active" }
  88.  
  89. $PastDueUsers = @()
  90. foreach ($User in $PastDue) {
  91.     $PastDueUsers += $User.email -Replace "$EmailDomainSuffix",''
  92. }
  93. $PastDueUsers = $PastDueUsers | Select-Object -Unique
  94.  
  95. # Update AD Group members to match array
  96. $Group = Get-AdGroup -Identity $GroupName
  97.  
  98. # Get current members of the group
  99. $CurrentMembers = Get-AdGroupMember -Identity $Group | Select-Object -ExpandProperty SamAccountName
  100. $AddedUsers = 0
  101. $RemovedUsers = 0
  102.  
  103. # Add users to the group if they are in the $PastDueUsers array and not currently in the group
  104. foreach ($User in $PastDueUsers) {
  105.     if ($User -notin $CurrentMembers) {
  106.         Add-AdGroupMember -Identity $Group -Members $User
  107.         #Write-Host "Added $User to $GroupName"
  108.         Write-Host "Added $User to `'$GroupName`'" -ForegroundColor DarkCyan
  109.         $AddedUsers += 1
  110.     }
  111. }
  112. if ($AddedUsers -eq 0) {
  113.     Write-Host "No new users added to `'$GroupName`'" -ForegroundColor DarkCyan
  114. }
  115.  
  116. # Remove users from the group if they are not in the $PastDueUsers array
  117. foreach ($Member in $CurrentMembers) {
  118.     if ($Member -notin $PastDueUsers) {
  119.         Remove-AdGroupMember -Identity $Group -Members $Member -Confirm:$false
  120.         #Write-Host "Removed $Member from $GroupName"
  121.         Write-Host "Removed $Member from `'$GroupName`'" -ForegroundColor DarkCyan
  122.         $RemovedUsers += 1
  123.     }
  124. }
  125. if ($RemovedUsers -eq 0) {
  126.     Write-Host "No users were removed from `'$GroupName`'" -ForegroundColor DarkCyan
  127. }
  128.  
  129. $TotalHighRiskUsers = (Get-AdGroupMember -Identity $Group | Select-Object -ExpandProperty SamAccountName).count
  130. if ($null -eq $TotalHighRiskUsers) { $TotalHighRiskUsers = 0 }
  131. Write-Host "$TotalHighRiskUsers total members of `'$GroupName`'" -ForegroundColor DarkCyan
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement