Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Fix Script for Knowledge Articles

WayneHadley
Tera Contributor

Greetings,

I have business request to help clean up knowledge articles where a new version was published but the old version was not retired. The ask is to identify and retire the older versions. After doing some research, I'm thinking of taking the approach of using a fix script (which I will run in a sub-prod instance first), but given I am not a very experienced developer, I'd welcome feedback on this approach as well as review of my script. Thank you!

// This Fix Script finds and retires old, published versions of knowledge articles.
// It is intended to be run once as a data cleanup task.
var articlesRetired = 0;
// Query for knowledge articles that are 'published' but are NOT the latest version.
var grOldArticles = new GlideRecord('kb_knowledge');
grOldArticles.addQuery('workflow_state', 'published');
grOldArticles.addQuery('latest', 'false');
grOldArticles.query();
gs.info('[Fix Script] Found ' + grOldArticles.getRowCount() + ' old, published articles that will be retired.');
// Loop through the results and update the state to 'retired'.
while (grOldArticles.next()) {
  var articleNumber = grOldArticles.getValue('number');
  var articleVersion = grOldArticles.getValue('version');
  // Set the state to 'retired'.
  grOldArticles.workflow_state = 'retired';
  
  // setWorkflow(false) to prevent any business rules/workflows on the kb_knowledge table from running for this update.
  grOldArticles.setWorkflow(false);
  
  // autoSysFields(false) to prevent the system from updating sys_updated_on, sys_updated_by
  grOldArticles.autoSysFields(false);
  
  grOldArticles.update();
  
  articlesRetired++;
  gs.info('[Fix Script] Retired article: ' + articleNumber + ', Version: ' + articleVersion);
}
gs.info('[Fix Script] Retirement of old articles is complete. Total retired: ' + articlesRetired);

 

2 ACCEPTED SOLUTIONS

Bert_c1
Kilo Patron

Hi,

 

I tested your script in my PDI, found one article to retire, however there was no 'latest' version. I don't know if you want that.  So I tried the following updates (a dry_run variable for testing, and function to test for a published and latest version, if statement to proceed based on the result).

 

// This Fix Script finds and retires old, published versions of knowledge articles.
// It is intended to be run once as a data cleanup task.
var dry_run = true;			// allow testing
var articlesRetired = 0;
// Query for knowledge articles that are 'published' but are NOT the latest version.
var grOldArticles = new GlideRecord('kb_knowledge');
grOldArticles.addQuery('workflow_state', 'published');
grOldArticles.addQuery('latest', 'false');
grOldArticles.query();
gs.info('[Fix Script] Found ' + grOldArticles.getRowCount() + ' old, published articles that will be retired.');
// Loop through the results and update the state to 'retired'.
while (grOldArticles.next()) {
  var articleNumber = grOldArticles.getValue('number');
  var articleVersion = grOldArticles.getValue('version');
  
  // Check for published version and latest is true
  newVersion = checkPublished(articleNumber);
  if (newVersion) {
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ' has latest published');

	  // Set the state to 'retired'.
	  grOldArticles.workflow_state = 'retired';
	  
	  // setWorkflow(false) to prevent any business rules/workflows on the kb_knowledge table from running for this update.
	  grOldArticles.setWorkflow(false);
	  
	  // autoSysFields(false) to prevent the system from updating sys_updated_on, sys_updated_by
	  grOldArticles.autoSysFields(false);
	  
	  if(!dry_run)
		  grOldArticles.update();
	  
	  articlesRetired++;
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ', Version: ' + articleVersion + ', latest: ' +grOldArticles.latest);
  }
}
gs.info('[Fix Script] Retirement of old articles is complete. Total retired: ' + articlesRetired);

function checkPublished(kbNumber) {
	var kb = new GlideRecord('kb_knowledge');
	kb.addQuery('number', kbNumber);
	kb.addQuery('latest', true);
	kb.query();
	if (kb.next()) {
		gs.info('KB: ' + kb.number + ' latest: ' + kb.latest);
		if (kb.latest)
			return true;
	}
	return false;
}

 

If you don't want to check for a latest version, then your script seems to work. In my instance, the latest version workflow is in an earlier state the the non-latest version.

 

Upon testing with dry_run being false, the 'Retired' field was not updated 🙂 However the workflow for that is 'retired'.

View solution in original post

WillieW
Tera Contributor

I also tested in my PDI, with modified logic to check for existing un-published version before retiring a kb_nowledge record.  That worked if you add that check.

 

// This Fix Script finds and retires old, published versions of knowledge articles.
// It is intended to be run once as a data cleanup task.
var dry_run = false;			// allow testing
var articlesRetired = 0;
// Query for knowledge articles that are 'published' but are NOT the latest version.
var grOldArticles = new GlideRecord('kb_knowledge');
grOldArticles.addQuery('workflow_state', 'published');
grOldArticles.addQuery('latest', 'false');
grOldArticles.query();
gs.info('[Fix Script] Found ' + grOldArticles.getRowCount() + ' old, published articles that will be retired.');
// Loop through the results and update the state to 'retired'.
while (grOldArticles.next()) {
  var articleNumber = grOldArticles.getValue('number');
  var articleVersion = grOldArticles.getValue('version');
  gs.info('[Fix Script] Checking: ' + articleNumber);
  // Check for published version and latest is true
  newVersion = checkPublished(articleNumber);
  if (newVersion) {
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ' has latest un-published');

	  // Set the state to 'retired'.
	  grOldArticles.workflow_state = 'retired';
	  
	  // setWorkflow(false) to prevent any business rules/workflows on the kb_knowledge table from running for this update.
	  grOldArticles.setWorkflow(false);
	  
	  // autoSysFields(false) to prevent the system from updating sys_updated_on, sys_updated_by
	  grOldArticles.autoSysFields(false);
	  
	  if(!dry_run)
		  grOldArticles.update();
	  
	  articlesRetired++;
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ', Version: ' + articleVersion + ', latest: ' +grOldArticles.latest);
  }
}
gs.info('[Fix Script] Retirement of old articles is complete. Total retired: ' + articlesRetired);

function checkPublished(kbNumber) {
	var kb = new GlideRecord('kb_knowledge');
	kb.addQuery('number', kbNumber);
	kb.addQuery('workflow_state', '!=', 'published');
	kb.addQuery('latest', true);
	kb.query();
	while (kb.next()) {
		gs.info('[Fix Script] Later KB: ' + kb.number + ' latest: ' + kb.latest);
		if (kb.latest)
			return true;
	}
	return false;
}

View solution in original post

3 REPLIES 3

Bert_c1
Kilo Patron

Hi,

 

I tested your script in my PDI, found one article to retire, however there was no 'latest' version. I don't know if you want that.  So I tried the following updates (a dry_run variable for testing, and function to test for a published and latest version, if statement to proceed based on the result).

 

// This Fix Script finds and retires old, published versions of knowledge articles.
// It is intended to be run once as a data cleanup task.
var dry_run = true;			// allow testing
var articlesRetired = 0;
// Query for knowledge articles that are 'published' but are NOT the latest version.
var grOldArticles = new GlideRecord('kb_knowledge');
grOldArticles.addQuery('workflow_state', 'published');
grOldArticles.addQuery('latest', 'false');
grOldArticles.query();
gs.info('[Fix Script] Found ' + grOldArticles.getRowCount() + ' old, published articles that will be retired.');
// Loop through the results and update the state to 'retired'.
while (grOldArticles.next()) {
  var articleNumber = grOldArticles.getValue('number');
  var articleVersion = grOldArticles.getValue('version');
  
  // Check for published version and latest is true
  newVersion = checkPublished(articleNumber);
  if (newVersion) {
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ' has latest published');

	  // Set the state to 'retired'.
	  grOldArticles.workflow_state = 'retired';
	  
	  // setWorkflow(false) to prevent any business rules/workflows on the kb_knowledge table from running for this update.
	  grOldArticles.setWorkflow(false);
	  
	  // autoSysFields(false) to prevent the system from updating sys_updated_on, sys_updated_by
	  grOldArticles.autoSysFields(false);
	  
	  if(!dry_run)
		  grOldArticles.update();
	  
	  articlesRetired++;
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ', Version: ' + articleVersion + ', latest: ' +grOldArticles.latest);
  }
}
gs.info('[Fix Script] Retirement of old articles is complete. Total retired: ' + articlesRetired);

function checkPublished(kbNumber) {
	var kb = new GlideRecord('kb_knowledge');
	kb.addQuery('number', kbNumber);
	kb.addQuery('latest', true);
	kb.query();
	if (kb.next()) {
		gs.info('KB: ' + kb.number + ' latest: ' + kb.latest);
		if (kb.latest)
			return true;
	}
	return false;
}

 

If you don't want to check for a latest version, then your script seems to work. In my instance, the latest version workflow is in an earlier state the the non-latest version.

 

Upon testing with dry_run being false, the 'Retired' field was not updated 🙂 However the workflow for that is 'retired'.

WayneHadley
Tera Contributor

@Bert_c1  thank you for testing and your feedback very much appreciated.

WillieW
Tera Contributor

I also tested in my PDI, with modified logic to check for existing un-published version before retiring a kb_nowledge record.  That worked if you add that check.

 

// This Fix Script finds and retires old, published versions of knowledge articles.
// It is intended to be run once as a data cleanup task.
var dry_run = false;			// allow testing
var articlesRetired = 0;
// Query for knowledge articles that are 'published' but are NOT the latest version.
var grOldArticles = new GlideRecord('kb_knowledge');
grOldArticles.addQuery('workflow_state', 'published');
grOldArticles.addQuery('latest', 'false');
grOldArticles.query();
gs.info('[Fix Script] Found ' + grOldArticles.getRowCount() + ' old, published articles that will be retired.');
// Loop through the results and update the state to 'retired'.
while (grOldArticles.next()) {
  var articleNumber = grOldArticles.getValue('number');
  var articleVersion = grOldArticles.getValue('version');
  gs.info('[Fix Script] Checking: ' + articleNumber);
  // Check for published version and latest is true
  newVersion = checkPublished(articleNumber);
  if (newVersion) {
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ' has latest un-published');

	  // Set the state to 'retired'.
	  grOldArticles.workflow_state = 'retired';
	  
	  // setWorkflow(false) to prevent any business rules/workflows on the kb_knowledge table from running for this update.
	  grOldArticles.setWorkflow(false);
	  
	  // autoSysFields(false) to prevent the system from updating sys_updated_on, sys_updated_by
	  grOldArticles.autoSysFields(false);
	  
	  if(!dry_run)
		  grOldArticles.update();
	  
	  articlesRetired++;
	  gs.info('[Fix Script] Retired article: ' + articleNumber + ', Version: ' + articleVersion + ', latest: ' +grOldArticles.latest);
  }
}
gs.info('[Fix Script] Retirement of old articles is complete. Total retired: ' + articlesRetired);

function checkPublished(kbNumber) {
	var kb = new GlideRecord('kb_knowledge');
	kb.addQuery('number', kbNumber);
	kb.addQuery('workflow_state', '!=', 'published');
	kb.addQuery('latest', true);
	kb.query();
	while (kb.next()) {
		gs.info('[Fix Script] Later KB: ' + kb.number + ' latest: ' + kb.latest);
		if (kb.latest)
			return true;
	}
	return false;
}