Document Management for ServiceNow
Document Management handles attachments, templates, and document generation.
Document Architecture Record ├── Attachments (sys_attachment) │ └── Attachment Data (sys_attachment_doc) ├── Generated Documents └── Document Templates
Key Tables Table Purpose sys_attachment Attachment metadata sys_attachment_doc Attachment content sys_report_template Report templates dms_document Document records Attachments (ES5) Upload Attachment // Attach file to record (ES5 ONLY!) function attachFile(tableName, recordSysId, fileName, contentType, content) { var attachment = new GlideSysAttachment();
// Content can be base64 encoded string
var attachmentSysId = attachment.write(
tableName,
recordSysId,
fileName,
contentType,
content
);
return attachmentSysId;
}
// Example var base64Content = 'SGVsbG8gV29ybGQh'; // Base64 encoded attachFile('incident', incidentSysId, 'notes.txt', 'text/plain', base64Content);
Read Attachment // Read attachment content (ES5 ONLY!) function getAttachmentContent(attachmentSysId) { var attachment = new GlideSysAttachment(); var content = attachment.getContent(attachmentSysId); return content; }
// Get attachment as base64 function getAttachmentBase64(attachmentSysId) { var attachment = new GlideSysAttachment(); var bytes = attachment.getBytes(attachmentSysId);
// Convert to base64
var base64 = GlideBase64.encode(bytes);
return base64;
}
List Attachments // Get all attachments for record (ES5 ONLY!) function getRecordAttachments(tableName, recordSysId) { var attachments = [];
var gr = new GlideRecord('sys_attachment');
gr.addQuery('table_name', tableName);
gr.addQuery('table_sys_id', recordSysId);
gr.query();
while (gr.next()) {
attachments.push({
sys_id: gr.getUniqueValue(),
file_name: gr.getValue('file_name'),
content_type: gr.getValue('content_type'),
size_bytes: gr.getValue('size_bytes'),
created_on: gr.getValue('sys_created_on'),
created_by: gr.sys_created_by.getDisplayValue()
});
}
return attachments;
}
Copy Attachments // Copy attachments between records (ES5 ONLY!) function copyAttachments(sourceTable, sourceSysId, targetTable, targetSysId) { var attachment = new GlideSysAttachment(); attachment.copy(sourceTable, sourceSysId, targetTable, targetSysId); }
// Copy specific attachment function copyOneAttachment(attachmentSysId, targetTable, targetSysId) { var source = new GlideRecord('sys_attachment'); if (!source.get(attachmentSysId)) { return null; }
var attachment = new GlideSysAttachment();
var content = attachment.getBytes(attachmentSysId);
return attachment.write(
targetTable,
targetSysId,
source.getValue('file_name'),
source.getValue('content_type'),
content
);
}
Document Templates (ES5) Create Document Template // Create document template (ES5 ONLY!) var template = new GlideRecord('sys_report_template'); template.initialize();
template.setValue('name', 'Incident Summary Report'); template.setValue('table', 'incident'); template.setValue('description', 'Summary report for incident resolution');
// Template content with placeholders template.setValue('template', '<html>\n' + '<head><title>Incident Summary</title></head>\n' + '<body>\n' + '
Incident Summary Report
\n' + '${number}
\n' + 'Description: ${short_description}
\n' + 'Caller: ${caller_id.name}
\n' + 'Priority: ${priority}
\n' + 'State: ${state}
\n' + 'Resolution: ${close_notes}
\n' + 'Resolved By: ${resolved_by.name}
\n' + 'Resolved On: ${resolved_at}
\n' + '</body>\n' + '</html>' );template.insert();
Generate Document from Template // Generate document from template (ES5 ONLY!) function generateDocumentFromTemplate(templateName, recordSysId) { // Get template var template = new GlideRecord('sys_report_template'); if (!template.get('name', templateName)) { return null; }
// Get record
var tableName = template.getValue('table');
var gr = new GlideRecord(tableName);
if (!gr.get(recordSysId)) {
return null;
}
// Process template
var content = template.getValue('template');
content = processTemplateVariables(content, gr);
return content;
}
function processTemplateVariables(template, gr) { // Replace ${field} and ${field.property} patterns var pattern = /\${([^}]+)}/g; var match;
while ((match = pattern.exec(template)) !== null) {
var fieldPath = match[1];
var value = getFieldValue(gr, fieldPath);
template = template.replace(match[0], value);
}
return template;
}
function getFieldValue(gr, fieldPath) { var parts = fieldPath.split('.'); var value = gr;
for (var i = 0; i < parts.length; i++) {
if (!value) return '';
if (i < parts.length - 1) {
// Reference field - get referenced record
value = value[parts[i]].getRefRecord();
} else {
// Final field
if (value.isValidField && value.isValidField(parts[i])) {
value = value[parts[i]].getDisplayValue() || value.getValue(parts[i]);
} else {
value = '';
}
}
}
return value || '';
}
PDF Generation (ES5) Generate PDF // Generate PDF from HTML (ES5 ONLY!) function generatePDF(htmlContent, fileName) { try { var pdfCreator = new sn_pdfgeneratorutils.PDFGenerationAPI(); var pdfBytes = pdfCreator.convertToPDF(htmlContent);
// Return as base64
return {
success: true,
content: GlideBase64.encode(pdfBytes),
fileName: fileName || 'document.pdf'
};
} catch (e) {
gs.error('PDF generation failed: ' + e.message);
return {
success: false,
error: e.message
};
}
}
// Generate and attach PDF to record function generateAndAttachPDF(templateName, recordSysId, fileName) { // Generate HTML from template var html = generateDocumentFromTemplate(templateName, recordSysId); if (!html) { return { success: false, error: 'Template generation failed' }; }
// Convert to PDF
var pdf = generatePDF(html, fileName);
if (!pdf.success) {
return pdf;
}
// Get table name from template
var template = new GlideRecord('sys_report_template');
template.get('name', templateName);
var tableName = template.getValue('table');
// Attach PDF
var attachmentSysId = attachFile(
tableName,
recordSysId,
fileName,
'application/pdf',
pdf.content
);
return {
success: true,
attachment_sys_id: attachmentSysId
};
}
Document Workflow (ES5) Document Approval // Create document for approval (ES5 ONLY!) function submitDocumentForApproval(documentSysId, approvers) { var doc = new GlideRecord('dms_document'); if (!doc.get(documentSysId)) { return { success: false, message: 'Document not found' }; }
// Update state
doc.setValue('state', 'pending_approval');
doc.update();
// Create approval records
for (var i = 0; i < approvers.length; i++) {
var approval = new GlideRecord('sysapproval_approver');
approval.initialize();
approval.setValue('sysapproval', documentSysId);
approval.setValue('approver', approvers[i]);
approval.setValue('state', 'requested');
approval.insert();
}
// Notify approvers
gs.eventQueue('document.approval.requested', doc, approvers.join(','), '');
return { success: true };
}
Version Control // Create new document version (ES5 ONLY!) function createDocumentVersion(documentSysId, newContent, changeNotes) { var doc = new GlideRecord('dms_document'); if (!doc.get(documentSysId)) { return null; }
// Get current version
var currentVersion = parseInt(doc.getValue('version'), 10) || 1;
var newVersion = currentVersion + 1;
// Archive current version
var archive = new GlideRecord('dms_document_version');
archive.initialize();
archive.setValue('document', documentSysId);
archive.setValue('version', currentVersion);
archive.setValue('content', doc.getValue('content'));
archive.setValue('created_by', gs.getUserID());
archive.insert();
// Update document with new version
doc.setValue('version', newVersion);
doc.setValue('content', newContent);
doc.work_notes = 'Version ' + newVersion + ': ' + changeNotes;
doc.update();
return {
document_sys_id: documentSysId,
version: newVersion
};
}
// Get document version history function getDocumentVersions(documentSysId) { var versions = [];
var version = new GlideRecord('dms_document_version');
version.addQuery('document', documentSysId);
version.orderByDesc('version');
version.query();
while (version.next()) {
versions.push({
version: version.getValue('version'),
created_on: version.getValue('sys_created_on'),
created_by: version.sys_created_by.getDisplayValue()
});
}
return versions;
}
Attachment Security (ES5) Check Attachment Access // Check if user can access attachment (ES5 ONLY!) function canAccessAttachment(attachmentSysId) { var attachment = new GlideRecord('sys_attachment'); if (!attachment.get(attachmentSysId)) { return false; }
// Check access to parent record
var parentTable = attachment.getValue('table_name');
var parentSysId = attachment.getValue('table_sys_id');
var parent = new GlideRecord(parentTable);
return parent.get(parentSysId); // Returns false if no read access
}
MCP Tool Integration Available Tools Tool Purpose snow_query_table Query attachments snow_execute_script_with_output Test document scripts snow_find_artifact Find templates Example Workflow // 1. Get record attachments await snow_query_table({ table: 'sys_attachment', query: 'table_name=incident^table_sys_id=inc_sys_id', fields: 'file_name,content_type,size_bytes,sys_created_on' });
// 2. Generate document
await snow_execute_script_with_output({
script: var html = generateDocumentFromTemplate('Incident Summary', 'inc_sys_id');
gs.info('Generated: ' + (html ? 'success' : 'failed'));
});
// 3. Find document templates await snow_query_table({ table: 'sys_report_template', query: 'table=incident', fields: 'name,description,table' });
Best Practices File Types - Restrict allowed types Size Limits - Set max file sizes Virus Scanning - Scan uploads Access Control - Inherit from parent Version Control - Track changes Cleanup - Remove orphaned files Templates - Use for consistency ES5 Only - No modern JavaScript syntax