Showing results for 
Search instead for 
Did you mean: 

Time Based Device Admin - A Working Prototype

Rising Star III
Rising Star III

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.


  • For MacOS and Windows devices only. 
  • No 3rd party tool needed; a PowerShell console is all you need.
  • And you need the JumpCloud username from the requesting individual. 
  • Admins can track the progress via a background job.shawnsong_1-1703745185803.png
  • Users will get notifications about the privilege changes through:
    • Toast Messages on Windows.  
    • Popup dialogs on MacOS.
  • The notifications will inform users about the duration of their privileges and provide a few reminders towards the end of the session.

mac.giftoastWin (1).gif


Let It Roll

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.

# 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"
   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

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


Step 2 - Granting the privilege 

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:
# 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.

# 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 $ -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 ($ {
        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 $  -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 $ -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 (
        $baseUrl = ''
        $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 $($ 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 $  -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 $ -keep


The interactive workflow looks like this:shawnsong_2-1703745597405.png

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,, Workato, or Zapier to create the workflow as a slash command on Slack. 😉

Happy New Year, folks!

You Might Like

New to the site? Take a look at these additional resources:

Community created scripts:

Our new Radical Admin blog:

Keep up with Product News:

Read our community guidelines

Ready to join us? You can register here.