> ## Documentation Index
> Fetch the complete documentation index at: https://help.gorelo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Write to a custom asset field with scripts

> Use Gorelo scripts to write values like BitLocker recovery keys, rotated local admin passwords, and third-party UIDs into custom asset fields automatically.

BitLocker keys, rotate local admin password, third-party UID etc.

You can write to a custom asset field via scripts. This is useful for things such as BitLocker keys, rotating local admin passwords, and third-party UID’s.

<Steps>
  <Step title="Create a custom asset field">
    1. Navigate to **Settings** > **Assets** > **Custom Fields**.
    2. Add custom field with the following details:

    <Tabs>
      <Tab title="BitLocker">
        * **Name**: BitLocker Recovery Key
        * **Variable**: bitlockerRecoveryKey

        <Frame>
          <img src="https://mintcdn.com/gorelo/hTBX2qpHbjxDttw-/images/image-116.png?fit=max&auto=format&n=hTBX2qpHbjxDttw-&q=85&s=2319913d92820567f3479e8016569176" alt="Image" width="778" height="619" data-path="images/image-116.png" />
        </Frame>
      </Tab>

      <Tab title="Windows Install Date">
        * **Name**: Windows Install Date
        * **Variable**: windowsInstallDate

        <Frame>
          <img src="https://mintcdn.com/gorelo/hTBX2qpHbjxDttw-/images/image-110.png?fit=max&auto=format&n=hTBX2qpHbjxDttw-&q=85&s=10e3f1f3314306dba75c38d4701feb7c" alt="Image" width="787" height="606" data-path="images/image-110.png" />
        </Frame>
      </Tab>

      <Tab title="Windows Product Key">
        * **Name**: Windows Product Key
        * **Variable**: windowsProductKey

        <Frame>
          <img src="https://mintcdn.com/gorelo/vUQ8OM8P3jBMi8Dq/images/image-118.png?fit=max&auto=format&n=vUQ8OM8P3jBMi8Dq&q=85&s=1dfb76668303d54756404bee5f0fbf4d" alt="Image" width="781" height="603" data-path="images/image-118.png" />
        </Frame>
      </Tab>

      <Tab title="MAC Address">
        * **Name**: MAC Address
        * **Variable**: macAddress

        <Frame>
          <img src="https://mintcdn.com/gorelo/fI4EZlX_4VIJ5gmy/images/image-119.png?fit=max&auto=format&n=fI4EZlX_4VIJ5gmy&q=85&s=5515c35750de344cd60cb7c3d62b4ee1" alt="Image" width="793" height="630" data-path="images/image-119.png" />
        </Frame>
      </Tab>

      <Tab title="RAM Slots Used">
        * **Name**: RAM Slots Used
        * **Variable**: ramSlotsUsed

        <Frame>
          <img src="https://mintcdn.com/gorelo/l3kfLaTp3Zy4uEi2/images/image-121.png?fit=max&auto=format&n=l3kfLaTp3Zy4uEi2&q=85&s=eb10f33b94faeaa1bf5b8441ff39ce97" alt="Image" width="786" height="602" data-path="images/image-121.png" />
        </Frame>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Create the script">
    1. Navigate to **Scripts**.
    2. Create a script with the following details:

    <Tabs>
      <Tab title="BitLocker">
        * **Name**: 🗝️Store-BitlockerRecoveryKey
        * **Content**:

        ```powershell theme={null}
        $ErrorActionPreference = 'SilentlyContinue' 

        # Get drives where BitLocker is "On" 
        $BitlockerDrives = Get-BitLockerVolume | Where-Object ProtectionStatus -EQ "On" -ErrorAction SilentlyContinue

        #Get FileSystem drives 
        $Drives = Get-PSDrive -PSProvider FileSystem

        #Create array of Drive Names with ":" added
        $DrivesName = @()
        $Drives |  foreach {$DrivesName += $_.name + ':' }

        #If any Bitlockered drives exist
        if($BitlockerDrives){

            #Foreach Drive
            Foreach ($DriveName in $DrivesName) {

                #Confirm is drive is bitlockered
                $BitlockerDrive = $BitlockerDrives | where { $DriveName -contains $_ }

                #If specific drive is bitlockered
                if ($BitlockerDrive){

                    #Get RecoveryKey 
                    $RecoveryKey = $BitlockerDrive.KeyProtector | Where-Object RecoveryPassword -NE "" | Select-Object -ExpandProperty RecoveryPassword -ErrorAction SilentlyContinue
              
                    #Join if multiple with ; delimiter 
                    $RecoveryKey = $RecoveryKey -join ";"

                    #Add the drive letter to the output
                    $RecoveryKey = "$($BitlockerDrive.mountpoint)$RecoveryKey"

                    #Add to other drive keys (If exist)
                    $RecoveryKeys += " $RecoveryKey "

                } else { $RecoveryKeys += $DriveName + "Not Enabled" }   
                
            }

            GoreloAction -SetCustomField -Name 'asset.bitlockerRecoveryKey' -Value $RecoveryKeys

        #If no bitlockered drives found
        }else { 
            
            Foreach ($DriveName in $DrivesName) { 
                
                $RecoveryKeys += $DriveName + "Not Enabled " 
                
            } 
            
            GoreloAction -SetCustomField -Name 'asset.bitlockerRecoveryKey' -Value $RecoveryKeys 
            
        }
        ```
      </Tab>

      <Tab title="Windows Install Date">
        * **Name**: 🗝️Store-WindowsInstallDate
        * **Content**:

        ```powershell theme={null}
        # Initialize array to store all valid dates
        $allDates = @()

        # Method 1: Win32_OperatingSystem class
        $osInfo = Get-WmiObject Win32_OperatingSystem
        $installDate = $osInfo.ConvertToDateTime($osInfo.InstallDate)
        $allDates += $installDate
        Write-Host "OS Installation Date (from Win32_OperatingSystem): $($installDate.ToString('MM/dd/yyyy'))" -ForegroundColor White

        # Method 2: Registry installation date
        $registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
        $registryInstallDate = Get-ItemProperty -Path $registryPath | Select-Object -ExpandProperty InstallDate
        $registryInstallDateTime = (Get-Date "1970-01-01 00:00:00.000Z").AddSeconds($registryInstallDate)
        $allDates += $registryInstallDateTime
        Write-Host "Registry Installation Date: $($registryInstallDateTime.ToString('MM/dd/yyyy'))" -ForegroundColor White

        # Method 3: Earliest system restore point (with proper date parsing)
        try {
            $restorePoints = Get-ComputerRestorePoint | Sort-Object -Property CreationTime
            if ($restorePoints) {
                $earliestRestorePoint = [datetime]::ParseExact($restorePoints[0].CreationTime.ToString(), "yyyyMMddHHmmss.ffffff-000", $null)
                $allDates += $earliestRestorePoint
                Write-Host "Earliest System Restore Point: $($earliestRestorePoint.ToString('MM/dd/yyyy'))" -ForegroundColor White
            }
        }
        catch {
            Write-Host "Unable to retrieve or parse system restore points." -ForegroundColor Yellow
        }

        # Method 4: Windows.old folder date (if exists)
        $windowsOldPath = "$env:SystemDrive\Windows.old"
        if (Test-Path $windowsOldPath) {
            $windowsOldDate = (Get-Item $windowsOldPath).CreationTime
            $allDates += $windowsOldDate
            Write-Host "Windows.old Folder Creation Date: $($windowsOldDate.ToString('MM/dd/yyyy'))" -ForegroundColor White
        }

        # Filter out any null dates and find the oldest
        $validDates = $allDates | Where-Object { $_ -ne $null }
        $oldestDate = $validDates | Sort-Object | Select-Object -First 1

        Write-Host "`nOldest detected date (likely original deployment): $($oldestDate.ToString('MM/dd/yyyy'))" -ForegroundColor Green

        # Format date for Gorelo (date only)
        $goreloDateString = Get-Date $oldestDate -Format "yyyy-MM-dd"

        # Set Gorelo custom field with the oldest date
        try {
            GoreloAction -SetCustomField -Name '$gorelo:asset.windowsInstallDate' -Value $goreloDateString
            Write-Host "Successfully updated Gorelo custom field" -ForegroundColor Green
        } catch {
            Write-Host "Error updating Gorelo custom field: $($_.Exception.Message)" -ForegroundColor Red
        }

        # Display difference between oldest and newest dates for verification
        $newestDate = $validDates | Sort-Object | Select-Object -Last 1
        $dateDifference = New-TimeSpan -Start $oldestDate -End $newestDate
        Write-Host "`nDate range span: $($dateDifference.Days) days" -ForegroundColor Cyan
        Write-Host "Newest date found: $($newestDate.ToString('MM/dd/yyyy'))" -ForegroundColor Cyan
        ```
      </Tab>

      <Tab title="Windows Product Key">
        * **Name**: 🗝️Store-WindowsProductKey
        * **Content**:

        ```powershell theme={null}
        # Get Windows Product Key and update Gorelo custom field
        try {
            # Get Windows Product Key using WMI
            $productKey = (Get-WmiObject -query 'select * from SoftwareLicensingService').OA3xOriginalProductKey

            if ([string]::IsNullOrEmpty($productKey)) {
                # If OA3xOriginalProductKey is empty, try getting it from registry
                $regPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform'
                $regValue = 'BackupProductKeyDefault'
                $productKey = (Get-ItemProperty -Path $regPath -Name $regValue -ErrorAction SilentlyContinue).$regValue
            }

            if ([string]::IsNullOrEmpty($productKey)) {
                # If still empty, try another registry method
                $regPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId"
                $digitalId = (Get-ItemProperty -Path $regPath).DigitalProductId
                
                # Convert Digital Product ID to Product Key
                $keyOffset = 52
                $isWin8 = ([math]::Floor($digitalId[66] / 6) -band 1)
                $productKey = ""
                $chars = "BCDFGHJKMPQRSTVWXY2346789"

                for ($i = 24; $i -ge 0; $i--) {
                    $r = 0
                    for ($j = 14; $j -ge 0; $j--) {
                        $r = ($r * 256) -bxor $digitalId[$j + $keyOffset]
                        $digitalId[$j + $keyOffset] = [math]::Floor($r / 24)
                        $r = $r % 24
                    }
                    $productKey = $chars[$r] + $productKey
                    if (($i % 5) -eq 0 -and $i -ne 0) {
                        $productKey = "-" + $productKey
                    }
                }
            }

            if (![string]::IsNullOrEmpty($productKey)) {
                # Update Gorelo RMM custom field
                GoreloAction -SetCustomField -Name '$gorelo:asset.WindowsProductKey' -Value $productKey
                Write-Output "Successfully updated Windows Product Key in Gorelo"
            } else {
                Write-Error "Could not retrieve Windows Product Key"
                exit 1
            }
        } catch {
            Write-Error "Error: $($_.Exception.Message)"
            exit 1
        }
        ```
      </Tab>

      <Tab title="MAC Address">
        * **Name**: MAC Address for Ethernet
        * **Content**:

        ```powershell theme={null}
        # Get Ethernet adapter MAC address only
        $MacAddress = (Get-NetAdapter | Where-Object {$_.Name -like "*Ethernet*" -and $_.Status -eq "Up"} | Select-Object -First 1 -ExpandProperty MacAddress)

        if ($MacAddress) {
            GoreloAction -SetCustomField -Name 'asset.macAddress' -Value $MacAddress
            Write-Host "Ethernet MAC Address set to: $MacAddress"
        } else {
            Write-Host "No active Ethernet adapter found"
        }
        ```
      </Tab>

      <Tab title="RAM Slots Used">
        * **Name**: 🗝️Store-ramSlotsUsed
        * **Content**:

        ```powershell theme={null}
        $totalSlots = (Get-CimInstance -ClassName Win32_PhysicalMemoryArray).MemoryDevices
        $usedSlots = (Get-CimInstance -ClassName Win32_PhysicalMemory).Count
        $emptySlots = $totalSlots - $usedSlots
        $totalRAM = [math]::Round((Get-CimInstance -ClassName Win32_ComputerSystem).TotalPhysicalMemory/1GB, 2)

        $ramInfo = "RAM: $totalRAM GB installed | Slots: $usedSlots/$totalSlots used ($emptySlots empty)"

        # Set Gorelo RMM custom field
        GoreloAction -SetCustomField -Name 'asset.ramSlotsUsed' -Value $ramInfo

        Write-Host "Set Gorelo field 'asset.ramSlotsUsed' to: $ramInfo"
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Deploy the script via a policy.">
    1. Navigate to **[Policies](https://app.gorelo.io/Asset/policy-management).**
    2. Edit an existing policy that covers the assets you want to store the keys or the addresses for.
    3. Add the script and set to repeat daily at your preferred time.
    4. **Save** and distribute the policy.
  </Step>
</Steps>
