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.