Windows 10

Utilizing Datto RMM User-Defined Custom Fields



INTRO

Greeting folks, Datto RMM is a powerful and fantastic tool for Systems Administrators. We can manage hundreds of computers and with the recent trend to move to domain-less networks it will surely be a tool of continued use in the future. I want to talk about the User-Defined Fields (UDFs) feature because it has made my life much easier.

While Datto RMM already gives us so much information about each endpoint, there was some information I wanted on the front-page of each device summary so I didn’t need to go digging through multiple tabs and also so I could export to Microsoft Excel.

THE COMPONENT STORE

The community component store has many options already available for you to add to your portal’s component store. Simply go through the list and add the ones you want. For example, you can have the device’s TPM status and Bitlocker Recovery Key shown. You can have Office and Windows Product Keys detected. Activation status, a Windows 11 compatibility check, backup product detection, and much more.

CONFIGURING THE UDF JOB

Under the Administrator account for your portal, go to Setup -> Account Settings -> User-Defined Fields.

This is where you will label the header for the value of data that will be in the field, but this is not where you will configure UDFs. Configuring them will be done under Jobs.

Create a new job called, “Managed IT [All] – Custom UDFs – Initial Audit” and for Job targets add the following:

  • Default Device Filters (All Sites): All Windows Servers
  • Default Device Filters (All Sites): All Windows Desktops

For a schedule set it for, “Once an initial audit has completed”. This means whenever a new device is added the job will run and add the UDFs.

You can also repeat the process with a job called, “Managed IT [All] – Custom UDFs – Schedule” where you can set a time each day that Datto RMM will run the UDF scripts for each device to keep the UDFs updated daily.

A screenshot of my configuration for the job is next to this section.


OUTPUT EXAMPLE

Here is also an example output of the job when it runs on an endpoint in New UI. I removed information that I would rather not share.

As you can see, I can get a lot of information on the summary page of an endpoint.  I can tell if an endpoint has an SSD, if it’s using Bitlocker, how it’s activated, if it’s running UEFI and Secure Boot, and more.

I can have the Windows OEM Product Key stored in BIOS given to me as well as the Windows Product Key stored in the Registry and used to activate Windows.

I also have the Bitlocker Recovery Key. User Profile Folders, Local User Accounts, and Enabled Local Administrators at the end. All of these fields get stored into columns as well and can be exported to an Excel document for auditing purposes.

Also, having the information acts as a backup in-case you lose Bitlocker or Product Key information.


POWERSHELL SCRIPT

If you notice from my configuration, I have several components that start with Managed IT. You will not find these in the Component Store for download as they are my own custom scripts that I created.

The scripts run and then the output is placed in the registry under a certain User-Defined Field number of my choosing. This is how we can customize the fields we want when no component is available for it. Here is my script for querying Local Administrators below:

PowerShell
# Get Local Users
$Administrators = Get-LocalGroupMember -Group "Administrators" | Select-Object Name | Format-Table -HideTableHeaders

$AdministratorsList = $Administrators | Out-String
      
# Validate the UDF Variable
[int]$env:usrUDF = '22'
if ([int]$env:usrUDF -and [int]$env:usrUDF -match '^\d+$') {
    
    # Validate the variable value is between 1 and 30
    if ([int]$env:usrUDF -ge 1 -and [int]$env:usrUDF -le 30) {     
            New-ItemProperty -Path "HKLM:\SOFTWARE\CentraStage" -Name Custom$env:usrUDF -Value $AdministratorsList -Force | Out-Null
            Write-Host "Value written to User-Defined Field $env:usrUDF`."
        } 
    else {
        Write-Host "User-Defined Field value must be an integer between 1 and 30."
    }
} else {
    Write-Host "User-Defined Field value invalid or not specified. Not writing results to the User-Defined Field."
}

The example is given so you can customize yourself with your own scripts.

COMPONENT UDF SCRIPTS

Below are the custom UDF scripts that I use to gather the details above. Simply add to the example script above before the “# Validate the UDF Variable” line and replace the UDF number with the one you desire. Then on line 12 replace with the correct variable in the script for output.

Managed IT – UDF-1 – Microsoft Office

PowerShell
# Get Microsoft Office Products Installed

$Microsoft32Bit = Get-ItemProperty HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.DisplayName -LIKE 'Microsoft Office P*' -or $_.DisplayName -LIKE 'Microsoft Office H*' -or $_.DisplayName -LIKE 'Microsoft Office S*' -or $_.DisplayName -LIKE 'Microsoft Visio*' -or $_.DisplayName -LIKE 'Microsoft Lync*' -or $_.DisplayName -LIKE 'Microsoft P*' -or $_.DisplayName -LIKE 'Microsoft O*' -or $_.DisplayName -LIKE 'Microsoft Access*' -or $_.DisplayName -LIKE 'Microsoft Excel*' -or $_.DisplayName -LIKE 'Microsoft Word*' -or $_.DisplayName -LIKE 'Microsoft InfoPath*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders
$Microsoft64Bit = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.DisplayName -LIKE 'Microsoft Office P*' -or $_.DisplayName -LIKE 'Microsoft Office H*' -or $_.DisplayName -LIKE 'Microsoft Office S*' -or $_.DisplayName -LIKE 'Microsoft Visio*' -or $_.DisplayName -LIKE 'Microsoft Lync*' -or $_.DisplayName -LIKE 'Microsoft P*' -or $_.DisplayName -LIKE 'Microsoft O*' -or $_.DisplayName -LIKE 'Microsoft Access*' -or $_.DisplayName -LIKE 'Microsoft Excel*' -or $_.DisplayName -LIKE 'Microsoft Word*' -or $_.DisplayName -LIKE 'Microsoft InfoPath*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders

$Microsoft = $Microsoft32Bit, $Microsoft64Bit | Out-String

Managed IT – UDF-6 – Microsoft 365

PowerShell
# Get Microsoft Office 365 Products Installed

$Microsoft32Bit = Get-ItemProperty HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.DisplayName -like 'Microsoft 365*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders
$Microsoft64Bit = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.DisplayName -like 'Microsoft 365*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders

$Microsoft365= $Microsoft32Bit, $Microsoft64Bit| Out-String

Managed IT – UDF-7 – Microsoft Office Keys

PowerShell
# Get Microsoft Office Product Keys:

function Search-RegistryKeyValues {
param(
[string]$Path,
[string]$valueName
)
Get-ChildItem $Path -recurse -ea SilentlyContinue | 
% { 
if ((Get-ItemProperty -Path $_.PsPath -ea SilentlyContinue) -match $valueName)
{
$_.PsPath
} 
}
}

# Find registry key that has value: "digitalproductid"
# 32-Bit Versions:
$Key = Search-RegistryKeyValues "HKLM:\SOFTWARE\Microsoft\Office" "digitalproductid"
if ($Key -eq $null) {
# 64-Bit Versions:
$Key = Search-RegistryKeyValues "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office" "digitalproductid"
if ($Key -eq $null) {Write-Host "Microsoft Office is NOT Installed.";break}
}

$ValueData = (Get-ItemProperty $Key).digitalproductid[52..66]

# Decrypt Base24 Encoded Binary Data:

$ProductKey = ""
$Chars = "BCDFGHJKMPQRTVWXY2346789"
for ($i = 24; $i -ge 0; $i--) { 
$r = 0 
for ($j = 14; $j -ge 0; $j--) { 
$r = ($r * 256) -bxor $ValueData[$j] 
$ValueData[$j] = [math]::Truncate($r / 24)
$r = $r % 24 
} 
$ProductKey = $Chars[$r] + $ProductKey 
if (($i % 5) -eq 0 -and $i -ne 0) { 
$ProductKey = "-" + $ProductKey 
} 
}

$MSOfficeKey= $ProductKey | Out-String

Managed IT – UDF-12 – Hardware Other

PowerShell
# Get Hardware Details

$Hardware = Get-ComputerInfo -Property BiosFirmwareType, CsAdminPasswordStatus, OsInstallDate | Format-List

$HardwareDetails = $Hardware | Out-String

Managed IT – UDF-13 – Secure Boot Status

PowerShell
# Get Secure Boot Status

$Status= Confirm-SecureBootUEFI | Format-List

$SecureBootDetails= $Status | Out-String

Managed IT – UDF-21 – Local User Accounts

PowerShell
# Get Local Users

$LocalUsers = Get-LocalUser | where{$_.Enabled -eq 'True'} | Select-Object Name, PasswordRequired, PasswordExpires, PasswordLastSet, LastLogon | Format-List

$List= $LocalUsers | Out-String

Managed IT – UDF-22 – All Local Administrators

PowerShell
# Get All Local Administrators

$AllAdministrators = Get-LocalGroupMember Administrators | Select-Object Name, PrincipalSource | Format-Table -HideTableHeaders

$AllAdministratorsList = $Administrators | Out-String

Managed IT – UDF-23 – Enabled Local Administrators

PowerShell
# Get Enabled Local Administrators

$EnabledAdministrators = Get-LocalGroupMember Administrators | Where-Object { (Get-LocalUser $_.SID -EA 0).Enabled } | Select-Object Name, PrincipalSource | Format-Table -HideTableHeaders

$EnabledAdministratorsList = $EnabledAdministrators | Out-String

Managed IT – UDF-25 – Intermedia

PowerShell
# Get Intermedia Products Installed

$Intermedia32Bit = Get-ItemProperty HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.Publisher -like 'Intermedia*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders
$Intermedia64Bit = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.Publisher -like 'Intermedia*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders

$Intermedia = $Intermedia32Bit, $Intermedia64Bit | Out-String

Managed IT – UDF-26 – Zyxel

PowerShell
# Get Zyxel Products Installed

$Zyxel32Bit = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.Publisher -like 'Zyxel*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders
$Zyxel64Bit = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.Publisher -like 'Zyxel*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders

$Zyxel = $Zyxel32Bit, $Zyxel64Bit | Out-String

Managed IT – UDF-27 – Alibi

PowerShell
# Get Alibi Products Installed

$Alibi32Bit = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.Publisher -like 'Observint Technologies*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders
$Alibi64Bit = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | where{$_.Publisher -like 'Observint Technologies*'} | Select-Object DisplayName, DisplayVersion | Format-Table -HideTableHeaders

$Alibi = $Alibi32Bit, $Alibi64Bit | Out-String

Managed IT – UDF-28 – Solidworks Serials

PowerShell
# Get Solidworks Serial Numbers

$SolidworksMain = Get-ItemProperty -Path "HKLM:\SOFTWARE\SolidWorks\Licenses\Serial Numbers" -Name "SolidWorks" | Select-Object Solidworks | Format-Table
$SolidworksVisualize = Get-ItemProperty -Path "HKLM:\SOFTWARE\SolidWorks\Licenses\Serial Numbers" -Name "Visualize" | Select-Object Visualize | Format-Table

$SolidworksSerials = $SolidworksMain, $SolidworksVisualize | Out-String

CONCLUSION

Well, there you have it! Hopefully this can save you some time in auditing. I would create a second duplicate job called, “Managed IT [All] – Custom UDFs – Schedule” that runs every day at around 11:00 AM as I find most computers are on at that time, this way the information stays updated after the initial audit. Stay tuned for more!

2 replies
  1. Carles T says:

    Hi,

    I found the article really useful. Thanks for placing it.
    Is there any way to read the value of a User defined field and based on it modify another User defined field?

    example: I have the purchase date of laptops and desktops in a User defined field. I created another field named “Marked for replacement”.
    I want to use this purchase date to calculate if device needs to be replaced already or not, and if that’s the case modify the field “Marked for replacement”. Life could be different for laptops, let’s say 3 years, while for desktops it can be 4 years. Therefore I also need to check the “Device Type” field to do the calculation.

    I think it can be done, but I didn’t find the way to obtain the data from those user defined fields from an script.

    Can you help me or provide me some guidance?

    Thanks a lot!

    Reply
    • WinReflection says:

      Hi Carles, I am glad you found the post helpful and thanks for letting me know!

      The UDFs are just values placed in the registry and then Datto RMM, whenever it audits the device it looks at those values and places them into the Device Summary area. You would need to create a PowerShell script to make the edits you’re looking to have done, and maybe run a schedule. I think what you’re doing can be done and I would recommend using ChatGPT for help.

      I would simply ask ChatGPT to give you a template to read a device’s purchase date value from the registry UDF key location and then have logic to determine the age of the device and if said age meets criteria then edit the “Market for replacement” UDF key in the registry.

      Datto RMM will then see that value on the device’s next audit and should be visible to you.

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *