06-20-2024 02:29 PM - edited 06-20-2024 02:56 PM
JumpCloud Directory Insights data contains a wide range of information about organization users, their systems and how they are accessing managed resources. Understanding how to access and use the Directory Insights data can help administrators secure their organization and identify trends. In this blog post, I will describe how to use the JumpCloud PowerShell Module to access Directory Insights data and return the latest event information.
The JumpCloud PowerShell Module is a tool designed to help interact with the JumpCloud API. It’s something that can be run and installed on any computer regardless of its operating system. The module provides several nice-to-have features like auto-pagination when returning data longer than our standard page size. It’s a tool commonly used to perform bulk actions and get data about a JumpCloud Organization. In this post, the JumpCloud PowerShell Module will be required to run commands and get data about an organization.
Note: Please update to the latest version of the JumpCloud PowerShell Module to run the code examples below. At the time of this writing, the latest JumpCloud PowerShell Module is 2.12.0. The SDKs should also be updated when the Module is updated. The latest version of the V2, V1 and DirectoryInsights SDK modules are 0.0.48, 0.0.44 0.0.32 respectively.
The JumpCloud PowerShell Module has a number of functions that interact with various endpoints in the JumpCloud API. Get-JCEvent is the function designed to get and filter data from Directory Insights. Help documentation for Get-JCEvent can be found on the corresponding GitHub help page or through PowerShell directly by typing “help Get-JCEvent” once the PowerShell Module is installed.
The Get-JCEvent function requires a parameter for “StartTime” and “Service”. “StartTime” is the furthest date in the past in which to return Directory Insights data. “Service” refers to the various services described in the Directory Insights Scheme documentation.
The function also supports various filtering and sorting parameters which limits the time it takes to return data and can be used to return specific information about events.
In the examples below I’ll show how to get various types of data from Directory Insights.
Get-JCEvent -Service:('all') -StartTime:((Get-date).AddDays(-1))
This command would return Directory Insights data between the current time and exactly 24 hours ago, data from all services would be included in this response.
Get-JCEvent -Service:('systems') -StartTime:((Get-date).AddDays(-1))
This command would return Directory Insights data filtered by the “systems” service between the current time and exactly 24 hours ago.
Get-JCEvent -Service:('systems') -StartTime:((Get-date).AddDays(-20)) -SearchTermAnd @{'username' = "reid.sullivan"}
This command would return Directory Insights data filtered by the “systems” service between the current time and exactly 20 days ago. Only events where the username is “reid.sullivan” would be returned.
Get-JCEvent -Service:('systems') -StartTime:((Get-date).AddDays(-20)) -SearchTermAnd @{'username' = "reid.sullivan"; 'event_type' = 'login_attempt'} -Limit 1 -Sort "DESC"
This command would return Directory Insights data filtered by the “systems” service between the current time and exactly 20 days ago. Only one single event where the username is “reid.sullivan” and the event_type is “login_attempt” would be returned.
The number of events returned is limited to just 1 single event. Calling this endpoint with a limit of just 1 event will return results much faster than not specifying a limit. The PowerShell Modules will auto-paginate and return all possible events otherwise.
A note on sorting:
The data returned is sorted in descending order because the sort parameter was set to: "DESC". The latest event which occurred is returned. By default, events are returned in ascending order. Removing the “Sort” parameter from the previous command would return the first event found which is ascending order ("ASC")
With the brief set of usage examples out of the way, the concept of variables and loops can be addressed. Loops are a rather simple programming concept and can be employed to perform work that would otherwise be impossible to hand code. In order to get all the latest events for users a loop will be required. The following example is just an introduction to the concept of iteration.
Imagine wanting to write a script to print the numbers 1 through 5. The following script would suffice:
Write-Host "1"
Write-Host "2"
Write-Host "3"
Write-Host "4"
Write-Host "5"
This would would produce this result:
The same result can be achieved with a loop:
for ($i = 1; $i -lt 5; $i++) {
Write-Host "$i"
}
The code above contains a definition for an initial state, a conditional test and a step of work to execute.
Essentially, the variable $i is given an initial value of “1”, the code body “Write-Host $i” will execute once and print “1” to the console.
The conditional test “$i -le 5” states that while $i is less than or equal to 5 that the code body should execute.
The step of work to execute, “$i++” states that after each code body iteration the value of $i should be incremented by 1.
Each step explained:
The concept of loops in general will go far beyond the scope of this post. I’d encourage anyone interested to read more.
In order to get login event data for every user, we’ll use a loop to iterate through each user and perform an action very similar to that loop example discussed previously. In these examples I’ll show how to build each part of the script before showing the final script.
At a high level the script we’ll create will need to do the following:
$users = Get-JCUser
This command will get all of the JumpCloud users in an organization and save the data into the $users variable.
Foreach ($user in $users){
Get-JCEvent -Service:('systems') -StartTime:((Get-date).AddDays(-20)) -SearchTermAnd @{'username' = "$($user.username)"; 'event_type' = 'login_attempt'} -Limit 1 -Sort "DESC"
}
This command will iterate through each user from the $users variable and return the user’s last login but it’s not really helpful unless we can save each event to our own table.
In order to return some set of data we need to create a variable to store that data within. Array lists are perfect for the application. To create an array list:
$list = New-Object System.Collections.ArrayList
This command will declare $list as an array list — some list we can store data in. To store each user’s last login event, the result from Get-JCEvent can be added to the $list variable with the “.Add()” method:
# Get all the users
$users = Get-JCUser
# Declare a new list
$list = New-Object System.Collections.ArrayList
# Get the login data for each user and add it to the list
Foreach ($user in $users){
$list.Add(Get-JCsdkEvent -Service:('systems') -StartTime:((Get-date).AddDays(-90)) -SearchTermAnd @{'username' = "$($user.username)"; 'event_type' = 'login_attempt'} -Limit 1 -Sort "DESC") | Out-Null
}
# Get the list data where data exists and save to a CSV File
$list | Where-Object {$_ -ne $null} | ConvertTo-CSV | Out-File ~/lastLogin.csv
The code will get all the users in the organization and write the contents of that report to a CSV.
Building on the previous examples, let’s create a custom report containing only certain fields and multiple event types. In the last example we simply added every property from the Get-JCEvent function into a list. In this example we’ll combine two different event types and pair down the report to only contain the information we need by building a PsCustomObject.
# Get all the users
$users = Get-JCUser
# Declare a new list
$list = New-Object System.Collections.ArrayList
# Get the login data for each user and add it to the list
Foreach ($user in $users){
$systemLogin = Get-JCsdkEvent -Service:('systems') -StartTime:((Get-date).AddDays(-90)) -SearchTermAnd @{'username' = "$($user.username)"; 'event_type' = 'login_attempt'} -Limit 1 -Sort "DESC"
$userPortalLogin = Get-JCsdkEvent -Service:('directory') -StartTime:((Get-date).AddDays(-90)) -SearchTermAnd @{'initiated_by.username' = "$($user.username)"; 'event_type' = 'user_login_attempt'} -Limit 1 -Sort "DESC"
$list.Add(
[PSCustomObject]@{
username = $user.username
firstName = $user.firstName
lastName = $user.lastName
email = $user.email
lastSystemLoginHostname = $systemLogin.system.hostname
lastSystemLoginId = $systemLogin.system.id
lastSystemLoginGeoip = $systemLogin.Geoip
lastSystemLoginSystemTimestamp = $systemLogin.system_timestamp
lastUserPortalLoginGeoip = $userPortalLogin.geoip
lastUserPortalLoginTimestamp = $userPortalLogin.timestamp
}
) | Out-Null
}
# Get the list data where data exists and save to a CSV File
$list | Where-Object {$_ -ne $null} | ConvertTo-CSV | Out-File ~/lastLogin.csv
The following report should only contain the fields specified in the PSCustomObject. For each user there should be a login event for the user portal login and system login.
Feel free to build upon this template and make it your own. Hopefully this is a helpful introduction to custom reports, our events API and some basic programming concepts.
New to the site? Take a look at these additional resources:
Ready to join us? You can register here.