Welcome to Community Week 2025! Join us to learn, connect, and be recognized as we celebrate the spirit of Community and the power of AI. Get the details  

Moving Attachments to a different ServiceNow instance

TomWright_Dos
Tera Contributor

I had a case were I needed to move Case back to OOB.  I exported all of the case records, made my changes and imported the case records into their respective case type table.  So now I need re-attach the attachments.  As part of the import, I moved the old case number into the correlation id field on the imported case record. 

In our test instance (a clone of PRD prior to moving case to OOB), I created a field on the sys_attachment table called u_correlation_id and ran a script that would do a lookup against the case table and record (based on the table_name and table_sys_id) and move the case number into the u_correlation_id field.  I then wrote a script that, using REST post call, would copy over the attachments to other instance. The problem I am seeing is that, while the attachment is getting created on the other instance, it is not bringing over the value in the u_correlation_id field.

 

function sendAttachment (sourceTable, targetInstanceURL){
    var answer = [0,0];
    var attachRec = new GlideRecord('sys_attachment');
    attachRec.setLimit(10);
    attachRec.addQuery('table_name', sourceTable);
    attachRec.query();
    if(attachRec.hasNext()){
        while (attachRec.next()){
            var attachMessage = new sn_ws.RESTMessageV2();
            attachMessage.setLogLevel('all');
            attachMessage.setHttpMethod("post");
            attachMessage.setEndpoint(targetInstanceURL+"/api/now/attachment/file");
            attachMessage.setQueryParameter("table_name", attachRec.table_name);
            attachMessage.setQueryParameter("file_name", attachRec.file_name);
            attachMessage.setQueryParameter('table_sys_id', attachRec.table_sys_id);
            attachMessage.setQueryParameter('u_correlation_id', attachRec.u_correlation_id);
            attachMessage.setRequestHeader("Content-Type", attachRec.content_type);
            attachMessage.setRequestHeader("Accept", "application/json");
            attachMessage.setRequestBodyFromAttachment(attachRec.sys_id);

            var response = attachMessage.execute();

            var responseBody = response.getBody();
            gs.info('Response Body: ' + responseBody);
            var httpStatus = response.getStatusCode();

            if (httpStatus.toString() == "201"){
                answer[0] += 1;
            }else{
                answer[1] += 1;
            }
        }
    } else {
        answer = "none";
    }
    gs.info("Number of attachments sent over to target instance: " + answer[0] + " number of attachments not sent over: " + answer[1]);

}

  

6 REPLIES 6

Rajesh Chopade1
Mega Sage

Hi @TomWright_Dos 

Could you try once by sending the 'u_correlation_id' in attachment metadata instead of query parameter:

function sendAttachment(sourceTable, targetInstanceURL) {
    var answer = [0, 0];
    var attachRec = new GlideRecord('sys_attachment');
    attachRec.setLimit(10); // Remove this or set higher if you need to process more than 10 attachments
    attachRec.addQuery('table_name', sourceTable);
    attachRec.query();
    if (attachRec.hasNext()) {
        while (attachRec.next()) {
            var attachMessage = new sn_ws.RESTMessageV2();
            attachMessage.setLogLevel('all');
            attachMessage.setHttpMethod("post");
            attachMessage.setEndpoint(targetInstanceURL + "/api/now/attachment/file");

            // Set request body to include metadata and attachment
            var body = {
                table_name: attachRec.table_name.toString(),
                file_name: attachRec.file_name.toString(),
                table_sys_id: attachRec.table_sys_id.toString(),
                u_correlation_id: attachRec.u_correlation_id.toString()
            };

            // Attach the request body and file as part of the POST request
            attachMessage.setRequestHeader("Content-Type", attachRec.content_type);
            attachMessage.setRequestHeader("Accept", "application/json");
            attachMessage.setRequestBodyFromAttachment(attachRec.sys_id);

            // Add the attachment metadata into the body as parameters
            attachMessage.setStringParameterNoEscape("table_name", attachRec.table_name.toString());
            attachMessage.setStringParameterNoEscape("table_sys_id", attachRec.table_sys_id.toString());
            attachMessage.setStringParameterNoEscape("u_correlation_id", attachRec.u_correlation_id.toString());

            // Execute the REST message
            var response = attachMessage.execute();
            var responseBody = response.getBody();
            gs.info('Response Body: ' + responseBody);

            var httpStatus = response.getStatusCode();
            if (httpStatus.toString() == "201") {
                answer[0] += 1;
            } else {
                answer[1] += 1;
            }
        }
    } else {
        answer = "none";
    }
    gs.info("Number of attachments sent to the target instance: " + answer[0] + ", failed attachments: " + answer[1]);
}

i hope my answer helps you to resolve your issue, if yes please mark my answer helpful and correct.

thank you

rajesh

Thanks for the reply.  I see that you created a body JSON object, but I do not see where you are using it.  

Hi @TomWright_Dos 

Thanks for highlighting, let me fix.

when uploading an attachment via the REST API, you typically need to handle metadata separately because the attachment itself is treated as a file upload. The additional fields you want to populate (like u_correlation_id) should generally be handled in a separate API call after the attachment has been created.

 

function sendAttachment(sourceTable, targetInstanceURL) {
    var answer = [0, 0];
    var attachRec = new GlideRecord('sys_attachment');
    attachRec.setLimit(10); // Adjust the limit as needed
    attachRec.addQuery('table_name', sourceTable);
    attachRec.query();

    if (attachRec.hasNext()) {
        while (attachRec.next()) {
            var attachMessage = new sn_ws.RESTMessageV2();
            attachMessage.setLogLevel('all');
            attachMessage.setHttpMethod("post");
            attachMessage.setEndpoint(targetInstanceURL + "/api/now/attachment/file");

            // Attach the file using the sys_id of the attachment
            attachMessage.setRequestBodyFromAttachment(attachRec.sys_id);
            attachMessage.setRequestHeader("Content-Type", attachRec.content_type);
            attachMessage.setRequestHeader("Accept", "application/json");

            // Execute the REST message to upload the attachment
            var response = attachMessage.execute();
            var responseBody = response.getBody();
            var httpStatus = response.getStatusCode();
            gs.info('Response Body: ' + responseBody);

            if (httpStatus.toString() == "201") {
                answer[0] += 1; // Successful attachment
                var responseJSON = JSON.parse(responseBody);
                var newAttachmentSysId = responseJSON.result.sys_id; // Capture the new attachment's Sys ID
                
                // Now update the u_correlation_id
                var updateMessage = new sn_ws.RESTMessageV2();
                updateMessage.setHttpMethod("patch"); // Use PATCH to update the record
                updateMessage.setEndpoint(targetInstanceURL + "/api/now/table/sys_attachment/" + newAttachmentSysId);
                updateMessage.setRequestHeader("Content-Type", "application/json");

                // Construct the body for the update
                var updateBody = {
                    u_correlation_id: attachRec.u_correlation_id ? attachRec.u_correlation_id.toString() : ''
                };

                updateMessage.setRequestBody(JSON.stringify(updateBody)); // Set the request body
                var updateResponse = updateMessage.execute();
                var updateResponseBody = updateResponse.getBody();
                gs.info('Update Response Body: ' + updateResponseBody);

                var updateHttpStatus = updateResponse.getStatusCode();
                if (updateHttpStatus.toString() !== "204") {
                    answer[1] += 1; // Failed to update the correlation ID
                }
            } else {
                answer[1] += 1; // Failed to upload attachment
            }
        }
    } else {
        answer = "none";
    }
    gs.info("Number of attachments sent to the target instance: " + answer[0] + ", failed attachments: " + answer[1]);
}

 

Got it.  Thanks for the help.  So it's getting the attachment over and the update to the record is coming back with a http status code of 200, but nothing is set on the record and I'm wondering if it's a timing issue.  So I may add a pause in the code and see if that helps.