From 78ffe240e71e1acdb4aa585fa846212470ebecd0 Mon Sep 17 00:00:00 2001 From: TechnoSavage Date: Thu, 13 Nov 2025 13:15:58 -0500 Subject: [PATCH 1/4] update to Snow License Manager to add epoch/unix timestamp formatting and additional attributes. --- snow_license_manager/snow.star | 179 +++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 63 deletions(-) diff --git a/snow_license_manager/snow.star b/snow_license_manager/snow.star index 457c7ee..f6c515f 100644 --- a/snow_license_manager/snow.star +++ b/snow_license_manager/snow.star @@ -1,9 +1,9 @@ load('runzero.types', 'ImportAsset', 'NetworkInterface', 'Software') load('base64', base64_encode='encode', base64_decode='decode') -load('flatten_json', 'flatten') load('http', http_get='get', http_post='post', 'url_encode') load('json', json_encode='encode', json_decode='decode') load('net', 'ip_address') +load('time', 'parse_time') load('uuid', 'new_uuid') #Change the URL to match your Snow Software License Manager server @@ -33,84 +33,117 @@ def build_assets(assets, creds): interfaces.append(interface) # Retrieve and map custom attributes - organization = item.get('Organization', '') - org_checksum = item.get('OrgChecksum', '') - is_virtual = item.get('IsVirtual', '') - status = item.get('Status', '') - last_scan_date = item.get('LastScanDate', '') - updated_by = item.get('UpdatedBy', '') - updated_date = item.get('UpdatedData', '') - domain = item.get('Domain', '') - total_disk_space = item.get('TotalDiskSpace', '') - physical_memory = item.get('PhyscialMemory', '') - processor_type = item.get('ProcessorType', '') - processor_count = item.get('ProcessorCount', '') - core_count = item.get('CoreCount', '') + hw = item.get('Hardware', {}) + bios_date = hw.get('BiosDate', '') + #Reformat bios_date timestamp for runZero parsing + if bios_date and bios_date != '': + bios_date = parse_time(bios_date + 'Z').unix bios_sn = item.get('BiosSerialNumber', '') + bios_version = hw.get('BiosVersion', '') + core_count = item.get('CoreCount', '') + cores_per_proc = hw.get('CoresPerProcessor', '') + domain = item.get('Domain', '') hyperv_name = item.get('HypervisorName', '') is_portable = item.get('IsPortable', '') is_server = item.get('IsServer', '') + is_virtual = item.get('IsVirtual', '') + last_scan_date = item.get('LastScanDate', '') + # Reformat last_scan_date timestamp for runZero parsing + if last_scan_date and last_scan_date != '': + last_scan_date = parse_time(last_scan_date + 'Z').unix + memory_slots = hw.get('MemorySlots', '') + memory_slots_avail = hw.get('MemorySlotsAvailable', '') most_freq_user = item.get('MostFrequentUserId', '') most_recent_user = item.get('MostRecentUserId', '') - logical_disk = hw.get('LogicalDisks', {}).get('LogicalDisk', {}) - disk_name = logical_disk.get('Name', '') - disk_size = logical_disk.get('SizeMb', '') - disk_vol = logical_disk.get('VolumeName', '') - optical_drives = hw.get('OpticalDrives', {}).get('OpticalDrive', {}) - drive_name = optical_drives.get('Name', '') - drive_type = optical_drives.get('Type', '') + number_of_procs = hw.get('NumberOfProcessors', '') + organization = item.get('Organization', '') + org_checksum = item.get('OrgChecksum', '') + processor_count = item.get('ProcessorCount', '') + physical_memory = item.get('PhysicalMemory', '') + physical_memory_mb = hw.get('PhysicalMemoryMb', '') + processor_type = item.get('ProcessorType', '') + status = item.get('Status', '') + system_disk_space_mb = hw.get('SystemDiskSpaceMb', '') + system_disk_space_avail_mb = hw.get('SystemDiskSpaceAvailableMb', '') + total_disk_space = item.get('TotalDiskSpace', '') + total_disk_space_mb = hw.get('TotalDiskSpaceMb', '') + total_disk_space_avail_mb = hw.get('TotalDiskSpaceAvailableMb', '') + updated_by = item.get('UpdatedBy', '') + updated_date = item.get('UpdatedData', '') custom_attributes = { - 'organization': organization, - 'orgChecksum': org_checksum, - 'isVirtual': is_virtual, - 'status': status, - 'lastScanDate': last_scan_date, - 'updatedBy': updated_by, - 'updatedDate': updated_date, - 'domain': domain, - 'totalDiskSpace': total_disk_space, - 'physicalMemory': physical_memory, - 'processorType': processor_type, - 'processorCount': processor_count, - 'coreCount': core_count, + 'biosDate': bios_date, 'biosSerialNumber': bios_sn, + 'biosVersion': bios_version, + 'coreCount': core_count, + 'coresPerProcessor': cores_per_proc, + 'domain': domain, 'hypervisorName': hyperv_name, 'isPortable': is_portable, 'isServer': is_server, + 'isVirtual': is_virtual, + 'lastScanDate': last_scan_date, + 'memorySlots': memory_slots, + 'memorySlotsAvailable': memory_slots_avail, 'mostFrequentUserId': most_freq_user, 'mostRecentUserId': most_recent_user, - 'logicalDisk.name': disk_name, - 'logicalDisk.sizeMb': disk_size, - 'logicalDisk.volumeName': disk_vol, - 'opticalDrive.name': drive_name, - 'opticalDrive.type': drive_type + 'numberOfProcessors': number_of_procs, + 'organization': organization, + 'orgChecksum': org_checksum, + 'processorCount': processor_count, + 'physicalMemory': physical_memory, + 'physicalMemoryMb': physical_memory_mb, + 'processorType': processor_type, + 'status': status, + 'systemDiskSpaceMb': system_disk_space_mb, + 'systemDiskSpaceAvailableMb': system_disk_space_avail_mb, + 'totalDiskSpace': total_disk_space, + 'totalDiskSpaceMb': total_disk_space_mb, + 'totalDiskSpaceAvailableMb': total_disk_space_avail_mb, + 'updatedBy': updated_by, + 'updatedDate': updated_date } + + logical_disks = hw.get('LogicalDisks', None) + if logical_disks and type(logical_disks) == 'list': + for disk in logical_disks: + if disk: + for k, v in disk.items(): + custom_attributes['logicalDisks.' + str(logical_disks.index(disk)) + '.' + k] = v + if logical_disks and type(logical_disks) == 'dict': + for k, v in logical_disks.items(): + custom_attributes['logicalDisks.0.' + k] = v - hw = item.get('Hardware', {}) - custom_attributes['hardware.biosSerialNumber'] = hw.get('BiosSerialNumber', '') - custom_attributes['hardware.biosVersion'] = hw.get('BiosVersion', '') - custom_attributes['hardware.biosDate'] = hw.get('BiosDate', '') - custom_attributes['hardware.processorType'] = hw.get('ProcessorType', '') - custom_attributes['hardware.numberOfProcessors'] = hw.get('NumberOfProcessors', '') - custom_attributes['hardware.coresPerProcessor.'] = hw.get('CoresPerProcessor', '') - custom_attributes['hardware.physicalMemoryMb'] = hw.get('PhysicalMemoryMb', '') - custom_attributes['hardware.memorySlots'] = hw.get('MemorySlots', '') - custom_attributes['hardware.memorySlotsAvailable'] = hw.get('MemorySlotsAvailable', '') - custom_attributes['hardware.systemDiskSpaceMb'] = hw.get('SystemDiskSpaceMb', '') - custom_attributes['hardware.systemDiskSpaceAvailableMb'] = hw.get('SystemDiskSpaceAvailableMb', '') - custom_attributes['hardware.totalDiskSpaceMb'] = hw.get('TotalDiskSpaceMb', '') - custom_attributes['hardware.totalDiskSpaceAvailableMb'] = hw.get('TotalDiskSpaceAvailableMb', '') - display_adapters = hw.get('DisplayAdapters', {}).get('DisplayAdapter', []) - for adapter in display_adapters: - for k, v in adapter: - custom_attributes['displayAdapter.' + str(display_adapters.index[adapter]) + '.' + k] = v - monitors = hw.get('Monitors', {}).get('Monitor', []) - for monitor in monitors: - for k, v in monitor: - custom_attributes['monitor.' + str(monitors.index[monitor]) + '.' + k] = v + optical_drives = hw.get('OpticalDrives', None) + if optical_drives and type(optical_drives) == 'list': + for drive in optical_drives: + if drive: + for k, v in drive.items(): + custom_attributes['opticalDrives.' + str(optical_drives.index(drive)) + '.' + k] = v + if optical_drives and type(optical_drives) == 'dict': + for k, v in optical_drives.items(): + custom_attributes['opticalDrives.0.' + k] = v + + display_adapters = hw.get('DisplayAdapters', None) + if display_adapters and type(display_adapters) == 'list': + for adapter in display_adapters: + if adapter: + for k, v in adapter.items(): + custom_attributes['displayAdapter.' + str(display_adapters.index(adapter)) + '.' + k] = v + if display_adapters and type(display_adapters) == 'dict': + for k, v in display_adapters.items(): + custom_attributes['displayAdapter.0.' + k] = v + monitors = hw.get('Monitors', None) + if monitors and type(monitors) == 'list': + for monitor in monitors: + if monitor: + for k, v in monitor.items(): + custom_attributes['monitor.' + str(monitors.index(monitor)) + '.' + k] = v + if monitors and type(monitors) == 'dict': + for k, v in monitors.items(): + custom_attributes['monitor.0.' + k] = v # Retrieve software information for asset # create software entries @@ -170,9 +203,29 @@ def build_app(software_entry): bundled_app_id = app.get('BundleApplicationId', '') bundled_app_name = app.get('BundleApplicationName', '') last_used = app.get('LastUsed', '') + # Reformat last_used timestamp for runZero parsing + if last_used and last_used != '': + last_used = parse_time(last_used + 'Z').unix + else: + last_used = 'n/a' first_used = app.get('FirstUsed', '') + # Reformat first_used timestamp for runZero parsing + if first_used and first_used != '': + first_used = parse_time(first_used + 'Z').unix + else: + first_used = 'n/a' install_date = app.get('InstallDate', '') - discvovered_date = app.get('DiscoveredDate', '') + # Reformat install_date timestamp for runZero parsing + if install_date and install_date != '': + install_date = parse_time(install_date + 'Z').unix + else: + install_date = 'n/a' + discovered_date = app.get('DiscoveredDate', '') + # Reformat discovered_date timestamp for runZero parsing + if discovered_date and discovered_date != '': + discovered_date = parse_time(discovered_date + 'Z').unix + else: + discovered_date = 'n/a' run = app.get('Run', '') avg_usage_time = app.get('AvgUsageTime', '') users = app.get('Users', '') @@ -196,7 +249,7 @@ def build_app(software_entry): 'last.used': last_used, 'first.used': first_used, 'install.date': install_date, - 'discovered.date': discvovered_date, + 'discovered.date': discovered_date, 'run': run, 'average.usage.time': avg_usage_time, 'users': users, From 459800716e739aa3baab54673f2303cb0ee627cc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 13 Nov 2025 18:20:42 +0000 Subject: [PATCH 2/4] Auto: update integrations JSON and README --- README.md | 2 +- docs/integrations.json | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3b0be41..ac41479 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ If you need help setting up a custom integration, you can create an [issue](http # Existing Integrations ## Import to runZero +- [Akamai Guardicore Centra](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/akamai-guardicore-centra/) - [Automox](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/automox/) - [Carbon Black](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/carbon-black/) - [Cisco-ISE](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/cisco-ise/) @@ -29,7 +30,6 @@ If you need help setting up a custom integration, you can create an [issue](http - [Drata](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/drata/) - [Extreme Networks CloudIQ](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/extreme-cloud-iq/) - [Ghost Security](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/ghost/) -- [Guardicore Centra](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/akamai_guardicore_centra/) - [JAMF](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/jamf/) - [Kandji](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/kandji/) - [Lima Charlie](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/lima-charlie/) diff --git a/docs/integrations.json b/docs/integrations.json index 6bd5ad3..205f95f 100644 --- a/docs/integrations.json +++ b/docs/integrations.json @@ -1,5 +1,5 @@ { - "lastUpdated": "2025-11-10T18:36:52.667035Z", + "lastUpdated": "2025-11-13T18:20:42.065154Z", "totalIntegrations": 28, "integrationDetails": [ { @@ -14,12 +14,6 @@ "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/sumo-logic/README.md", "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/sumo-logic/custom-integration-sumo.star" }, - { - "name": "Guardicore Centra", - "type": "inbound", - "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/akamai_guardicore_centra/README.md", - "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/akamai_guardicore_centra/centrav3.star" - }, { "name": "Cyberint", "type": "inbound", @@ -86,6 +80,12 @@ "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/digital-ocean/README.md", "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/digital-ocean/custom-integration-digital-ocean.star" }, + { + "name": "Akamai Guardicore Centra", + "type": "inbound", + "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/akamai-guardicore-centra/README.md", + "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/akamai-guardicore-centra/custom-integration-centra-v3-api.star" + }, { "name": "Device42", "type": "inbound", From 7522eeec7cc758b2f481b0488edd567cc3a532ce Mon Sep 17 00:00:00 2001 From: Tyler Diderich Date: Fri, 14 Nov 2025 13:10:03 -0600 Subject: [PATCH 3/4] nit picks on naming --- {snow_license_manager => snow-license-manager}/README.md | 0 {snow_license_manager => snow-license-manager}/config.json | 0 .../custom-integration-snow.star | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {snow_license_manager => snow-license-manager}/README.md (100%) rename {snow_license_manager => snow-license-manager}/config.json (100%) rename snow_license_manager/snow.star => snow-license-manager/custom-integration-snow.star (100%) diff --git a/snow_license_manager/README.md b/snow-license-manager/README.md similarity index 100% rename from snow_license_manager/README.md rename to snow-license-manager/README.md diff --git a/snow_license_manager/config.json b/snow-license-manager/config.json similarity index 100% rename from snow_license_manager/config.json rename to snow-license-manager/config.json diff --git a/snow_license_manager/snow.star b/snow-license-manager/custom-integration-snow.star similarity index 100% rename from snow_license_manager/snow.star rename to snow-license-manager/custom-integration-snow.star From 57deb2ceabb9c6f30130dfa8ed3c734770ed6138 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 14 Nov 2025 19:10:56 +0000 Subject: [PATCH 4/4] Auto: update integrations JSON and README --- README.md | 2 +- docs/integrations.json | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4c3d4ca..097cd09 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ If you need help setting up a custom integration, you can create an [issue](http - [runZero Task Sync](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/task-sync/) - [Scale Computing](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/scale-computing/) - [Snipe-IT](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snipe-it/) -- [Snow License Manager](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snow_license_manager/) +- [Snow License Manager](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snow-license-manager/) - [Stairwell](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/stairwell/) - [Tailscale](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/tailscale/) - [Tanium](https://github.com/runZeroInc/runzero-custom-integrations/blob/main/tanium/) diff --git a/docs/integrations.json b/docs/integrations.json index 4638017..53b4045 100644 --- a/docs/integrations.json +++ b/docs/integrations.json @@ -1,5 +1,5 @@ { - "lastUpdated": "2025-11-13T17:39:24.733491Z", + "lastUpdated": "2025-11-14T19:10:56.291488Z", "totalIntegrations": 29, "integrationDetails": [ { @@ -68,6 +68,12 @@ "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/tailscale/README.md", "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/tailscale/custom-integration-tailscale.star" }, + { + "name": "Snow License Manager", + "type": "inbound", + "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snow-license-manager/README.md", + "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snow-license-manager/custom-integration-snow.star" + }, { "name": "Automox", "type": "inbound", @@ -169,12 +175,6 @@ "type": "inbound", "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/proxmox/README.md", "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/proxmox/custom-integration-proxmox.star" - }, - { - "name": "Snow License Manager", - "type": "inbound", - "readme": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snow_license_manager/README.md", - "integration": "https://github.com/runZeroInc/runzero-custom-integrations/blob/main/snow_license_manager/snow.star" } ] } \ No newline at end of file