Attachment variable on flow

SnowDevOps
Giga Guru

Hello team

I have a catalog item related to inventory management. The catalog item includes an attachment variable where users are required to upload a picture of the PC.

The catalog item creates a record in a custom table that contains an Image column for storing the device image. My requirement is to create a record in the custom table and include the uploaded device image.

In Flow Designer, I selected the Image column on the custom table. However, when I click the data pill picker, I do not see many available options to map the attachment to the Image field.

I'm not sure if I am implementing this correctly. Could you please advise on the proper approach for populating the Image field with the uploaded attachment from the catalog item? Thanks for your help 

 

I'm trying to dot walk into add_image variable, i don't know what to pick

SnowDevOps_0-1790712434251.png

 

5 REPLIES 5

Mayuraaa
Mega Guru

Hi, have you tried with add image sysid?

I have never done that before. This is my first time to deal with the image attachment 

SaurabhT7455244
Tera Contributor

Don’t dot-walk into add_image looking for something like File name, Hash, Created, etc. Those are just fields from the underlying sys_attachment record.

Your add_image attachment variable effectively gives you the sys_id of a sys_attachment record. ServiceNow attachment variables store their uploaded file in sys_attachment.

For an Image field, I would not map the attachment pill directly in the Create Record step. An Image field has special attachment storage semantics: the image is represented by an attachment associated with the target record, normally with table_name = ZZ_YY<target_table> and the image field name as the attachment file_name. 

Use this pattern:

  1. Create Record on your custom table first.
  2. Leave the Image field blank.
  3. Add a custom Action / Script step after Create Record.
  4. Pass:
    • add_image → attachment sys_id
    • Created Record → target record/sys_id
  5. Copy the attachment content to the target Image field.

For example, if your table is:

u_inventory

and Image field is:

u_device_image

use a server-side script like:

(function execute(inputs, outputs) {

    var sourceAttachmentId = inputs.attachment_sys_id;
    var targetSysId = inputs.target_sys_id;

    var sourceAtt = new GlideRecord('sys_attachment');
    if (!sourceAtt.get(sourceAttachmentId))
        return;

    // Validate that it is actually an image
    if (!sourceAtt.getValue('content_type').startsWith('image/'))
        return;

    var target = new GlideRecord('u_inventory');
    if (!target.get(targetSysId))
        return;

    var gsa = new GlideSysAttachment();

    // Copy the actual binary content
    var newAttachmentId = gsa.writeContentStream(
        target,
        'u_device_image',
        sourceAtt.getValue('content_type'),
        gsa.getContentStream(sourceAttachmentId)
    );

    // Convert the normal attachment into an Image-field attachment
    var newAtt = new GlideRecord('sys_attachment');
    if (newAtt.get(newAttachmentId)) {
        newAtt.setValue('table_name', 'ZZ_YYu_inventory');
        newAtt.setValue('table_sys_id', targetSysId);
        newAtt.setValue('file_name', 'u_device_image');
        newAtt.update();

        target.setValue('u_device_image', newAttachmentId);
        target.update();
    }

})(inputs, outputs);

GlideSysAttachment.getContentStream() and writeContentStream() are documented ServiceNow APIs specifically for copying attachment binary content without converting it into a string. 

So in your screenshot, do not select File name, Description, Hash, etc. If you need an input for your Script Action, use the attachment variable itself:

Get Catalog Variables
    → add_image

That represents the source attachment. If Flow Designer exposes:

add_image
    → Sys ID

you can use Sys ID explicitly. The value you ultimately need is:

sys_attachment.sys_id

Your flow should therefore look like:

Get Catalog Variables
        |
        | add_image
        v
Create Record
u_inventory
Image = EMPTY
        |
        v
Custom Action: Set Image
   attachment_sys_id = add_image
   target_sys_id      = Create Record → Record → Sys ID
        |
        v
u_inventory.u_device_image

The important distinction is: an Attachment variable and an Image field are not interchangeable Flow Designer data types, even though both ultimately use sys_attachment. That is why the pill picker is showing attachment metadata rather than giving you a clean Image-field mapping. 

This is how my flow looks like. I left the image field blank, then i created the custom actions for the modify and add new device. I tested the catalog item. It didn't add the image to the table or modify it. I'm not sure where it went wrong. 

 

Trigger: Service Catalog

Action:
1. Get Catalog Variables
2 If the request is modify the device
1. Modify name
OS
Model:
Type:
Image = Blank

SnowDevOps_1-1791230399693.png

 

Custom Action: action to set image

3. If the request is add new device
1. Add name
OS
Model:
Type:
Image = Blank
Custom Action: Add action to set image

SnowDevOps_0-1791230385319.png

This is my custom action looks like 

SnowDevOps_2-1791230761322.png

(function execute(inputs, outputs) {
var sourceAttachmentId = inputs.attachment_sys_id;
    var targetSysId = inputs.target_sys_id;
    
    //gs.info('Attachment ID: ' + sourceAttachmentId);
    //gs.info('Target Sys ID: ' + targetSysId);
    
    var sourceAtt = new GlideRecord('sys_attachment');
    if (!sourceAtt.get(sourceAttachmentId))
        return;

    // Validate that it is actually an image
    if (!sourceAtt.getValue('content_type').startsWith('image/'))
        return;

    var target = new GlideRecord('u_am_device');
    if (!target.get(targetSysId))
        return;

    var gsa = new GlideSysAttachment();

    // Copy the actual binary content
    var newAttachmentId = gsa.writeContentStream(
        target,
        'image',
        sourceAtt.getValue('content_type'),
        gsa.getContentStream(sourceAttachmentId)
    );

    // Convert the normal attachment into an Image-field attachment
    var newAtt = new GlideRecord('sys_attachment');
    if (newAtt.get(newAttachmentId)) {
        newAtt.setValue('table_name', 'u_am_device');
        newAtt.setValue('table_sys_id', targetSysId);
        newAtt.setValue('file_name', 'image');
        newAtt.update();

        target.setValue('image', newAttachmentId);
        target.update();
    }
})(inputs, outputs);