Windows 10, Windows Server

ConnectWise Extra Data Fields | Setup



INTRO

We migrated from Datto RMM to ConnectWise Automate | ScreenConnect and it has been a year or so now, so I would like to share the Extra Data Fields that I implemented. I will say ConnectWise Automate requires far more learning and training than Datto RMM, but has many more options and capabilities that are very nice. I would say for those that don’t have the desire or will to dive deep into a platform than you should stay with Datto RMM or other, over ConnectWise. However if you have the drive to dive deep, ConnectWise will be interesting for you and adds some job security since someone won’t be able to just pick it up, it takes weeks of training to understand a good portion of the platform.

SETUP

Below is an example of what I can see when I go to Info -> Extra Data Fields of a computer’s dashboard. Each one links to a custom script I created that when completed sends the output into one of these Extra Data Fields. You will find my PowerShell scripts below except for the Dell Docking Station and Group Policy Base ones as those are still being tested by me still.

Getting started you’re going to first need to create the Extra Data Field headers in the thick-client that will be visible when going to a computer’s dashboard and selecting Info -> Extra Data Fields. I use the thin-client 95% of the time, but I need to use the thick-client from time to time to configure items and use additional features like the RDP tunnel to a device which is not usable in the thin-client.

You install the thick-client by logging into the thin-client and going to System -> Installers -> Automate Control Center where you will be given a Windows-based installer. Once in the thick-client, you need go to System -> Configuration -> Dashboard, then in there you need to navigate to Config -> Configurations -> Additional Fields. Below you will see a picture of my ± Administrator Password field. The special characters used in the name are for sorting in a specific order as I wanted some fields first before others. You can configure the fields and related settings here. Your scripts will have to be configure to output to these fields. I run them on a schedule hourly to run every 8 hours.


EXTRA DATA FIELDS | SCRIPTS

± Administrator Password:

This script will randomize a 10-character password that will consist of Upper-case, Lower-case, Numerals, and Symbols and apply it to the domain or local user account in Windows named Administrator.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @PasswordRotationAdministrator@
PowerShell
# $Error[1].Exception.GetType().FullName
$DomainControllerCheck = (Get-WmiObject -Query "select * from Win32_OperatingSystem where ProductType='2'")
$VerbosePreference = 'Continue'
$Username = "Administrator"
$ErrorActionPreference = 'Stop'

Function Create-String([Int]$Size = 10, [Char[]]$CharSets = "ULNS", [Char[]]$Exclude) {
    $Chars = @(); $TokenSet = @()
    If (!$TokenSets) {$Global:TokenSets = @{
        U = [Char[]]'ABCDEFGHJKMNOPQRSTUVWXYZ'                                  #Upper case
        L = [Char[]]'abcdefghjkmnopqrstuvwxyz'                                  #Lower case
        N = [Char[]]'0123456789'                                                #Numerals
        S = [Char[]]'!#$%&*+=?@'                                                #Symbols
    }}
    $CharSets | ForEach {
        $Tokens = $TokenSets."$_" | ForEach {If ($Exclude -cNotContains $_) {$_}}
        If ($Tokens) {
            $TokensSet += $Tokens
            If ($_ -cle [Char]"Z") {$Chars += $Tokens | Get-Random}             #Character sets defined in upper case are mandatory
        }
    }
    While ($Chars.Count -lt $Size) {$Chars += $TokensSet | Get-Random}
    ($Chars | Sort-Object {Get-Random}) -Join ""                                #Mix the (mandatory) characters and output string
}

# Generating a new random password.
$Passwd = Create-String 10 UNLS

# Converting random generated password to a secure string for insertion.
$PasswdSecStr = ConvertTo-SecureString $Passwd -AsPlainText -Force


if ($DomainControllerCheck -eq $null ) {
    # Write-Verbose "Endpoint is not a Domain Controller, swithcing to local user commands."
    try {
        # Write-Verbose "Searching for the local user account named $Username in the LocalUser database."
        $ObjLocalUser = Get-LocalUser $Username
        # Write-Verbose "The local user account named $Username was found."
        # Write-Verbose "Setting the new randomly generated password."
        Set-LocalUser -Name $Username -Password $PasswdSecStr -PasswordNeverExpires 1
        # Write-Verbose "This is the newly random generated password for the local user account named: $Username."; 
        $Passwd
    }
    catch [Microsoft.PowerShell.Commands.UserNotFoundException] {
          New-LocalUser $Username -Password $PasswdSecStr -FullName $Username -PasswordNeverExpires | Out-Null
          # Write-Verbose "Adding the $Username account to the Local Administrators Group."
          Add-LocalGroupMember -Group Administrators -Member $Username | Out-Null
          # Write-Verbose "This is the newly random generated password for the local user account named: $Username.";
          $Passwd
    }
}
else {
     # Write-Verbose "Endpoint is a Domain Controller, running AD commands."
     try {
         # Write-Verbose "Searching for the domain user account named $Username in Active Directory."
         $ObjADUser = Get-ADUser -Identity $Username
         # Write-Verbose "Setting the new randomly generated password."
         Set-ADAccountPassword -Identity $Username -Reset -NewPassword $PasswdSecStr
         Set-ADUser -Identity $Username -PasswordNeverExpires $True
         # Write-Verbose "This is the newly random generated password for the domain user account named: $Username."; 
         $Passwd
    }
    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
          # Write-Verbose "Creating a domain user account named $Username and setting the randomly generated password."
          New-ADUser -Name $USERNAME -AccountPassword $PasswdSecStr -PasswordNeverExpires $True -Enabled $True
          # Write-Verbose "Adding the $Username account to the Administrators Group."
          Add-ADGroupMember -Identity Administrators -Members $Username
          # Write-Verbose "This is the newly random generated password for the domain user account named: $Username.";
          $Passwd
    }
}

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: ± Administrator Password
  • ID *: %ComputerID%
  • Value *: @PasswordRotationAdministrator@

± Support Password:

This script will randomize a 16-character password that will consist of Upper-case, Lower-case, Numerals, and Symbols and apply it the domain or local user account in Windows named Support.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @PasswordRotationSupport@
PowerShell
# $Error[1].Exception.GetType().FullName
$DomainControllerCheck = (Get-WmiObject -Query "select * from Win32_OperatingSystem where ProductType='2'")
$VerbosePreference = 'Continue'
$Username = "Support"
$ErrorActionPreference = 'Stop'

Function Create-String([Int]$Size = 16, [Char[]]$CharSets = "ULNS", [Char[]]$Exclude) {
    $Chars = @(); $TokenSet = @()
    If (!$TokenSets) {$Global:TokenSets = @{
        U = [Char[]]'ABCDEFGHJKMNOPQRSTUVWXYZ'                                  #Upper case
        L = [Char[]]'abcdefghjkmnopqrstuvwxyz'                                  #Lower case
        N = [Char[]]'0123456789'                                                #Numerals
        S = [Char[]]'!#$%&*+=?@'                                                #Symbols
    }}
    $CharSets | ForEach {
        $Tokens = $TokenSets."$_" | ForEach {If ($Exclude -cNotContains $_) {$_}}
        If ($Tokens) {
            $TokensSet += $Tokens
            If ($_ -cle [Char]"Z") {$Chars += $Tokens | Get-Random}             #Character sets defined in upper case are mandatory
        }
    }
    While ($Chars.Count -lt $Size) {$Chars += $TokensSet | Get-Random}
    ($Chars | Sort-Object {Get-Random}) -Join ""                                #Mix the (mandatory) characters and output string
}

# Generating a new random password.
$Passwd = Create-String 16 UNLS

# Converting random generated password to a secure string for insertion.
$PasswdSecStr = ConvertTo-SecureString $Passwd -AsPlainText -Force


if ($DomainControllerCheck -eq $null ) {
    # Write-Verbose "Endpoint is not a Domain Controller, swithcing to local user commands."
    try {
        # Write-Verbose "Searching for the local user account named $Username in the LocalUser database."
        $ObjLocalUser = Get-LocalUser $Username
        # Write-Verbose "The local user account named $Username was found."
        # Write-Verbose "Setting the new randomly generated password."
        Set-LocalUser -Name $Username -Password $PasswdSecStr -PasswordNeverExpires 1
        # Write-Verbose "This is the newly random generated password for the local user account named: $Username."; 
        $Passwd
    }
    catch [Microsoft.PowerShell.Commands.UserNotFoundException] {
          New-LocalUser $Username -Password $PasswdSecStr -FullName $Username -PasswordNeverExpires | Out-Null
          # Write-Verbose "Adding the $Username account to the Local Administrators Group."
          Add-LocalGroupMember -Group Administrators -Member $Username | Out-Null
          # Write-Verbose "This is the newly random generated password for the local user account named: $Username.";
          $Passwd
    }
}
else {
     # Write-Verbose "Endpoint is a Domain Controller, running AD commands."
     try {
         # Write-Verbose "Searching for the domain user account named $Username in Active Directory."
         $ObjADUser = Get-ADUser -Identity $Username
         # Write-Verbose "Setting the new randomly generated password."
         Set-ADAccountPassword -Identity $Username -Reset -NewPassword $PasswdSecStr
         Set-ADUser -Identity $Username -PasswordNeverExpires $True
         # Write-Verbose "This is the newly random generated password for the domain user account named: $Username."; 
         $Passwd
    }

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: ± Support Password
  • ID *: %ComputerID%
  • Value *: @PasswordRotationSupport@

‡ Enabled Local Users:

This Extra Data Field will query enabled local users in Windows.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @EnabledLocalUsers@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

(Get-LocalUser | where{$_.Enabled -eq 'True'} | Select-Object Name | Format-Table -HideTableHeaders | Out-String).Trim()

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: ‡ Enabled Local Users
  • ID *: %ComputerID%
  • Value *: @EnabledLocalUsers@

• Alibi

This Extra Data Field will query the Alibi software installed in Windows.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @Alibi@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

# 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

# Merge Values and Output
$Alibi = ($Alibi32Bit, $Alibi64Bit | Out-String).Trim(); $Alibi

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • Alibi
  • ID *: %ComputerID%
  • Value *: @Alibi@

OS Install Date

This Extra Data Field will query the OS install date of Windows.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @OSInstallDate@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

(Get-ComputerInfo -Property OsInstallDate | Format-Table -HideTableHeaders | Out-String).Trim()

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • OS Install Date
  • ID *: %ComputerID%
  • Value *: @OSInstallDate@

• Solidworks Serials

This Extra Data Field will query the serial numbers for Solidworks for the main and visualize licenses in the Windows registry.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @SolidworksSerialNumbers@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

# 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

# Merge Values and Output
$SolidworksSerials = ($SolidworksMain, $SolidworksVisualize | Out-String).Trim(); $SolidworksSerials

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • Solidworks Serials
  • ID *: %ComputerID%
  • Value *: @SolidworksSerialNumbers@

± BitLocker Recovery Password

This Extra Data Field will query the BitLocker Recovery Password for the C: drive in Windows.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @BitLockerRecoveryPassword@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

((Get-BitLockerVolume -MountPoint C).KeyProtector | Select-Object RecoveryPassword | Format-Table -HideTableHeaders | Out-String).Trim()

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: ± BitLocker Recovery Password
  • ID *: %ComputerID%
  • Value *: @BitLockerRecoveryPassword@

‡ Enabled Local Admins

This Extra Data Field will query enabled local Admin accounts.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @EnabledLocalAdmins@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

(Get-LocalGroupMember Administrators | where{(Get-LocalUser $_.SID -EA 0).Enabled} | Select-Object Name | Format-Table -HideTableHeaders | Out-String).Trim()

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: ‡ Enabled Local Admins
  • ID *: %ComputerID%
  • Value *: @EnabledLocalAdmins@

• BIOS Firmware Type

This Extra Data Field will query the status in Windows on what BIOS firmware type the is currently set.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @BIOSFirmwareType@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

(Get-ComputerInfo -Property BiosFirmwareType | Format-Table -HideTableHeaders | Out-String).Trim()

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • BIOS Firmware Type
  • ID *: %ComputerID%
  • Value *: @BIOSFirmwareType@

• Intermedia

This Extra Data Field will query the Intermedia software installed in Windows.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @Intermedia@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

# 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

# Merge Values and Output
$Intermedia = ($Intermeida32Bit, $Intermedia64Bit | Out-String).Trim(); $Intermedia

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • Intermedia
  • ID *: %ComputerID%
  • Value *: @Intermedia@

• Secure Boot

This Extra Data Field will query the status in Windows on whether Secure Boot is enabled or not.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @SecureBootStatus@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

(Confirm-SecureBootUEFI | Out-String).Trim()

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • Secure Boot
  • ID *: %ComputerID%
  • Value *: @SecureBootStatus@

• Zyxel

This Extra Data Field will query the Zyxel software installed in Windows.

Function: Execute Script

  • Script Type: PowerShell Bypass
  • Script Parameters: -f -t 00
  • Script Credentials *: Local Agent
  • Variable: @Zyxel@
PowerShell
$ErrorActionPreference = 'SilentlyContinue'

# 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

# Merge Values and Output
$Zyxel = ($Zyxel32Bit, $Zyxel64Bit | Out-String).Trim(); $Zyxel

Function: ExtraData Set Value

  • Scope: Computer
  • Extra Data Field *: • Zyxel
  • ID *: %ComputerID%
  • Value *: @Zyxel@

CONCLUSION

Well that’s it, hope this post helped you and guided you on how to better utilize ConnectWise Automate.

2 replies
  1. Corey says:

    Are you able to update EDF’s that have checkbox types? or is it just text. I have a number of boolean values I want to use the checkbox with ideally. If I just have to save True/False to a text I suppose that is fine but less ideal.

    Reply
    • WinReflection says:

      That’s a good question. I do not have an answer as I did not use checkboxes. There may be a function included in CW that can check a box for an EDF. Would be a good question for CW support.

      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 *