Duplicate SAM Value Builder Task Numbers on samp_sp_vb_task Table<!-- /*NS Branding Styles*/ --> .ns-kb-css-body-editor-container { p { font-size: 12pt; font-family: Lato; color: #000000; } span { font-size: 12pt; font-family: Lato; color: #000000; } h2 { font-size: 24pt; font-family: Lato; color: black; } h3 { font-size: 18pt; font-family: Lato; color: black; } h4 { font-size: 14pt; font-family: Lato; color: black; } a { font-size: 12pt; font-family: Lato; color: #00718F; } a:hover { font-size: 12pt; color: #024F69; } a:target { font-size: 12pt; color: #032D42; } a:visited { font-size: 12pt; color: #00718f; } ul { font-size: 12pt; font-family: Lato; } li { font-size: 12pt; font-family: Lato; } img { display: ; max-width: ; width: ; height: ; } } Issue Duplicate Number values exist on the SAM Value Builder Task (samp_sp_vb_task) table, causing records to be flagged during ServiceNow Health Scans. Symptoms Two or more SAM Value Builder Task records share the same Number field value (e.g., SVB0001014, SVB0001015).ServiceNow Health Scan results flag duplicate record numbers on the samp_sp_vb_task table.The duplicate records may have different Sys IDs but identical Number and Name values. Facts • The original (non-duplicate) records are installed via plugin XML with hardcoded Number values and Sys IDs. These records are consistent across all instances: NumberNameSys ID SVB0001014 Complete Microsoft SQL Server License Management Guided Setup 82114d270f4d3110ebd9579ac4767ef7 SVB0001015 Complete Microsoft Windows Server License Management Guided Setup fb744de70f4d3110ebd9579ac4767e77 • The duplicate records are created by an update script during a plugin install or upgrade. These records share the same Number and Name across instances but have different Sys IDs per instance: NumberNameSys ID (varies per instance) SVB0001014 Cisco Webex Meetings Instance-specific SVB0001015 Roadmunk Instance-specific • The duplicates do not impact the creation or numbering of new SAM Value Builder Tasks. The UI Actions on samp_usage_under_management, samp_sp_apps_and_plugins, and samp_sp_publisher_pack_utilization correctly assign the next sequential Number when creating new tasks. Cause During a SAM plugin install or upgrade, an update script creates additional SAM Value Builder Task records (e.g., for Cisco Webex Meetings and Roadmunk) using hardcoded Number values that conflict with existing records already installed via the plugin XML. Because the original records have their Numbers baked into the XML rather than assigned by the sys_number_counter sequencer, the update script inadvertently reuses the same Number values, resulting in duplicates. Solution Run the background script below to renumber the duplicate records and update the sys_number_counter sequencer so that future records continue in the correct sequence. Before You Begin The script includes a dry-run mode enabled by default (dryRun = true). Run it in dry-run mode first to review the planned changes in the system logs before committing.Validate the output in the system logs to confirm the correct records are identified for renumbering.Once satisfied, set dryRun = false and run the script again to apply the changes. Steps Navigate to System Definition > Scripts - Background.Paste the script below into the editor.Run the script with dryRun = true (default) and review the output in the system logs.Confirm the correct duplicate records are identified and the proposed new Numbers are appropriate.Set dryRun = false and run the script again to apply the changes.Verify the duplicates have been renumbered by checking the samp_sp_vb_task table.Re-run the Health Scan to confirm the duplicate number findings are resolved. Background Script // ============================================================================ // Fix Duplicate Numbers on samp_sp_vb_task // ============================================================================ // PURPOSE: Finds duplicate Number values, renumbers the newer duplicates // with the next available numbers, and updates the sys_number_counter // sequencer so future records continue in sequence. // // TABLE: samp_sp_vb_task (SAM Value Builder Tasks) // PREFIX: SBV // // ⚠️ DRY RUN MODE: Set dryRun = false to commit changes. // ============================================================================ var dryRun = true; // Set to false to apply changes // Step 1 & 2: Find all duplicate Numbers and identify the newer record in each set var duplicateMap = {}; // { number: [sys_ids sorted oldest to newest] } var ga = new GlideAggregate('samp_sp_vb_task'); ga.addAggregate('COUNT', 'number'); ga.addHaving('COUNT', 'number', '>', 1); ga.query(); while (ga.next()) { var dupNumber = ga.getValue('number'); var records = []; var gr = new GlideRecord('samp_sp_vb_task'); gr.addQuery('number', dupNumber); gr.orderBy('sys_created_on'); // Oldest first gr.query(); while (gr.next()) { records.push({ sys_id: gr.getUniqueValue(), number: gr.getValue('number'), created_on: gr.getValue('sys_created_on') }); } duplicateMap[dupNumber] = records; } // Build list of records that need renumbering (newer duplicates) var toRenumber = []; for (var num in duplicateMap) { var set = duplicateMap[num]; gs.info('Duplicate Number: ' + num + ' — ' + set.length + ' records found'); gs.info(' Keeping oldest: sys_id=' + set[0].sys_id + ', created_on=' + set[0].created_on); // All records after the first (oldest) are duplicates to renumber for (var i = 1; i < set.length; i++) { gs.info(' Will renumber: sys_id=' + set[i].sys_id + ', created_on=' + set[i].created_on); toRenumber.push(set[i].sys_id); } } if (toRenumber.length === 0) { gs.info('No duplicate Numbers found. No changes needed.'); } else { gs.info('Total records to renumber: ' + toRenumber.length); // Step 3: Get the highest existing Number to determine the next available var grMax = new GlideRecord('samp_sp_vb_task'); grMax.orderByDesc('number'); grMax.setLimit(1); grMax.query(); var highestNumber = 0; if (grMax.next()) { var currentMax = grMax.getValue('number'); // Extract numeric portion from the prefix (e.g., SBV0001015 -> 1015) highestNumber = parseInt(currentMax.replace(/[^0-9]/g, ''), 10); gs.info('Current highest Number on table: ' + currentMax + ' (numeric: ' + highestNumber + ')'); } // Determine padding length from the current highest number format var sampleNumber = grMax.getValue('number'); var numericPart = sampleNumber.replace(/^[A-Za-z]+/, ''); var padLength = numericPart.length; // e.g., 7 for SBV0001015 // Step 4: Assign new sequential Numbers to each duplicate var nextNumber = highestNumber; for (var j = 0; j < toRenumber.length; j++) { nextNumber++; var paddedNum = String(nextNumber); while (paddedNum.length < padLength) { paddedNum = '0' + paddedNum; } var newNumber = 'SBV' + paddedNum; var grUpdate = new GlideRecord('samp_sp_vb_task'); if (grUpdate.get(toRenumber[j])) { var oldNumber = grUpdate.getValue('number'); if (dryRun) { gs.info('[DRY RUN] Would update sys_id=' + toRenumber[j] + ': ' + oldNumber + ' → ' + newNumber); } else { grUpdate.setValue('number', newNumber); grUpdate.setWorkflow(false); // Skip business rules grUpdate.autoSysFields(false); // Don't update sys_updated_on/by grUpdate.update(); gs.info('Updated sys_id=' + toRenumber[j] + ': ' + oldNumber + ' → ' + newNumber); } } } // Step 5: Update the sys_number_counter sequencer so new records continue // after the last assigned number var grSeq = new GlideRecord('sys_number_counter'); grSeq.addQuery('table', 'samp_sp_vb_task'); grSeq.query(); if (grSeq.next()) { var oldSeqNumber = grSeq.getValue('number'); if (dryRun) { gs.info('[DRY RUN] Would update sys_number_counter sequencer from ' + oldSeqNumber + ' → ' + nextNumber); } else { grSeq.setValue('number', nextNumber); grSeq.update(); gs.info('Updated sys_number_counter sequencer: ' + oldSeqNumber + ' → ' + nextNumber); } } else { gs.warn('Could not find sys_number_counter record with category "samp_sp_vb_task". Check the category value manually.'); } gs.info('============================================================'); if (dryRun) { gs.info('DRY RUN COMPLETE. Set dryRun = false to apply changes.'); } else { gs.info('COMPLETE. ' + toRenumber.length + ' records renumbered. Sequencer updated to ' + nextNumber + '.'); } } Script Behavior Summary The script performs the following actions: Identifies duplicates — Queries the samp_sp_vb_task table using GlideAggregate to find Number values with more than one record.Preserves the oldest record — For each duplicate set, the record with the earliest sys_created_on timestamp retains its original Number.Renumbers newer duplicates — Assigns the next available sequential Number (based on the current highest Number on the table) to each duplicate.Updates the sequencer — Modifies the sys_number_counter record for the samp_sp_vb_task table so that future records continue numbering from the correct value.Respects system fields — Uses setWorkflow(false) and autoSysFields(false) to prevent business rules from firing and to preserve the original sys_updated_on and sys_updated_by values. This is a cosmetic issue only. The duplicate Numbers do not affect SAM Value Builder Task functionality or the creation of new tasks. The resolution is recommended to clear Health Scan findings.