Overview
When you create a deployment policy in the Code42 console, the process generates user-detection scripts and agent install command arguments. This article provides details about the scripts for Windows, Mac, and Linux devices.
Use the scripts for the agents in your Code42 environment. If you use the wrong script, agent deployment will fail.
This article applies to devices where both the insider risk and backup agents are being deployed. If you are only deploying the insider risk agent, see Deployment script and command reference for the insider risk agent.
For assistance, contact your Customer Success Manager (CSM) to engage the Code42 Professional Services team. If you don't know who your CSM is, contact our Technical Support Engineers.
Considerations
This article assumes you understand the introduction to deployment provided by the article Deploy Code42 agents.
- To use these deployment tools, you need to sign in to your Code42 console as a user with the Security Administrator role.
- In the Code42 federal environment, app installations must be deployed with a deployment policy to ensure the use of FIPS encryption in the Code42 agent. Users cannot download the installation package from the Code42 console.
Deployment is a secure process:
- During installation, device-server communications are encrypted.
- Devices can use a proxy to reach the Code42 cloud. See the PROXY_URL parameter.
- Deployment can run silently, with no intervention from users at devices.
About user detection scripts
Code42 relies on usernames having an email format, for instance, firstname.lastname@example.com. A user detection script detects the usernames in another system, such as a directory service, and transforms them to a username format that Code42 can use. When you create a user detection script, you must customize it for the system where you need to detect usernames.
To make it easier to create a user detection script that's right for your situation, we provide example scripts for Windows and Mac systems. You can use these examples as a starting place when creating your own user detection script.
Deploying both the insider risk and backup agents to a single device requires:
- Two code42.deployment.properties files (the deployment policy contains separate properties for each agent type).
- A single user detection script. Only use the user detection script for the backup agent; it also detects the user for the insider risk agent. If you use the detection script for the insider risk agent, the backup agent will not be able to register.
Windows
For Code42 agents on Windows devices, a deployment policy provides:
- A user detection script to provide the Code42 agent with a username and home directory for the device. The script can also optionally specify the user's organization.
- Installation properties to serve as the arguments string to a Code42 agent install command.
Windows user detection script
When you create a deployment policy, you must also create a custom user detection script. A user detection script examines the host device and provides the Code42 agent with a username and home directory. The script resides on the Code42 cloud. The Code42 agent retrieves it during the install process.
Because user names in the Code42 cloud must be email addresses, deployments for connection to the Code42 cloud always require a customized user detection script.
You need to create a custom script because Code42 usernames must be email addresses. If you need help, contact your Customer Success Manager (CSM) to engage the Professional Services team.
How the Windows script works
The user detection script for Windows:
- Uses the device's operating system to determine the most recent logged-on username.
- Calculates the typical home directory for that username.
The user detection script then reports these two values to a standard output.
To require users to enter their usernames manually, do not use a detection script. In the deployment policy, leave all operating systems deselected to create a deployment policy without a user detection script.
Tips to create a custom Windows script
Create a custom script and paste your script into your deployment policy. If you need help, contact your Customer Success Manager (CSM) for enterprise support.
When creating your custom script, be aware of the following:
- Every script must end by echoing values for two variables.
echo C42_USERNAME=<value> echo C42_USER_HOME=<value>
- Usernames must be email addresses.
echo C42_USERNAME=%current_user%@example.com - Optionally, you can also specify the the organization for the user. Use the registration key for the organization. If the organization is not defined, the user registers to the organization specified in the deployment policy.
echo C42_ORG_REG_KEY=<value>
- You must provide values. Null values and empty strings will not work.
- If you cannot write a script to provide a workable value, write a message for the username field of the Code42 agent sign in dialog, for example:
echo C42_USERNAME=Enter name and click Sign in
- The values cannot include either single (') or double (") quotation marks.
Windows command and arguments
Deployment policy command arguments need to be imported into your software management tool.
Commands and arguments are detailed here in case you need to modify them for some reason, or to help you deploy without a software management tool.
- To install a Code42 agent for all users of a device, sign in to an account with administrative rights and issue a command like the following:
msiexec /i Code42_n.n.n_Win64.msi CP_ARGS="DEPLOYMENT_URL=https://.host &DEPLOYMENT_POLICY_TOKEN=0fb12341-246b-448d-b07f-c6573ad5ad02 &PROXY_URL=http://.host/fname.pac" CP_SILENT=true DEVICE_CLOAKED=false /norestart /qn
- To install for one user only, sign in as that user, and append the following three parameters to the command:
- ALLUSERS=2
- MSIINSTALLPERUSER=1
- INSTALL_PER_USER=1
Here are the individual parts of a command:
| Element | Description |
| msiexec /i | Windows command to install a product. |
| Code42_n.n.n_Win64.msi |
Name of Code42 agent installer file, version n.n.n. You must update the filename and version number to match the version being deployed. |
| CP_ARGS=" | Start of the installation properties copied from the deployment policy. |
| DEPLOYMENT_URL= https://.host |
The address of your Code42 console. The Code42 agent requests its deployment policy from this address. |
| DEPLOYMENT_POLICY_TOKEN= | A unique ID string identifies each deployment policy. |
|
PROXY_URL= http://.host/fname.pac |
The address of a proxy auto-config file. The file tells a Code42 agent how to communicate with Code42 through a proxy server. This argument is only present when your policy configuration says Use Org Proxy URL: Yes. If the argument is present, but has no value, the policy says use proxy: yes, but the organization has no proxy addresses defined. |
| " | The value of CP_ARGS begins and ends with quote marks. |
| CP_SILENT=true or false |
|
| DEVICE_CLOAKED=true or false |
The Client Visibility setting for this organization.
This argument only affects client visibility during initial deployment. Future changes to the Client Visibility setting in the Code42 console are automatically pushed to the device. |
| /norestart | The Windows operating system does not restart after the Code42 agent installs. |
| /qn | Quiet: The Windows installer does not open a console and does not prompt the user. |
| /l* filename | Code42 agent writes installation logs to filename. |
| ALLUSERS=2 MSIINSTALLPERUSER=1 INSTALL_PER_USER=1 |
Add these three parameters if you wish to install the Code42 agent for only the currently signed-in user, not all users of the device. |
| ARPNOREMOVE= |
(Optional) Add this parameter to prevent users from uninstalling the Code42 agent from the Start menu and Add/Remove programs in the Control Panel.
The |
Example Windows user detection scripts
Following are example user detection scripts for the Windows platform. For help with these scripts, contact your Customer Success Manager (CSM) to engage the Professional Services team.
General usage:
- Add the known domains that are used by the company in the "IncludedDomains" list in the format of '*@domain.com'; include all domains that are used by user's emails in the company.
- Add users you want to exclude from processing to the denylist in each script (look for "ExcludedUsers" or "Excluded Users"). This helps IT teams ensure that the Code42 installation is set up for the correct end users, and not the support staff setting up the Windows computers for the first time.
- Check if the script has additional variables for controlling how it outputs. For example, some scripts need 'UseDomain' filled with the standard domain used by the company for appending.
Domain-joined username detection script
Professional Services filename: win_am_domain_joined_device_user_detection_script.bat
This script detects users running explorer.exe and determines their email addresses from the directory. This script is the default Windows user detection script used by the Code42 Professional Services team. For Azure, the script looks at the registry keys in IdentityStore Name2Sid. If no valid email is found, it then tries ADSI lookup. If no ADSI is not found then is looks for HKLM:\SOFTWARE\Microsoft\Enrollments\* for the Microsoft Enrollments RegKey. This script requires an active connection to a Windows domain and requires Powershell v.4.0 or later.
<# : batch script
@echo off
setlocal
cd %~dp0
powershell -executionpolicy bypass -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
#win_am_domain_joined_device_user_detection_script.bat #for Incydr and Backup Agents #last updated 2025-06-10 #Add Domains to this list that Code42 can register with; must start with *@ $IncludedDomains = @( '*@domain.com' '*@domain2.com' ) #Add users and domains to this list that Code42 should not register; using * as wildcard $ExcludedUsersAndDomains = @( '*@domain.com' 'user1' 'defaultuser0*' 'Localadmin' 'admin' 'Administrator' 'admin-*' ) function Find-User { ################################################# $global:emailfound=$false $excludedusersanddomainscount=$ExcludedUsersAndDomains.count Write-Log "---" Write-Log "-----------------------------------User Detection Run Start-----------------------------------" Write-Log "---" Write-Log "Running user detection script: win_am_domain_joined_device_user_detection_script.bat" Write-Log "Starting user detection...version 2025-06-02" $hostname = $env:computername $OsInfo = (Get-CimInstance -ClassName CIM_OperatingSystem | Select-Object Caption, Version, OSArchitecture, BuildNumber) Write-Log "Machine hostname: ($hostname)" Write-Log "$OsInfo".replace("@{Caption=","{") $username = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] $AgentUUID = (Get-ItemProperty HKLM:\Software\Code42-AAT | Select-Object -ExpandProperty AgentUUID) $InstallUUID = (Get-ItemProperty HKLM:\Software\Code42-AAT | Select-Object -ExpandProperty InstallUUID) Write-Log "AgentUUID is ($AgentUUID)" Write-Log "InstallUUID is ($InstallUUID)" Write-Log "Local explorer OS username found ($username)" Write-Log "ExcludedUsers List is length ($excludedusersanddomainscount)" Get-childItem C:\Users | forEach $path { $userlist = $userlist + ( $_ | Select-Object -ExpandProperty Name) + ", " } Write-Log "UserList: ($userlist)" $C42_USERNAME = "" $C42_USERNAME = "@ Local User is ($username)" #Start of Hybrid Azure Reg Key Logic Write-Log "~" Write-Log "~" Write-Log "Trying to find from hybrid Azure/EntraID reg key..." $LastLoggedOnUser = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI | Select-Object -ExpandProperty LastLoggedOnUser).Split('\')[-1].Split('@')[0] $displayname = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI | Select-Object -ExpandProperty LastLoggedOnDisplayName) Write-Log "LastLoggedOnUser name found: ($LastLoggedOnUser)" Write-Log "LastLoggedOnDisplayName name found: ($displayname)" if (!(Check-Exclusion-List $LastLoggedOnUser)) { $azureregkeys = (Get-ItemProperty HKLM:SOFTWARE\Microsoft\IdentityStore\LogonCache\*\Name2Sid\* | Where-Object {$_.DisplayName -eq $displayname} | Select-Object -Unique -ExpandProperty identityName) Write-Log "Azure/EntraID Reg Key(s) returned: ($azureregkeys)" #Using first email that matches domain if (!([string]::IsNullOrEmpty($azureregkeys))) { $azurekeyarray = $azureregkeys.split(" ") Write-Log "Found Email(s) in Azure Reg Key(s)" foreach ($email in $azurekeyarray) { Write-Log "Checking ($email)" if (Check-Exclusion-List $email) { Write-Log "Email in Azure/EntraID Reg Key is on excluded user list : ($email)" $C42_USERNAME = "Azure/EntraID Email Exclusion ($email)@" continue } if (Check-Domain-List $email) { Write-Log "An Email in Azure/EntraID Reg Key has matched domain list : ($email)" if ($global:emailfound) { Write-Log "Could also have used Azure/EntraID Reg Key: ($email)" } else { $C42_USERNAME = $email $global:emailfound=$true Write-Log "**********************************" Write-Log "**********************************" Write-Log "****** Email found via Azure/EntraID Reg Key lookup: ($C42_USERNAME)" Write-Log "****** Attempting to register Code42 Agent with this Email" Write-Log "**********************************" Write-Log "**********************************" } continue } else { Write-Log "Email address failed validation checks on domain($email)" if (!($global:emailfound)) { $C42_USERNAME = "Email Domain validation Fail ($email)@" } } } } else { Write-Log "No Emails found in Azure Regkey ($azureregkeys)" $C42_USERNAME = "No Emails found in Azure/EntraID Regkey @" } } else { Write-Log "The LastLoggedOnUser is on the Exclusion List ($LastLoggedOnUser)" $C42_USERNAME = "Excluded LastLoggedOnUser ($LastLoggedOnUser)@" } #Start of AD ADSI Searcher Logic Write-Log "~" Write-Log "~" Write-Log "Trying to Query ADSI domain search..." $explorerusername = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] Write-log "Using explorer user: ($explorerusername)" if (!(Check-Exclusion-List $explorerusername)) { $searcher = [adsisearcher]"(samaccountname=$explorerusername)" $userupn = ($searcher.FindOne().Properties.userprincipalname) if ([string]::IsNullOrEmpty($userupn)) { Write-Log "ADSI domain search returned null for UPN check if domain record exists for user" Write-Log "ADSI domain search returned null for UPN check if machine is domain bound" if (!($global:emailfound)) { $C42_USERNAME = "Azure/EntraID and ADSI search returned null @ ($explorerusername)" } } else { $usermail = ($searcher.FindOne().Properties.mail) $userdisplayname = ($searcher.FindOne().Properties.name) $usercreate = ($searcher.FindOne().Properties.whencreated) Write-Log "User ($explorerusername) has a domain record of mail ($usermail)" Write-Log "User ($explorerusername) has a domain record of userprincipalname ($userupn)" Write-Log "User ($explorerusername) has a domain record of name ($userdisplayname)" Write-Log "User ($explorerusername) has a domain record of whencreated ($usercreate)" if ($global:emailfound) { Write-Log "Could also have used ADSI domain search: ($usermail)" } else { if ([string]::IsNullOrEmpty($usermail)) { Write-Log "usermail is empty trying: ($userupn)" $C42_USERNAME = "$userupn" } else { $C42_USERNAME = "$usermail" } $global:emailfound=$true Write-Log "**********************************" Write-Log "**********************************" Write-Log "****** Email found via ADSI domain search: ($C42_USERNAME)" Write-Log "****** Attempting to register Code42 Agent with this Email" Write-Log "**********************************" Write-Log "**********************************" } } } else { Write-Log "The explorerusername is on the Exclusion List ($explorerusername)" $C42_USERNAME = "Explorer Exclusion User ($explorerusername) @" } #Start of Microsoft Enrollments RegKey Logic Write-Log "~" Write-Log "~" Write-Log "Trying to Query Microsoft Enrollments RegKey..." $explorerusername = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] Write-log "Using explorer user: ($explorerusername)" if (!(Check-Exclusion-List $explorerusername)) { $enrollemntsregkeys = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Enrollments\* | Select-Object -ExpandProperty UPN) Write-Log "O365 Enrollment Reg Key(s) returned: ($enrollemntsregkeys)" #Using first email that matches domain if (!([string]::IsNullOrEmpty($enrollemntsregkeys))) { $enrollemntsarray = $enrollemntsregkeys.split(" ") Write-Log "Found Email(s) in Enrollment Reg Key(s)" foreach ($email in $enrollemntsarray) { Write-Log "Checking ($email)" if ([string]::IsNullOrEmpty($email)) { Write-Log "Microsoft Enrollments RegKey returned null for UPN" if (!($global:emailfound)) { $C42_USERNAME = "Microsoft Enrollments RegKey returned null @ ($explorerusername)" } } else { if (Check-Exclusion-List $email) { Write-Log "Email in Microsoft Enrollments RegKey is on excluded user list : ($email)" $C42_USERNAME = "Microsoft Enrollments RegKey Exclusion ($email)@" continue } if (Check-Domain-List $email) { Write-Log "Email in Microsoft Enrollments RegKey has matched domain list : ($email)" if ($global:emailfound) { Write-Log "Could also have used Microsoft Enrollments RegKey:($email)" } else { $C42_USERNAME = "$email" $global:emailfound=$true Write-Log "**********************************" Write-Log "**********************************" Write-Log "****** Email found via Microsoft Enrollments RegKey: ($C42_USERNAME)" Write-Log "****** Attempting to register Code42 Agent with this Email" Write-Log "**********************************" Write-Log "**********************************" } continue } else { Write-Log "Email address failed validation checks on domain($email)" if (!($global:emailfound)) { $C42_USERNAME = "Email Domain validation Fail ($email)@" } } } } } } else { Write-Log "The explorerusername is on the Exclusion List ($explorerusername)" $C42_USERNAME = "Explorer Exclusion User ($explorerusername) @" } Write-Log "~" Write-Log "~" $ExplorerUser = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] $wmiuser = Get-CimInstance Win32_UserAccount -Filter "Name = '$ExplorerUser'" $C42_USER_HOME = Get-CimInstance Win32_UserProfile -Filter "SID = '$($wmiuser.SID)'" | Select-Object -ExpandProperty LocalPath if (!$C42_USER_HOME) { Write-Log "User home query from WMI failed. Using fallback home detection method" $C42_USER_HOME = "$env:HOMEDRIVE\Users\$ExplorerUser" Write-Log "User home set by appending $ExplorerUser to home path ($C42_USER_HOME)" } else { Write-Log "User home queried from WMI successfully ($C42_USER_HOME)" } Write-Log "~" Write-Log "~" $C42_USERNAME = $C42_USERNAME.ToLower() Write-Log "Returning C42_USERNAME: $C42_USERNAME" Write-Log "Returning C42_USER_HOME: $C42_USER_HOME" if (!($global:emailfound)) { Write-log "Will retry user detection again in few minutes, or when next service restart or device reboot occurs." } Write-Host C42_USERNAME=$C42_USERNAME Write-Host C42_USER_HOME=$C42_USER_HOME } $Scriptpath = Get-Location $PROC_LOG = "$env:HOMEDRIVE\ProgramData\CrashPlan\log\preservation_user_detection_result.log" if ("$Scriptpath" -eq "C:\WINDOWS\system32") {$PROC_LOG = "$env:HOMEDRIVE\ProgramData\Code42-AAT\logs\incydr_user_detection_result.log"} function Check-Exclusion-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$checkvalue ) $checkvalue=$checkvalue.ToLower() $ExcludedUsersAndDomains | ForEach-Object { if (($checkvalue -like $_.ToLower()) -or ([string]::IsNullOrEmpty($checkvalue))) { return $true } } return $false } function Check-Domain-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$email ) $email=$email.ToLower() $IncludedDomains | ForEach-Object { if ($email -like $_.ToLower()) { return $true } } return $false } function Write-Log { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [string]$LogMessage ) write-output $LogMessage Add-Content -Path $PROC_LOG -Value (Write-Output ("{0} - {1}" -f (Get-Date), $LogMessage)) } Find-User
Username Append Domain Script
Professional Services filename: win_am_username_append_domain_user_detection_script.bat
The following script detects users running explorer.exe and appends the domain of the email address. The script sets the home directory by adding the username to the \Users directory path in Windows. This script requires PowerShell v.4.0 or later. This script can also be set to detect the LastLoggedOnUser instead of the user currently running explorer.exe.
<# : batch script
@echo off
setlocal
cd %~dp0
powershell -executionpolicy bypass -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
#win_am_username_append_domain_user_detection_script.bat #for Incydr and Backup Agents #last updated 2024-03-04 #Add Domains to this list that Code42 can register with; must start with *@ $IncludedDomains = @( '*@domain.com' '*@domain2.com' ) #Add users and domains to this list that Code42 should not register; using * as wildcard $ExcludedUsersAndDomains = @( '*@yahoo.com' '*@gmail.com' '*@outlook.com' '*@domain.com' 'user1' 'admin' 'Administrator' 'admin-*' ) #Domain to be used for appending to UserName must be in IncludedDomains $companydomain="domain.com" function Find-User { ################################################# $global:emailfound=$false $excludedusersanddomainscount=$ExcludedUsersAndDomains.count Write-Log "---" Write-Log "-----------------------------------User Detection Run Start-----------------------------------" Write-Log "---" Write-Log "Running user detection script: win_am_username_append_domain_user_detection_script.bat" Write-Log "Starting user detection...version 2024-03-04" $hostname = $env:computername Write-Log "Machine hostname: ($hostname)" $username = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] $usernameclean = $username.replace(" ","") Write-Log "Local explorer OS username found ($username)" Write-Log "ExcludedUsers List is length ($excludedusersanddomainscount)" $C42_USERNAME = "" #Start of Username @ Domain Logic if using make sure to update the domain value Write-Log "~" Write-Log "~" $LastLoggedOnUser = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI | Select-Object -ExpandProperty LastLoggedOnUser).Split('\')[-1].Split('@')[0] Write-log "Explorer User: ($username)" Write-Log "LastLoggedOnUser Username found ($LastLoggedOnUser)" #Change attribute to $usernameclean from $LastLoggedOnUser if needed $tempemail= $usernameclean + '@' + $companydomain if (Check-Exclusion-List $username) { Write-Log "User failed excluded validation checks ($usernameclean)" } elseif (Check-Domain-List $tempemail) { if ($global:emailfound) { Write-Log "Could also have used Username+Domain: ($tempemail)" } else { $C42_USERNAME = $tempemail $global:emailfound=$true Write-Log "**********************************" Write-Log "**********************************" Write-Log "****** Email assembled by appending domain to LastLoggedOnUser: ($C42_USERNAME)" Write-Log "****** Attempting to register Code42 Agent with this Email" Write-Log "**********************************" Write-Log "**********************************" } } else { Write-Log "Email address failed validation checks ($tempemail)" } Write-Log "~" Write-Log "~" $ExplorerUser = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] $wmiuser = Get-CimInstance Win32_UserAccount -Filter "Name = '$ExplorerUser'" $C42_USER_HOME = Get-CimInstance Win32_UserProfile -Filter "SID = '$($wmiuser.SID)'" | Select-Object -ExpandProperty LocalPath if (!$C42_USER_HOME) { Write-Log "User home query from WMI failed. Using fallback home detection method" $C42_USER_HOME = "$env:HOMEDRIVE\Users\$ExplorerUser" Write-Log "User home set by appending $ExplorerUser to home path ($C42_USER_HOME)" } else { Write-Log "User home queried from WMI successfully ($C42_USER_HOME)" } Write-Log "~" $C42_USERNAME = $C42_USERNAME.ToLower() Write-Log "Returning C42_USERNAME: $C42_USERNAME" Write-Log "Returning C42_USER_HOME: $C42_USER_HOME" if (!($global:emailfound)) { Write-log "Will retry user detection again in few minutes, or when next service restart or device reboot occurs." } Write-Host C42_USERNAME=$C42_USERNAME Write-Host C42_USER_HOME=$C42_USER_HOME } $Scriptpath = Get-Location $PROC_LOG = "$env:HOMEDRIVE\ProgramData\CrashPlan\log\preservation_user_detection_result.log" if ("$Scriptpath" -eq "C:\WINDOWS\system32") {$PROC_LOG = "$env:HOMEDRIVE\ProgramData\Code42-AAT\logs\incydr_user_detection_result.log"} function Check-Exclusion-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$checkvalue ) $checkvalue=$checkvalue.ToLower() $ExcludedUsersAndDomains | ForEach-Object { if (($checkvalue -like $_.ToLower()) -or ([string]::IsNullOrEmpty($checkvalue))) { return $true } } return $false } function Check-Domain-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$email ) $email=$email.ToLower() $IncludedDomains | ForEach-Object { if ($email -like $_.ToLower()) { return $true } } return $false } function Write-Log { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [string]$LogMessage ) write-output $LogMessage Add-Content -Path $PROC_LOG -Value (Write-Output ("{0} - {1}" -f (Get-Date), $LogMessage)) } Find-User
First name and last name script
Professional Services filename: win_am_firstname_lastname_append_domain_user_detection_script.bat
The following script detects the locally logged-in users' displayname then processes it to first and last names. How the displayname is used is controlled by variables. Possible output: firstname.lastname@domain.com, firstnamelastname@domain.com, flastname@domain.com
- To use only the first letter of the user's first name instead of the full name, change
usefirstinitialonly=falsetousefirstinitialonly=true - To remove the period between the first name or initial and the last name, change
noperiodinbetween=falsetonoperiodinbetween=true - To remove special characters, change
removeapostrophes,removehyphen, orremovetildefromfalsetotrueas needed.
<# : batch script
@echo off
setlocal
cd %~dp0
powershell -executionpolicy bypass -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
#win_am_firstname_lastname_append_domain_user_detection_script.bat #for Incydr and Backup Agents #last updated 2024-03-27 #Add Domains to this list that Code42 can register with; must start with *@ $IncludedDomains = @( '*@domain.com' '*@domain2.com' ) #Add users and domains to this list that Code42 should not register; using * as wildcard $ExcludedUsersAndDomains = @( '*@yahoo.com' '*@gmail.com' '*@outlook.com' '*@domain.com' 'user1' 'admin' 'Administrator' 'admin-*' ) #Options for script #Domain to be used for appending to name example: code42.com must be in IncludedDomains $companydomain="domain.com" #Use f.lastname@domain.com $usefirstinitialonly=$false #Use firstnamelastname@domain.com or flastname@domain.com $noperiodinbetween=$false #Removes all & if true $remove_apostrophes=$false #Removes all - if true $remove_hyphen=$false #Removes all ~ if true $remove_tilde=$false function Find-User { ################################################# $global:emailfound=$false $excludedusersanddomainscount=$ExcludedUsersAndDomains.count Write-Log "---" Write-Log "-----------------------------------User Detection Run Start-----------------------------------" Write-Log "---" Write-Log "Running user detection script: win_am_firstname_lastname_append_domain_user_detection_script.bat" Write-Log "Starting user detection...version 2024-03-27" $hostname = $env:computername Write-Log "Machine hostname: ($hostname)" $username = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] Write-Log "Local explorer OS username found ($username)" Write-Log "ExcludedUsers List is length ($excludedusersanddomainscount)" $C42_USERNAME = "" #Start of First Name - Last Name Logic Write-Log "~" Write-Log "~" Write-Log "usefirstinitialonly is set to ($usefirstinitialonly)" Write-Log "noperiodinbetween is set to ($noperiodinbetween)" Write-Log "remove_apostrophes is set to ($remove_apostrophes)" Write-Log "remove_hyphen is set to ($remove_hyphen)" Write-Log "remove_tilde is set to ($remove_tilde)" Write-Log "~" Write-Log "~" $displayname = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI | Select-Object -ExpandProperty LastLoggedOnDisplayName) #Remove and start and end spaces on the string and force lowercase $displayname= $($displayname.Trim()).ToLower() Write-Log "User name found ($username)" Write-Log "DisplayName found ($displayname)" Write-Log "~" Write-Log "~" if([string]::IsNullOrEmpty($displayname) -or $displayname -like ""){ Write-log "Regkey LastLoggedOnDisplayName not found or empty." } elseif (Check-Exclusion-List $username) { Write-Log "User failed excluded validation checks ($username)" } else { #Check for firstname lastname or lastname, firstname in the regkey LastLoggedOnDisplayName #if there are two lastnames with a " " the space will be removed if($displayname -like "*,*"){ Write-Log "Lastname, Firstname Mode" $namearray= $displayname.Split(",") $lastname= $($namearray[0].Trim()).Trim(",") $lastname= $lastname.replace(" ","") Write-Log "Lastname: ($lastname)" $firstname= $namearray[1].Trim() $firstname= $firstname.replace(" ","") Write-Log "Firstname: ($firstname)" } else{ Write-Log "Firstname Lastname Mode" $namearray= $displayname.Split(" ") $firstname= $namearray[0].Trim() $lastname= $namearray[-1].Trim() Write-Log "Firstname: ($firstname)" $namearraycount=$namearray.count if ($namearraycount -eq 1) { Write-log "There is no lastname" $nolastname=$true } else { Write-Log "Lastname: ($lastname)" } } if ($nolastname) { $tempemail = $firstname + '@' + $companydomain } else { if ($usefirstinitialonly) {$firstname = $firstname[0]} if ($noperiodinbetween) {$tempemail = $firstname + $lastname + '@' + $companydomain} else {$tempemail = $firstname + "." + $lastname + '@' + $companydomain} } if ($remove_apostrophes) {$tempemail=$tempemail.replace("''","")} if ($remove_hyphen) {$tempemail=$tempemail.replace("-","")} if ($remove_tilde) {$tempemail=$tempemail.replace("~","")} if (Check-Domain-List $tempemail) { $C42_USERNAME = $tempemail $global:emailfound=$true Write-Log "**********************************" Write-Log "**********************************" Write-Log "****** Email assembled by appending domain to LastLoggedOnUser: ($C42_USERNAME)" Write-Log "****** Attempting to register Code42 Agent with this Email" Write-Log "**********************************" Write-Log "**********************************" } else { Write-Log "Email address failed validation checks ($tempemail)" } } Write-Log "~" Write-Log "~" $ExplorerUser = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] $wmiuser = Get-CimInstance Win32_UserAccount -Filter "Name = '$ExplorerUser'" $C42_USER_HOME = Get-CimInstance Win32_UserProfile -Filter "SID = '$($wmiuser.SID)'" | Select-Object -ExpandProperty LocalPath if (!$C42_USER_HOME) { Write-Log "User home query from WMI failed. Using fallback home detection method" $C42_USER_HOME = "$env:HOMEDRIVE\Users\$ExplorerUser" Write-Log "User home set by appending $ExplorerUser to home path ($C42_USER_HOME)" } else { Write-Log "User home queried from WMI successfully ($C42_USER_HOME)" } Write-Log "~" Write-Log "~" $C42_USERNAME = $C42_USERNAME.ToLower() Write-Log "Returning C42_USERNAME: $C42_USERNAME" Write-Log "Returning C42_USER_HOME: $C42_USER_HOME" if (!($global:emailfound)) { Write-log "Will retry user detection again in few minutes, or when next service restart or device reboot occurs." } Write-Host C42_USERNAME=$C42_USERNAME Write-Host C42_USER_HOME=$C42_USER_HOME } $Scriptpath = Get-Location $PROC_LOG = "$env:HOMEDRIVE\ProgramData\CrashPlan\log\preservation_user_detection_result.log" if ("$Scriptpath" -eq "C:\WINDOWS\system32") {$PROC_LOG = "$env:HOMEDRIVE\ProgramData\Code42-AAT\logs\incydr_user_detection_result.log"} function Check-Exclusion-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$checkvalue ) $checkvalue=$checkvalue.ToLower() $ExcludedUsersAndDomains | ForEach-Object { if (($checkvalue -like $_.ToLower()) -or ([string]::IsNullOrEmpty($checkvalue))) { return $true } } return $false } function Check-Domain-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$email ) $email=$email.ToLower() $IncludedDomains | ForEach-Object { if ($email -like $_.ToLower()) { return $true } } return $false } function Write-Log { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [string]$LogMessage ) write-output $LogMessage Add-Content -Path $PROC_LOG -Value (Write-Output ("{0} - {1}" -f (Get-Date), $LogMessage)) } Find-User
Text file script
Professional Services filename: win_am_textfile_read_in_user_detection_script.bat
The following script reads a text file (default location C:\ProgramData\C42_Email.txt) for the user's email address and sets the home directory by adding the username to the \Users directory path in Windows. This script requires PowerShell v4.0 or later.
<# : batch script
@echo off
setlocal
cd %~dp0
powershell -executionpolicy bypass -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
#win_am_textfile_read_in_user_detection_script.bat #for Incydr and Backup Agents #last updated 2024-03-04 #Add Domains to this list that Code42 can register with; must start with *@ $IncludedDomains = @( '*@domain.com' '*@domain2.com' ) #Add users and domains to this list that Code42 should not register; using * as wildcard $ExcludedUsersAndDomains = @( '*@yahoo.com' '*@gmail.com' '*@outlook.com' '*@domain.com' 'user1' 'admin' 'Administrator' 'admin-*' ) #Full File Path Location of Textfile to be read #should only contain the user's email address, no headings $Textfile_Email = Get-Content $env:HOMEDRIVE\ProgramData\C42_Email.txt function Find-User { ################################################# $global:emailfound=$false $excludedusersanddomainscount=$ExcludedUsersAndDomains.count Write-Log "---" Write-Log "-----------------------------------User Detection Run Start-----------------------------------" Write-Log "---" Write-Log "Running user detection script: win_am_textfile_read_in_user_detection_script.bat" Write-Log "Starting user detection...version 2024-03-04" $hostname = $env:computername Write-Log "Machine hostname: ($hostname)" $username = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] Write-Log "Local explorer OS username found ($username)" Write-Log "ExcludedUsers List is length ($excludedusersanddomainscount)" $C42_USERNAME = "" #Start of TextFile @ Domain Logic Write-Log "~" Write-Log "~" Write-Log "TextFile Username found ($Textfile_Email)" if (Check-Exclusion-List $username) { Write-Log "User failed excluded validation checks ($username)" } elseif (Check-Domain-List $Textfile_Email) { $C42_USERNAME = $Textfile_Email $global:emailfound=$true Write-Log "*****************" Write-Log "*****************" Write-Log "****** Email Found via TextFile: ($C42_USERNAME)" Write-Log "****** Attempting to register Code42 Agent with this Email" Write-Log "*****************" Write-Log "*****************" } else { Write-Log "Email address failed validation checks ($Textfile_Email)" } Write-Log "~" Write-Log "~" $ExplorerUser = (Get-Process -IncludeUserName -Name explorer | Select-Object -ExpandProperty UserName).Split('\')[1] $wmiuser = Get-CimInstance Win32_UserAccount -Filter "Name = '$ExplorerUser'" $C42_USER_HOME = Get-CimInstance Win32_UserProfile -Filter "SID = '$($wmiuser.SID)'" | Select-Object -ExpandProperty LocalPath if (!$C42_USER_HOME) { Write-Log "User home query from WMI failed. Using fallback home detection method" $C42_USER_HOME = "$env:HOMEDRIVE\Users\$ExplorerUser" Write-Log "User home set by appending $ExplorerUser to home path ($C42_USER_HOME)" } else { Write-Log "User home queried from WMI successfully ($C42_USER_HOME)" } Write-Log "~" Write-Log "~" $C42_USERNAME = $C42_USERNAME.ToLower() Write-Log "Returning C42_USERNAME: $C42_USERNAME" Write-Log "Returning C42_USER_HOME: $C42_USER_HOME" if (!($global:emailfound)) { Write-log "Will retry user detection again in few minutes, or when next service restart or device reboot occurs." } Write-Host C42_USERNAME=$C42_USERNAME Write-Host C42_USER_HOME=$C42_USER_HOME } $Scriptpath = Get-Location $PROC_LOG = "$env:HOMEDRIVE\ProgramData\CrashPlan\log\preservation_user_detection_result.log" if ("$Scriptpath" -eq "C:\WINDOWS\system32") {$PROC_LOG = "$env:HOMEDRIVE\ProgramData\Code42-AAT\logs\incydr_user_detection_result.log"} function Check-Exclusion-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$checkvalue ) $checkvalue=$checkvalue.ToLower() $ExcludedUsersAndDomains | ForEach-Object { if (($checkvalue -like $_.ToLower()) -or ([string]::IsNullOrEmpty($checkvalue))) { return $true } } return $false } function Check-Domain-List { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [AllowNull()] [AllowEmptyString()] [string]$email ) $email=$email.ToLower() $IncludedDomains | ForEach-Object { if ($email -like $_.ToLower()) { return $true } } return $false } function Write-Log { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=0)] [string]$LogMessage ) write-output $LogMessage Add-Content -Path $PROC_LOG -Value (Write-Output ("{0} - {1}" -f (Get-Date), $LogMessage)) } Find-User
Mac
For Code42 agents on Mac devices, a deployment policy provides:
- A detection script to provide the Code42 agent with a username and home directory for the device. The script can also optionally specify the user's organization.
- A deploy.properties file to distribute along with the Code42 agent installer package.
Before Code42 agent installers can run properly, the deploy.properties file must be in placed in the management tool or the device's file system.
Mac user detection script
When you create a deployment policy, you must also create a custom user detection script. A user detection script examines the host device and provides the Code42 agent with a username and home directory. The script resides on the Code42 cloud. The Code42 agent retrieves it during the install process.
Because user names in the Code42 cloud must be email addresses, deployments for connection to the Code42 cloud always require a customized user detection script.
You need to create a custom script because Code42 usernames must be email addresses. If you need help, contact your Customer Success Manager (CSM) for enterprise support.
How the Mac script works
The user detection script for Mac:
- Uses the device's operating system to determine the most recent logged-on username.
- Calculates the typical home directory for that username.
The detection script then reports these two values to a standard output.
To require users to enter their usernames manually, do not use a detection script. In the deployment policy, leave all operating systems deselected to create a deployment policy without a user detection script.
Tips to create a custom Mac script
Create a custom script and paste your script into your deployment policy. If you need help, contact your Customer Success Manager (CSM) for enterprise support.
When creating your custom script, be aware of the following:
- Every script must end by echoing values for two variables:
echo "C42_USERNAME=<value>" echo "C42_USER_HOME=<value>"
- Usernames must be email addresses.
echo "C42_USERNAME=${user}@example.com" - Optionally, you can also specify the the organization for the user. Use the registration key for the organization. If the organization is not defined, the user registers to the organization specified in the deployment policy.
echo C42_ORG_REG_KEY=<value>
- You must provide values. Null values and empty strings will not work.
- If you cannot write a script to provide a workable value, write a message for the username field of the Code42 agent sign in dialog, for example:
echo "C42_USERNAME=Enter name and click Sign in"
- The values cannot include either single (') or double (") quotation marks.
Mac commands
Deployment policy command arguments need to be imported into your software management tool.
Commands and arguments are detailed here in case you need to modify them for some reason, or to help you deploy without a device management tool.
- To install a Code42 agent for all users of a device, sign in to an account with administrative rights and issue a command like the following.
hdiutil attach Code42_n.n.n_Mac.dmg installer -package "/Volumes/Code42/Install Code42.pkg" -target LocalSystem hdiutil detach /Volumes/Code42
-
To install for one user only, sign in as that user and use
targetCurrentUserHomeDirectory.
Individual parts of the commands are as follows:
| Element | Description |
| hdiutil attach Code42_n.n.n_Mac.dmg |
Mount the Code42 agent disk image. You must update the name of the installer file to match the exact name and version number being deployed. |
| installer -package "/Volumes/Code42/Install Code42.pkg" |
Run the install program. |
|
-target LocalSystem -target CurrentUserHomeDirectory |
Install the Code42 agent for all users of the device. Or, install for only the current user. |
| hdiutil detach /Volumes/Code42 |
Unmount the Code42 agent disk image. |
Mac deploy.properties file
The typical deploy.properties file reads like this:
DEPLOYMENT_URL=https://.host DEPLOYMENT_POLICY_TOKEN=0fb12341-246b-448d-b07f-c6573ad5ad02 CP_SILENT=true DEVICE_CLOAKED=false PROXY_URL=http://.host/fname.pac
Individual parts of that file are as follows:
| Element | Description |
| DEPLOYMENT_URL= https://.host |
The address of your Code42 console. The Code42 agent requests its deployment policy from this address. |
| DEPLOYMENT_POLICY_TOKEN= | A unique ID string identifies each deployment policy. |
| CP_SILENT=true or false |
|
| DEVICE_CLOAKED=true or false |
The Client Visibility setting for this organization.
This argument only affects client visibility during initial deployment. Future changes to the Client Visibility setting in the Code42 console are automatically pushed to the device. |
|
PROXY_URL= http://.host/fname.pac |
The address of a proxy auto-config file. The file tells a Code42 agent how to communicate with Code42 through a proxy server. This argument is only present when your policy configuration says Use Org Proxy URL: Yes. If the argument is present, but has no value, the policy says use proxy: yes, but the organization has no proxy addresses defined. |
Mac deploy.properties file location
When the Code42 agent installer runs on Mac, it looks for the deploy.properties file in three locations, in the following order:
-
(Best practice) In the directory /Library/Application Support/CrashPlan
Installations for a single user use ~/Library rather than /Library. - In the disk image, typically in: /Volumes/Code42
- In a Jamf Pro temp directory: /tmp/mountpt/Code42
For most software management tools, the best location is the first option:
/Library/Application Support/CrashPlan
Location 1, Application Support (best practice)
For deployment with most software management tools, including Jamf Pro, store the file here:
/Library/Application Support/CrashPlan/deploy.properties
To install for a single user, rather than all users of a device, use ~/Library rather than /Library.
To create the directory and write the file, run a bash script like the following where you replace <deploy.properties> with the text from your deploy.properties file:
#!/bin/bash mkdir -p /Library/Application\ Support/CrashPlan echo "<deploy.properties>" > /Library/Application\ Support/CrashPlan/deploy.properties
Location 2, the disk image
Adding deploy.properties to the installer disk image is best for users starting an install manually, by clicking on the *.dmg file.
Not all deployment software mounts the disk image in the same location, making deploy.properties in the disk image hard to find.
Add deploy.properties to the disk image as follows:
- Make a writable copy of the disk image.
- Mount the writable copy.
- Copy deploy.properties to the new image's root directory.
- Unmount the image.
- Return the image to the read-only state.
The following example shows the commands needed to add the deploy.properties file to the disk image.
hdiutil convert -format UDRW Code42_n.n.n_Mac.dmg -o C42_n.n.n_w.dmg hdiutil attach C42_n.n.n_w.dmg cp deploy.properties /Volumes/Code42/deploy.properties hdiutil detach /Volumes/Code42 hdiutil convert -format UDRO C42_n.n.n_w.dmg -o C42_n.n.n_ro.dmg
Location 3, Jamf Pro tmp
/tmp/mountpt/Code42
This location is unique to the Jamf Pro device management tool.
Example Mac user detection scripts
Following are example user detection scripts for the Mac platform. For help with these scripts, contact your Customer Success Manager (CSM) to engage the Professional Services team.
General usage:
- Replace "domain.com" with your domain name.
- Add users you want to exclude from processing to the denylist in each script (look for "admin1|admin2|admin3"). This helps IT teams ensure that the Code42 installation is set up for the correct users, and not the support staff setting up the Mac computers for the first time.
- Depending on your environment, some scripts may require you to set additional flags.
MacOS plist script
Professional Services filename: macos_am_plist_user_detection_script.sh
The following script is helpful if you use main MacOS MDM's for device management. The script reads a plist on the local machine that is populated with the email associated with the device from the MDM. It checks for JAMF Connect Plist, Kandji Global Variable Plist (Kandji Global Variable), Okta Network User Plist, or the Code42 Plist (additional setup in Jamf)
#!/bin/bash
#macos_am_plist_user_detection_script.sh
#for Incydr and Backup Agents
#last updated 2025-04-15
function main () {
extensionslist="$(systemextensionsctl list | grep -i "com.code42.agent.extension")"
userrealname=$(id -P $(stat -f%Su /dev/console) | cut -d : -f 8)
loggedinuser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }')
jamfplistuser=$(/usr/libexec/PlistBuddy -c "Print:DisplayName" /Users/$loggedinuser/Library/Preferences/com.jamf.connect.state.plist)
code42plistuser=$(defaults read /Library/Managed\ Preferences/com.code42.email.plist code42ActivationEmail)
kandjiplistuser=$(/usr/libexec/PlistBuddy -c ‘print :EMAIL’ /Library/Managed\ Preferences/io.kandji.globalvariables.plist)
kandjiplist2user=$(defaults read /Library/Managed\ Preferences/io.kandji.globalvariables.plist EMAIL)
oktanetworkuser=$(dscl . -read /Users/$last_user dsAttrTypeStandard:NetworkUser 2/dev/null | awk -F ': ' '{print $2}')
dLocalHostName=$(scutil --get LocalHostName)
currentdate=$(date)
C42_USERNAME=""
C42_USERNAME="@logged in user ($loggedinuser)"
writeLog "---"
writeLog "-----------------------------------User Detection Run Start-----------------------------------"
writeLog "---"
writeLog "Running user detection script: macos_am_plist_user_detection_script.sh"
writeLog "Starting user detection...version 2025-04-15"
writeLog "$currentdate"
writeLog "LocalHostName found ($dLocalHostName)"
writeLog "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
writeLog "extensionslist:"
writeLog "$extensionslist"
writeLog "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
writeLog "userrealname: ($userrealname)"
writeLog "loggedinuser: ($loggedinuser)"
writeLog "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
writeLog "jamfplistuser: ($jamfplistuser)"
writeLog "kandjiplistuser: ($kandjiplistuser)"
writeLog "kandjiplist2user: ($kandjiplist2user)"
writeLog "oktanetworkuser: ($oktanetworkuser)"
writeLog "code42plistuser: ($code42plistuser)"
writeLog "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
if [[ ! $jamfplistuser =~ "@" ]] || [[ $jamfplistuser =~ "com.jamf.connect.state.plist" ]]; then
jamfplistuser=""
fi
if [[ ! $kandjiplistuser =~ "@" ]] || [[ $jamfplistuser =~ "io.kandji.globalvariables.plist" ]]; then
kandjiplistuser=""
fi
if [[ ! $kandjiplist2user =~ "@" ]] || [[ $jamfplistuser =~ "io.kandji.globalvariables.plist" ]]; then
kandjiplist2user=""
fi
if [[ ! $oktanetworkuser =~ "@" ]] || [[ $jamfplistuser =~ "doesn't exist" ]]; then
oktanetworkuser=""
fi
if [[ ! $code42plistuser =~ "@" ]] || [[ $jamfplistuser =~ "doesn't exist" ]]; then
code42plistuser=""
fi
for user in /Users/*; do
writeLog "Users: ($user)"
done
#Start of Plist Logic
writeLog "~"
if [[ "$loggedinuser" =~ ^(admin1|admin2|admin|root|jamfadmin|_mbsetupuser)$ ]] || [[ -z "$user" ]]; then
writeLog "User failed excluded validation checks ($loggedinuser)"
C42_USERNAME="@Excluded User ($loggedinuser)"
else
if [[ -n "$jamfplistuser" ]]; then
writeLog "Using JAMF Config Profile PLIST ($jamfplistuser)"
C42_USERNAME="$jamfplistuser"
elif [[ -n "$kandjiplistuser" ]]; then
writeLog "Using Kandji Config Profile PLIST ($kandjiplistuser)"
C42_USERNAME="$kandjiplistuser"
elif [[ -n "$kandjiplist2user" ]]; then
writeLog "Using Kandji Config Profile PLIST ($kandjiplist2user)"
C42_USERNAME="$kandjiplist2user"
elif [[ -n "$oktanetworkuser" ]]; then
writeLog "Using Okta Config Profile PLIST ($oktanetworkuser)"
C42_USERNAME="$oktanetworkuser"
elif [[ -n "$code42plistuser" ]]; then
writeLog "Using JAMF Connect PLIST ($code42plistuser)"
C42_USERNAME="$code42plistuser"
elif [[ -z "$jamfplistuser" ]] && [[ -z "$code42plistuser" ]]; then
writeLog "Known PLISTs empty $code42plistuser($code42plistuser) $jamfplistuser($jamfplistuser)"
if [[ -z "$kandjiplistuser" ]] && [[ -z "$oktanetworkuser" ]]; then
writeLog "Known PLISTs empty $kandjiplistuser($kandjiplistuser) $oktanetworkuser($oktanetworkuser)"
fi
C42_USERNAME="@PLIST(s) are empty"
fi
writeLog "Email read from plist ($C42_USERNAME)"
writeLog "Returning C42_USERNAME=$C42_USERNAME"
C42_USER_HOME=$(dscl . -read "/users/${loggedinuser}" NFSHomeDirectory | cut -d ' ' -f 2)
writeLog "Home directory read from dscl ($C42_USER_HOME)"
writeLog "Returning C42_USER_HOME=$C42_USER_HOME"
echo "C42_USERNAME=$C42_USERNAME"
echo "C42_USER_HOME=$C42_USER_HOME"
fi
}
SCRIPT_PATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
logPath="/Library/Logs/CrashPlan/preservation_user_detection_result.log"
if [[ "$SCRIPT_PATH" == "/" ]]; then
logPath="/Library/Application Support/Code42-AAT/logs/incydr_user_detection_result.log"
fi
function writeLog () {
echo "$(date) - $@" >> $logPath
}
main "$@"
- Place the script into your deployment policy.
You may need to update the script depending on your Jamf version and configuration. Earlier versions of Jamf put the plist in ~/Library/Preferences/, but later versions put it in/Library/Managed Preferences/. - In Jamf, go to Computers, then Configuration Profiles, and create a New configuration profile.
- Go Application & Custom Settings, in the left scroll menu, click on the Upload sub-option
- Click "+ Add" in the top right
- In the Preference Domain type
com.code42.emailwhen pushed by JAMF the .plist file extension will be appended - Copy and paste the following below script into the "Property List" field
- This is a sample plist file. If you prefer, you can create your own, as long as the EMAIL variable is present as a key that matches what the deployment policy is set up to read.
- Scope the Privacy Preferences Policy Control (PPPC) to the users.
Use appropriate scoping. Whether you scope to users or machines depends on your environment. JAMF must have an email on file for whatever you scope the profile to. - Save and Deploy as normal.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>code42ActivationEmail</key>
<string>$EMAIL</string>
</dict>
</plist>
Scutil Username Append Domain script
Professional Services filename: macos_am_username_append_domain_user_detection_script.sh
The following script uses the system configuration utility (scutil) to detect the logged-in user. Enter your email domain in the usedomain variable to generate a valid Code42 email username.
#!/bin/bash
#macos_am_username_append_domain_user_detection_script.sh
#for Incydr and Backup Agents
#last updated 2024-09-20
function main () {
companydomain="domain.com"
extensionslist="$(systemextensionsctl list | grep -i "com.code42.agent.extension")"
userrealname=$(id -P $(stat -f%Su /dev/console) | cut -d : -f 8)
loggedinuser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }')
dLocalHostName=$(scutil --get LocalHostName)
currentdate=$(date)
C42_USERNAME=""
writeLog "---"
writeLog "-----------------------------------User Detection Run Start-----------------------------------"
writeLog "---"
writeLog "Running user detection script: macos_am_username_append_domain_user_detection_script.sh"
writeLog "Starting user detection...version 2024-09-20"
writeLog "$currentdate"
writeLog "LocalHostName found ($dLocalHostName)"
writeLog "extensionslist:"
writeLog "$extensionslist"
writeLog "userrealname: ($userrealname)"
writeLog "loggedinuser: ($loggedinuser)"
for user in /Users/*; do
writeLog "Users: ($user)"
done
#Start of Username Append Domain Logic
writeLog "~"
writeLog "~"
if [[ "$loggedinuser" =~ ^(admin1|admin2|root)$ ]] || [[ -z "$user" ]]; then
writeLog "User failed excluded validation checks ($loggedinuser)"
else
C42_USERNAME="$loggedinuser@$companydomain"
writeLog "Email assembled by appending domain ($C42_USERNAME)"
C42_USER_HOME=$(dscl . -read "/users/${loggedinuser}" NFSHomeDirectory | cut -d ' ' -f 2)
writeLog "Home directory read from dscl ($C42_USER_HOME)"
writeLog "Returning C42_USERNAME=$C42_USERNAME"
writeLog "Returning C42_USER_HOME=$C42_USER_HOME"
echo "C42_USERNAME=$C42_USERNAME"
echo "C42_USER_HOME=$C42_USER_HOME"
fi
}
SCRIPT_PATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
logPath="/Library/Logs/CrashPlan/preservation_user_detection_result.log"
if [[ "$SCRIPT_PATH" == "/" ]]; then
logPath="/Library/Application Support/Code42-AAT/logs/incydr_user_detection_result.log"
fi
function writeLog () {
echo "$(date) - $@" >> $logPath
}
main "$@"
Local logged-in user first and last name script
Professional Services filename: macos_am_firstname_lastname_append_domain_user_detection_script.sh
The following script detects the locally logged-in user's first and last names (based on the macOS string variable realname) and edits the string to create a username. This script handles both firstname lastname and lastname, firstname formats. By default, the script uses first and last names in the format firstname.lastname. To change the default format, update the script parameters below:
- To use only the first letter of the user's first name instead of the full name, change
usefirstinitial=falsetousefirstinitial=true - To remove the period between the first name or initial and the last name, change
noperiodinbetween=falsetonoperiodinbetween=true - To remove special characters, change
removeapostrophes,removehyphen, orremovetildefromfalsetotrueas needed.
#!/bin/bash
#macos_am_firstname_lastname_append_domain_user_detection_script.sh
#for Incydr and Backup Agents
#last updated 2024-09-20
function main () {
#set the domain
companydomain="domain.com"
#Set the style for firstname
usefirstinitial=false
noperiodinbetween=false
#useusernamedigits is for when the email address needs numbers at the end that are in the OS user's username
#i.e. realname is "John Smith" username is "Jsmith06" need email of "john.smith06@domain.com"
useusernamedigits=false
#check for special Chars
removeapostrophes=false
removehyphen=false
removetilde=false
extensionslist="$(systemextensionsctl list | grep -i "com.code42.agent.extension")"
userrealname=$(id -P $(stat -f%Su /dev/console) | cut -d : -f 8)
loggedinuser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }')
dLocalHostName=$(scutil --get LocalHostName)
currentdate=$(date)
C42_USERNAME=""
writeLog "---"
writeLog "-----------------------------------User Detection Run Start-----------------------------------"
writeLog "---"
writeLog "Running user detection script: macos_am_firstname_lastname_append_domain_user_detection_script.sh"
writeLog "Starting user detection...version 2024-09-20"
writeLog "$currentdate"
writeLog "LocalHostName found ($dLocalHostName)"
writeLog "extensionslist:"
writeLog "$extensionslist"
writeLog "userrealname: ($userrealname)"
writeLog "loggedinuser: ($loggedinuser)"
for user in /Users/*; do
writeLog "Users: ($user)"
done
#Start of Username Append Domain Logic
writeLog "~"
writeLog "~"
if [[ "$loggedinuser" =~ ^(admin1|admin2|root)$ ]] || [[ -z "$loggedinuser" ]]; then
writeLog "User failed excluded validation checks ($loggedinuser)"
else
realname="$(dscl . -read /Users/$loggedinuser RealName | cut -d: -f2)"
realname="$(echo $realname | sed ':a;N;$!ba;s/\n//g' )"
writeLog "dscl returned realname of ($realname)"
if [[ ($realname =~ 'dsRecTypeStandard') ]]; then
realname="$(id -F $loggedinuser)"
realname="$(echo $realname | sed ':a;N;$!ba;s/\n//g' )"
writeLog "ip -P returned realname of ($realname)"
fi
writeLog "Realname user field of $loggedinuser is ($realname)"
if [[ "$removeapostrophes" == "true" ]]; then
realname="$(echo $realname | sed "s/\'//g")"
writeLog "Realname user field checked for apostrophes updated to ($realname)"
fi
if [[ "$removehyphen" == "true" ]]; then
realname="$(echo $realname | sed "s/-//g")"
writeLog "Realname user field checked for hyphens updated to ($realname)"
fi
if [[ "$removetilde" == "true" ]]; then
realname="$(echo $realname | sed "s/~//g")"
writeLog "Realname user field checked for tildes updated to ($realname)"
fi
if [[ ($realname =~ ',') ]]; then
writeLog "Real name contains a comma, assuming 'last, first' format."
if [[ "$usefirstinitial" == "true" ]]; then
writeLog "usefirstinitial is set to ($usefirstinitial)"
realname="$(echo $realname | sed -e 's/[[:space:]]*//g' | grep -v "^$" | tr '[:upper:]' '[:lower:]' | awk -F , '{print substr($2,1,1) "." $1}')"
else
realname="$(echo $realname | sed -e 's/[[:space:]]*//g' | grep -v "^$" | tr '[:upper:]' '[:lower:]' | awk -F , '{print $2 "." $1}')"
fi
else
if [[ "$usefirstinitial" == "true" ]]; then
writeLog "usefirstinitial is set to ($usefirstinitial)"
realname="$(echo $realname | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/ /./; s/[[:space:]]*//g' | grep -v "^$" | tr '[:upper:]' '[:lower:]' | awk -F . '{print substr($1,1,1) "." $2}')"
else
realname="$(echo $realname | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/ /./; s/[[:space:]]*//g' | grep -v "^$" | tr '[:upper:]' '[:lower:]')"
fi
fi
writeLog "Realname user field converted to ($realname)"
if [[ "$noperiodinbetween" == "true" ]]; then
realname="$(echo $realname | sed "s/\.//g")"
writeLog "email user set to no period inbetween names ($realname)"
fi
if [[ "$useusernamedigits" == "true" ]]; then
if [[ "$loggedinuser" =~ [[:digit:]] ]]; then
numhold="$(echo $loggedinuser | sed 's/[^0-9]*//g')"
realname="$realname$numhold"
writeLog "useusernamedigits set to true updated to ($realname)"
else
writeLog "There are no numbers in the username ($loggedinuser) left output as ($realname)"
fi
fi
writeLog "companydomain set to ($companydomain)"
local C42_USERNAME="$realname@$companydomain"
writeLog "Email assembled from realname: $C42_USERNAME"
local C42_USER_HOME=$(dscl . -read "/users/${loggedinuser}" NFSHomeDirectory | cut -d ' ' -f 2)
writeLog "Home directory read from dscl ($C42_USER_HOME)"
writeLog "Returning C42_USERNAME=$C42_USERNAME"
writeLog "Returning C42_USER_HOME=$C42_USER_HOME"
echo "C42_USERNAME=$C42_USERNAME"
echo "C42_USER_HOME=$C42_USER_HOME"
fi
}
SCRIPT_PATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
logPath="/Library/Logs/CrashPlan/preservation_user_detection_result.log"
if [[ "$SCRIPT_PATH" == "/" ]]; then
logPath="/Library/Application Support/Code42-AAT/logs/incydr_user_detection_result.log"
fi
function writeLog () {
echo "$(date) - $@" >> $logPath
}
main "$@"
Text file script
Professional Services filename: macos_am_textfile_read_in_user_detection_script.sh
The following script reads the username from a text file (located by default at /tmp/code42_email.txt). Use when no other logical way of finding the username can be determined and no user interaction is desired.
#!/bin/bash
#macos_am_textfile_read_in_user_detection_script.sh
#for Incydr and Backup Agents
#last updated 2024-09-20
function main () {
textfileemail=$(cat /tmp/Code42_Email.txt)
extensionslist="$(systemextensionsctl list | grep -i "com.code42.agent.extension")"
userrealname=$(id -P $(stat -f%Su /dev/console) | cut -d : -f 8)
loggedinuser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }')
dLocalHostName=$(scutil --get LocalHostName)
currentdate=$(date)
C42_USERNAME=""
writeLog "---"
writeLog "-----------------------------------User Detection Run Start-----------------------------------"
writeLog "---"
writeLog "Running user detection script: macos_am_textfile_read_in_user_detection_script.sh"
writeLog "Starting user detection...version 2024-09-20"
writeLog "$currentdate"
writeLog "LocalHostName found ($dLocalHostName)"
writeLog "extensionslist:"
writeLog "$extensionslist"
writeLog "userrealname: ($userrealname)"
writeLog "loggedinuser: ($loggedinuser)"
for user in /Users/*; do
writeLog "Users: ($user)"
done
#Start of Textfile read in Logic
writeLog "~"
writeLog "~"
if [[ "$loggedinuser" =~ ^(admin1|admin2|root)$ ]] || [[ -z "$user" ]]; then
writeLog "User failed excluded validation checks ($loggedinuser)"
else
C42_USERNAME="$textfileemail"
writeLog "Email read from Text File at /tmp/code42_email.txt ($C42_USERNAME)"
C42_USER_HOME=$(dscl . -read "/users/${loggedinuser}" NFSHomeDirectory | cut -d ' ' -f 2)
writeLog "Home directory read from dscl ($C42_USER_HOME)"
writeLog "Returning C42_USERNAME=$C42_USERNAME"
writeLog "Returning C42_USER_HOME=$C42_USER_HOME"
echo "C42_USERNAME=$C42_USERNAME"
echo "C42_USER_HOME=$C42_USER_HOME"
fi
}
SCRIPT_PATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
logPath="/Library/Logs/CrashPlan/preservation_user_detection_result.log"
if [[ "$SCRIPT_PATH" == "/" ]]; then
logPath="/Library/Application Support/Code42-AAT/logs/incydr_user_detection_result.log"
fi
function writeLog () {
echo "$(date) - $@" >> $logPath
}
main "$@"
Linux
For Code42 agents on Linux devices, a deployment policy provides:
- A custom-written detection script to provide the Code42 agent with a username and home directory for the device. The script can also optionally specify the user's organization.
- Installation properties to serve as the arguments string to a Code42 agent install command.
Linux user detection script
A user detection script examines the host device and provides the Code42 agent with a username and home directory. The script resides on the Code42 cloud. The Code42 agent retrieves it during the install process.
To require users to enter their usernames manually, do not use a detection script. In the deployment policy, leave all operating systems deselected to create a deployment policy without a user detection script.
Tips to create a custom Linux script
Create a custom script and paste your script into your deployment policy. If you need help, contact your Customer Success Manager (CSM) for enterprise support.
When creating your custom script, be aware of the following:
- Every script must end by echoing values for two variables:
echo C42_USERNAME=<value>; echo C42_USER_HOME=<value>;
- In the Code42 cloud, usernames must be email addresses.
- Optionally, you can also specify the the organization for the user. Use the registration key for the organization. If the organization is not defined, the user registers to the organization specified in the deployment policy.
echo C42_ORG_REG_KEY=<value>
- You must provide values. Null values and empty strings will not work.
- If you cannot write a script to provide a workable value, write a message for the username field of the Code42 agent sign in dialog, for example:
echo C42_USERNAME=Enter name and click Sign in;
- The values cannot include either single (') or double (") quotation marks.
Linux commands and arguments
Deployment policy command arguments need to be imported into your software management tool.
Commands and arguments are detailed here in case you need to modify them for some reason, or to help you deploy without a device management tool.
- To install a Code42 agent for all users of a device, sign in to an account with root access and issue a command like the following:
tar -xvf Code42_n.n.n_Linux.tgz sudo code42-install/install.sh -q -d "DEPLOYMENT_URL=https://host &DEPLOYMENT_POLICY_TOKEN=0fb12341-246b-448d-b07f-c6573ad5ad02 &PROXY_URL=http://host/filename.pac"
-
To install for one user only:
Append the-ucommand with a user name. For example:-u "first.last"
| Element | Description |
| tar -xvf Code42_n.n.n_Linux.tgz |
Unpack the installer file. You must update the name of the installer file to match the exact name and version number being deployed. |
|
code42-install/install.sh |
Run the Code42 agent install script. |
|
-q -d -u -c |
q: Quiet. Do not open a console. Do not prompt the user. d: Deployment. Apply the following properties. u: Install for the specified username c: Client visibility for this organization is set to Hidden, which hides most Code42 agent user interface elements from users. This only affects client visibility during initial deployment. Future changes to the Client Visibility setting in the Code42 console are automatically pushed to the device. |
| " | Start and end the following properties with a quote. |
| DEPLOYMENT_URL= https://.host |
The address of your Code42 console. The Code42 agent requests its deployment policy from that address. |
| DEPLOYMENT_POLICY_TOKEN= | A unique ID string identifies each deployment policy. |
|
PROXY_URL= http://.host/fname.pac |
The address of a proxy auto-config file. The file tells a Code42 agent how to communicate with Code42 through a proxy server. This argument is only present when your policy configuration says Use Org Proxy URL: Yes. If the argument is present, but has no value, the policy says use proxy: yes, but the organization has no proxy addresses defined. |
| " | Start and end the above properties with a quote. |
Example Ubuntu user detection script
The following script detects which user last logged in using the last -p now command for logins, then appends the domain of the company to make an email address. A single user needs to be logged into the device to pass the user check. This script requires the device is owned and used by a single user. The script does not support multi-user workstations.
#!/bin/sh
#ubuntu_am_username_append_domain_user_detection_script.sh
#for Incydr and Backup Agents
#last updated 2024-04-11
function main () {
writeLog "---"
writeLog "-----------------------------------User Detection Run Start-----------------------------------"
writeLog "---"
writeLog "Running user detection script: ubuntu_am_username_append_domain_user_detection_script.sh"
writeLog "Starting user detection...version 2024-04-11"
writeLog "Date: $(date)"
local companydomain="domain.com"
local userent=$(eval getent passwd {$(awk '/^UID_MIN/ {print $2}' /etc/login.defs)..$(awk '/^UID_MAX/ {print $2}' /etc/login.defs)} | cut -d: -f1)
local userwho=$(whoami)
local userwholist=$(who)
local userlastlist=$(last -p now | grep -i "logged in")
local userlastshort=$(last -p now | grep -i "logged in" | cut -d " " -f 1-1)
local userlastlong=$(who | grep -m 1 -i $userlastshort | cut -d " " -f 1-1)
local userhostname=$(hostname)
#Update all lines to use the variable required for the enviorment: Default is $userlastlong
writeLog "Hostname found via hostname ($userhostname)"
writeLog "Username found via getent ($userent)"
writeLog "Usernames found via userwholist ($userwholist)"
writeLog "Username found via userwho ($userwho)"
writeLog "Usernames currently logged in ($userlastlist)"
#Grabs the first currently logged in user
writeLog "Username found via lastshort -p now ($userlastshort)"
writeLog "Username found via lastlong -p now ($userlastlong)"
#Leave as is if changing variable
if [[ "$userlastlong" =~ ^(root|admin|reboot|shutdown|local|user1)$ ]] || [[ -z "$userlastlong" ]]; then
writeLog "Excluded or null username detected ($userlast). Will retry user detection in few minutes, or when servie reboot occurs."
exit
elif [[ "$userlastshort" =~ $'\n' ]] || [[ -z "$userlastlist" ]]; then
writeLog "Mulitple Logged on Users found: $userlastlist. Will retry user detection in few minutes, or when service reboot occurs."
exit
else
writeLog "Username ($userlastlong) passed Excluded Username Check"
local userlasthome=$(getent passwd | grep -i $userlastlong | cut -d : -f 6)
writeLog "userlasthome ($userlasthome)"
local C42_USER_HOME=$userlasthome
writeLog "Home directory read from dscl ($C42_USER_HOME)"
userlastlong="$(echo $userlastlong | sed -e 's/[[:space:]]//g' | tr '[:upper:]' '[:lower:]')"
local C42_USERNAME="$userlastlong@$companydomain"
writeLog "Username assembled by appending domain ($C42_USERNAME)"
writeLog "Returning C42_USERNAME=$C42_USERNAME"
writeLog "Returning C42_USER_HOME=$C42_USER_HOME"
echo "C42_USERNAME=$C42_USERNAME"
echo "C42_USER_HOME=$C42_USER_HOME"
fi
}
SCRIPT_PATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
logPath="/usr/local/crashplan/log/preservation_user_detection_result.log"
if [[ "$SCRIPT_PATH" == "/opt/code42-aat" ]]; then
logPath="/var/opt/code42-aat/logs/incydr_user_detection_result.log"
fi
function writeLog () {
echo "$(date) - $@" >> $logPath
}
main "$@"
Comments
Please sign in to leave a comment.