3

With the new year I am trying to create a fresh start by cleaning up old folders and files from our MID. It's quite a tedious job to move folders and files manually within automation studio. I am trying to follow a programmatic approach and found the following resource: https://ampscript.xyz/how-tos/how-to-use-wsproxy-to-work-with-automations-in-server-side-javascript/

While testing with this resource I managed to create and delete automations. I have tried to write an update script to move an automation from one folder to another.

<script runat=server>
    Platform.Load("Core","1");

    var api = new Script.Util.WSProxy();

    try {

        api.setClientId({
            "ID": Platform.Function.AuthenticatedMemberID(),
            "UserID": Platform.Function.AuthenticatedEmployeeID()
        });

        var options = {
            SaveOptions: [
                {
                    PropertyName: '*',
                    SaveAction: 'UpdateAdd'
                }
            ]
        };

        var config = {
            Name: "My Automation",
            CustomerKey: "xxx-xxx-xxx",
            Description: "Updated through script activity",
            CategoryID: 000000 (integer, number of the destination folder)
        };

        var result = api.updateItem("Automation", config, options);

        Write(Stringify(result));

    } catch(err) {
        Write(Stringify(err));
    }
</script>

The update operation returns succesful, but the CategoryID in the response is null. The update on the description happens, but the automation doesn't change folders. Is this even possible at all? And if so, is it also possible to do the same thing with entire categories?

1 Answer 1

2

Despite the docs saying it is possible and the describe request stating it is editable, I have not found a way to do this via SOAP API (Which is what WSProxy is currently running). I have tried both the 'Automation' SOAP Object as well as the undocumented old 'Program' SOAP Object with no luck. The only one I have found any success with is an undocumented REST API route. Perhaps if the rumors are true and there is a REST WSProxy coming out, this can be transitioned to WSProxy then.

See below:

PATCH /automation/v1/automations/{{autoID}}
Host: {{et_subdomain}}.rest.marketingcloudapis.com
Authorization: Bearer {{dne_etAccessToken}}
Content-Type: application/json

{
    "categoryId": {{categoryID}}
}

In order to use this, you will need both the Object ID of the automation as well as the Category ID of the target folder.

The Automation Object ID would be inserted on the endpoint at the end to target the automation.

The Category ID would be added into the JSON payload to change it to the new folder.

As a note, you only need to include the parts you want changed inside the JSON of the call as the Automation is selected via the endpoint.

To translate this into SSJS to match what you are attempting to do via WSProxy would require you to do 2 API calls - an API call to get a token and then a second for the PATCH API call. (NOTE this will require you to have REST API credentials and scope to change this)

Something like below should work:

<script runat=server>
Platform.Load("Core","1.1.1");

var clientId = '{{myClientId}}';
var clientSecret = '{{myClientSecret';
var subDomain = '{{mySubDomain}}';
var authURL = 'https://' + subDomain + '.auth.marketingcloudapis.com/'
var restBase = 'https://' + subDomain + '.rest.marketingcloudapis.com/'
var version = 2;

var autoID = "{{myAutoID}}";
var catID = {{myCategoryID}};

var token = 'Bearer ' + generateToken(clientId, clientSecret, mid, authURL, version);

var res = patchAuto(restBase,autoID,catID);

function patchAuto(restBase,autoID,catID) {

  var url = restBase + 'automation/v1/automations/' + autoID;
  var req = new Script.Util.HttpRequest(url);
  var payload = {"categoryid": catID}
  req.emptyContentHandling = 0;
  req.retries = 2;
  req.continueOnError = true;
  req.contentType = "application/json";
  req.setHeader("Authorization", token);
  req.method = 'PATCH';
  req.postData = Platform.Function.Stringify(payload);

  var resp = req.send();

  var resultStr = String(resp.content);
  var resultJSON = Platform.Function.ParseJSON(String(resp.content));

  return resultJSON;
}

function generateToken(clientId, clientSecret, mid, authURL, version) {
  
  if (version == 2) {
    var versionEndpoint = '/v2/token'

    var authJSON = {
  "grant_type": "client_credentials",
  "client_id": clientId,
  "client_secret": clientSecret,
  "account_id": mid
  }
  } else {
    var versionEndpoint = '/v1/requestToken'
 
 //URL changes for V1 endpoints
 
      var authJSON = {
    "clientId": clientId,
    "clientSecret": clientSecret
  }
  }

  var authUrl = authURL + versionEndpoint;
  var contentType = 'application/json';
  var authPayload = Platform.Function.Stringify(authJSON);

  var accessTokenResult = HTTP.Post(authUrl, contentType, authPayload);

  var statusCode = accessTokenResult["StatusCode"];
  var response = accessTokenResult["Response"][0];

  if(version == 2) {
      var accessToken = Platform.Function.ParseJSON(response).access_token;
  } else {
      var accessToken = Platform.Function.ParseJSON(response).accessToken;
  }

  return accessToken;
}

</script>
1
  • 1
    Thank you for the thorough response Gortonington! I'll try to fiddle around with the REST Api to see if I can produce something useful :)
    – PatrickSF
    Jan 12, 2021 at 15:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.