12-28-2023 01:40 AM - edited 12-28-2023 02:53 AM
Hi Folks,
Hope you had a wonderful Christmas holiday! Before we head to the brand new 2024, would you like a 2023 closing gift? 😀
I’ll keep it short: this feature is probably the most requested during my customer calls. And I hear you, I really do. I've been working on this on and off for the past few months. So, I’m committed to wrapping up a working prototype this year - for all of us!
Here you go.
A Quick Stop Sign
In the spirit of practicing better security discipline to protect our secrets, particularly the JumpCloud API keys, I have consistently used $env:JCRW variable throughout the project. Please ensure you store your API keys securely in the system environment variables. DO NOT clear text in any scripts or files.
TL;DR - Head to my repo here if you know the drill already.
Step 1 - Create the commands for toast messages. You only need to do it once.
# Connect to your JC Tenant - Manager role is good enough!
Connect-JCOnline -JumpCloudApiKey $env:JCRW #strongly suggest storing the API key in the system env variable,
## i.e. https://medium.com/@sonykey2003/protect-your-secrets-in-environment-variables-a07eff7699f0
# Create the toast msg cmd trigger for Windows
$winTriggerName = "WinToast"
$winCmd = @'
# Writting the env var to a file for the user session to access
$env:remainingTime | Out-File $env:public\rt.txt -Force
# Make sure the required modules are installed
$modules = get-module -ListAvailable burnttoast,runasuser
if ($modules.count -ne 2){
Install-Module BurntToast,RunAsUser -force
}
# Popping the msg
$scriptBlock = {
$remainingTime = get-content C:\Users\Public\rt.txt; New-BurntToastNotification -Text "Your admin privilege has been granted, it will be revoked in $remainingTime mins"
}
invoke-ascurrentuser -scriptblock $scriptBlock
# Cleaning up
remove-item $env:public\rt.txt -force
'@
New-JCCommand -commandType windows -launchType trigger -name $winTriggerName -trigger $winTriggerName -command $winCmd
# Create the toast msg cmd trigger for MacOS
$MacTriggerName = "MacToast"
$MacCmd = @'
# get the current user's UID
uid=$(id -u "$currentUser")
# convenience function to run a command as the current user
# usage:
# runAsUser command arguments...
runAsUser() {
if [ "$currentUser" != "loginwindow" ]; then
#launchctl asuser "$uid" sudo -u "$currentUser" "$@"
launchctl asuser "$uid" sudo -u "$currentUser" "$@" -c "echo $remainingTime"
else
echo "no user logged in"
# uncomment the exit command
# to make the function exit with an error when no user is logged in
# exit 1
fi
}
osascript -e "display dialog \"Your admin privilege has been granted, it will be revoked in $remainingTime mins\" buttons {\"OK\"}"
'@
New-JCCommand -commandType mac -launchType trigger -name $MacTriggerName -trigger $MacTriggerName -command $MacCmd
Make sure you are aware of the API key conceal practise highlighted above, btw$env:JCRW variable is referenced in line 11,63,68, and 118, in case you wanted to change it.
# ----------------------------------------------------------------------------------------------------------
# Script: Invoke-TimeBasedAdmin.ps1
# Version: 1.0.0
# Author: Shawn Song
# Reference: https://docs.jumpcloud.com/api/1.0/index.html
# Notes: Please run this script on an adminstrative device with the latest version of PowerShell installed.
# ----------------------------------------------------------------------------------------------------------
# Connect to your JC Tenant - Manager role is good enough!
Connect-JCOnline -JumpCloudApiKey $env:JCRW #strongly suggest storing the API key in the system env variable,
## i.e. https://medium.com/@sonykey2003/protect-your-secrets-in-environment-variables-a07eff7699f0
# Get JC user - please do it one at a time
$username = Read-Host "What is the user name you want to promot to admin"
[Int32]$time = Read-Host "How long you want to grant the admin privilege, in mins? (input the integer - i.e. 15,20,30)"
$jcuser = Get-JCUser -username $username
# List the assoicated devices
$systems = Get-JCAssociation -Type user -Id $jcuser.id -TargetType system
$outSystems = @()
foreach ($s in $systems){
$sysinfo = Get-JCSystem -SystemID $s.targetId
if ($sysinfo.osFamily -ne 'ios' -and $sysinfo.osFamily -ne 'android'){
$outSystems += $sysinfo
}
}
Write-Host "Here is a list of systems $username is binding to:"
foreach ($system in $outSystems){
if ($system.active) {
Write-Host "$($system.hostname) --- is online" -ForegroundColor Green
}
else {
Write-Host "$($system.hostname) --- is offline, changes might not be applied until it connects back online." -ForegroundColor Yellow
}
}
$targetHostname = Read-Host "Which system you are prompting the user to admin? Pick a hostname (online) from above"
$targetSystem = $outSystems | where {$_.hostname -eq $targethostname}
Set-JCSystemUser -Username $jcuser.username -SystemID $targetSystem.id -Administrator $true
# Set trigger name depends on the os type
switch ($targetSystem.osFamily) {
"windows" {$triggerName = "WinToast"}
"darwin" {$triggerName = "MacToast"}
}
# Get cmd info
$cmd = Get-JCCommand -name $triggerName
#start a timer
$startTime = Get-Date
$endTime = $startTime.AddMinutes($time) # Adjust the time as needed
# Start a background job to keep track of the time
Write-Output 'Kicking off a background job for $username...Check the status by using "receive-Job -id $job.id -keep" '
$job = Start-Job -Name ($username+'Temp Admin '+$time+' mins') -ScriptBlock {
param ($env:JCRW,$time,$startTime,$endTime,$jcuser,$targetSystem,$triggerName,$cmd)
Connect-JCOnline -JumpCloudApiKey $env:JCRW -force
# Trigger cmd function
function Trigger-JCCmd {
param (
[int]$remainingTime,
$JCAPIKEY=$env:JCRW,
$TriggerName
)
$baseUrl = 'https://console.jumpcloud.com/api/command/trigger/'
$headers = @{
"x-api-key" = $JCAPIKEY
"Content-Type" = "application/json"
"Accept" = "application/json"
}
$body = @{
"remainingTime" = $remainingTime
} | ConvertTo-Json
$response = Invoke-RestMethod -Uri ($baseUrl+$triggerName) -Method Post -Headers $headers -Body $body
return $response
}
# Binding the cmd trigger to the designated system
Set-JcSdkCommandAssociation -CommandId $cmd._id -Op "add" -Type 'system' -Id $targetSystem._id
# Giving user a heads up when the privillege been granted.
Trigger-JCCmd -TriggerName $triggerName -remainingTime $time
# Running a timer effectively
do {
# Trigger cmd function
$currentTime = Get-Date
[Int32]$remainingTime = [math]::Ceiling(($endTime - $currentTime).TotalMinutes)
Write-Output "$($jcuser.username)'s admin previllege will be revoked at: $endtime, time remianing: $remainingTime mins"
sleep 60
if ($remainingTime -lt $time * 0.3 ) {
Write-Output "Triggering $($cmd.name) to $($targetSystem.hostname)..."
Trigger-JCCmd -TriggerName $triggerName -remainingTime $remainingTime
}
else {
Write-Output "Nothing to trigger for $($targetSystem.hostname)..."
}
} while ($currentTime -lt $endTime)
# Times up, reverting back
set-JCSystemUser -Username $jcuser.username -SystemID $targetSystem.id -Administrator $false
Write-Output "$($jcuser.username)'s admin previllege is revoked at: $currentTime."
# remove once it done.
Set-JcSdkCommandAssociation -CommandId $cmd._id -Op "remove" -Type 'system' -Id $targetSystem._id
} -ArgumentList $env:JCRW,$time,$startTime,$endTime,$jcuser,$targetSystem,$triggerName,$cmd
# Getting the status of the job
receive-Job -id $job.id -keep
The interactive workflow looks like this:
Hope this helps! Feel free to build a comprehensive approval workflow before obtaining the JC username for admin promotion. For example, you can use platforms like make.com, tray.io, Workato, or Zapier to create the workflow as a slash command on Slack. 😉
Happy New Year, folks!
New to the site? Take a look at these additional resources:
Ready to join us? You can register here.