Repository: Accenture/sfmc-devtools
Pull request #961 (2023-06-05 09:57:36)

5.1.0 release
- [ ] wiki updated?

## Wiki changes


- PR #919 

https://github.com/Accenture/sfmc-devtools/wiki/06.b-~-Standard-Commands/_edit

### execute
_Command:_ `mcdev execute <business unit> <type> <external key>`

_Alias:_ `mcdev exec`

This command lets you start / run / execute metadata of a given type and key. Currently, this is only supported for queries.

**Currently supported types:**

| Name | CLI Argument | Effect |
| :-- | :-- | :-- |
| Query | query | Starts query execution |


_Example:_

```
mcdev execute  MyProject/DEV query key1
mcdev execute  MyProject/DEV query "key1,key2,key3"
```

#### execute on all BUs

This is a variation of execute command that allows you to execute specified items on all BUs. mcdev will look for the items of specified types and keys on all BUs and execute them. 

_Example:_

```
mcdev execute  MyProject/* query key1
mcdev execute  MyProject/* query "key1,key2,key3"
```





- PR #904

https://github.com/Accenture/sfmc-devtools/wiki/08.-Metadata-specific-settings-%26-options/_edit

## Automation (`automation`)

**Relevant code to add / update notifications in your automation's JSON:**
```json
    "notifications": [
        {
            "type": "Complete",
            "email": "automation-completed@demo.accenture.com",
            "message": "optional COMPLETION note that will be included in the email notification"
        },
        {
            "type": "Error",
            "email": ["automation-errors@demo.accenture.com","qa-team@demo.accenture.com"]
            "message": "optional ERROR note that will be included in the email notification"
        }
    ],
```

**Only setting a notification for one type / removing notifications:**
```json
    "notifications": [
        {
            "type": "Error",
            "email": ["automation-errors@demo.accenture.com"]
            "message": "optional ERROR note that will be included in the email notification"
        }
    ],
```

**Only setting a notification for one type / removing notifications without a custom message:**
```json
    "notifications": [
        {
            "type": "Error",
            "email": ["automation-errors@demo.accenture.com"]
            "message": ""
        }
    ],
```

To delete notifications, simply remove them from `notifications` or remove the `notifications` attribute all together. The above example would effectively remove existing notifications for type `Complete` and add/update the notification for `Error`.

**Full example for adding notifications for Complete and Error:**
```json
{
    "name": "Automation_with_notification",
    "description": "",
    "key": "Automation_with_notification",
    "type": "scheduled",
    "status": "PausedSchedule",
    "schedule": {
        "typeId": 3,
        "startDate": "2023-05-31T00:00:00",
        "endDate": "2023-05-31T00:00:00",
        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
        "timezoneName": "W. Europe Standard Time"
    },
    "steps": [
        {
            "name": "",
            "activities": [
                {
                    "name": "myWonderfulscript",
                    "r__type": "script"
                }
            ]
        }
    ],
    "notifications": [
        {
            "type": "Complete",
            "email": "automation-completed@demo.accenture.com",
            "message": "optional COMPLETION note that will be included in the email notification"
        },
        {
            "type": "Error",
            "email": ["automation-errors@demo.accenture.com","qa-team@demo.accenture.com"]
            "message": "optional ERROR note that will be included in the email notification"
        }
    ],
    "r__folder_Path": "my automations"
}
```

- PR #971

https://github.com/Accenture/sfmc-devtools/wiki/07.-Advanced-Configuration/_edit

### --api=[log|api]

Optionally, you can see API requests & responses in the logfile or directly in CLI.

Examples:
```batch
mcdev retrieve --api=log
mcdev deploy --api=cli
```

### --noLogFile

Optionally, you can disable creating the 2 logfiles when running mcdev.

Examples:
```batch
mcdev retrieve --noLogFile
mcdev deploy --noLogFile
```


Patch:
diff --git a/.coverage-comment-template.md b/.coverage-comment-template.md
deleted file mode 100644
index 4aceff38..00000000
--- a/.coverage-comment-template.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Coverage Report
-
-Commit: [{{short_commit_sha}}]({{commit_link}})
-Base: [{{base_ref}}@{{base_short_commit_sha}}]({{base_commit_link}})
-
-| Type                      | Base                                       | This PR                                                                            |
-| ------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------- |
-| Total Statements Coverage | {{base_total_statements_coverage_percent}} | {{total_statements_coverage_percent}} ({{total_statements_coverage_percent_diff}}) |
-| Total Branches Coverage   | {{base_total_branches_coverage_percent}}   | {{total_branches_coverage_percent}} ({{total_branches_coverage_percent_diff}})     |
-| Total Functions Coverage  | {{base_total_functions_coverage_percent}}  | {{total_functions_coverage_percent}} ({{total_functions_coverage_percent_diff}})   |
-| Total Lines Coverage      | {{base_total_lines_coverage_percent}}      | {{total_lines_coverage_percent}} ({{total_lines_coverage_percent_diff}})           |
-
-<details>
-<summary>Details (changed files)</summary>
-{{changed_files_coverage_table}}
-</details>
-<details>
-<summary>Details (all files)</summary>
-{{files_coverage_table}}
-</details>
diff --git a/.coverage-comment-template.svelte b/.coverage-comment-template.svelte
index 8455cd02..ae2267b2 100644
--- a/.coverage-comment-template.svelte
+++ b/.coverage-comment-template.svelte
@@ -1,178 +1,194 @@
 <script>
-  export let total_statements_coverage_percent_raw;
-  export let total_branches_coverage_percent_raw;
-  export let total_functions_coverage_percent_raw;
-  export let total_lines_coverage_percent_raw;
-
-  export let base_total_statements_coverage_percent_raw;
-  export let base_total_branches_coverage_percent_raw;
-  export let base_total_functions_coverage_percent_raw;
-  export let base_total_lines_coverage_percent_raw;
-
-  export let commit_sha;
-  export let short_commit_sha;
-  export let commit_link;
-
-  export let base_commit_sha;
-  export let base_short_commit_sha;
-  export let base_commit_link;
-  export let base_ref;
-
-  export let changed_files_coverage_data;
-
-  const has_base_data = base_total_branches_coverage_percent_raw !== '?';
-  const summary_list = [
-    {
-      type: 'Total Statements Coverage',
-      percent: {
-        total: total_statements_coverage_percent_raw,
-        base: has_base_data ? base_total_statements_coverage_percent_raw: null,
-        diff: has_base_data ? (total_statements_coverage_percent_raw - base_total_statements_coverage_percent_raw) : null,
-      }
-    },
-    {
-      type: 'Total Branches Coverage',
-      percent: {
-        total: total_branches_coverage_percent_raw,
-        base: has_base_data ? base_total_branches_coverage_percent_raw: null,
-        diff: has_base_data ? (total_branches_coverage_percent_raw - base_total_branches_coverage_percent_raw) : null,
-      }
-    },
-    {
-      type: 'Total Functions Coverage',
-      percent: {
-        total: total_functions_coverage_percent_raw,
-        base: has_base_data ? base_total_functions_coverage_percent_raw: null,
-        diff: has_base_data ? (total_functions_coverage_percent_raw - base_total_functions_coverage_percent_raw) : null,
-      }
-    },
-    {
-      type: 'Total Lines Coverage',
-      percent: {
-        total: total_lines_coverage_percent_raw,
-        base: has_base_data ? base_total_lines_coverage_percent_raw: null,
-        diff: has_base_data ? (total_lines_coverage_percent_raw - base_total_lines_coverage_percent_raw) : null,
-      }
-    }];
-
-  const LETTER_LABEL = {
-    S: 'Statements',
-    B: 'Branches',
-    F: 'Functions',
-    L: 'Lines',
-  };
-
-  const COVERAGE_LEVEL_IMAGE = {
-    low: 'https://user-images.githubusercontent.com/11299391/159445221-fe3dc085-8c56-4e03-9642-219784c88fe7.svg',
-    medium:
-      'https://user-images.githubusercontent.com/11299391/159445212-f135c6d7-f354-4e8c-9a9f-28bb3ff1b7b5.svg',
-    high: 'https://user-images.githubusercontent.com/11299391/159445220-d88b3624-0814-4664-80c8-09f0f2b8e68b.svg',
-  };
-
-  function formatPercentDiff(percent) {
-    if (!Number.isFinite(percent)) {
-      return '';
+    export let total_statements_coverage_percent_raw;
+    export let total_branches_coverage_percent_raw;
+    export let total_functions_coverage_percent_raw;
+    export let total_lines_coverage_percent_raw;
+
+    export let base_total_statements_coverage_percent_raw;
+    export let base_total_branches_coverage_percent_raw;
+    export let base_total_functions_coverage_percent_raw;
+    export let base_total_lines_coverage_percent_raw;
+
+    export let commit_sha;
+    export let short_commit_sha;
+    export let commit_link;
+
+    export let base_commit_sha;
+    export let base_short_commit_sha;
+    export let base_commit_link;
+    export let base_ref;
+
+    export let changed_files_coverage_data;
+
+    const has_base_data = base_total_branches_coverage_percent_raw !== '?';
+    const summary_list = [
+        {
+            type: 'Total Statements Coverage',
+            percent: {
+                total: total_statements_coverage_percent_raw,
+                base: has_base_data ? base_total_statements_coverage_percent_raw : null,
+                diff: has_base_data
+                    ? total_statements_coverage_percent_raw -
+                      base_total_statements_coverage_percent_raw
+                    : null,
+            },
+        },
+        {
+            type: 'Total Branches Coverage',
+            percent: {
+                total: total_branches_coverage_percent_raw,
+                base: has_base_data ? base_total_branches_coverage_percent_raw : null,
+                diff: has_base_data
+                    ? total_branches_coverage_percent_raw - base_total_branches_coverage_percent_raw
+                    : null,
+            },
+        },
+        {
+            type: 'Total Functions Coverage',
+            percent: {
+                total: total_functions_coverage_percent_raw,
+                base: has_base_data ? base_total_functions_coverage_percent_raw : null,
+                diff: has_base_data
+                    ? total_functions_coverage_percent_raw -
+                      base_total_functions_coverage_percent_raw
+                    : null,
+            },
+        },
+        {
+            type: 'Total Lines Coverage',
+            percent: {
+                total: total_lines_coverage_percent_raw,
+                base: has_base_data ? base_total_lines_coverage_percent_raw : null,
+                diff: has_base_data
+                    ? total_lines_coverage_percent_raw - base_total_lines_coverage_percent_raw
+                    : null,
+            },
+        },
+    ];
+
+    const LETTER_LABEL = {
+        S: 'Statements',
+        B: 'Branches',
+        F: 'Functions',
+        L: 'Lines',
+    };
+
+    const COVERAGE_LEVEL_IMAGE = {
+        low: 'https://user-images.githubusercontent.com/11299391/159445221-fe3dc085-8c56-4e03-9642-219784c88fe7.svg',
+        medium: 'https://user-images.githubusercontent.com/11299391/159445212-f135c6d7-f354-4e8c-9a9f-28bb3ff1b7b5.svg',
+        high: 'https://user-images.githubusercontent.com/11299391/159445220-d88b3624-0814-4664-80c8-09f0f2b8e68b.svg',
+    };
+
+    function formatPercentDiff(percent) {
+        if (!Number.isFinite(percent)) {
+            return '';
+        }
+
+        const roundedPercent = `${Number(percent.toFixed(2))}%`;
+
+        if (percent >= 0) {
+            return '+' + roundedPercent;
+        }
+
+        return roundedPercent;
     }
 
-    const roundedPercent = `${Number(percent.toFixed(2))}%`;
-
-    if (percent >= 0) {
-      return '+' + roundedPercent;
+    function getCoverageLevelImage(percent) {
+        // https://github.com/istanbuljs/istanbuljs/blob/c1559005b3bb318da01f505740adb0e782aaf14e/packages/istanbul-lib-report/lib/watermarks.js
+        if (percent >= 80) {
+            return COVERAGE_LEVEL_IMAGE.high;
+        } else if (percent >= 50) {
+            return COVERAGE_LEVEL_IMAGE.medium;
+        } else {
+            return COVERAGE_LEVEL_IMAGE.low;
+        }
     }
 
-    return roundedPercent;
-  }
-
-  function getCoverageLevelImage(percent) {
-    // https://github.com/istanbuljs/istanbuljs/blob/c1559005b3bb318da01f505740adb0e782aaf14e/packages/istanbul-lib-report/lib/watermarks.js
-    if (percent >= 80) {
-      return COVERAGE_LEVEL_IMAGE.high;
-    } else if (percent >= 50) {
-      return COVERAGE_LEVEL_IMAGE.medium;
-    } else {
-      return COVERAGE_LEVEL_IMAGE.low;
+    function getFilePrefix() {
+        return `../blob/${commit_sha}/`;
     }
-  }
-
-  function getFilePrefix() {
-    return `../blob/${commit_sha}/`;
-  }
 </script>
 
 <h2>Coverage Report</h2>
 
-Commit: <a href="{commit_link}">{short_commit_sha}</a><br>
-Base: <a href="{base_commit_link}">{base_ref}@{base_short_commit_sha}</a><br><br>
+Commit:<a href={commit_link}>{short_commit_sha}</a><br />
+Base: <a href={base_commit_link}>{base_ref}@{base_short_commit_sha}</a><br /><br />
 
 <table>
-  <thead>
-    <th>Type</th>
-      {#if has_base_data}
-        <th>Base</th>
-      {/if}
-    <th>This PR</th>
-  </thead>
-  <tbody>
-    {#each summary_list as {type, percent}}
-      <tr>
-        <td>{type}</td>
+    <thead>
+        <th>Type</th>
         {#if has_base_data}
-          <td>
-            {#if Number.isFinite(percent.base)}
-              <img src="{getCoverageLevelImage(percent.base)}" alt="">&nbsp;{percent.base}%
-            {:else}
-              -
-            {/if}
-          </td>
+            <th>Base</th>
         {/if}
-        <td>
-          {#if Number.isFinite(percent.total)}
-            <img src="{getCoverageLevelImage(percent.total)}" alt="">&nbsp;{percent.total}%
-            {#if has_base_data}
-              &nbsp;({formatPercentDiff(percent.diff)})
-            {/if}
-          {:else}
-            -
-          {/if}
-        </td>
-      </tr>
-    {/each}
-  </tbody>
-</table>
-
-<details>
-  <summary>Details (changed testable files):</summary><br>
-  <table>
-    <thead>
-      <th>File</th>
-      <th>Statements</th>
-      <th>Branches</th>
-      <th>Functions</th>
-      <th>Lines</th>
+        <th>This PR</th>
     </thead>
     <tbody>
-      {#each changed_files_coverage_data as [file, data]}
-        {@const percents = [
-          data.statements.pct,
-          data.branches.pct,
-          data.functions.pct,
-          data.lines.pct
-        ]}
-        <tr>
-          <td>
-            <a href="{getFilePrefix()}{file}">{file}</a>
-          </td>
-          {#each percents as percent}
-            <td>
-              {#if Number.isFinite(percent)}
-                <img src="{getCoverageLevelImage(percent)}" alt="">&nbsp;{percent}%
-              {:else}
-                -
-              {/if}
-            </td>
-          {/each}
-        </tr>
-      {/each}
+        {#each summary_list as { type, percent }}
+            <tr>
+                <td>{type}</td>
+                {#if has_base_data}
+                    <td>
+                        {#if Number.isFinite(percent.base)}
+                            <img
+                                src={getCoverageLevelImage(percent.base)}
+                                alt=""
+                            />&nbsp;{percent.base}%
+                        {:else}
+                            -
+                        {/if}
+                    </td>
+                {/if}
+                <td>
+                    {#if Number.isFinite(percent.total)}
+                        <img
+                            src={getCoverageLevelImage(percent.total)}
+                            alt=""
+                        />&nbsp;{percent.total}%
+                        {#if has_base_data}
+                            &nbsp;({formatPercentDiff(percent.diff)})
+                        {/if}
+                    {:else}
+                        -
+                    {/if}
+                </td>
+            </tr>
+        {/each}
     </tbody>
-  </table>
-</details>
\ No newline at end of file
+</table>
+
+<details>
+    <summary>Details (changed files):</summary><br />
+    <table>
+        <thead>
+            <th>File</th>
+            <th>Statements</th>
+            <th>Branches</th>
+            <th>Functions</th>
+            <th>Lines</th>
+        </thead>
+        <tbody>
+            {#each changed_files_coverage_data as [file, data]}
+                {@const percents = [
+                    data.statements.pct,
+                    data.branches.pct,
+                    data.functions.pct,
+                    data.lines.pct,
+                ]}
+                <tr>
+                    <td>
+                        <a href="{getFilePrefix()}{file}">{file}</a>
+                    </td>
+                    {#each percents as percent}
+                        <td>
+                            {#if Number.isFinite(percent)}
+                                <img src={getCoverageLevelImage(percent)} alt="" />&nbsp;{percent}%
+                            {:else}
+                                -
+                            {/if}
+                        </td>
+                    {/each}
+                </tr>
+            {/each}
+        </tbody>
+    </table>
+</details>
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index bca92801..c133ed59 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -39,6 +39,7 @@ body:
           label: Version
           description: What version of our software are you running? (mcdev --version)
           options:
+              - 5.1.0
               - 5.0.2
               - 5.0.1
               - 5.0.0
diff --git a/.github/workflows/coverage-base-update.yml b/.github/workflows/coverage-base-update.yml
index 87dd0f1b..a84e002d 100644
--- a/.github/workflows/coverage-base-update.yml
+++ b/.github/workflows/coverage-base-update.yml
@@ -1,8 +1,12 @@
-name: Update coverage comment
+name: Update coverage comment # base-update.yml
 on:
     pull_request:
         types: [edited]
 
+permissions:
+    # allow dependabot to execute this workflow
+    pull-requests: write
+
 jobs:
     hello_world_job:
         runs-on: ubuntu-latest
@@ -48,7 +52,7 @@ jobs:
                   files: 'base-artifacts/coverage-summary.json, artifacts/coverage-summary.json'
 
             - name: Update Coverage comment
-              uses: sidx1024/report-nyc-coverage-github-action@v1.2.6
+              uses: sidx1024/report-nyc-coverage-github-action@v1.2.7
               if: steps.check_files.outputs.files_exists == 'true'
               # Only runs if all of the files exists
               with:
diff --git a/.github/workflows/coverage-develop-branch.yml b/.github/workflows/coverage-develop-branch.yml
index 9ace0197..d14c5fbe 100644
--- a/.github/workflows/coverage-develop-branch.yml
+++ b/.github/workflows/coverage-develop-branch.yml
@@ -1,24 +1,25 @@
-name: Test coverage for develop branch
+name: Test coverage for develop branch # default-branch.yml
 
 on:
     push:
         branches:
             - develop
 
+permissions:
+    # allow dependabot to execute this workflow
+    pull-requests: write
+
 jobs:
     hello_world_job:
         runs-on: ubuntu-latest
-        name: Test and report
+        name: Test and upload coverage
         steps:
             - name: Checkout
               uses: actions/checkout@v3
               with:
-                  ref: ${{ github.event.pull_request.head.sha }}
+                  ref: ${{ github.event.ref }}
                   fetch-depth: 1000
 
-            - name: Fetch base
-              run: git fetch origin ${{ github.event.pull_request.base.ref }} --depth=1000
-
             - uses: actions/setup-node@v3
               with:
                   node-version: 16
diff --git a/.github/workflows/coverage-main-branch.yml b/.github/workflows/coverage-main-branch.yml
index ce40479d..9aa2b1ff 100644
--- a/.github/workflows/coverage-main-branch.yml
+++ b/.github/workflows/coverage-main-branch.yml
@@ -1,24 +1,25 @@
-name: Test coverage for main branch
+name: Test coverage for main branch # default-branch.yml
 
 on:
     push:
         branches:
             - main
 
+permissions:
+    # allow dependabot to execute this workflow
+    pull-requests: write
+
 jobs:
     hello_world_job:
         runs-on: ubuntu-latest
-        name: Test and report
+        name: Test and upload coverage
         steps:
             - name: Checkout
               uses: actions/checkout@v3
               with:
-                  ref: ${{ github.event.pull_request.head.sha }}
+                  ref: ${{ github.event.ref }}
                   fetch-depth: 1000
 
-            - name: Fetch base
-              run: git fetch origin ${{ github.event.pull_request.base.ref }} --depth=1000
-
             - uses: actions/setup-node@v3
               with:
                   node-version: 16
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 9ea664a6..82d75fb3 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -1,6 +1,11 @@
 on: [pull_request]
 
-name: Test coverage report
+name: Test coverage report # main.yml
+
+permissions:
+    # allow dependabot to execute this workflow
+    pull-requests: write
+
 jobs:
     hello_world_job:
         runs-on: ubuntu-latest
@@ -69,7 +74,7 @@ jobs:
                   files: 'base-artifacts/coverage-summary.json'
 
             - name: Report coverage
-              uses: sidx1024/report-nyc-coverage-github-action@v1.2.6
+              uses: sidx1024/report-nyc-coverage-github-action@v1.2.7
               id: report
               with:
                   coverage_file: 'artifacts/test-coverage-output/coverage-summary.json'
diff --git a/.husky/post-checkout b/.husky/post-checkout
index e2201380..2607e40f 100644
--- a/.husky/post-checkout
+++ b/.husky/post-checkout
@@ -10,7 +10,8 @@ then
 fi
 TEMPLATE="#$TICKETID: "
 echo "[POST_CHECKOUT] Setting template commit to '$TEMPLATE'"
-echo $TEMPLATE > ".git/templatemessage"
+# wrap $TEMPLATE in quotes or else it is trimmed automatically
+echo "$TEMPLATE" > ".git/templatemessage"
 
 
 # ### run npm install ###
@@ -21,7 +22,7 @@ IFS=$'\n'
 NEWHEAD=$1
 # $2 is the previous HEAD pointer
 OLDHEAD=$2
-# extract all paths to package-lock.json files 
+# extract all paths to package-lock.json files
 PACKAGE_LOCK_REGEX="(^package-lock\.json)"
 PACKAGES=$(git diff --name-only $NEWHEAD $OLDHEAD | grep -E $PACKAGE_LOCK_REGEX || true)
 
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index d9363cd3..8027e753 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -186,17 +186,17 @@ Provides default functionality that can be overwritten by child metadata type cl
 <dt><a href="#csvToArray">csvToArray(csv)</a> ⇒ <code>Array.&lt;string&gt;</code></dt>
 <dd><p>helper to convert CSVs into an array. if only one value was given, it&#39;s also returned as an array</p>
 </dd>
+<dt><a href="#Automation.">Automation.(metadataMap, key)</a> ⇒ <code>Promise.&lt;void&gt;</code></dt>
+<dd><p>helper for <a href="#Automation.postDeployTasks">postDeployTasks</a></p>
+</dd>
+<dt><a href="#Automation.">Automation.(metadataMap, originalMetadataMap, key)</a></dt>
+<dd><p>helper for <a href="postDeployTasks">postDeployTasks</a></p>
+</dd>
 <dt><a href="#getUserName">getUserName(userList, item, fieldname)</a> ⇒ <code>string</code></dt>
 <dd></dd>
 <dt><a href="#setupSDK">setupSDK(sessionKey, authObject)</a> ⇒ <code><a href="#SDK">SDK</a></code></dt>
 <dd><p>Returns an SDK instance to be used for API calls</p>
 </dd>
-<dt><a href="#createNewLoggerTransport">createNewLoggerTransport()</a> ⇒ <code>object</code></dt>
-<dd><p>wrapper around our standard winston logging to console and logfile</p>
-</dd>
-<dt><a href="#startLogger">startLogger()</a> ⇒ <code>void</code></dt>
-<dd><p>initiate winston logger</p>
-</dd>
 </dl>
 
 ## Typedefs
@@ -496,6 +496,8 @@ main class
     * [.buildDefinition(businessUnit, selectedType, name, market)](#Mcdev.buildDefinition) ⇒ <code>Promise.&lt;void&gt;</code>
     * [.buildDefinitionBulk(listName, type, name)](#Mcdev.buildDefinitionBulk) ⇒ <code>Promise.&lt;void&gt;</code>
     * [.getFilesToCommit(businessUnit, selectedType, keyArr)](#Mcdev.getFilesToCommit) ⇒ <code>Promise.&lt;Array.&lt;string&gt;&gt;</code>
+    * [.execute(businessUnit, [selectedTypesArr], keys)](#Mcdev.execute) ⇒ <code>Promise.&lt;boolean&gt;</code>
+    * [._executeBU(cred, bu, [selectedTypesArr], keyArr)](#Mcdev._executeBU) ⇒ <code>Promise.&lt;boolean&gt;</code>
 
 <a name="Mcdev.setSkipInteraction"></a>
 
@@ -748,6 +750,35 @@ Build a specific metadata file based on a template using a list of bu-market com
 | selectedType | <code>string</code> | supported metadata type |
 | keyArr | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |
 
+<a name="Mcdev.execute"></a>
+
+### Mcdev.execute(businessUnit, [selectedTypesArr], keys) ⇒ <code>Promise.&lt;boolean&gt;</code>
+Start an item (query)
+
+**Kind**: static method of [<code>Mcdev</code>](#Mcdev)  
+**Returns**: <code>Promise.&lt;boolean&gt;</code> - true if all started successfully, false if not  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| businessUnit | <code>string</code> | name of BU |
+| [selectedTypesArr] | <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code> | limit to given metadata types |
+| keys | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |
+
+<a name="Mcdev._executeBU"></a>
+
+### Mcdev.\_executeBU(cred, bu, [selectedTypesArr], keyArr) ⇒ <code>Promise.&lt;boolean&gt;</code>
+helper for [execute](execute)
+
+**Kind**: static method of [<code>Mcdev</code>](#Mcdev)  
+**Returns**: <code>Promise.&lt;boolean&gt;</code> - true if all items were executed, false otherwise  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| cred | <code>string</code> | name of Credential |
+| bu | <code>string</code> | name of BU |
+| [selectedTypesArr] | <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code> | limit execution to given metadata type |
+| keyArr | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |
+
 <a name="Asset"></a>
 
 ## Asset ⇐ [<code>MetadataType</code>](#MetadataType)
@@ -1206,7 +1237,7 @@ Automation MetadataType
     * [.retrieveChangelog()](#Automation.retrieveChangelog) ⇒ <code>Promise.&lt;TYPE.AutomationMapObj&gt;</code>
     * [.retrieveForCache()](#Automation.retrieveForCache) ⇒ <code>Promise.&lt;TYPE.AutomationMapObj&gt;</code>
     * [.retrieveAsTemplate(templateDir, name, templateVariables)](#Automation.retrieveAsTemplate) ⇒ <code>Promise.&lt;TYPE.AutomationItemObj&gt;</code>
-    * [.postRetrieveTasks(metadata)](#Automation.postRetrieveTasks) ⇒ <code>TYPE.AutomationItem</code>
+    * [.postRetrieveTasks(metadata)](#Automation.postRetrieveTasks) ⇒ <code>TYPE.AutomationItem</code> \| <code>void</code>
     * [.deploy(metadata, targetBU, retrieveDir, [isRefresh])](#Automation.deploy) ⇒ <code>Promise.&lt;TYPE.AutomationMap&gt;</code>
     * [.create(metadata)](#Automation.create) ⇒ <code>Promise</code>
     * [.update(metadata, metadataBefore)](#Automation.update) ⇒ <code>Promise</code>
@@ -1215,7 +1246,6 @@ Automation MetadataType
     * [.postDeployTasks(metadataMap, originalMetadataMap)](#Automation.postDeployTasks) ⇒ <code>Promise.&lt;void&gt;</code>
     * [.setFolderPath(metadata)](#Automation.setFolderPath)
     * [.setFolderId(metadata)](#Automation.setFolderId)
-    * [.parseMetadata(metadata)](#Automation.parseMetadata) ⇒ <code>TYPE.AutomationItem</code> \| <code>void</code>
     * [._buildSchedule(scheduleObject)](#Automation._buildSchedule) ⇒ <code>TYPE.AutomationScheduleSoap</code>
     * [._calcTime(offsetServer, dateInput, [offsetInput])](#Automation._calcTime) ⇒ <code>string</code>
     * [.document([metadata])](#Automation.document) ⇒ <code>Promise.&lt;void&gt;</code>
@@ -1268,11 +1298,11 @@ Retrieve a specific Automation Definition by Name
 
 <a name="Automation.postRetrieveTasks"></a>
 
-### Automation.postRetrieveTasks(metadata) ⇒ <code>TYPE.AutomationItem</code>
+### Automation.postRetrieveTasks(metadata) ⇒ <code>TYPE.AutomationItem</code> \| <code>void</code>
 manages post retrieve steps
 
 **Kind**: static method of [<code>Automation</code>](#Automation)  
-**Returns**: <code>TYPE.AutomationItem</code> - metadata  
+**Returns**: <code>TYPE.AutomationItem</code> \| <code>void</code> - parsed item  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -1378,18 +1408,6 @@ automation-specific script that retrieves the folder ID from cache and updates t
 | --- | --- | --- |
 | metadata | <code>TYPE.MetadataTypeItem</code> | a single item |
 
-<a name="Automation.parseMetadata"></a>
-
-### Automation.parseMetadata(metadata) ⇒ <code>TYPE.AutomationItem</code> \| <code>void</code>
-parses retrieved Metadata before saving
-
-**Kind**: static method of [<code>Automation</code>](#Automation)  
-**Returns**: <code>TYPE.AutomationItem</code> \| <code>void</code> - parsed item  
-
-| Param | Type | Description |
-| --- | --- | --- |
-| metadata | <code>TYPE.AutomationItem</code> | a single automation definition |
-
 <a name="Automation._buildSchedule"></a>
 
 ### Automation.\_buildSchedule(scheduleObject) ⇒ <code>TYPE.AutomationScheduleSoap</code>
@@ -3155,6 +3173,7 @@ Provides default functionality that can be overwritten by child metadata type cl
     * [.create(metadata, deployDir)](#MetadataType.create) ⇒ <code>void</code>
     * [.update(metadata, [metadataBefore])](#MetadataType.update) ⇒ <code>void</code>
     * [.refresh()](#MetadataType.refresh) ⇒ <code>void</code>
+    * [.execute()](#MetadataType.execute) ⇒ <code>void</code>
     * [.hasChanged(cachedVersion, metadata, [fieldName])](#MetadataType.hasChanged) ⇒ <code>boolean</code>
     * [.hasChangedGeneric(cachedVersion, metadata, [fieldName], [silent])](#MetadataType.hasChangedGeneric) ⇒ <code>boolean</code>
     * [.upsert(metadataMap, deployDir, [isRefresh])](#MetadataType.upsert) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMap&gt;</code>
@@ -3167,6 +3186,7 @@ Provides default functionality that can be overwritten by child metadata type cl
     * [.getSOAPErrorMsg(ex)](#MetadataType.getSOAPErrorMsg) ⇒ <code>string</code>
     * [.retrieveSOAP(retrieveDir, [requestParams], [singleRetrieve], [additionalFields])](#MetadataType.retrieveSOAP) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
     * [.retrieveREST(retrieveDir, uri, [templateVariables], [singleRetrieve])](#MetadataType.retrieveREST) ⇒ <code>Promise.&lt;{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}&gt;</code>
+    * [.executeREST(uri, key)](#MetadataType.executeREST) ⇒ <code>Promise.&lt;string&gt;</code>
     * [.runDocumentOnRetrieve([singleRetrieve], metadataMap)](#MetadataType.runDocumentOnRetrieve) ⇒ <code>Promise.&lt;void&gt;</code>
     * [.parseResponseBody(body, [singleRetrieve])](#MetadataType.parseResponseBody) ⇒ <code>TYPE.MetadataTypeMap</code>
     * [.deleteFieldByDefinition(metadataEntry, fieldPath, definitionProperty, origin)](#MetadataType.deleteFieldByDefinition) ⇒ <code>void</code>
@@ -3466,6 +3486,12 @@ Abstract update method that needs to be implemented in child metadata type
 ### MetadataType.refresh() ⇒ <code>void</code>
 Abstract refresh method that needs to be implemented in child metadata type
 
+**Kind**: static method of [<code>MetadataType</code>](#MetadataType)  
+<a name="MetadataType.execute"></a>
+
+### MetadataType.execute() ⇒ <code>void</code>
+Abstract execute method that needs to be implemented in child metadata type
+
 **Kind**: static method of [<code>MetadataType</code>](#MetadataType)  
 <a name="MetadataType.hasChanged"></a>
 
@@ -3633,6 +3659,19 @@ Retrieves Metadata for Rest Types
 | [templateVariables] | <code>TYPE.TemplateMap</code> | variables to be replaced in the metadata |
 | [singleRetrieve] | <code>string</code> \| <code>number</code> | key of single item to filter by |
 
+<a name="MetadataType.executeREST"></a>
+
+### MetadataType.executeREST(uri, key) ⇒ <code>Promise.&lt;string&gt;</code>
+Used to execute a query/automation etc.
+
+**Kind**: static method of [<code>MetadataType</code>](#MetadataType)  
+**Returns**: <code>Promise.&lt;string&gt;</code> - 'OK' if started execution successfully, otherwise - 'Error'  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| uri | <code>string</code> | REST endpoint where the POST request should be sent |
+| key | <code>string</code> | item key |
+
 <a name="MetadataType.runDocumentOnRetrieve"></a>
 
 ### MetadataType.runDocumentOnRetrieve([singleRetrieve], metadataMap) ⇒ <code>Promise.&lt;void&gt;</code>
@@ -4548,6 +4587,7 @@ Query MetadataType
 
 * [Query](#Query) ⇐ [<code>MetadataType</code>](#MetadataType)
     * [.retrieve(retrieveDir, [_], [__], [key])](#Query.retrieve) ⇒ <code>Promise.&lt;{metadata: TYPE.QueryMap, type: string}&gt;</code>
+    * [.execute(keyArr)](#Query.execute) ⇒ <code>Promise.&lt;boolean&gt;</code>
     * [.retrieveForCache()](#Query.retrieveForCache) ⇒ <code>Promise.&lt;{metadata: TYPE.QueryMap, type: string}&gt;</code>
     * [.retrieveAsTemplate(templateDir, name, templateVariables)](#Query.retrieveAsTemplate) ⇒ <code>Promise.&lt;{metadata: Query, type: string}&gt;</code>
     * [.postRetrieveTasks(metadata)](#Query.postRetrieveTasks) ⇒ <code>TYPE.CodeExtractItem</code>
@@ -4577,6 +4617,18 @@ Retrieves Metadata of queries
 | [__] | <code>void</code> | unused parameter |
 | [key] | <code>string</code> | customer key of single item to retrieve |
 
+<a name="Query.execute"></a>
+
+### Query.execute(keyArr) ⇒ <code>Promise.&lt;boolean&gt;</code>
+a function to start query execution via API
+
+**Kind**: static method of [<code>Query</code>](#Query)  
+**Returns**: <code>Promise.&lt;boolean&gt;</code> - Returns true if all items were executed successfully, otherwise false  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| keyArr | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |
+
 <a name="Query.retrieveForCache"></a>
 
 ### Query.retrieveForCache() ⇒ <code>Promise.&lt;{metadata: TYPE.QueryMap, type: string}&gt;</code>
@@ -5833,19 +5885,21 @@ CLI entry for SFMC DevTools
     * [.includesStartsWith(arr, search)](#Util.includesStartsWith) ⇒ <code>boolean</code>
     * [.includesStartsWithIndex(arr, search)](#Util.includesStartsWithIndex) ⇒ <code>number</code>
     * [.checkMarket(market, properties)](#Util.checkMarket) ⇒ <code>boolean</code>
-    * [.verifyMarketList(mlName, properties)](#Util.verifyMarketList) ⇒ <code>void</code>
+    * [.verifyMarketList(mlName, properties)](#Util.verifyMarketList)
     * [.signalFatalError()](#Util.signalFatalError) ⇒ <code>void</code>
     * [.isTrue(attrValue)](#Util.isTrue) ⇒ <code>boolean</code>
     * [.isFalse(attrValue)](#Util.isFalse) ⇒ <code>boolean</code>
     * [._isValidType(selectedType, [handleOutside])](#Util._isValidType) ⇒ <code>boolean</code>
     * [.getTypeAndSubType(selectedType)](#Util.getTypeAndSubType) ⇒ <code>Array.&lt;string&gt;</code>
     * [.getRetrieveTypeChoices()](#Util.getRetrieveTypeChoices) ⇒ <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code>
+    * [._createNewLoggerTransport([noLogFile])](#Util._createNewLoggerTransport) ⇒ <code>object</code>
+    * [.startLogger([restart], [noLogFile])](#Util.startLogger) ⇒ <code>void</code>
     * [.metadataLogger(level, type, method, payload, [source])](#Util.metadataLogger) ⇒ <code>void</code>
     * [.replaceByObject(str, obj)](#Util.replaceByObject) ⇒ <code>string</code> \| <code>object</code>
     * [.inverseGet(objs, val)](#Util.inverseGet) ⇒ <code>string</code>
     * [.getMetadataHierachy(metadataTypes)](#Util.getMetadataHierachy) ⇒ <code>Object.&lt;string, Array.&lt;string&gt;&gt;</code>
     * [.resolveObjPath(path, obj)](#Util.resolveObjPath) ⇒ <code>any</code>
-    * [.execSync(cmd, [args], [hideOutput])](#Util.execSync) ⇒ <code>string</code>
+    * [.execSync(cmd, [args], [hideOutput])](#Util.execSync) ⇒ <code>string</code> \| <code>void</code>
     * [.templateSearchResult(results, keyToSearch, searchValue)](#Util.templateSearchResult) ⇒ <code>TYPE.MetadataTypeItem</code>
     * [.setLoggingLevel(argv)](#Util.setLoggingLevel) ⇒ <code>void</code>
     * [.logBeta(type)](#Util.logBeta)
@@ -5919,11 +5973,10 @@ check if a market name exists in current mcdev config
 
 <a name="Util.verifyMarketList"></a>
 
-### Util.verifyMarketList(mlName, properties) ⇒ <code>void</code>
+### Util.verifyMarketList(mlName, properties)
 ensure provided MarketList exists and it's content including markets and BUs checks out
 
 **Kind**: static method of [<code>Util</code>](#Util)  
-**Returns**: <code>void</code> - throws errors if problems were found  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -5992,6 +6045,30 @@ helper for getDefaultProperties()
 
 **Kind**: static method of [<code>Util</code>](#Util)  
 **Returns**: <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code> - type choices  
+<a name="Util._createNewLoggerTransport"></a>
+
+### Util.\_createNewLoggerTransport([noLogFile]) ⇒ <code>object</code>
+wrapper around our standard winston logging to console and logfile
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+**Returns**: <code>object</code> - initiated logger for console and file  
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| [noLogFile] | <code>boolean</code> | <code>false</code> | optional flag to indicate if we should log to file; CLI logs are always on |
+
+<a name="Util.startLogger"></a>
+
+### Util.startLogger([restart], [noLogFile]) ⇒ <code>void</code>
+initiate winston logger
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| [restart] | <code>boolean</code> | <code>false</code> | if true, logger will be restarted; otherwise, an existing logger will be used |
+| [noLogFile] | <code>boolean</code> | <code>false</code> | if false, logger will log to file; otherwise, only to console |
+
 <a name="Util.metadataLogger"></a>
 
 ### Util.metadataLogger(level, type, method, payload, [source]) ⇒ <code>void</code>
@@ -6061,11 +6138,11 @@ let's you dynamically walk down an object and get a value
 
 <a name="Util.execSync"></a>
 
-### Util.execSync(cmd, [args], [hideOutput]) ⇒ <code>string</code>
+### Util.execSync(cmd, [args], [hideOutput]) ⇒ <code>string</code> \| <code>void</code>
 helper to run other commands as if run manually by user
 
 **Kind**: static method of [<code>Util</code>](#Util)  
-**Returns**: <code>string</code> - output of command if hideOutput is true  
+**Returns**: <code>string</code> \| <code>void</code> - output of command if hideOutput is true  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -7698,19 +7775,21 @@ Util that contains logger and simple util methods
     * [.includesStartsWith(arr, search)](#Util.includesStartsWith) ⇒ <code>boolean</code>
     * [.includesStartsWithIndex(arr, search)](#Util.includesStartsWithIndex) ⇒ <code>number</code>
     * [.checkMarket(market, properties)](#Util.checkMarket) ⇒ <code>boolean</code>
-    * [.verifyMarketList(mlName, properties)](#Util.verifyMarketList) ⇒ <code>void</code>
+    * [.verifyMarketList(mlName, properties)](#Util.verifyMarketList)
     * [.signalFatalError()](#Util.signalFatalError) ⇒ <code>void</code>
     * [.isTrue(attrValue)](#Util.isTrue) ⇒ <code>boolean</code>
     * [.isFalse(attrValue)](#Util.isFalse) ⇒ <code>boolean</code>
     * [._isValidType(selectedType, [handleOutside])](#Util._isValidType) ⇒ <code>boolean</code>
     * [.getTypeAndSubType(selectedType)](#Util.getTypeAndSubType) ⇒ <code>Array.&lt;string&gt;</code>
     * [.getRetrieveTypeChoices()](#Util.getRetrieveTypeChoices) ⇒ <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code>
+    * [._createNewLoggerTransport([noLogFile])](#Util._createNewLoggerTransport) ⇒ <code>object</code>
+    * [.startLogger([restart], [noLogFile])](#Util.startLogger) ⇒ <code>void</code>
     * [.metadataLogger(level, type, method, payload, [source])](#Util.metadataLogger) ⇒ <code>void</code>
     * [.replaceByObject(str, obj)](#Util.replaceByObject) ⇒ <code>string</code> \| <code>object</code>
     * [.inverseGet(objs, val)](#Util.inverseGet) ⇒ <code>string</code>
     * [.getMetadataHierachy(metadataTypes)](#Util.getMetadataHierachy) ⇒ <code>Object.&lt;string, Array.&lt;string&gt;&gt;</code>
     * [.resolveObjPath(path, obj)](#Util.resolveObjPath) ⇒ <code>any</code>
-    * [.execSync(cmd, [args], [hideOutput])](#Util.execSync) ⇒ <code>string</code>
+    * [.execSync(cmd, [args], [hideOutput])](#Util.execSync) ⇒ <code>string</code> \| <code>void</code>
     * [.templateSearchResult(results, keyToSearch, searchValue)](#Util.templateSearchResult) ⇒ <code>TYPE.MetadataTypeItem</code>
     * [.setLoggingLevel(argv)](#Util.setLoggingLevel) ⇒ <code>void</code>
     * [.logBeta(type)](#Util.logBeta)
@@ -7784,11 +7863,10 @@ check if a market name exists in current mcdev config
 
 <a name="Util.verifyMarketList"></a>
 
-### Util.verifyMarketList(mlName, properties) ⇒ <code>void</code>
+### Util.verifyMarketList(mlName, properties)
 ensure provided MarketList exists and it's content including markets and BUs checks out
 
 **Kind**: static method of [<code>Util</code>](#Util)  
-**Returns**: <code>void</code> - throws errors if problems were found  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -7857,6 +7935,30 @@ helper for getDefaultProperties()
 
 **Kind**: static method of [<code>Util</code>](#Util)  
 **Returns**: <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code> - type choices  
+<a name="Util._createNewLoggerTransport"></a>
+
+### Util.\_createNewLoggerTransport([noLogFile]) ⇒ <code>object</code>
+wrapper around our standard winston logging to console and logfile
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+**Returns**: <code>object</code> - initiated logger for console and file  
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| [noLogFile] | <code>boolean</code> | <code>false</code> | optional flag to indicate if we should log to file; CLI logs are always on |
+
+<a name="Util.startLogger"></a>
+
+### Util.startLogger([restart], [noLogFile]) ⇒ <code>void</code>
+initiate winston logger
+
+**Kind**: static method of [<code>Util</code>](#Util)  
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| [restart] | <code>boolean</code> | <code>false</code> | if true, logger will be restarted; otherwise, an existing logger will be used |
+| [noLogFile] | <code>boolean</code> | <code>false</code> | if false, logger will log to file; otherwise, only to console |
+
 <a name="Util.metadataLogger"></a>
 
 ### Util.metadataLogger(level, type, method, payload, [source]) ⇒ <code>void</code>
@@ -7926,11 +8028,11 @@ let's you dynamically walk down an object and get a value
 
 <a name="Util.execSync"></a>
 
-### Util.execSync(cmd, [args], [hideOutput]) ⇒ <code>string</code>
+### Util.execSync(cmd, [args], [hideOutput]) ⇒ <code>string</code> \| <code>void</code>
 helper to run other commands as if run manually by user
 
 **Kind**: static method of [<code>Util</code>](#Util)  
-**Returns**: <code>string</code> - output of command if hideOutput is true  
+**Returns**: <code>string</code> \| <code>void</code> - output of command if hideOutput is true  
 
 | Param | Type | Description |
 | --- | --- | --- |
@@ -8064,6 +8166,32 @@ helper to convert CSVs into an array. if only one value was given, it's also ret
 | --- | --- | --- |
 | csv | <code>string</code> | potentially comma-separated value or null |
 
+<a name="Automation."></a>
+
+## Automation.(metadataMap, key) ⇒ <code>Promise.&lt;void&gt;</code>
+helper for [postDeployTasks](#Automation.postDeployTasks)
+
+**Kind**: global function  
+**Returns**: <code>Promise.&lt;void&gt;</code> - -  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadataMap | <code>TYPE.AutomationMap</code> | metadata mapped by their keyField |
+| key | <code>string</code> | current customer key |
+
+<a name="Automation."></a>
+
+## Automation.(metadataMap, originalMetadataMap, key)
+helper for [postDeployTasks](postDeployTasks)
+
+**Kind**: global function  
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadataMap | <code>TYPE.AutomationMap</code> | metadata mapped by their keyField |
+| originalMetadataMap | <code>TYPE.AutomationMap</code> | metadata to be updated (contains additioanl fields) |
+| key | <code>string</code> | current customer key |
+
 <a name="getUserName"></a>
 
 ## getUserName(userList, item, fieldname) ⇒ <code>string</code>
@@ -8089,19 +8217,6 @@ Returns an SDK instance to be used for API calls
 | sessionKey | <code>string</code> | key for specific BU |
 | authObject | <code>TYPE.AuthObject</code> | credentials for specific BU |
 
-<a name="createNewLoggerTransport"></a>
-
-## createNewLoggerTransport() ⇒ <code>object</code>
-wrapper around our standard winston logging to console and logfile
-
-**Kind**: global function  
-**Returns**: <code>object</code> - initiated logger for console and file  
-<a name="startLogger"></a>
-
-## startLogger() ⇒ <code>void</code>
-initiate winston logger
-
-**Kind**: global function  
 <a name="TypeKeyCombo"></a>
 
 ## TypeKeyCombo : <code>Object.&lt;string, string&gt;</code>
diff --git a/lib/Deployer.js b/lib/Deployer.js
index 29e267c2..3d064049 100644
--- a/lib/Deployer.js
+++ b/lib/Deployer.js
@@ -103,7 +103,7 @@ class Deployer {
                 buMultiMetadataTypeMap[cred + '/' + bu] = multiMetadataTypeMap;
                 counter_credBu++;
                 Util.logger.info('');
-                Util.restartLogger();
+                Util.startLogger(true);
             }
         } else {
             // anything but "*" passed in
@@ -157,7 +157,7 @@ class Deployer {
                     buMultiMetadataTypeMap[cred + '/' + buPath] = multiMetadataTypeMap;
                     counter_credBu++;
                     Util.logger.info('');
-                    Util.restartLogger();
+                    Util.startLogger(true);
                 }
                 Util.logger.info(`\n               :: ${counter_credBu} BUs for ${cred}\n`);
             } else {
@@ -387,7 +387,7 @@ class Deployer {
             const allFolders = Object.keys(metadata[metadataType])
                 .filter(
                     // filter out root folders (which would not have a slash in their path)
-                    (key) => metadata[metadataType][key].r__folder_Path.includes('/')
+                    (key) => metadata[metadataType][key].r__folder_Path?.includes('/')
                 )
                 .filter(
                     // filter out dataExtension folders other than standard & shared (--> synchronized / salesforce are not allowed)
diff --git a/lib/cli.js b/lib/cli.js
index 992d6f9f..931c78b1 100644
--- a/lib/cli.js
+++ b/lib/cli.js
@@ -389,6 +389,30 @@ yargs
             Mcdev.refresh(argv.BU, argv.TYPE, csvToArray(argv.KEY));
         },
     })
+    .command({
+        command: 'execute <BU> <TYPE> <KEY>',
+        aliases: ['exec'],
+        desc: 'executes the entity (query/journey/automation etc.)',
+        builder: (yargs) => {
+            yargs
+                .positional('BU', {
+                    type: 'string',
+                    describe: 'the business unit where to start an item',
+                })
+                .positional('TYPE', {
+                    type: 'string',
+                    describe: 'metadata type',
+                })
+                .positional('KEY', {
+                    type: 'string',
+                    describe: 'key(s) of the metadata component(s)',
+                });
+        },
+        handler: (argv) => {
+            Mcdev.setOptions(argv);
+            Mcdev.execute(argv.BU, csvToArray(argv.TYPE), csvToArray(argv.KEY));
+        },
+    })
     .command({
         command: 'upgrade',
         aliases: ['up'],
@@ -410,6 +434,10 @@ yargs
         type: 'boolean',
         description: 'Only output errors to CLI',
     })
+    .option('noLogFile', {
+        type: 'boolean',
+        description: 'Only output log to CLI but not to files',
+    })
     .option('skipInteraction', {
         alias: ['yes', 'y'],
         description: 'Interactive questions where possible and go with defaults instead',
diff --git a/lib/index.js b/lib/index.js
index ecd28d29..3589f02b 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -59,6 +59,7 @@ class Mcdev {
             'json',
             'refresh',
             'skipInteraction',
+            'noLogFile',
         ];
         for (const option of knownOptions) {
             if (argv[option] !== undefined) {
@@ -89,6 +90,7 @@ class Mcdev {
      * @returns {Promise.<TYPE.DeltaPkgItem[]>} list of changed items
      */
     static async createDeltaPkg(argv) {
+        Util.startLogger();
         Util.logger.info('Create Delta Package ::');
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
@@ -111,6 +113,7 @@ class Mcdev {
      * @returns {Promise} .
      */
     static async selectTypes() {
+        Util.startLogger();
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
             return null;
@@ -127,6 +130,7 @@ class Mcdev {
      * @returns {Promise.<boolean>} success flag
      */
     static async upgrade() {
+        Util.startLogger();
         const properties = await config.getProperties();
         if (!properties) {
             Util.logger.error('No config found. Please run mcdev init');
@@ -149,6 +153,7 @@ class Mcdev {
      * @returns {Promise.<object>} -
      */
     static async retrieve(businessUnit, selectedTypesArr, keys, changelogOnly) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Retrieve');
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
@@ -176,7 +181,7 @@ class Mcdev {
                 for (const bu in properties.credentials[cred].businessUnits) {
                     await this._retrieveBU(cred, bu, selectedTypesArr, keys);
                     counter_credBu++;
-                    Util.restartLogger();
+                    Util.startLogger(true);
                 }
                 counter_credTotal += counter_credBu;
                 Util.logger.info(`\n               :: ${counter_credBu} BUs for ${cred}\n`);
@@ -210,7 +215,7 @@ class Mcdev {
                 for (const bu in properties.credentials[cred].businessUnits) {
                     await this._retrieveBU(cred, bu, selectedTypesArr, keys);
                     counter_credBu++;
-                    Util.restartLogger();
+                    Util.startLogger(true);
                 }
                 Util.logger.info(`\n               :: ${counter_credBu} BUs for ${cred}\n`);
             } else {
@@ -351,6 +356,7 @@ class Mcdev {
      * @returns {Promise.<Object.<string,TYPE.MultiMetadataTypeMap>>} deployed metadata per BU (first key: bu name, second key: metadata type)
      */
     static async deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve = false) {
+        Util.startLogger();
         return Deployer.deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve);
     }
 
@@ -361,6 +367,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async initProject(credentialsName) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Setting up project');
         const properties = await config.getProperties(!!credentialsName, true);
         await Init.initProject(properties, credentialsName);
@@ -371,6 +378,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async joinProject() {
+        Util.startLogger();
         Util.logger.info('mcdev:: Joining an existing project');
         await Init.joinProject();
     }
@@ -382,6 +390,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async findBUs(credentialsName) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Load BUs');
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
@@ -401,6 +410,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async document(businessUnit, type) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Document');
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
@@ -440,6 +450,7 @@ class Mcdev {
      * @returns {Promise.<boolean>} true if successful, false otherwise
      */
     static async deleteByKey(businessUnit, type, customerKey) {
+        Util.startLogger();
         Util.logger.info('mcdev:: delete');
         if (!Util._isValidType(type)) {
             return;
@@ -477,6 +488,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async refresh(businessUnit, type, keyArr) {
+        Util.startLogger();
         Util.logger.info('mcdev:: refresh');
         if (!type || !Util._isValidType(type, true)) {
             type = 'triggeredSend';
@@ -512,6 +524,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async badKeys(businessUnit) {
+        Util.startLogger();
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
             return null;
@@ -585,6 +598,7 @@ class Mcdev {
      * @returns {Promise.<TYPE.MultiMetadataTypeList>} -
      */
     static async retrieveAsTemplate(businessUnit, selectedType, name, market) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Retrieve as Template');
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
@@ -626,6 +640,7 @@ class Mcdev {
      * @returns {Promise.<TYPE.MultiMetadataTypeList>} -
      */
     static async buildTemplate(businessUnit, selectedType, keyArr, market) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Build Template from retrieved files');
         return Builder.buildTemplate(businessUnit, selectedType, keyArr, market);
     }
@@ -639,6 +654,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async buildDefinition(businessUnit, selectedType, name, market) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Build Definition from Template');
         return Builder.buildDefinition(businessUnit, selectedType, name, market);
     }
@@ -652,6 +668,7 @@ class Mcdev {
      * @returns {Promise.<void>} -
      */
     static async buildDefinitionBulk(listName, type, name) {
+        Util.startLogger();
         Util.logger.info('mcdev:: Build Definition from Template Bulk');
         return Builder.buildDefinitionBulk(listName, type, name);
     }
@@ -663,6 +680,7 @@ class Mcdev {
      * @returns {Promise.<string[]>} list of all files that need to be committed in a flat array ['path/file1.ext', 'path/file2.ext']
      */
     static async getFilesToCommit(businessUnit, selectedType, keyArr) {
+        Util.startLogger();
         Util.logger.info('mcdev:: getFilesToCommit');
         const properties = await config.getProperties();
         if (!(await config.checkProperties(properties))) {
@@ -682,6 +700,159 @@ class Mcdev {
             return DevOps.getFilesToCommit(properties, buObject, selectedType, keyArr);
         }
     }
+    /**
+     * Start an item (query)
+     *
+     * @param {string} businessUnit name of BU
+     * @param {TYPE.SupportedMetadataTypes[]} [selectedTypesArr] limit to given metadata types
+     * @param {string[]} keys customerkey of the metadata
+     * @returns {Promise.<boolean>} true if all started successfully, false if not
+     */
+    static async execute(businessUnit, selectedTypesArr, keys) {
+        Util.startLogger();
+        Util.logger.info('mcdev:: Execute');
+        const properties = await config.getProperties();
+        let counter_credBu = 0;
+        let counter_failed = 0;
+        if (!(await config.checkProperties(properties))) {
+            // return null here to avoid seeing 2 error messages for the same issue
+            return null;
+        }
+        if (Array.isArray(selectedTypesArr)) {
+            // types and keys can be provided but for each type all provided keys are applied as filter
+            for (const selectedType of Array.isArray(selectedTypesArr)
+                ? selectedTypesArr
+                : Object.keys(selectedTypesArr)) {
+                if (!Util._isValidType(selectedType)) {
+                    return;
+                }
+            }
+        }
+        if (businessUnit === '*') {
+            Util.logger.info(
+                '\n               :: Executing the entity on all BUs for all credentials'
+            );
+            let counter_credTotal = 0;
+            for (const cred in properties.credentials) {
+                Util.logger.info(`\n               :: Executing the entity on all BUs for ${cred}`);
+
+                for (const bu in properties.credentials[cred].businessUnits) {
+                    if (await this._executeBU(cred, bu, selectedTypesArr, keys)) {
+                        counter_credBu++;
+                    } else {
+                        counter_failed++;
+                    }
+                    Util.startLogger(true);
+                }
+                counter_credTotal += counter_credBu;
+                Util.logger.info(
+                    `\n               :: Executed the entity on ${counter_credBu} BUs for ${cred}\n`
+                );
+            }
+            Util.logger.info(
+                `\n               :: Executed the entity on ${counter_credTotal} BUs in total\n`
+            );
+        } else {
+            let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
+            // to allow all-BU via user selection we need to run this here already
+            if (
+                properties.credentials &&
+                (!properties.credentials[cred] ||
+                    (bu !== '*' && !properties.credentials[cred].businessUnits[bu]))
+            ) {
+                const buObject = await Cli.getCredentialObject(
+                    properties,
+                    cred === null ? null : cred + '/' + bu,
+                    null,
+                    true
+                );
+                if (buObject === null) {
+                    return;
+                } else {
+                    cred = buObject.credential;
+                    bu = buObject.businessUnit;
+                }
+            }
+            if (bu === '*' && properties.credentials && properties.credentials[cred]) {
+                Util.logger.info(`\n               :: Executing the entity on all BUs for ${cred}`);
+                let counter_credBu = 0;
+                for (const bu in properties.credentials[cred].businessUnits) {
+                    if (await this._executeBU(cred, bu, selectedTypesArr, keys)) {
+                        counter_credBu++;
+                    } else {
+                        counter_failed++;
+                    }
+                    Util.startLogger(true);
+                }
+                Util.logger.info(
+                    `\n               :: Executed the entity on ${counter_credBu} BUs for ${cred}\n`
+                );
+            } else {
+                // execute the entity on one BU only
+                if (await this._executeBU(cred, bu, selectedTypesArr, keys)) {
+                    counter_credBu++;
+                } else {
+                    counter_failed++;
+                }
+                Util.logger.info(`\n               :: Done\n`);
+            }
+        }
+        if (counter_credBu !== 0) {
+            Util.logger.info(`\n               :: Executed query on ${counter_credBu} BUs\n`);
+        }
+        return counter_failed === 0 ? true : false;
+    }
+    /**
+     * helper for {@link execute}
+     *
+     * @param {string} cred name of Credential
+     * @param {string} bu name of BU
+     * @param {TYPE.SupportedMetadataTypes[]} [selectedTypesArr] limit execution to given metadata type
+     * @param {string[]} keyArr customerkey of the metadata
+     * @returns {Promise.<boolean>} true if all items were executed, false otherwise
+     */
+    static async _executeBU(cred, bu, selectedTypesArr, keyArr) {
+        const properties = await config.getProperties();
+        let counter_failed = 0;
+        const buObject = await Cli.getCredentialObject(
+            properties,
+            cred === null ? null : cred + '/' + bu,
+            null,
+            true
+        );
+        if (!keyArr || (Array.isArray(keyArr) && !keyArr.length)) {
+            throw new Error('No keys were provided');
+        }
+        if (!selectedTypesArr || (Array.isArray(selectedTypesArr) && !selectedTypesArr.length)) {
+            throw new Error('No type was provided');
+        }
+        if (buObject !== null) {
+            cache.initCache(buObject);
+            cred = buObject.credential;
+            bu = buObject.businessUnit;
+        }
+        Util.logger.info(
+            `\n               :: Executing ${selectedTypesArr.join(', ')} on ${cred}/${bu}\n`
+        );
+        try {
+            // more than one type was provided, iterate types and execute items
+            for (const type of selectedTypesArr) {
+                try {
+                    MetadataTypeInfo[type].client = auth.getSDK(buObject);
+                } catch (ex) {
+                    Util.logger.error(ex.message);
+                    return;
+                }
+                // result will be undefined (false) if execute is not supported for the type
+                if (!(await MetadataTypeInfo[type].execute(keyArr))) {
+                    counter_failed++;
+                }
+            }
+        } catch (ex) {
+            Util.logger.errorStack(ex, 'mcdev.execute failed');
+        }
+        return counter_failed === 0 ? true : false;
+    }
 }
 
 module.exports = Mcdev;
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index 8232a2e1..560ed94e 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -6,6 +6,7 @@ const Util = require('../util/util');
 const File = require('../util/file');
 const Definitions = require('../MetadataTypeDefinitions');
 const cache = require('../util/cache');
+const pLimit = require('p-limit');
 
 /**
  * Automation MetadataType
@@ -13,6 +14,7 @@ const cache = require('../util/cache');
  * @augments MetadataType
  */
 class Automation extends MetadataType {
+    static notificationUpdates = {};
     /**
      * Retrieves Metadata of Automation
      *
@@ -35,11 +37,13 @@ class Automation extends MetadataType {
             };
         }
         const results = await this.client.soap.retrieveBulk('Program', ['ObjectID'], requestParams);
-        if (results.Results?.length) {
+        if (results.Results?.length && !key) {
             // empty results will come back without "Results" defined
             Util.logger.info(
                 Util.getGrayMsg(
-                    ` - ${results.Results?.length} Automations found. Retrieving details...`
+                    ` - ${results.Results?.length} automation${
+                        results.Results?.length === 1 ? '' : 's'
+                    } found. Retrieving details...`
                 )
             );
         }
@@ -71,6 +75,12 @@ class Automation extends MetadataType {
               )
             : [];
         let metadataMap = this.parseResponseBody({ items: details });
+
+        if (Object.keys(metadataMap).length) {
+            // attach notification information to each automation that has any
+            await this.#getAutomationNotificationsREST(metadataMap);
+        }
+
         // * retrieveDir can be empty when we use it in the context of postDeployTasks
         if (retrieveDir) {
             metadataMap = await this.saveResults(metadataMap, retrieveDir, null, null);
@@ -83,6 +93,77 @@ class Automation extends MetadataType {
         }
         return { metadata: metadataMap, type: this.definition.type };
     }
+
+    /**
+     * helper for {@link Automation.retrieve} to get Automation Notifications
+     *
+     * @private
+     * @param {TYPE.MetadataTypeMap} metadataMap keyField => metadata map
+     * @returns {Promise.<void>} Promise of nothing
+     */
+    static async #getAutomationNotificationsREST(metadataMap) {
+        Util.logger.info(Util.getGrayMsg(` Retrieving Automation Notification information...`));
+
+        // get list of keys that we retrieved so far
+        const foundKeys = Object.keys(metadataMap);
+
+        // get encodedAutomationID to retrieve notification information
+        const iteratorBackup = this.definition.bodyIteratorField;
+        this.definition.bodyIteratorField = 'entry';
+        const automationLegacyMapObj = await super.retrieveREST(
+            undefined,
+            `/legacy/v1/beta/bulk/automations/automation/definition/`
+        );
+        this.definition.bodyIteratorField = iteratorBackup;
+        const automationLegacyMap = Object.keys(automationLegacyMapObj.metadata)
+            .filter((key) => foundKeys.includes(key))
+            // ! using the `id` field to retrieve notifications does not work. instead one needs to use the URL in the `notifications` field
+            .map((key) => ({
+                id: automationLegacyMapObj.metadata[key].id,
+                key,
+            }));
+
+        // get notifications for each automation
+        const rateLimit = pLimit(5);
+        let found = 0;
+        let skipped = 0;
+        const promiseMap = await Promise.all(
+            automationLegacyMap.map((automationLegacy) =>
+                rateLimit(async () => {
+                    // this is a file so extended is at another endpoint
+                    try {
+                        const notificationsResult = await this.client.rest.get(
+                            '/legacy/v1/beta/automations/notifications/' + automationLegacy.id
+                        );
+                        if (Array.isArray(notificationsResult?.workers)) {
+                            metadataMap[automationLegacy.key].notifications =
+                                notificationsResult.workers.map((n) => ({
+                                    email: n.definition.split(',').map((item) => item.trim()),
+                                    message: n.body,
+                                    type: n.notificationType,
+                                }));
+                            found++;
+                        } else {
+                            throw new TypeError(JSON.stringify(notificationsResult));
+                        }
+                    } catch (ex) {
+                        Util.logger.debug(
+                            ` ☇ skipping Notifications for Automation ${automationLegacy.key}: ${ex.message} ${ex.code}`
+                        );
+                        skipped++;
+                    }
+                })
+            )
+        );
+        Util.logger.info(
+            Util.getGrayMsg(` Notifications found for ${found} automation${found === 1 ? '' : 's'}`)
+        );
+        Util.logger.debug(
+            `Notifications not found for ${skipped} automation${skipped === 1 ? '' : 's'}`
+        );
+        return promiseMap;
+    }
+
     /**
      * Retrieves Metadata of Automation
      *
@@ -134,6 +215,7 @@ class Automation extends MetadataType {
      * @returns {Promise.<TYPE.AutomationMapObj>} Promise of metadata
      */
     static async retrieveForCache() {
+        // get automations for cache
         const results = await this.client.soap.retrieveBulk('Program', [
             'ObjectID',
             'CustomerKey',
@@ -141,14 +223,29 @@ class Automation extends MetadataType {
         ]);
         const resultsConverted = {};
         if (Array.isArray(results?.Results)) {
+            // get encodedAutomationID to retrieve notification information
+            const keyBackup = this.definition.keyField;
+            const iteratorBackup = this.definition.bodyIteratorField;
+            this.definition.keyField = 'key';
+            this.definition.bodyIteratorField = 'entry';
+            const automationsLegacy = await super.retrieveREST(
+                undefined,
+                `/legacy/v1/beta/bulk/automations/automation/definition/`
+            );
+            this.definition.keyField = keyBackup;
+            this.definition.bodyIteratorField = iteratorBackup;
+
+            // merge encodedAutomationID into results
             for (const m of results.Results) {
                 resultsConverted[m.CustomerKey] = {
                     id: m.ObjectID,
                     key: m.CustomerKey,
                     name: m.Name,
+                    programId: automationsLegacy.metadata[m.CustomerKey]?.id,
                 };
             }
         }
+
         return { metadata: resultsConverted, type: this.definition.type };
     }
 
@@ -175,14 +272,21 @@ class Automation extends MetadataType {
                 Util.logger.error(`${this.definition.type} '${name}' not found on server.`);
                 return;
             }
-            const details = await this.client.rest.get(
+            let details = await this.client.rest.get(
                 '/automation/v1/automations/' + metadata.ObjectID
             );
+            const metadataMap = this.parseResponseBody({ items: [details] });
+            if (Object.keys(metadataMap).length) {
+                // attach notification information to each automation that has any
+                await this.#getAutomationNotificationsREST(metadataMap);
+                details = Object.values(metadataMap)[0];
+            }
+
             let val = null;
             let originalKey;
             // if parsing fails, we should just save what we get
             try {
-                const parsedDetails = this.parseMetadata(details);
+                const parsedDetails = this.postRetrieveTasks(details);
                 originalKey = parsedDetails[this.definition.keyField];
                 if (parsedDetails !== null) {
                     val = JSON.parse(
@@ -218,10 +322,128 @@ class Automation extends MetadataType {
      * manages post retrieve steps
      *
      * @param {TYPE.AutomationItem} metadata a single automation
-     * @returns {TYPE.AutomationItem} metadata
+     * @returns {TYPE.AutomationItem | void} parsed item
      */
     static postRetrieveTasks(metadata) {
-        return this.parseMetadata(metadata);
+        // folder
+        this.setFolderPath(metadata);
+        // automations are often skipped due to lack of support.
+        try {
+            if (metadata.type === 'scheduled' && metadata.schedule?.startDate) {
+                // Starting Source == 'Schedule'
+
+                try {
+                    if (this.definition.timeZoneMapping[metadata.schedule.timezoneName]) {
+                        // if we found the id in our list, remove the redundant data
+                        delete metadata.schedule.timezoneId;
+                    }
+                } catch {
+                    Util.logger.debug(
+                        `- Schedule name '${metadata.schedule.timezoneName}' not found in definition.timeZoneMapping`
+                    );
+                }
+                try {
+                    // type 'Running' is temporary status only, overwrite with Scheduled for storage.
+                    if (metadata.type === 'scheduled' && metadata.status === 'Running') {
+                        metadata.status = 'Scheduled';
+                    }
+                } catch {
+                    Util.logger.error(
+                        `- ${this.definition.type} ${metadata.name} does not have a valid schedule setting.`
+                    );
+                    return;
+                }
+            } else if (metadata.type === 'triggered' && metadata.fileTrigger) {
+                // Starting Source == 'File Drop'
+                // Do nothing for now
+            }
+            if (metadata.steps) {
+                for (const step of metadata.steps) {
+                    const stepNumber = step.stepNumber || step.step;
+                    delete step.stepNumber;
+                    delete step.step;
+
+                    for (const activity of step.activities) {
+                        try {
+                            // get metadata type of activity
+                            activity.r__type = Util.inverseGet(
+                                this.definition.activityTypeMapping,
+                                activity.objectTypeId
+                            );
+                            delete activity.objectTypeId;
+                        } catch {
+                            Util.logger.warn(
+                                ` - Unknown activity type '${activity.objectTypeId}'` +
+                                    ` in step ${stepNumber}.${activity.displayOrder}` +
+                                    ` of Automation '${metadata.name}'`
+                            );
+                            continue;
+                        }
+
+                        // if no activityObjectId then either serialized activity
+                        // (config in Automation ) or unconfigured so no further action to be taken
+                        if (
+                            activity.activityObjectId === '00000000-0000-0000-0000-000000000000' ||
+                            activity.activityObjectId == null
+                        ) {
+                            Util.logger.debug(
+                                ` - skip parsing of activity due to missing activityObjectId: ${JSON.stringify(
+                                    activity
+                                )}`
+                            );
+                            // empty if block
+                        } else if (!this.definition.dependencies.includes(activity.r__type)) {
+                            Util.logger.debug(
+                                ` - skip parsing because the type is not set up as a dependecy for ${this.definition.type}`
+                            );
+                        }
+                        // / if managed by cache we can update references to support deployment
+                        else if (
+                            Definitions[activity.r__type]?.['idField'] &&
+                            cache.getCache(this.buObject.mid)[activity.r__type]
+                        ) {
+                            try {
+                                // this will override the name returned by the API in case this activity's name was changed since the automation was last updated, keeping things nicely in sync for mcdev
+                                const name = cache.searchForField(
+                                    activity.r__type,
+                                    activity.activityObjectId,
+                                    Definitions[activity.r__type].idField,
+                                    Definitions[activity.r__type].nameField
+                                );
+                                if (name !== activity.name) {
+                                    Util.logger.debug(
+                                        ` - updated name of step ${stepNumber}.${activity.displayOrder}` +
+                                            ` in Automation '${metadata.name}' from ${activity.name} to ${name}`
+                                    );
+                                    activity.name = name;
+                                }
+                            } catch (ex) {
+                                // getFromCache throws error where the dependent metadata is not found
+                                Util.logger.warn(
+                                    ` - Missing ${activity.r__type} activity '${activity.name}'` +
+                                        ` in step ${stepNumber}.${activity.displayOrder}` +
+                                        ` of Automation '${metadata.name}' (${ex.message})`
+                                );
+                            }
+                        } else {
+                            Util.logger.warn(
+                                ` - Missing ${activity.r__type} activity '${activity.name}'` +
+                                    ` in step ${stepNumber}.${activity.displayOrder}` +
+                                    ` of Automation '${metadata.name}' (Not Found in Cache)`
+                            );
+                        }
+                    }
+                }
+            }
+            return JSON.parse(JSON.stringify(metadata));
+        } catch (ex) {
+            Util.logger.warn(
+                ` - ${this.definition.typeName} '${metadata[this.definition.nameField]}': ${
+                    ex.message
+                }`
+            );
+            return null;
+        }
     }
 
     /**
@@ -235,7 +457,15 @@ class Automation extends MetadataType {
      */
     static async deploy(metadata, targetBU, retrieveDir, isRefresh) {
         const upsertResults = await this.upsert(metadata, targetBU, isRefresh);
-        await this.saveResults(upsertResults, retrieveDir, null);
+        const savedMetadata = await this.saveResults(upsertResults, retrieveDir, null);
+        if (
+            this.properties.metaDataTypes.documentOnRetrieve.includes(this.definition.type) &&
+            !this.definition.documentInOneFile
+        ) {
+            const count = Object.keys(savedMetadata).length;
+            Util.logger.debug(` - Running document for ${count} record${count === 1 ? '' : 's'}`);
+            await this.document(savedMetadata);
+        }
         return upsertResults;
     }
 
@@ -270,6 +500,15 @@ class Automation extends MetadataType {
      * @returns {Promise.<TYPE.AutomationItem>} Promise
      */
     static async preDeployTasks(metadata) {
+        if (metadata.notifications) {
+            this.notificationUpdates[metadata.key] = metadata.notifications;
+        } else {
+            const cached = cache.getByKey(metadata.key);
+            if (cached?.notifications) {
+                // if notifications existed but are no longer present in the deployment package, we need to run an empty update call to remove them
+                this.notificationUpdates[metadata.key] = [];
+            }
+        }
         if (this.validateDeployMetadata(metadata)) {
             // folder
             this.setFolderId(metadata);
@@ -404,86 +643,146 @@ class Automation extends MetadataType {
     static async postDeployTasks(metadataMap, originalMetadataMap) {
         for (const key in metadataMap) {
             // need to put schedule on here if status is scheduled
+            await Automation.#scheduleAutomation(metadataMap, originalMetadataMap, key);
+
+            // need to update notifications separately if there are any
+            await Automation.#updateNotificationInfoREST(metadataMap, key);
+
+            // rewrite upsert to retrieve fields
+            const metadata = metadataMap[key];
+            if (metadata.steps) {
+                for (const step of metadata.steps) {
+                    step.name = step.annotation;
+                    delete step.annotation;
+                }
+            }
+        }
+    }
+    /**
+     * helper for {@link Automation.postDeployTasks}
+     *
+     * @param {TYPE.AutomationMap} metadataMap metadata mapped by their keyField
+     * @param {string} key current customer key
+     * @returns {Promise.<void>} -
+     */
+    static async #updateNotificationInfoREST(metadataMap, key) {
+        if (this.notificationUpdates[key]) {
+            // create & update automation calls return programId as 'legacyId'; retrieve does not return it
+            const programId = metadataMap[key]?.legacyId;
+            if (programId) {
+                const notificationBody = {
+                    programId,
+                    workers: this.notificationUpdates[key].map((notification) => ({
+                        programId,
+                        notificationType: notification.type,
+                        definition: Array.isArray(notification.email)
+                            ? notification.email.join(',')
+                            : notification.email,
+                        body: notification.message,
+                        channelType: 'Account',
+                    })),
+                };
+                try {
+                    const result = await this.client.rest.post(
+                        '/legacy/v1/beta/automations/notifications/' + programId,
+                        notificationBody
+                    );
+                    if (result) {
+                        // should be empty if all OK
+                        throw new Error(result);
+                    }
+                } catch (ex) {
+                    Util.logger.error(
+                        `Error updating notifications for automation '${metadataMap[key].name}': ${ex.message} (${ex.code}))`
+                    );
+                }
+                Util.logger.info(
+                    Util.getGrayMsg(
+                        ` - updated notifications for automation '${metadataMap[key].name}'`
+                    )
+                );
+            }
+        }
+    }
 
-            if (originalMetadataMap[key]?.type === 'scheduled') {
-                // Starting Source == 'Schedule': Try starting the automation
-                if (originalMetadataMap[key].status === 'Scheduled') {
-                    let schedule = null;
+    /**
+     * helper for {@link postDeployTasks}
+     *
+     * @param {TYPE.AutomationMap} metadataMap metadata mapped by their keyField
+     * @param {TYPE.AutomationMap} originalMetadataMap metadata to be updated (contains additioanl fields)
+     * @param {string} key current customer key
+     */
+    static async #scheduleAutomation(metadataMap, originalMetadataMap, key) {
+        if (originalMetadataMap[key]?.type === 'scheduled') {
+            // Starting Source == 'Schedule': Try starting the automation
+            if (originalMetadataMap[key].status === 'Scheduled') {
+                let schedule = null;
+                try {
+                    schedule = this._buildSchedule(originalMetadataMap[key].schedule);
+                } catch (ex) {
+                    Util.logger.error(
+                        `- Could not create schedule for automation '${originalMetadataMap[key].name}' to start it: ${ex.message}`
+                    );
+                }
+                if (schedule !== null) {
                     try {
-                        schedule = this._buildSchedule(originalMetadataMap[key].schedule);
+                        // remove the fields that are not needed for the schedule but only for CLI output
+                        const schedule_StartDateTime = schedule._StartDateTime;
+                        delete schedule._StartDateTime;
+                        const schedule_interval = schedule._interval;
+                        delete schedule._interval;
+                        const schedule_timezoneString = schedule._timezoneString;
+                        delete schedule._timezoneString;
+                        // start the automation
+                        await this.client.soap.schedule(
+                            'Automation',
+                            schedule,
+                            {
+                                Interaction: {
+                                    ObjectID: metadataMap[key].id,
+                                },
+                            },
+                            'start',
+                            {}
+                        );
+                        const intervalString =
+                            (schedule_interval > 1 ? `${schedule_interval} ` : '') +
+                            (schedule.RecurrenceType === 'Daily'
+                                ? 'Day'
+                                : schedule.RecurrenceType.slice(0, -2) +
+                                  (schedule_interval > 1 ? 's' : ''));
+                        Util.logger.warn(
+                            ` - scheduled automation '${
+                                originalMetadataMap[key].name
+                            }' deployed as Active: runs every ${intervalString} starting ${
+                                schedule_StartDateTime.split('T').join(' ').split('.')[0]
+                            } ${schedule_timezoneString}`
+                        );
                     } catch (ex) {
                         Util.logger.error(
-                            `- Could not create schedule for automation ${originalMetadataMap[key].name} to start it: ${ex.message}`
+                            `- Could not start scheduled automation '${originalMetadataMap[key].name}': ${ex.message}`
                         );
                     }
-                    if (schedule !== null) {
-                        try {
-                            // remove the fields that are not needed for the schedule but only for CLI output
-                            const schedule_StartDateTime = schedule._StartDateTime;
-                            delete schedule._StartDateTime;
-                            const schedule_interval = schedule._interval;
-                            delete schedule._interval;
-                            const schedule_timezoneString = schedule._timezoneString;
-                            delete schedule._timezoneString;
-                            // start the automation
-                            await this.client.soap.schedule(
-                                'Automation',
-                                schedule,
-                                {
-                                    Interaction: {
-                                        ObjectID: metadataMap[key].id,
-                                    },
-                                },
-                                'start',
-                                {}
-                            );
-                            const intervalString =
-                                (schedule_interval > 1 ? `${schedule_interval} ` : '') +
-                                (schedule.RecurrenceType === 'Daily'
-                                    ? 'Day'
-                                    : schedule.RecurrenceType.slice(0, -2) +
-                                      (schedule_interval > 1 ? 's' : ''));
-                            Util.logger.warn(
-                                ` - scheduled automation '${
-                                    originalMetadataMap[key].name
-                                }' deployed Active: runs every ${intervalString} starting ${
-                                    schedule_StartDateTime.split('T').join(' ').split('.')[0]
-                                } ${schedule_timezoneString}`
-                            );
-                        } catch (ex) {
-                            Util.logger.error(
-                                `- Could not start scheduled automation '${originalMetadataMap[key].name}': ${ex.message}`
-                            );
-                        }
-                    }
-                } else {
-                    Util.logger.warn(
-                        ` - scheduled automation '${originalMetadataMap[key].name}' deployed Paused`
-                    );
                 }
-            }
-            if (metadataMap[key].startSource) {
-                metadataMap[key].schedule = metadataMap[key].startSource.schedule;
-
-                delete metadataMap[key].startSource;
-            }
-            if (metadataMap[key].schedule) {
-                metadataMap[key].schedule.typeId = metadataMap[key].schedule.scheduleTypeId;
-                delete metadataMap[key].schedule.scheduleTypeId;
-            }
-
-            // re-retrieve deployed items because the API does not return any info for them except the new id (api key)
-            try {
-                const { metadata } = await this.retrieve(null, null, null, key);
-                metadataMap[key] = Object.values(metadata)[0];
-                // postRetrieveTasks will be run automatically on this via super.saveResult
-            } catch (ex) {
-                throw new Error(
-                    `Could not get details for new ${this.definition.type} ${key} from server (${ex.message})`
+            } else {
+                Util.logger.info(
+                    Util.getGrayMsg(
+                        ` - scheduled automation '${originalMetadataMap[key].name}' deployed as Paused`
+                    )
                 );
             }
         }
+        if (metadataMap[key].startSource) {
+            metadataMap[key].schedule = metadataMap[key].startSource.schedule;
+
+            delete metadataMap[key].startSource;
+        }
+        if (metadataMap[key].schedule?.scheduleTypeId) {
+            metadataMap[key].schedule.typeId = metadataMap[key].schedule.scheduleTypeId;
+            delete metadataMap[key].schedule.scheduleTypeId;
+        }
     }
+
     /**
      * generic script that retrieves the folder path from cache and updates the given metadata with it after retrieve
      *
@@ -549,118 +848,6 @@ class Automation extends MetadataType {
         }
     }
 
-    /**
-     * parses retrieved Metadata before saving
-     *
-     * @param {TYPE.AutomationItem} metadata a single automation definition
-     * @returns {TYPE.AutomationItem | void} parsed item
-     */
-    static parseMetadata(metadata) {
-        // folder
-        this.setFolderPath(metadata);
-        // automations are often skipped due to lack of support.
-        try {
-            if (metadata.type === 'scheduled' && metadata.schedule?.startDate) {
-                // Starting Source == 'Schedule'
-
-                try {
-                    if (this.definition.timeZoneMapping[metadata.schedule.timezoneName]) {
-                        // if we found the id in our list, remove the redundant data
-                        delete metadata.schedule.timezoneId;
-                    }
-                } catch {
-                    Util.logger.debug(
-                        `- Schedule name '${metadata.schedule.timezoneName}' not found in definition.timeZoneMapping`
-                    );
-                }
-                try {
-                    // type 'Running' is temporary status only, overwrite with Scheduled for storage.
-                    if (metadata.type === 'scheduled' && metadata.status === 'Running') {
-                        metadata.status = 'Scheduled';
-                    }
-                } catch {
-                    Util.logger.error(
-                        `- ${this.definition.type} ${metadata.name} does not have a valid schedule setting.`
-                    );
-                    return;
-                }
-            } else if (metadata.type === 'triggered' && metadata.fileTrigger) {
-                // Starting Source == 'File Drop'
-                // Do nothing for now
-            }
-            if (metadata.steps) {
-                for (const step of metadata.steps) {
-                    const stepNumber = step.stepNumber || step.step;
-                    delete step.stepNumber;
-                    delete step.step;
-
-                    for (const activity of step.activities) {
-                        try {
-                            // get metadata type of activity
-                            activity.r__type = Util.inverseGet(
-                                this.definition.activityTypeMapping,
-                                activity.objectTypeId
-                            );
-                            delete activity.objectTypeId;
-                        } catch {
-                            Util.logger.warn(
-                                ` - Unknown activity type '${activity.objectTypeId}'` +
-                                    ` in step ${stepNumber}.${activity.displayOrder}` +
-                                    ` of Automation '${metadata.name}'`
-                            );
-                            continue;
-                        }
-
-                        // if no activityObjectId then either serialized activity
-                        // (config in Automation ) or unconfigured so no further action to be taken
-                        if (
-                            activity.activityObjectId === '00000000-0000-0000-0000-000000000000' ||
-                            activity.activityObjectId == null ||
-                            !this.definition.dependencies.includes(activity.r__type)
-                        ) {
-                            // empty if block
-                        }
-                        // / if managed by cache we can update references to support deployment
-                        else if (
-                            Definitions[activity.r__type]?.['idField'] &&
-                            cache.getCache(this.buObject.mid)[activity.r__type]
-                        ) {
-                            try {
-                                activity.activityObjectId = cache.searchForField(
-                                    activity.r__type,
-                                    activity.activityObjectId,
-                                    Definitions[activity.r__type].idField,
-                                    Definitions[activity.r__type].nameField
-                                );
-                            } catch (ex) {
-                                // getFromCache throws error where the dependent metadata is not found
-                                Util.logger.warn(
-                                    ` - Missing ${activity.r__type} activity '${activity.name}'` +
-                                        ` in step ${stepNumber}.${activity.displayOrder}` +
-                                        ` of Automation '${metadata.name}' (${ex.message})`
-                                );
-                            }
-                        } else {
-                            Util.logger.warn(
-                                ` - Missing ${activity.r__type} activity '${activity.name}'` +
-                                    ` in step ${stepNumber}.${activity.displayOrder}` +
-                                    ` of Automation '${metadata.name}' (Not Found in Cache)`
-                            );
-                        }
-                    }
-                }
-            }
-            return JSON.parse(JSON.stringify(metadata));
-        } catch (ex) {
-            Util.logger.warn(
-                ` - ${this.definition.typeName} '${metadata[this.definition.nameField]}': ${
-                    ex.message
-                }`
-            );
-            return null;
-        }
-    }
-
     /**
      * Builds a schedule object to be used for scheduling an automation
      * based on combination of ical string and start/end dates.
@@ -868,6 +1055,27 @@ class Automation extends MetadataType {
             output += `* Pattern: ${json.fileTrigger.fileNamingPattern}\n`;
             output += `* Folder:  ${json.fileTrigger.folderLocationText}\n`;
         }
+        // add empty line to ensure the following notifications are rendered properly
+        output += '\n';
+        if (json.notifications?.length) {
+            output += `**Notifications:**\n\n`;
+            // ensure notifications are sorted by type regardless of how the API returns it
+            const notifications = {};
+            for (const n of json.notifications) {
+                notifications[n.type] =
+                    (Array.isArray(n.email) ? n.email.join(',') : n.email) +
+                    (n.message ? ` ("${n.message}")` : '');
+            }
+            if (notifications.Complete) {
+                output += `* Complete: ${notifications.Complete}\n`;
+            }
+            if (notifications.Error) {
+                output += `* Error: ${notifications.Error}\n`;
+            }
+        } else {
+            output += `**Notifications:** _none_\n\n`;
+        }
+
         // show table with automation steps
         if (tabled && tabled.length) {
             // add empty line to ensure the following table is rendered properly
@@ -975,11 +1183,10 @@ class Automation extends MetadataType {
                 // as part of retrieve & manual execution we could face an empty folder
                 return;
             }
-            await Promise.all(
-                Object.keys(metadata).map((key) => {
-                    this._writeDoc(docPath + '/', key, metadata[key], 'md');
-                    return metadata[key];
-                })
+            return await Promise.all(
+                Object.keys(metadata).map((key) =>
+                    this._writeDoc(docPath + '/', key, metadata[key], 'md')
+                )
             );
         }
     }
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index cd50d099..43e9dcfc 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -59,8 +59,8 @@ class DataExtension extends MetadataType {
                 // output error & remove from deploy list
                 Util.logger.error(
                     ` ☇ skipping ${this.definition.type} ${
-                        metadataMap[this.definition.keyField]
-                    } / ${metadataMap[this.definition.nameField]}: ${ex.message}`
+                        metadataMap[metadataKey][this.definition.keyField]
+                    } / ${metadataMap[metadataKey][this.definition.nameField]}: ${ex.message}`
                 );
                 delete metadataMap[metadataKey];
                 // skip rest of handling for this DE
@@ -624,16 +624,16 @@ class DataExtension extends MetadataType {
      * @returns {Promise.<TYPE.DataExtensionItem>} Promise of updated single DE
      */
     static async preDeployTasks(metadata) {
-        if (metadata.Name.startsWith('_')) {
+        if (metadata.Name?.startsWith('_')) {
             throw new Error(`Cannot Upsert Strongly Typed Data Extensions`);
         }
         if (
             this.buObject.eid !== this.buObject.mid &&
-            metadata.r__folder_Path.startsWith('Shared Items')
+            metadata.r__folder_Path?.startsWith('Shared Items')
         ) {
             throw new Error(`Cannot Create/Update a Shared Data Extension from the Child BU`);
         }
-        if (metadata.r__folder_Path.startsWith('Synchronized Data Extensions')) {
+        if (metadata.r__folder_Path?.startsWith('Synchronized Data Extensions')) {
             throw new Error(
                 `Cannot Create/Update a Synchronized Data Extension. Please use Contact Builder to maintain these`
             );
diff --git a/lib/metadataTypes/MetadataType.js b/lib/metadataTypes/MetadataType.js
index 69b58259..92b1686d 100644
--- a/lib/metadataTypes/MetadataType.js
+++ b/lib/metadataTypes/MetadataType.js
@@ -58,15 +58,9 @@ class MetadataType {
                         if (key === fileNameWithoutEnding || listBadKeys) {
                             fileName2FileContent[fileNameWithoutEnding] = fileContent;
                         } else {
-                            Util.metadataLogger(
-                                'error',
-                                this.definition.type,
-                                'getJsonFromFS',
-                                'Name of the Metadata and the External Identifier must match',
-                                JSON.stringify({
-                                    Filename: fileNameWithoutEnding,
-                                    ExternalIdentifier: key,
-                                })
+                            Util.logger.error(
+                                ` ${this.definition.type} ${key}: Name of the metadata file and the JSON-key (${this.definition.keyField}) must match` +
+                                    Util.getGrayMsg(` - ${dir}/${fileName}`)
                             );
                         }
                     }
@@ -460,6 +454,18 @@ class MetadataType {
         return;
     }
 
+    /**
+     * Abstract execute method that needs to be implemented in child metadata type
+     *
+     * @returns {void}
+     */
+    static execute() {
+        Util.logger.error(
+            ` ☇ skipping ${this.definition.type}: execute is not supported yet for ${this.definition.type}`
+        );
+        return;
+    }
+
     /**
      * test if metadata was actually changed or not to potentially skip it during deployment
      *
@@ -650,6 +656,7 @@ class MetadataType {
             metadataMap[metadataKey][this.definition.keyField]
         );
         // Update if it already exists; Create it if not
+        const maxKeyLength = this.definition.maxKeyLength || 36;
         if (
             Util.logger.level === 'debug' &&
             metadataMap[metadataKey][this.definition.idField] &&
@@ -703,11 +710,11 @@ class MetadataType {
                     // NOTE: trim twice while getting the newKey value to remove leading spaces before limiting the length
                     const newKey = (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '')
                         .trim()
-                        .slice(0, 36)
+                        .slice(0, maxKeyLength)
                         .trim();
-                    if (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '' > 36) {
+                    if (metadataMap[metadataKey][Util.OPTIONS.changeKeyField] + '' > maxKeyLength) {
                         Util.logger.warn(
-                            `Customer Keys may not exceed 36 characters. Truncated the value in field ${Util.OPTIONS.changeKeyField} to ${newKey}`
+                            `${this.definition.type} ${this.definition.keyField} may not exceed ${maxKeyLength} characters. Truncated the value in field ${Util.OPTIONS.changeKeyField} to ${newKey}`
                         );
                     }
                     if (metadataKey == newKey) {
@@ -727,10 +734,10 @@ class MetadataType {
                 }
             } else if (Util.OPTIONS.changeKeyValue) {
                 // NOTE: trim twice while getting the newKey value to remove leading spaces before limiting the length
-                const newKey = Util.OPTIONS.changeKeyValue.trim().slice(0, 36).trim();
-                if (Util.OPTIONS.changeKeyValue.trim().length > 36) {
+                const newKey = Util.OPTIONS.changeKeyValue.trim().slice(0, maxKeyLength).trim();
+                if (Util.OPTIONS.changeKeyValue.trim().length > maxKeyLength) {
                     Util.logger.warn(
-                        `Customer Keys may not exceed 36 characters. Truncated your value to ${newKey}`
+                        `${this.definition.type} ${this.definition.keyField} may not exceed ${maxKeyLength} characters. Truncated your value to ${newKey}`
                     );
                 }
                 if (this.definition.keyField == this.definition.idField) {
@@ -1066,6 +1073,26 @@ class MetadataType {
             type: this.definition.type,
         };
     }
+    /**
+     * Used to execute a query/automation etc.
+     *
+     * @param {string} uri REST endpoint where the POST request should be sent
+     * @param {string} key item key
+     * @returns {Promise.<string>} 'OK' if started execution successfully, otherwise - 'Error'
+     */
+    static async executeREST(uri, key) {
+        try {
+            const response = await this.client.rest.post(uri, {}); // payload is empty for this request
+            if (response === 'OK') {
+                Util.logger.info(`Executed ${this.definition.type}: ${key}`);
+            } else {
+                throw new Error(response);
+            }
+            return response;
+        } catch (ex) {
+            Util.logger.error(`Failed to execute ${this.definition.type} ${key}: ${ex.message}`);
+        }
+    }
 
     /**
      * helper for {@link retrieveREST} and {@link retrieveSOAP}
diff --git a/lib/metadataTypes/Query.js b/lib/metadataTypes/Query.js
index 1b3d331d..e9149613 100644
--- a/lib/metadataTypes/Query.js
+++ b/lib/metadataTypes/Query.js
@@ -50,6 +50,32 @@ class Query extends MetadataType {
             key
         );
     }
+    /**
+     * a function to start query execution via API
+     *
+     * @param {string[]} keyArr customerkey of the metadata
+     * @returns {Promise.<boolean>} Returns true if all items were executed successfully, otherwise false
+     */
+    static async execute(keyArr) {
+        const results = [];
+        // works only with objectId
+        let objectId;
+        for (const key of keyArr) {
+            if (key) {
+                objectId = await this._getObjectIdForSingleRetrieve(key);
+                if (!objectId) {
+                    Util.logger.info(`Skipping ${key} - did not find an item with such key`);
+                    break;
+                }
+            }
+            results.push(
+                super.executeREST(`/automation/v1/queries/${objectId}/actions/start/`, key)
+            );
+        }
+        const successCounter = (await Promise.all(results)).filter((r) => r === 'OK').length;
+        Util.logger.info(`Executed ${successCounter} of ${keyArr.length} items`);
+        return successCounter === keyArr.length;
+    }
     /**
      * helper to allow us to select single metadata entries via REST
      *
diff --git a/lib/metadataTypes/definitions/Asset.definition.js b/lib/metadataTypes/definitions/Asset.definition.js
index ad600765..96d42725 100644
--- a/lib/metadataTypes/definitions/Asset.definition.js
+++ b/lib/metadataTypes/definitions/Asset.definition.js
@@ -13,6 +13,7 @@ module.exports = {
     lastmodDateField: 'modifiedDate',
     lastmodNameField: 'modifiedBy.name',
     restPagination: true,
+    maxKeyLength: 36, // confirmed max length
     type: 'asset',
     typeDescription: 'Assets from Content Builder grouped into subtypes.',
     typeRetrieveByDefault: ['asset', 'code', 'textfile', 'block', 'message', 'template', 'other'],
diff --git a/lib/metadataTypes/definitions/Automation.definition.js b/lib/metadataTypes/definitions/Automation.definition.js
index 5be143e5..c7ab19a1 100644
--- a/lib/metadataTypes/definitions/Automation.definition.js
+++ b/lib/metadataTypes/definitions/Automation.definition.js
@@ -46,7 +46,8 @@ module.exports = {
     createdNameField: 'createdByName',
     lastmodDateField: 'lastSavedDate',
     lastmodNameField: 'lastSavedByName',
-    restPagination: false,
+    restPagination: true,
+    maxKeyLength: 200, // confirmed max length
     statusMapping: {
         AwaitingTrigger: 7,
         Building: 1,
@@ -329,7 +330,7 @@ module.exports = {
         legacyId: {
             isCreateable: false,
             isUpdateable: false,
-            retrieving: true,
+            retrieving: false,
             template: false,
         },
         lastSavedDate: {
@@ -368,6 +369,45 @@ module.exports = {
             retrieving: true,
             template: true,
         },
+        notifications: {
+            isCreateable: true,
+            isUpdateable: true,
+            retrieving: true,
+            template: true,
+        },
+        'notifications[].email': {
+            isCreateable: true,
+            isUpdateable: true,
+            retrieving: true,
+            template: true,
+        },
+        'notifications[].message': {
+            isCreateable: true,
+            isUpdateable: true,
+            retrieving: true,
+            template: true,
+        },
+        'notifications[].channelType': {
+            // always 'Account'
+            isCreateable: true,
+            isUpdateable: true,
+            retrieving: false,
+            template: false,
+        },
+        'notifications[].type': {
+            // custom shorthand for channelType
+            isCreateable: true,
+            isUpdateable: true,
+            retrieving: true,
+            template: true,
+        },
+        'notifications[].notificationType': {
+            // Error, Complete
+            isCreateable: true,
+            isUpdateable: true,
+            retrieving: true,
+            template: true,
+        },
         startSource: {
             skipValidation: true,
         },
@@ -411,7 +451,7 @@ module.exports = {
             isCreateable: true,
             isUpdateable: true,
             retrieving: false,
-            template: true,
+            template: false,
         },
         'schedule.scheduleStatus': {
             isCreateable: false,
@@ -425,6 +465,12 @@ module.exports = {
             retrieving: true,
             template: true,
         },
+        'schedule.statusId': {
+            isCreateable: false,
+            isUpdateable: false,
+            retrieving: false,
+            template: false,
+        },
         'schedule.timezoneId': {
             isCreateable: true,
             isUpdateable: true,
@@ -527,8 +573,8 @@ module.exports = {
         'steps[].annotation': {
             isCreateable: true,
             isUpdateable: true,
-            retrieving: true,
-            template: true,
+            retrieving: false,
+            template: false,
         },
         'steps[].id': {
             isCreateable: true,
@@ -564,7 +610,7 @@ module.exports = {
             isCreateable: true,
             isUpdateable: true,
             retrieving: false,
-            template: true,
+            template: false,
         },
         r__folder_Path: { skipValidation: true },
     },
diff --git a/lib/metadataTypes/definitions/DataExtension.definition.js b/lib/metadataTypes/definitions/DataExtension.definition.js
index ff68df68..67a224d4 100644
--- a/lib/metadataTypes/definitions/DataExtension.definition.js
+++ b/lib/metadataTypes/definitions/DataExtension.definition.js
@@ -96,6 +96,7 @@ module.exports = {
     lastmodDateField: 'ModifiedDate',
     lastmodNameField: null,
     restPagination: false,
+    maxKeyLength: 200, // confirmed max length
     type: 'dataExtension',
     typeDescription: 'Database table schemas.',
     typeRetrieveByDefault: true,
diff --git a/lib/metadataTypes/definitions/DataExtract.definition.js b/lib/metadataTypes/definitions/DataExtract.definition.js
index 4736cc7d..0b0f009e 100644
--- a/lib/metadataTypes/definitions/DataExtract.definition.js
+++ b/lib/metadataTypes/definitions/DataExtract.definition.js
@@ -11,6 +11,7 @@ module.exports = {
     lastmodNameField: 'modifiedBy',
     nameField: 'name',
     restPagination: true,
+    maxKeyLength: 36, // confirmed max length
     type: 'dataExtract',
     typeDescription: 'Creates zipped files in your FTP directory or convert XML into CSV.',
     typeRetrieveByDefault: true,
diff --git a/lib/metadataTypes/definitions/EmailSend.definition.js b/lib/metadataTypes/definitions/EmailSend.definition.js
index d8a8241f..9be557b4 100644
--- a/lib/metadataTypes/definitions/EmailSend.definition.js
+++ b/lib/metadataTypes/definitions/EmailSend.definition.js
@@ -14,6 +14,7 @@ module.exports = {
     lastmodDateField: 'ModifiedDate',
     lastmodNameField: null,
     restPagination: null,
+    maxKeyLength: 36, // confirmed max length
     type: 'emailSend',
     soapType: 'emailSendDefinition',
     typeDescription: 'Mainly used in Automations as "Send Email Activity".',
diff --git a/lib/metadataTypes/definitions/Event.definition.js b/lib/metadataTypes/definitions/Event.definition.js
index 9a923af6..b2217d88 100644
--- a/lib/metadataTypes/definitions/Event.definition.js
+++ b/lib/metadataTypes/definitions/Event.definition.js
@@ -11,6 +11,7 @@ module.exports = {
     lastmodDateField: 'modifiedDate',
     lastmodNameField: 'modifiedBy',
     restPagination: true,
+    maxKeyLength: 200, // confirmed max length
     type: 'event',
     typeDescription: 'Used in Journeys (Interactions) to define Entry Events.',
     typeRetrieveByDefault: true,
diff --git a/lib/metadataTypes/definitions/Filter.definition.js b/lib/metadataTypes/definitions/Filter.definition.js
index e93ccfb0..ef649910 100644
--- a/lib/metadataTypes/definitions/Filter.definition.js
+++ b/lib/metadataTypes/definitions/Filter.definition.js
@@ -11,6 +11,7 @@ module.exports = {
     lastmodDateField: 'modifiedDate',
     lastmodNameField: null,
     restPagination: true,
+    maxKeyLength: 36, // confirmed max length
     type: 'filter',
     typeDescription:
         'BETA: Part of how filtered Data Extensions are created. Depends on type "FilterDefinitions".',
diff --git a/lib/metadataTypes/definitions/ImportFile.definition.js b/lib/metadataTypes/definitions/ImportFile.definition.js
index 27bf5c20..b1938c78 100644
--- a/lib/metadataTypes/definitions/ImportFile.definition.js
+++ b/lib/metadataTypes/definitions/ImportFile.definition.js
@@ -22,6 +22,7 @@ module.exports = {
         DataExtension: 255,
         Email: 0,
     },
+    maxKeyLength: 36, // confirmed max length
     type: 'importFile',
     typeDescription: 'Reads files in FTP directory for further processing.',
     typeRetrieveByDefault: true,
diff --git a/lib/metadataTypes/definitions/MobileKeyword.definition.js b/lib/metadataTypes/definitions/MobileKeyword.definition.js
index 72ac918a..5108ae96 100644
--- a/lib/metadataTypes/definitions/MobileKeyword.definition.js
+++ b/lib/metadataTypes/definitions/MobileKeyword.definition.js
@@ -12,6 +12,7 @@ module.exports = {
     lastmodNameField: null,
     restPagination: true,
     restPageSize: 50,
+    maxKeyLength: 50, // assumed max length
     type: 'mobileKeyword',
     typeDescription: 'Used for managing subscriptions for Mobile numbers in Mobile Connect',
     typeRetrieveByDefault: true,
diff --git a/lib/metadataTypes/definitions/Query.definition.js b/lib/metadataTypes/definitions/Query.definition.js
index adfbff65..98d04742 100644
--- a/lib/metadataTypes/definitions/Query.definition.js
+++ b/lib/metadataTypes/definitions/Query.definition.js
@@ -21,6 +21,7 @@ module.exports = {
         Overwrite: 0,
         Update: 1,
     },
+    maxKeyLength: 36, // confirmed max length
     type: 'query',
     typeDescription: 'Select & transform data using SQL.',
     typeRetrieveByDefault: true,
diff --git a/lib/metadataTypes/definitions/Role.definition.js b/lib/metadataTypes/definitions/Role.definition.js
index d6de3262..0f5a6c0b 100644
--- a/lib/metadataTypes/definitions/Role.definition.js
+++ b/lib/metadataTypes/definitions/Role.definition.js
@@ -23,6 +23,7 @@ module.exports = {
     createdNameField: null,
     lastmodDateField: 'ModifiedDate',
     lastmodNameField: null,
+    maxKeyLength: 36, // confirmed max length
     type: 'role',
     typeDescription:
         'User Roles define groups that are used to grant users access to SFMC systems.',
diff --git a/lib/metadataTypes/definitions/TriggeredSend.definition.js b/lib/metadataTypes/definitions/TriggeredSend.definition.js
index 789afad7..e5afad57 100644
--- a/lib/metadataTypes/definitions/TriggeredSend.definition.js
+++ b/lib/metadataTypes/definitions/TriggeredSend.definition.js
@@ -21,6 +21,7 @@ module.exports = {
     lastmodDateField: 'ModifiedDate',
     lastmodNameField: null,
     restPagination: null,
+    maxKeyLength: 36, // confirmed max length
     type: 'triggeredSend',
     soapType: 'triggeredSendDefinition',
     typeDescription: 'DEPRECATED: Sends emails via API or DataExtension Event.',
diff --git a/lib/metadataTypes/definitions/User.definition.js b/lib/metadataTypes/definitions/User.definition.js
index 34d3b5e0..34fea100 100644
--- a/lib/metadataTypes/definitions/User.definition.js
+++ b/lib/metadataTypes/definitions/User.definition.js
@@ -12,6 +12,7 @@ module.exports = {
     createdNameField: null,
     lastmodDateField: 'ModifiedDate',
     lastmodNameField: 'Client.ModifiedBy',
+    maxKeyLength: 50, // confirmed max length
     type: 'user',
     soapType: 'AccountUser',
     typeDescription: 'Marketing Cloud users',
diff --git a/lib/util/devops.js b/lib/util/devops.js
index 208e838a..d08f51ff 100644
--- a/lib/util/devops.js
+++ b/lib/util/devops.js
@@ -293,17 +293,19 @@ const DevOps = {
             }
 
             /** @type {TYPE.DeltaPkgItem[]} */
-            const copied = delta.map((file) =>
-                File.copyFile(
-                    file.file,
-                    path
-                        .normalize(file.file)
-                        .replace(
-                            path.normalize(properties.directories.retrieve),
-                            path.normalize(properties.directories.deploy)
-                        )
-                )
-            );
+            const copied = delta
+                .filter((file) => !file.file.endsWith('.md')) // filter documentation files
+                .map((file) =>
+                    File.copyFile(
+                        file.file,
+                        path
+                            .normalize(file.file)
+                            .replace(
+                                path.normalize(properties.directories.retrieve),
+                                path.normalize(properties.directories.deploy)
+                            )
+                    )
+                );
             const results = await Promise.all(copied);
             const failed = results.filter((result) => result.status === 'failed');
             const skipped = results.filter((result) => result.status === 'skipped');
diff --git a/lib/util/util.js b/lib/util/util.js
index 482cbd0c..a5bfe7cf 100644
--- a/lib/util/util.js
+++ b/lib/util/util.js
@@ -85,7 +85,6 @@ const Util = {
      *
      * @param {string} mlName name of marketList
      * @param {TYPE.Mcdevrc} properties General configuration to be used in retrieve
-     * @returns {void} throws errors if problems were found
      */
     verifyMarketList(mlName, properties) {
         if (properties.marketList[mlName]) {
@@ -227,6 +226,65 @@ const Util = {
 
         return typeChoices;
     },
+    /**
+     * wrapper around our standard winston logging to console and logfile
+     *
+     * @param {boolean} [noLogFile=false] optional flag to indicate if we should log to file; CLI logs are always on
+     * @returns {object} initiated logger for console and file
+     */
+    _createNewLoggerTransport: function (noLogFile = false) {
+        // {
+        //   error: 0,
+        //   warn: 1,
+        //   info: 2,
+        //   http: 3,
+        //   verbose: 4,
+        //   debug: 5,
+        //   silly: 6
+        // }
+        const logFileName = new Date().toISOString().split(':').join('.');
+        const transports = {
+            console: new winston.transports.Console({
+                // Write logs to Console
+                level: Util.OPTIONS.loggerLevel || 'info',
+                format: winston.format.combine(
+                    winston.format.colorize(),
+                    winston.format.timestamp({ format: 'HH:mm:ss' }),
+                    winston.format.simple(),
+                    winston.format.printf(
+                        (info) => `${info.timestamp} ${info.level}: ${info.message}`
+                    )
+                ),
+            }),
+        };
+        if (!noLogFile) {
+            transports.file = new winston.transports.File({
+                // Write logs to logfile
+                filename: 'logs/' + logFileName + '.log',
+                level: 'debug', // log everything
+                format: winston.format.combine(
+                    winston.format.timestamp({ format: 'HH:mm:ss.SSS' }),
+                    winston.format.simple(),
+                    winston.format.printf(
+                        (info) => `${info.timestamp} ${info.level}: ${info.message}`
+                    )
+                ),
+            });
+            transports.fileError = new winston.transports.File({
+                // Write logs to additional error-logfile for better visibility of errors
+                filename: 'logs/' + logFileName + '-errors.log',
+                level: 'error', // only log errors
+                format: winston.format.combine(
+                    winston.format.timestamp({ format: 'HH:mm:ss.SSS' }),
+                    winston.format.simple(),
+                    winston.format.printf(
+                        (info) => `${info.timestamp} ${info.level}: ${info.message}`
+                    )
+                ),
+            });
+        }
+        return transports;
+    },
 
     loggerTransports: null,
     /**
@@ -235,7 +293,91 @@ const Util = {
      * @type {TYPE.Logger}
      */
     logger: null,
-    restartLogger: startLogger,
+    /**
+     * initiate winston logger
+     *
+     * @param {boolean} [restart=false] if true, logger will be restarted; otherwise, an existing logger will be used
+     * @param {boolean} [noLogFile=false] if false, logger will log to file; otherwise, only to console
+     * @returns {void}
+     */
+    startLogger: function (restart = false, noLogFile = false) {
+        if (
+            !(
+                Util.loggerTransports === null ||
+                restart ||
+                (!Util.loggerTransports?.file && !noLogFile && !Util.OPTIONS?.noLogFile)
+            )
+        ) {
+            // logger already started
+            return;
+        }
+        Util.loggerTransports = this._createNewLoggerTransport(
+            noLogFile || Util.OPTIONS?.noLogFile
+        );
+        const myWinston = winston.createLogger({
+            level: Util.OPTIONS.loggerLevel,
+            levels: winston.config.npm.levels,
+            transports: Object.values(Util.loggerTransports),
+        });
+        const winstonError = myWinston.error;
+        const winstonExtension = {
+            /**
+             * helper that prints better stack trace for errors
+             *
+             * @param {Error} ex the error
+             * @param {string} [message] optional custom message to be printed as error together with the exception's message
+             * @returns {void}
+             */
+            errorStack: function (ex, message) {
+                if (message) {
+                    // ! this method only sets exitCode=1 if message-param was set
+                    // if not, then this method purely outputs debug information and should not change the exitCode
+                    winstonError(message + ':');
+                    winstonError(`    ${ex.message} (${ex.code})`);
+                    if (ex.endpoint) {
+                        // ex.endpoint is only available if 'ex' is of type RestError
+                        winstonError('    endpoint: ' + ex.endpoint);
+                    }
+                    Util.signalFatalError();
+                }
+                let stack;
+                /* eslint-disable unicorn/prefer-ternary */
+                if (
+                    [
+                        'ETIMEDOUT',
+                        'EHOSTUNREACH',
+                        'ENOTFOUND',
+                        'ECONNRESET',
+                        'ECONNABORTED',
+                    ].includes(ex.code)
+                ) {
+                    // the stack would just return a one-liner that does not help
+                    stack = new Error().stack; // eslint-disable-line unicorn/error-message
+                } else {
+                    stack = ex.stack;
+                }
+                /* eslint-enable unicorn/prefer-ternary */
+                myWinston.debug(stack);
+            },
+            /**
+             * errors should cause surrounding applications to take notice
+             * hence we overwrite the default error function here
+             *
+             * @param {string} msg - the message to log
+             * @returns {void}
+             */
+            error: function (msg) {
+                winstonError(msg);
+                Util.signalFatalError();
+            },
+        };
+        Util.logger = Object.assign(myWinston, winstonExtension);
+
+        const processArgv = process.argv.slice(2);
+        Util.logger.debug(
+            `:: mcdev ${packageJsonMcdev.version} :: ⚡ mcdev ${processArgv.join(' ')}`
+        );
+    },
     /**
      * Logger helper for Metadata functions
      *
@@ -416,7 +558,7 @@ const Util = {
      * @param {string} cmd to be executed command
      * @param {string[]} [args] list of arguments
      * @param {boolean} [hideOutput] if true, output of command will be hidden from CLI
-     * @returns {string} output of command if hideOutput is true
+     * @returns {string|void} output of command if hideOutput is true
      */
     execSync(cmd, args, hideOutput) {
         args ||= [];
@@ -471,34 +613,30 @@ const Util = {
      * @returns {void}
      */
     setLoggingLevel(argv) {
-        Util.loggerTransports.console.file = 'debug';
         if (argv.silent) {
             // only errors printed to CLI
-            Util.logger.level = 'error';
             Util.OPTIONS.loggerLevel = 'error';
-            Util.loggerTransports.console.level = 'error';
             Util.logger.debug('CLI logger set to: silent');
         } else if (argv.verbose) {
             // chatty user cli logs
-            Util.logger.level = 'verbose';
             Util.OPTIONS.loggerLevel = 'verbose';
-            Util.loggerTransports.console.level = 'verbose';
             Util.logger.debug('CLI logger set to: verbose');
         } else {
             // default user cli logs
-            // TODO to be switched to "warn" when cli-process is integrated
-            Util.logger.level = 'info';
             Util.OPTIONS.loggerLevel = 'info';
-            Util.loggerTransports.console.level = 'info';
             Util.logger.debug('CLI logger set to: info / default');
         }
         if (argv.debug) {
             // enables developer output & features. no change to actual logs
-            Util.logger.level = 'debug';
             Util.OPTIONS.loggerLevel = 'debug';
-            Util.loggerTransports.console.level = 'debug';
             Util.logger.debug('CLI logger set to: debug');
         }
+        if (Util.loggerTransports?.console) {
+            Util.loggerTransports.console.level = Util.OPTIONS.loggerLevel;
+        }
+        if (Util.logger) {
+            Util.logger.level = Util.OPTIONS.loggerLevel;
+        }
     },
     /**
      * outputs a warning that the given type is still in beta
@@ -643,122 +781,7 @@ const Util = {
         return null;
     },
 };
-/**
- * wrapper around our standard winston logging to console and logfile
- *
- * @returns {object} initiated logger for console and file
- */
-function createNewLoggerTransport() {
-    // {
-    //   error: 0,
-    //   warn: 1,
-    //   info: 2,
-    //   http: 3,
-    //   verbose: 4,
-    //   debug: 5,
-    //   silly: 6
-    // }
-    const logFileName = new Date().toISOString().split(':').join('.');
-    return {
-        console: new winston.transports.Console({
-            // Write logs to Console
-            level: 'info', // log error, warn, info
-            format: winston.format.combine(
-                winston.format.colorize(),
-                winston.format.timestamp({ format: 'HH:mm:ss' }),
-                winston.format.simple(),
-                winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)
-            ),
-        }),
-        file: new winston.transports.File({
-            // Write logs to logfile
-            filename: 'logs/' + logFileName + '.log',
-            level: 'debug', // log everything
-            format: winston.format.combine(
-                winston.format.timestamp({ format: 'HH:mm:ss.SSS' }),
-                winston.format.simple(),
-                winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)
-            ),
-        }),
-        fileError: new winston.transports.File({
-            // Write logs to additional error-logfile for better visibility of errors
-            filename: 'logs/' + logFileName + '-errors.log',
-            level: 'error', // only log errors
-            format: winston.format.combine(
-                winston.format.timestamp({ format: 'HH:mm:ss.SSS' }),
-                winston.format.simple(),
-                winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)
-            ),
-        }),
-    };
-}
-/**
- * initiate winston logger
- *
- * @returns {void}
- */
-function startLogger() {
-    Util.loggerTransports = createNewLoggerTransport();
-    const myWinston = winston.createLogger({
-        levels: winston.config.npm.levels,
-        transports: [
-            Util.loggerTransports.console,
-            Util.loggerTransports.file,
-            Util.loggerTransports.fileError,
-        ],
-    });
-    const winstonError = myWinston.error;
-    const winstonExtension = {
-        /**
-         * helper that prints better stack trace for errors
-         *
-         * @param {Error} ex the error
-         * @param {string} [message] optional custom message to be printed as error together with the exception's message
-         * @returns {void}
-         */
-        errorStack: function (ex, message) {
-            if (message) {
-                // ! this method only sets exitCode=1 if message-param was set
-                // if not, then this method purely outputs debug information and should not change the exitCode
-                winstonError(message + ':');
-                winstonError(`    ${ex.message} (${ex.code})`);
-                if (ex.endpoint) {
-                    // ex.endpoint is only available if 'ex' is of type RestError
-                    winstonError('    endpoint: ' + ex.endpoint);
-                }
-                Util.signalFatalError();
-            }
-            let stack;
-            /* eslint-disable unicorn/prefer-ternary */
-            if (
-                ['ETIMEDOUT', 'EHOSTUNREACH', 'ENOTFOUND', 'ECONNRESET', 'ECONNABORTED'].includes(
-                    ex.code
-                )
-            ) {
-                // the stack would just return a one-liner that does not help
-                stack = new Error().stack; // eslint-disable-line unicorn/error-message
-            } else {
-                stack = ex.stack;
-            }
-            /* eslint-enable unicorn/prefer-ternary */
-            myWinston.debug(stack);
-        },
-        /**
-         * errors should cause surrounding applications to take notice
-         * hence we overwrite the default error function here
-         *
-         * @param {string} msg - the message to log
-         * @returns {void}
-         */
-        error: function (msg) {
-            winstonError(msg);
-            Util.signalFatalError();
-        },
-    };
-    Util.logger = Object.assign(myWinston, winstonExtension);
 
-    Util.logger.debug(`:: mcdev ${packageJsonMcdev.version} ::`);
-}
-startLogger();
+Util.startLogger(false, true);
 
 module.exports = Util;
diff --git a/package-lock.json b/package-lock.json
index cdc2e50d..f9ca5851 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
     "name": "mcdev",
-    "version": "5.0.2",
+    "version": "5.1.0",
     "lockfileVersion": 2,
     "requires": true,
     "packages": {
         "": {
             "name": "mcdev",
-            "version": "5.0.2",
+            "version": "5.1.0",
             "license": "MIT",
             "dependencies": {
                 "beauty-amp-core": "0.3.7",
@@ -27,7 +27,7 @@
                 "simple-git": "3.18.0",
                 "toposort": "2.0.2",
                 "update-notifier": "5.1.0",
-                "winston": "3.8.2",
+                "winston": "3.9.0",
                 "yargs": "17.7.2"
             },
             "bin": {
@@ -38,14 +38,14 @@
                 "axios-mock-adapter": "1.21.3",
                 "chai": "4.3.7",
                 "chai-files": "1.4.0",
-                "eslint": "8.41.0",
+                "eslint": "8.42.0",
                 "eslint-config-prettier": "8.7.0",
                 "eslint-config-ssjs": "1.1.11",
-                "eslint-plugin-jsdoc": "45.0.0",
+                "eslint-plugin-jsdoc": "46.2.5",
                 "eslint-plugin-mocha": "10.1.0",
                 "eslint-plugin-prettier": "4.2.1",
                 "eslint-plugin-unicorn": "47.0.0",
-                "fast-xml-parser": "4.2.2",
+                "fast-xml-parser": "4.2.4",
                 "husky": "8.0.3",
                 "jsdoc-to-markdown": "8.0.0",
                 "lint-staged": "13.2.2",
@@ -590,18 +590,18 @@
             "dev": true
         },
         "node_modules/@eslint/js": {
-            "version": "8.41.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
-            "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
+            "version": "8.42.0",
+            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
+            "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
             "dev": true,
             "engines": {
                 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
             }
         },
         "node_modules/@humanwhocodes/config-array": {
-            "version": "0.11.8",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
-            "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+            "version": "0.11.10",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
+            "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
             "dev": true,
             "dependencies": {
                 "@humanwhocodes/object-schema": "^1.2.1",
@@ -3138,16 +3138,16 @@
             }
         },
         "node_modules/eslint": {
-            "version": "8.41.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
-            "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
+            "version": "8.42.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
+            "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
             "dev": true,
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.2.0",
                 "@eslint-community/regexpp": "^4.4.0",
                 "@eslint/eslintrc": "^2.0.3",
-                "@eslint/js": "8.41.0",
-                "@humanwhocodes/config-array": "^0.11.8",
+                "@eslint/js": "8.42.0",
+                "@humanwhocodes/config-array": "^0.11.10",
                 "@humanwhocodes/module-importer": "^1.0.1",
                 "@nodelib/fs.walk": "^1.2.8",
                 "ajv": "^6.10.0",
@@ -3221,9 +3221,9 @@
             }
         },
         "node_modules/eslint-plugin-jsdoc": {
-            "version": "45.0.0",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-45.0.0.tgz",
-            "integrity": "sha512-l2+Jcs/Ps7oFA+SWY+0sweU/e5LgricnEl6EsDlyRTF5y0+NWL1y9Qwz9PHwHAxtdJq6lxPjEQWmYLMkvhzD4g==",
+            "version": "46.2.5",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.2.5.tgz",
+            "integrity": "sha512-Rmd0pb6S5fv9/lGbJMiVUZn56XvjKTGQoq9H5yfNjj6jcJHkTaq+Pqj2KHK/8EO01f8auFFy2kNL64cFisMEDw==",
             "dev": true,
             "dependencies": {
                 "@es-joy/jsdoccomment": "~0.39.4",
@@ -3232,6 +3232,7 @@
                 "debug": "^4.3.4",
                 "escape-string-regexp": "^4.0.0",
                 "esquery": "^1.5.0",
+                "is-builtin-module": "^3.2.1",
                 "semver": "^7.5.1",
                 "spdx-expression-parse": "^3.0.1"
             },
@@ -3636,9 +3637,9 @@
             "dev": true
         },
         "node_modules/fast-xml-parser": {
-            "version": "4.2.2",
-            "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.2.tgz",
-            "integrity": "sha512-DLzIPtQqmvmdq3VUKR7T6omPK/VCRNqgFlGtbESfyhcH2R4I8EzK1/K6E8PkRCK2EabWrUHK32NjYRbEFnnz0Q==",
+            "version": "4.2.4",
+            "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.4.tgz",
+            "integrity": "sha512-fbfMDvgBNIdDJLdLOwacjFAPYt67tr31H9ZhWSm45CDAxvd0I6WTlSOUo7K2P/K5sA5JgMKG64PI3DMcaFdWpQ==",
             "dev": true,
             "funding": [
                 {
@@ -9757,9 +9758,9 @@
             }
         },
         "node_modules/winston": {
-            "version": "3.8.2",
-            "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz",
-            "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==",
+            "version": "3.9.0",
+            "resolved": "https://registry.npmjs.org/winston/-/winston-3.9.0.tgz",
+            "integrity": "sha512-jW51iW/X95BCW6MMtZWr2jKQBP4hV5bIDq9QrIjfDk6Q9QuxvTKEAlpUNAzP+HYHFFCeENhph16s0zEunu4uuQ==",
             "dependencies": {
                 "@colors/colors": "1.5.0",
                 "@dabh/diagnostics": "^2.0.2",
@@ -10395,15 +10396,15 @@
             }
         },
         "@eslint/js": {
-            "version": "8.41.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
-            "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
+            "version": "8.42.0",
+            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
+            "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
             "dev": true
         },
         "@humanwhocodes/config-array": {
-            "version": "0.11.8",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
-            "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+            "version": "0.11.10",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
+            "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
             "dev": true,
             "requires": {
                 "@humanwhocodes/object-schema": "^1.2.1",
@@ -12334,16 +12335,16 @@
             "dev": true
         },
         "eslint": {
-            "version": "8.41.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
-            "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
+            "version": "8.42.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
+            "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
             "dev": true,
             "requires": {
                 "@eslint-community/eslint-utils": "^4.2.0",
                 "@eslint-community/regexpp": "^4.4.0",
                 "@eslint/eslintrc": "^2.0.3",
-                "@eslint/js": "8.41.0",
-                "@humanwhocodes/config-array": "^0.11.8",
+                "@eslint/js": "8.42.0",
+                "@humanwhocodes/config-array": "^0.11.10",
                 "@humanwhocodes/module-importer": "^1.0.1",
                 "@nodelib/fs.walk": "^1.2.8",
                 "ajv": "^6.10.0",
@@ -12415,9 +12416,9 @@
             "requires": {}
         },
         "eslint-plugin-jsdoc": {
-            "version": "45.0.0",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-45.0.0.tgz",
-            "integrity": "sha512-l2+Jcs/Ps7oFA+SWY+0sweU/e5LgricnEl6EsDlyRTF5y0+NWL1y9Qwz9PHwHAxtdJq6lxPjEQWmYLMkvhzD4g==",
+            "version": "46.2.5",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.2.5.tgz",
+            "integrity": "sha512-Rmd0pb6S5fv9/lGbJMiVUZn56XvjKTGQoq9H5yfNjj6jcJHkTaq+Pqj2KHK/8EO01f8auFFy2kNL64cFisMEDw==",
             "dev": true,
             "requires": {
                 "@es-joy/jsdoccomment": "~0.39.4",
@@ -12426,6 +12427,7 @@
                 "debug": "^4.3.4",
                 "escape-string-regexp": "^4.0.0",
                 "esquery": "^1.5.0",
+                "is-builtin-module": "^3.2.1",
                 "semver": "^7.5.1",
                 "spdx-expression-parse": "^3.0.1"
             },
@@ -12682,9 +12684,9 @@
             "dev": true
         },
         "fast-xml-parser": {
-            "version": "4.2.2",
-            "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.2.tgz",
-            "integrity": "sha512-DLzIPtQqmvmdq3VUKR7T6omPK/VCRNqgFlGtbESfyhcH2R4I8EzK1/K6E8PkRCK2EabWrUHK32NjYRbEFnnz0Q==",
+            "version": "4.2.4",
+            "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.4.tgz",
+            "integrity": "sha512-fbfMDvgBNIdDJLdLOwacjFAPYt67tr31H9ZhWSm45CDAxvd0I6WTlSOUo7K2P/K5sA5JgMKG64PI3DMcaFdWpQ==",
             "dev": true,
             "requires": {
                 "strnum": "^1.0.5"
@@ -17223,9 +17225,9 @@
             }
         },
         "winston": {
-            "version": "3.8.2",
-            "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz",
-            "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==",
+            "version": "3.9.0",
+            "resolved": "https://registry.npmjs.org/winston/-/winston-3.9.0.tgz",
+            "integrity": "sha512-jW51iW/X95BCW6MMtZWr2jKQBP4hV5bIDq9QrIjfDk6Q9QuxvTKEAlpUNAzP+HYHFFCeENhph16s0zEunu4uuQ==",
             "requires": {
                 "@colors/colors": "1.5.0",
                 "@dabh/diagnostics": "^2.0.2",
diff --git a/package.json b/package.json
index 255dd321..e9975d47 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "mcdev",
-    "version": "5.0.2",
+    "version": "5.1.0",
     "description": "Accenture Salesforce Marketing Cloud DevTools",
     "author": "Accenture: joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
     "license": "MIT",
@@ -76,7 +76,7 @@
         "simple-git": "3.18.0",
         "toposort": "2.0.2",
         "update-notifier": "5.1.0",
-        "winston": "3.8.2",
+        "winston": "3.9.0",
         "yargs": "17.7.2"
     },
     "devDependencies": {
@@ -84,14 +84,14 @@
         "axios-mock-adapter": "1.21.3",
         "chai": "4.3.7",
         "chai-files": "1.4.0",
-        "eslint": "8.41.0",
+        "eslint": "8.42.0",
         "eslint-config-prettier": "8.7.0",
         "eslint-config-ssjs": "1.1.11",
-        "eslint-plugin-jsdoc": "45.0.0",
+        "eslint-plugin-jsdoc": "46.2.5",
         "eslint-plugin-mocha": "10.1.0",
         "eslint-plugin-prettier": "4.2.1",
         "eslint-plugin-unicorn": "47.0.0",
-        "fast-xml-parser": "4.2.2",
+        "fast-xml-parser": "4.2.4",
         "husky": "8.0.3",
         "jsdoc-to-markdown": "8.0.0",
         "lint-staged": "13.2.2",


Test patch:
diff --git a/test/general.test.js b/test/general.test.js
index 1a3036d6..b92831f7 100644
--- a/test/general.test.js
+++ b/test/general.test.js
@@ -14,6 +14,22 @@ describe('GENERAL', () => {
         testUtils.mockReset();
     });
 
+    describe('init ================', () => {
+        it('should init a local project without downloading BUs');
+        it('should init a local project and download all BUs');
+    });
+    describe('join ================', () => {
+        it('should clone a project from git');
+    });
+    describe('upgrade ================', () => {
+        it('should upgrade a project to the latest version');
+    });
+    describe('reloadBUs ================', () => {
+        it('should load all BUs from the server and refresh the config');
+    });
+    describe('selectTypes ================', () => {
+        it('should change which types are selected for default retrieval');
+    });
     describe('explainTypes ================', () => {
         it('without options', () => {
             handler.explainTypes();
@@ -59,4 +75,14 @@ describe('GENERAL', () => {
             return;
         });
     });
+    describe('createDeltaPkg ================', () => {
+        it('should show diff to master branch');
+        // mcdev createDeltaPkg master # resolves to master..HEAD
+        it('should show diff between master and develop branch');
+        // mcdev createDeltaPkg master..develop
+        it(
+            'should show diff between master and develop branch and filter the results to only show MyProject/BU1'
+        );
+        // mcdev createDeltaPkg master..develop --filter 'MyProject/BU1'
+    });
 });
diff --git a/test/mockRoot/.mcdevrc.json b/test/mockRoot/.mcdevrc.json
index f8e5c389..29f14ebd 100644
--- a/test/mockRoot/.mcdevrc.json
+++ b/test/mockRoot/.mcdevrc.json
@@ -78,5 +78,5 @@
             "triggeredSend"
         ]
     },
-    "version": "5.0.2"
+    "version": "5.1.0"
 }
diff --git a/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json b/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json
new file mode 100644
index 00000000..b901a271
--- /dev/null
+++ b/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json
@@ -0,0 +1,53 @@
+{
+    "description": "updated on deploy",
+    "key": "testExisting_automation",
+    "name": "testExisting_automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "testExisting_dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "testExisting_emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "testExisting_fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "testExisting_importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "testExisting_query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "testExisting_script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "notifications": [
+        {
+            "email": ["error-updated@test.accenture.com"],
+            "message": "test updated",
+            "type": "Error"
+        }
+    ],
+    "type": "scheduled"
+}
diff --git a/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json b/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json
new file mode 100644
index 00000000..2a1caee1
--- /dev/null
+++ b/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json
@@ -0,0 +1,46 @@
+{
+    "description": "created on deploy",
+    "key": "testNew_automation",
+    "name": "testNew_automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "testExisting_dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "testExisting_emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "testExisting_fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "testExisting_importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "testExisting_query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "testExisting_script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "type": "scheduled"
+}
diff --git a/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json b/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query.query-meta.json
similarity index 80%
rename from test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json
rename to test/mockRoot/deploy/testInstance/testBU/query/testExisting_query.query-meta.json
index 72ba5f15..421e918e 100644
--- a/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json
+++ b/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query.query-meta.json
@@ -1,6 +1,6 @@
 {
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "testExisting_query",
+    "key": "testExisting_query",
     "description": "updated on deploy",
     "targetKey": "testExisting_dataExtension",
     "createdDate": "2022-04-26T15:21:16.453",
diff --git a/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql b/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query.query-meta.sql
similarity index 100%
rename from test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql
rename to test/mockRoot/deploy/testInstance/testBU/query/testExisting_query.query-meta.sql
diff --git a/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.json b/test/mockRoot/deploy/testInstance/testBU/query/testNew_query.query-meta.json
similarity index 82%
rename from test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.json
rename to test/mockRoot/deploy/testInstance/testBU/query/testNew_query.query-meta.json
index b2fc695a..7e4bdc09 100644
--- a/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.json
+++ b/test/mockRoot/deploy/testInstance/testBU/query/testNew_query.query-meta.json
@@ -1,6 +1,6 @@
 {
-    "name": "testNewQuery",
-    "key": "testNewQuery",
+    "name": "testNew_query",
+    "key": "testNew_query",
     "description": "created on deploy",
     "targetKey": "testExisting_dataExtension",
     "createdDate": "2022-04-26T15:21:16.453",
diff --git a/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.sql b/test/mockRoot/deploy/testInstance/testBU/query/testNew_query.query-meta.sql
similarity index 100%
rename from test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.sql
rename to test/mockRoot/deploy/testInstance/testBU/query/testNew_query.query-meta.sql
diff --git a/test/resourceFactory.js b/test/resourceFactory.js
index 13b9a664..5cdd5550 100644
--- a/test/resourceFactory.js
+++ b/test/resourceFactory.js
@@ -10,33 +10,55 @@ const attributeParser = new XMLParser({ ignoreAttributes: false });
  * @param {string} mcdevAction SOAP action
  * @param {string} type metadata Type
  * @param {string} mid of Business Unit
+ * @param {object} filter likely for customer key
  * @returns {string} relevant metadata stringified
  */
-exports.loadSOAPRecords = async (mcdevAction, type, mid) => {
+exports.loadSOAPRecords = async (mcdevAction, type, mid, filter) => {
     type = type[0].toLowerCase() + type.slice(1);
-    const testPath = path.join(
-        'test',
-        'resources',
-        mid.toString(),
-        type,
-        mcdevAction + '-response.xml'
-    );
-    if (await fs.pathExists(testPath)) {
-        return fs.readFile(testPath, {
+    const testPath = path.join('test', 'resources', mid.toString(), type, mcdevAction);
+    const filterPath = this.filterToPath(filter);
+    if (await fs.pathExists(testPath + filterPath + '-response.xml')) {
+        return fs.readFile(testPath + filterPath + '-response.xml', {
+            encoding: 'utf8',
+        });
+    } else if (await fs.pathExists(testPath + '-response.xml')) {
+        if (filterPath) {
+            /* eslint-disable no-console */
+            console.log(
+                `${color.bgYellow}${color.fgBlack}test-warning${
+                    color.reset
+                }: You are loading your reponse from ${
+                    testPath + '-response.xml'
+                } instead of the more specific ${
+                    testPath + filterPath + '-response.xml'
+                }. Make sure this is intended`
+            );
+            /* eslint-enable no-console */
+        }
+        return fs.readFile(testPath + '-response.xml', {
             encoding: 'utf8',
         });
     }
     /* eslint-disable no-console */
     console.log(
-        `${color.bgRed}${color.fgBlack}test-error${color.reset}: Please create file ${testPath}`
+        `${color.bgRed}${color.fgBlack}test-error${color.reset}: Please create file ${
+            testPath + filterPath + '-response.xml'
+        } or ${testPath + '-response.xml'}`
     );
     /* eslint-enable no-console */
-    process.exitCode = 404;
 
+    // return error
+    process.exitCode = 404;
     return fs.readFile(path.join('test', 'resources', mcdevAction + '-response.xml'), {
         encoding: 'utf8',
     });
 };
+exports.filterToPath = (filter) => {
+    if (filter && filter.Property && filter.SimpleOperator && filter.Value) {
+        return `-${filter.Property}${filter.SimpleOperator.replace('equals', '=')}${filter.Value}`;
+    }
+    return '';
+};
 /**
  * based on request, respond with different soap data
  *
@@ -53,7 +75,8 @@ exports.handleSOAPRequest = async (config) => {
             responseXML = await this.loadSOAPRecords(
                 config.headers.SOAPAction.toLocaleLowerCase(),
                 jObj.Envelope.Body.RetrieveRequestMsg.RetrieveRequest.ObjectType,
-                jObj.Envelope.Header.fueloauth
+                jObj.Envelope.Header.fueloauth,
+                jObj.Envelope.Body.RetrieveRequestMsg.RetrieveRequest.Filter
             );
 
             break;
@@ -62,7 +85,8 @@ exports.handleSOAPRequest = async (config) => {
             responseXML = await this.loadSOAPRecords(
                 config.headers.SOAPAction.toLocaleLowerCase(),
                 fullObj.Envelope.Body.CreateRequest.Objects['@_xsi:type'],
-                jObj.Envelope.Header.fueloauth
+                jObj.Envelope.Header.fueloauth,
+                null
             );
 
             break;
@@ -71,7 +95,8 @@ exports.handleSOAPRequest = async (config) => {
             responseXML = await this.loadSOAPRecords(
                 config.headers.SOAPAction.toLocaleLowerCase(),
                 fullObj.Envelope.Body.UpdateRequest.Objects['@_xsi:type'],
-                jObj.Envelope.Header.fueloauth
+                jObj.Envelope.Header.fueloauth,
+                null
             );
 
             break;
@@ -82,7 +107,18 @@ exports.handleSOAPRequest = async (config) => {
                 fullObj.Envelope.Body.ConfigureRequestMsg.Configurations.Configuration[0][
                     '@_xsi:type'
                 ],
-                jObj.Envelope.Header.fueloauth
+                jObj.Envelope.Header.fueloauth,
+                null
+            );
+
+            break;
+        }
+        case 'Delete': {
+            responseXML = await this.loadSOAPRecords(
+                config.headers.SOAPAction.toLocaleLowerCase(),
+                fullObj.Envelope.Body.DeleteRequest.Objects['@_xsi:type'],
+                jObj.Envelope.Header.fueloauth,
+                null
             );
 
             break;
@@ -121,15 +157,15 @@ exports.handleRESTRequest = async (config) => {
                 'resources',
                 config.headers.Authorization.replace('Bearer ', ''),
                 urlObj.pathname,
-                config.method + '-response.json'
+                config.method + '-response'
             )
             .replace(':', '_'); // replace : with _ for Windows
 
-        if (await fs.pathExists(testPath)) {
+        if (await fs.pathExists(testPath + '.json')) {
             // build filter logic to ensure templating works
             if (filterName) {
                 const response = JSON.parse(
-                    await fs.readFile(testPath, {
+                    await fs.readFile(testPath + '.json', {
                         encoding: 'utf8',
                     })
                 );
@@ -139,15 +175,22 @@ exports.handleRESTRequest = async (config) => {
             } else {
                 return [
                     200,
-                    await fs.readFile(testPath, {
+                    await fs.readFile(testPath + '.json', {
                         encoding: 'utf8',
                     }),
                 ];
             }
+        } else if (await fs.pathExists(testPath + '.txt')) {
+            return [
+                200,
+                await fs.readFile(testPath + '.txt', {
+                    encoding: 'utf8',
+                }),
+            ];
         } else {
             /* eslint-disable no-console */
             console.log(
-                `${color.bgRed}${color.fgBlack}test-error${color.reset}: Please create file ${testPath}`
+                `${color.bgRed}${color.fgBlack}test-error${color.reset}: Please create file ${testPath}.json/.txt`
             );
             /* eslint-enable no-console */
             process.exitCode = 404;
diff --git a/test/resources/9999999/automation/build-expected.json b/test/resources/9999999/automation/build-expected.json
new file mode 100644
index 00000000..ecd94cb3
--- /dev/null
+++ b/test/resources/9999999/automation/build-expected.json
@@ -0,0 +1,58 @@
+{
+    "description": "foobar",
+    "key": "testTemplated_automation",
+    "name": "testTemplated_automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "testTemplated_dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "testTemplated_emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "testTemplated_fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "testTemplated_importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "testTemplated_query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "testTemplated_script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "type": "scheduled",
+    "notifications": [
+        {
+            "email": ["complete@test.accenture.com"],
+            "message": "",
+            "type": "Complete"
+        },
+        {
+            "email": ["error@test.accenture.com"],
+            "message": "test",
+            "type": "Error"
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/create-expected.json b/test/resources/9999999/automation/create-expected.json
new file mode 100644
index 00000000..2a1caee1
--- /dev/null
+++ b/test/resources/9999999/automation/create-expected.json
@@ -0,0 +1,46 @@
+{
+    "description": "created on deploy",
+    "key": "testNew_automation",
+    "name": "testNew_automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "testExisting_dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "testExisting_emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "testExisting_fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "testExisting_importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "testExisting_query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "testExisting_script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "type": "scheduled"
+}
diff --git a/test/resources/9999999/automation/create-testNew_automation-expected.md b/test/resources/9999999/automation/create-testNew_automation-expected.md
new file mode 100644
index 00000000..d596cc54
--- /dev/null
+++ b/test/resources/9999999/automation/create-testNew_automation-expected.md
@@ -0,0 +1,28 @@
+## testNew_automation
+
+**Description:** created on deploy
+
+**Folder:** my automations/
+
+**Started by:** Schedule
+
+**Status:** PausedSchedule
+
+**Schedule:**
+
+* Start: 2022-07-30 00:00:00 +01:00
+* End: 2022-07-30 00:00:00 +01:00
+* Timezone:  W. Europe Standard Time
+* Recurrance: every  day for 1 times
+
+**Notifications:** _none_
+
+
+| Step 1<br>_<small>-</small>_ |
+| --- |
+| _1.1: dataExtract_<br>testExisting_dataExtract |
+| _1.2: emailSend_<br>testExisting_emailSend |
+| _1.3: fileTransfer_<br>testExisting_fileTransfer |
+| _1.4: importFile_<br>testExisting_importFile |
+| _1.5: query_<br>testExisting_query |
+| _1.6: script_<br>testExisting_script |
diff --git a/test/resources/9999999/automation/delete-response.xml b/test/resources/9999999/automation/delete-response.xml
new file mode 100644
index 00000000..54cce0eb
--- /dev/null
+++ b/test/resources/9999999/automation/delete-response.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>DeleteResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:cc45bb83-15a3-4a82-ba48-47ac4fb13000</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:29986848-a0c3-4f3b-bf5a-91151f784449</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-4e8dad58-7a68-4653-8406-a172d1960c8a">
+                <wsu:Created>2023-06-02T13:41:30Z</wsu:Created>
+                <wsu:Expires>2023-06-02T13:46:30Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <DeleteResponse xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <Results>
+                <StatusCode>OK</StatusCode>
+                <StatusMessage>Program deleted</StatusMessage>
+                <OrdinalID>0</OrdinalID>
+                <Object xsi:type="Automation">
+                    <PartnerKey xsi:nil="true" />
+                    <ObjectID>08afb0e2-b00a-4c88-ad2e-1f7f8788c560</ObjectID>
+                    <CustomerKey>testExisting_automation</CustomerKey>
+                    <IsPlatformObject>false</IsPlatformObject>
+                    <Name />
+                    <Description />
+                    <IsActive>true</IsActive>
+                </Object>
+            </Results>
+            <RequestID>898702fc-a432-4176-8130-5d6dd5ad9ca6</RequestID>
+            <OverallStatus>OK</OverallStatus>
+        </DeleteResponse>
+    </soap:Body>
+</soap:Envelope>
\ No newline at end of file
diff --git a/test/resources/9999999/automation/retrieve-expected.json b/test/resources/9999999/automation/retrieve-expected.json
new file mode 100644
index 00000000..fa80b0f9
--- /dev/null
+++ b/test/resources/9999999/automation/retrieve-expected.json
@@ -0,0 +1,58 @@
+{
+    "description": "bla bla",
+    "key": "testExisting_automation",
+    "name": "testExisting_automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "testExisting_dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "testExisting_emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "testExisting_fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "testExisting_importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "testExisting_query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "testExisting_script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "type": "scheduled",
+    "notifications": [
+        {
+            "email": ["complete@test.accenture.com"],
+            "message": "",
+            "type": "Complete"
+        },
+        {
+            "email": ["error@test.accenture.com"],
+            "message": "test",
+            "type": "Error"
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md b/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md
new file mode 100644
index 00000000..22bd4c50
--- /dev/null
+++ b/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md
@@ -0,0 +1,30 @@
+## testExisting_automation
+
+**Description:** bla bla
+
+**Folder:** my automations/
+
+**Started by:** Schedule
+
+**Status:** PausedSchedule
+
+**Schedule:**
+
+* Start: 2022-07-30 00:00:00 +01:00
+* End: 2022-07-30 00:00:00 +01:00
+* Timezone:  W. Europe Standard Time
+* Recurrance: every  day for 1 times
+
+**Notifications:**
+
+* Complete: complete@test.accenture.com
+* Error: error@test.accenture.com ("test")
+
+| Step 1<br>_<small>-</small>_ |
+| --- |
+| _1.1: dataExtract_<br>testExisting_dataExtract |
+| _1.2: emailSend_<br>testExisting_emailSend |
+| _1.3: fileTransfer_<br>testExisting_fileTransfer |
+| _1.4: importFile_<br>testExisting_importFile |
+| _1.5: query_<br>testExisting_query |
+| _1.6: script_<br>testExisting_script |
diff --git a/test/resources/9999999/automation/template-expected.json b/test/resources/9999999/automation/template-expected.json
new file mode 100644
index 00000000..038ecc7f
--- /dev/null
+++ b/test/resources/9999999/automation/template-expected.json
@@ -0,0 +1,58 @@
+{
+    "description": "{{{description}}}",
+    "key": "{{{prefix}}}automation",
+    "name": "{{{prefix}}}automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "{{{prefix}}}dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "{{{prefix}}}emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "{{{prefix}}}fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "{{{prefix}}}importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "{{{prefix}}}query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "{{{prefix}}}script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "type": "scheduled",
+    "notifications": [
+        {
+            "email": ["complete@test.accenture.com"],
+            "message": "",
+            "type": "Complete"
+        },
+        {
+            "email": ["error@test.accenture.com"],
+            "message": "test",
+            "type": "Error"
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/update-expected.json b/test/resources/9999999/automation/update-expected.json
new file mode 100644
index 00000000..47860e94
--- /dev/null
+++ b/test/resources/9999999/automation/update-expected.json
@@ -0,0 +1,46 @@
+{
+    "description": "updated on deploy",
+    "key": "testExisting_automation",
+    "name": "testExisting_automation",
+    "r__folder_Path": "my automations",
+    "schedule": {
+        "endDate": "2022-07-30T00:00:00",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "startDate": "2022-07-30T00:00:00",
+        "timezoneName": "W. Europe Standard Time",
+        "typeId": 3
+    },
+    "status": "PausedSchedule",
+    "steps": [
+        {
+            "activities": [
+                {
+                    "name": "testExisting_dataExtract",
+                    "r__type": "dataExtract"
+                },
+                {
+                    "name": "testExisting_emailSend",
+                    "r__type": "emailSend"
+                },
+                {
+                    "name": "testExisting_fileTransfer",
+                    "r__type": "fileTransfer"
+                },
+                {
+                    "name": "testExisting_importFile",
+                    "r__type": "importFile"
+                },
+                {
+                    "name": "testExisting_query",
+                    "r__type": "query"
+                },
+                {
+                    "name": "testExisting_script",
+                    "r__type": "script"
+                }
+            ],
+            "name": ""
+        }
+    ],
+    "type": "scheduled"
+}
diff --git a/test/resources/9999999/automation/update-testExisting_automation-expected.md b/test/resources/9999999/automation/update-testExisting_automation-expected.md
new file mode 100644
index 00000000..681c2a69
--- /dev/null
+++ b/test/resources/9999999/automation/update-testExisting_automation-expected.md
@@ -0,0 +1,28 @@
+## testExisting_automation
+
+**Description:** updated on deploy
+
+**Folder:** my automations/
+
+**Started by:** Schedule
+
+**Status:** PausedSchedule
+
+**Schedule:**
+
+* Start: 2022-07-30 00:00:00 +01:00
+* End: 2022-07-30 00:00:00 +01:00
+* Timezone:  W. Europe Standard Time
+* Recurrance: every  day for 1 times
+
+**Notifications:** _none_
+
+
+| Step 1<br>_<small>-</small>_ |
+| --- |
+| _1.1: dataExtract_<br>testExisting_dataExtract |
+| _1.2: emailSend_<br>testExisting_emailSend |
+| _1.3: fileTransfer_<br>testExisting_fileTransfer |
+| _1.4: importFile_<br>testExisting_importFile |
+| _1.5: query_<br>testExisting_query |
+| _1.6: script_<br>testExisting_script |
diff --git a/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json b/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
new file mode 100644
index 00000000..5d86c87b
--- /dev/null
+++ b/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
@@ -0,0 +1,85 @@
+{
+    "id": "08afb0e2-b00a-4c88-ad2e-1f7f8788c560",
+    "name": "testExisting_automation",
+    "description": "bla bla",
+    "key": "testExisting_automation",
+    "typeId": 1,
+    "type": "scheduled",
+    "statusId": 4,
+    "status": "PausedSchedule",
+    "categoryId": 290937,
+    "schedule": {
+        "id": "b393aa6c-a4a8-4c0f-a148-9250258a7339",
+        "typeId": 3,
+        "startDate": "2022-07-30T00:00:00",
+        "endDate": "2022-07-30T00:00:00",
+        "scheduledTime": "0001-01-01T07:00:00",
+        "rangeTypeId": 0,
+        "occurrences": 1,
+        "pattern": "<Pattern><PatternType>0</PatternType><DayInterval>1</DayInterval></Pattern>",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "timezoneName": "W. Europe Standard Time",
+        "scheduleStatus": "paused",
+        "timezoneId": 5
+    },
+    "steps": [
+        {
+            "id": "13fda077-0e82-4936-b936-a36b0997fc44",
+            "name": "",
+            "step": 1,
+            "activities": [
+                {
+                    "id": "8081a992-a27d-4a43-984a-d60114ea1025",
+                    "name": "testExisting_dataExtract",
+                    "activityObjectId": "56c5370a-f988-4f36-b0ee-0f876573f6d7",
+                    "objectTypeId": 73,
+                    "displayOrder": 1
+                },
+                {
+                    "id": "d3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_emailSend",
+                    "activityObjectId": "9b1c7bf9-4964-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 42,
+                    "displayOrder": 2
+                },
+                {
+                    "id": "2c77fc42-85eb-4611-98f9-223d29d89d72",
+                    "name": "testExisting_fileTransfer",
+                    "activityObjectId": "72c328ac-f5b0-4e37-91d3-a775666f15a6",
+                    "objectTypeId": 53,
+                    "displayOrder": 3
+                },
+                {
+                    "id": "298b2794-28cb-4c70-b7ad-58b2c8cf48f7",
+                    "name": "testExisting_importFile",
+                    "activityObjectId": "9d16f42c-2260-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 43,
+                    "displayOrder": 4,
+                    "targetDataExtensions": [
+                        {
+                            "id": "21711373-72c1-ec11-b83b-48df37d1deb7",
+                            "name": "testExisting_dataExtension",
+                            "key": "testExisting_dataExtension",
+                            "description": "bla bla",
+                            "rowCount": 0
+                        }
+                    ]
+                },
+                {
+                    "id": "e3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_query_WRONG_NAME",
+                    "activityObjectId": "549f0568-607c-4940-afef-437965094dat",
+                    "objectTypeId": 300,
+                    "displayOrder": 5
+                },
+                {
+                    "id": "g3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_script",
+                    "activityObjectId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
+                    "objectTypeId": 423,
+                    "displayOrder": 6
+                }
+            ]
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/patch-response.json b/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/patch-response.json
new file mode 100644
index 00000000..1c0dc1b0
--- /dev/null
+++ b/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/patch-response.json
@@ -0,0 +1,85 @@
+{
+    "legacyId": "RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow",
+    "name": "testExisting_automation",
+    "description": "updated on deploy",
+    "key": "testExisting_automation",
+    "typeId": 1,
+    "type": "scheduled",
+    "statusId": 4,
+    "status": "PausedSchedule",
+    "schedule": {
+        "id": "b393aa6c-a4a8-4c0f-a148-9250258a7339",
+        "typeId": 3,
+        "startDate": "2022-07-30T00:00:00",
+        "endDate": "2022-07-30T00:00:00",
+        "scheduledTime": "0001-01-01T07:00:00",
+        "rangeTypeId": 0,
+        "occurrences": 1,
+        "pattern": "<Pattern><PatternType>0</PatternType><DayInterval>1</DayInterval></Pattern>",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "timezoneName": "W. Europe Standard Time",
+        "scheduleStatus": "paused",
+        "timezoneId": 5
+    },
+    "steps": [
+        {
+            "activities": [
+                {
+                    "id": "8081a992-a27d-4a43-984a-d60114ea1025",
+                    "name": "testExisting_dataExtract",
+                    "activityObjectId": "56c5370a-f988-4f36-b0ee-0f876573f6d7",
+                    "objectTypeId": 73,
+                    "displayOrder": 1
+                },
+                {
+                    "id": "d3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_emailSend",
+                    "activityObjectId": "9b1c7bf9-4964-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 42,
+                    "displayOrder": 2
+                },
+                {
+                    "id": "2c77fc42-85eb-4611-98f9-223d29d89d72",
+                    "name": "testExisting_fileTransfer",
+                    "activityObjectId": "72c328ac-f5b0-4e37-91d3-a775666f15a6",
+                    "objectTypeId": 53,
+                    "displayOrder": 3
+                },
+                {
+                    "id": "298b2794-28cb-4c70-b7ad-58b2c8cf48f7",
+                    "name": "testExisting_importFile",
+                    "activityObjectId": "9d16f42c-2260-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 43,
+                    "displayOrder": 4,
+                    "targetDataExtensions": [
+                        {
+                            "id": "21711373-72c1-ec11-b83b-48df37d1deb7",
+                            "name": "testExisting_dataExtension",
+                            "key": "testExisting_dataExtension",
+                            "description": "bla bla",
+                            "rowCount": 0
+                        }
+                    ]
+                },
+                {
+                    "id": "e3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_query_WRONG_NAME",
+                    "activityObjectId": "549f0568-607c-4940-afef-437965094dat",
+                    "objectTypeId": 300,
+                    "displayOrder": 5
+                },
+                {
+                    "id": "g3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_script",
+                    "activityObjectId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
+                    "objectTypeId": 423,
+                    "displayOrder": 6
+                }
+            ],
+            "annotation": "",
+            "stepNumber": 0
+        }
+    ],
+    "categoryId": 290937,
+    "id": "08afb0e2-b00a-4c88-ad2e-1f7f8788c560"
+}
diff --git a/test/resources/9999999/automation/v1/automations/a8afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json b/test/resources/9999999/automation/v1/automations/a8afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
new file mode 100644
index 00000000..b58d358f
--- /dev/null
+++ b/test/resources/9999999/automation/v1/automations/a8afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
@@ -0,0 +1,85 @@
+{
+    "id": "a8afb0e2-b00a-4c88-ad2e-1f7f8788c560",
+    "name": "testNew_automation",
+    "description": "created on deploy",
+    "key": "testNew_automation",
+    "typeId": 1,
+    "type": "scheduled",
+    "statusId": 4,
+    "status": "PausedSchedule",
+    "categoryId": 290937,
+    "schedule": {
+        "id": "b393aa6c-a4a8-4c0f-a148-9250258a7339",
+        "typeId": 3,
+        "startDate": "2022-07-30T00:00:00",
+        "endDate": "2022-07-30T00:00:00",
+        "scheduledTime": "0001-01-01T07:00:00",
+        "rangeTypeId": 0,
+        "occurrences": 1,
+        "pattern": "<Pattern><PatternType>0</PatternType><DayInterval>1</DayInterval></Pattern>",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "timezoneName": "W. Europe Standard Time",
+        "scheduleStatus": "paused",
+        "timezoneId": 5
+    },
+    "steps": [
+        {
+            "id": "13fda077-0e82-4936-b936-a36b0997fc44",
+            "name": "",
+            "step": 1,
+            "activities": [
+                {
+                    "id": "8081a992-a27d-4a43-984a-d60114ea1025",
+                    "name": "testExisting_dataExtract",
+                    "activityObjectId": "56c5370a-f988-4f36-b0ee-0f876573f6d7",
+                    "objectTypeId": 73,
+                    "displayOrder": 1
+                },
+                {
+                    "id": "d3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_emailSend",
+                    "activityObjectId": "9b1c7bf9-4964-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 42,
+                    "displayOrder": 2
+                },
+                {
+                    "id": "2c77fc42-85eb-4611-98f9-223d29d89d72",
+                    "name": "testExisting_fileTransfer",
+                    "activityObjectId": "72c328ac-f5b0-4e37-91d3-a775666f15a6",
+                    "objectTypeId": 53,
+                    "displayOrder": 3
+                },
+                {
+                    "id": "298b2794-28cb-4c70-b7ad-58b2c8cf48f7",
+                    "name": "testExisting_importFile",
+                    "activityObjectId": "9d16f42c-2260-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 43,
+                    "displayOrder": 4,
+                    "targetDataExtensions": [
+                        {
+                            "id": "21711373-72c1-ec11-b83b-48df37d1deb7",
+                            "name": "testExisting_dataExtension",
+                            "key": "testExisting_dataExtension",
+                            "description": "bla bla",
+                            "rowCount": 0
+                        }
+                    ]
+                },
+                {
+                    "id": "e3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_query_WRONG_NAME",
+                    "activityObjectId": "549f0568-607c-4940-afef-437965094dat",
+                    "objectTypeId": 300,
+                    "displayOrder": 5
+                },
+                {
+                    "id": "g3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_script",
+                    "activityObjectId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
+                    "objectTypeId": 423,
+                    "displayOrder": 6
+                }
+            ]
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/v1/automations/post-response.json b/test/resources/9999999/automation/v1/automations/post-response.json
new file mode 100644
index 00000000..6f82ef7c
--- /dev/null
+++ b/test/resources/9999999/automation/v1/automations/post-response.json
@@ -0,0 +1,85 @@
+{
+    "legacyId": "NewRkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow",
+    "name": "testNew_automation",
+    "description": "created on deploy",
+    "key": "testNew_automation",
+    "typeId": 1,
+    "type": "scheduled",
+    "statusId": 4,
+    "status": "PausedSchedule",
+    "schedule": {
+        "id": "b393aa6c-a4a8-4c0f-a148-9250258a7339",
+        "typeId": 3,
+        "startDate": "2022-07-30T00:00:00",
+        "endDate": "2022-07-30T00:00:00",
+        "scheduledTime": "0001-01-01T07:00:00",
+        "rangeTypeId": 0,
+        "occurrences": 1,
+        "pattern": "<Pattern><PatternType>0</PatternType><DayInterval>1</DayInterval></Pattern>",
+        "icalRecur": "FREQ=DAILY;COUNT=1;INTERVAL=1",
+        "timezoneName": "W. Europe Standard Time",
+        "scheduleStatus": "paused",
+        "timezoneId": 5
+    },
+    "steps": [
+        {
+            "activities": [
+                {
+                    "id": "8081a992-a27d-4a43-984a-d60114ea1025",
+                    "name": "testExisting_dataExtract",
+                    "activityObjectId": "56c5370a-f988-4f36-b0ee-0f876573f6d7",
+                    "objectTypeId": 73,
+                    "displayOrder": 1
+                },
+                {
+                    "id": "d3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_emailSend",
+                    "activityObjectId": "9b1c7bf9-4964-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 42,
+                    "displayOrder": 2
+                },
+                {
+                    "id": "2c77fc42-85eb-4611-98f9-223d29d89d72",
+                    "name": "testExisting_fileTransfer",
+                    "activityObjectId": "72c328ac-f5b0-4e37-91d3-a775666f15a6",
+                    "objectTypeId": 53,
+                    "displayOrder": 3
+                },
+                {
+                    "id": "298b2794-28cb-4c70-b7ad-58b2c8cf48f7",
+                    "name": "testExisting_importFile",
+                    "activityObjectId": "9d16f42c-2260-ed11-b849-48df37d1de8b",
+                    "objectTypeId": 43,
+                    "displayOrder": 4,
+                    "targetDataExtensions": [
+                        {
+                            "id": "21711373-72c1-ec11-b83b-48df37d1deb7",
+                            "name": "testExisting_dataExtension",
+                            "key": "testExisting_dataExtension",
+                            "description": "bla bla",
+                            "rowCount": 0
+                        }
+                    ]
+                },
+                {
+                    "id": "e3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_query_WRONG_NAME",
+                    "activityObjectId": "549f0568-607c-4940-afef-437965094dat",
+                    "objectTypeId": 300,
+                    "displayOrder": 5
+                },
+                {
+                    "id": "g3774dc2-a271-4a44-8cbe-f630a6d6545e",
+                    "name": "testExisting_script",
+                    "activityObjectId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
+                    "objectTypeId": 423,
+                    "displayOrder": 6
+                }
+            ],
+            "annotation": "",
+            "stepNumber": 0
+        }
+    ],
+    "categoryId": 290937,
+    "id": "a8afb0e2-b00a-4c88-ad2e-1f7f8788c560"
+}
diff --git a/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/get-response.json b/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/get-response.json
new file mode 100644
index 00000000..70564f61
--- /dev/null
+++ b/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/get-response.json
@@ -0,0 +1,38 @@
+{
+    "dataExtractDefinitionId": "56c5370a-f988-4f36-b0ee-0f876573f6d7",
+    "name": "testExisting_dataExtract",
+    "key": "testExisting_dataExtract",
+    "description": "blabla",
+    "dataExtractTypeId": "bb94a04d-9632-4623-be47-daabc3f588a6",
+    "fileSpec": "testExisting-%%Year%%-%%Month%%-%%Day%%",
+    "createdBy": 700301950,
+    "modifiedBy": 700301950,
+    "intervalType": 0,
+    "dataFields": [
+        {
+            "name": "ColumnDelimiter",
+            "type": "string",
+            "value": ","
+        },
+        {
+            "name": "DECustomerKey",
+            "type": "string",
+            "value": "testExisting_dataExtension"
+        },
+        {
+            "name": "HasColumnHeaders",
+            "type": "bool",
+            "value": "False"
+        },
+        {
+            "name": "TextQualified",
+            "type": "bool",
+            "value": "False"
+        },
+        {
+            "name": "UsesLineFeed",
+            "type": "bool",
+            "value": "False"
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/v1/dataextracts/get-response.json b/test/resources/9999999/automation/v1/dataextracts/get-response.json
new file mode 100644
index 00000000..462a6979
--- /dev/null
+++ b/test/resources/9999999/automation/v1/dataextracts/get-response.json
@@ -0,0 +1,20 @@
+{
+    "count": 1,
+    "page": 1,
+    "pageSize": 500,
+    "items": [
+        {
+            "dataExtractDefinitionId": "56c5370a-f988-4f36-b0ee-0f876573f6d7",
+            "name": "testExisting_dataExtract",
+            "key": "testExisting_dataExtract",
+            "description": "bla bla",
+            "dataExtractTypeId": "bb94a04d-9632-4623-be47-daabc3f588a6",
+            "fileSpec": "testExisting-%%Year%%-%%Month%%-%%Day%%",
+            "createdDate": "2022-11-09T05:31:21.667",
+            "modifiedDate": "2022-11-17T07:13:36.9",
+            "createdBy": 700301950,
+            "modifiedBy": 700301950,
+            "intervalType": 0
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/get-response.json b/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/get-response.json
new file mode 100644
index 00000000..4775efdc
--- /dev/null
+++ b/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/get-response.json
@@ -0,0 +1,18 @@
+{
+    "id": "72c328ac-f5b0-4e37-91d3-a775666f15a6",
+    "name": "testExisting_fileTransfer",
+    "description": "17.11.2022",
+    "customerKey": "testExisting_fileTransfer",
+    "fileSpec": "%%Year%%",
+    "isEncrypted": false,
+    "isCompressed": false,
+    "maxFileAge": 0,
+    "maxFileAgeScheduleOffset": 0,
+    "maxImportFrequency": 0,
+    "fileTransferLocationId": "41a5ded7-0d98-4910-a15f-d09e7ab0af24",
+    "isUpload": true,
+    "isPgp": false,
+    "isFileSpecLocalized": false,
+    "createdDate": "2022-11-09T05:31:56.477",
+    "modifiedDate": "2022-11-17T07:13:20.05"
+}
diff --git a/test/resources/9999999/automation/v1/filetransfers/get-response.json b/test/resources/9999999/automation/v1/filetransfers/get-response.json
new file mode 100644
index 00000000..1a925b68
--- /dev/null
+++ b/test/resources/9999999/automation/v1/filetransfers/get-response.json
@@ -0,0 +1,15 @@
+{
+    "page": 1,
+    "pageSize": 500,
+    "count": 1,
+    "items": [
+        {
+            "id": "72c328ac-f5b0-4e37-91d3-a775666f15a6",
+            "name": "testExisting_fileTransfer",
+            "description": "17.11.2022",
+            "customerKey": "testExisting_fileTransfer",
+            "createdDate": "2022-11-09T05:31:56.477",
+            "modifiedDate": "2022-11-17T07:13:20.05"
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/v1/imports/get-response.json b/test/resources/9999999/automation/v1/imports/get-response.json
new file mode 100644
index 00000000..d58fc438
--- /dev/null
+++ b/test/resources/9999999/automation/v1/imports/get-response.json
@@ -0,0 +1,38 @@
+{
+    "page": 1,
+    "pageSize": 500,
+    "count": 1,
+    "items": [
+        {
+            "allowErrors": true,
+            "customerKey": "testExisting_importFile",
+            "createdDate": "2022-11-09T05:32:30.533",
+            "modifiedDate": "2022-11-17T07:13:03.95",
+            "dateFormatLocale": "en-US",
+            "deleteFile": false,
+            "description": "17.11.2022",
+            "destinationObjectId": "bf457cfa-ca04-ec11-b82d-48df37d1da95",
+            "destinationId": 0,
+            "destinationObjectTypeId": 310,
+            "fieldMappings": [],
+            "fieldMappingType": "InferFromColumnHeadings",
+            "fileNamingPattern": "blabla",
+            "fileTransferLocationId": "41a5ded7-0d98-4910-a15f-d09e7ab0af24",
+            "fileType": "CSV",
+            "filter": "",
+            "hasColumnHeader": true,
+            "importDefinitionId": "9d16f42c-2260-ed11-b849-48df37d1de8b",
+            "isOrderedImport": true,
+            "isSequential": true,
+            "maxFileAgeHours": 0,
+            "maxImportFrequencyHours": 0,
+            "maxFileAgeScheduleOffsetHours": 0,
+            "name": "testExisting_importFile",
+            "sendEmailNotification": false,
+            "standardQuotedStrings": true,
+            "subscriberImportTypeId": 255,
+            "updateTypeId": 0,
+            "fileTransferLocationTypeId": 0
+        }
+    ]
+}
diff --git a/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/actions/start/post-response.txt b/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/actions/start/post-response.txt
new file mode 100644
index 00000000..a0aba931
--- /dev/null
+++ b/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/actions/start/post-response.txt
@@ -0,0 +1,1 @@
+OK
\ No newline at end of file
diff --git a/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json b/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json
index bc8651c2..9144d0e0 100644
--- a/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json
+++ b/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json
@@ -1,7 +1,7 @@
 {
     "queryDefinitionId": "549f0568-607c-4940-afef-437965094dat",
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "testExisting_query",
+    "key": "testExisting_query",
     "description": "bla bla",
     "queryText": "SELECT\n    SubscriberKey as testField\nFROM\n    _Subscribers\nWHERE\n    country IN ('test')\n",
     "targetName": "testExisting_dataExtension",
diff --git a/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json b/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json
index a647f711..6414f11d 100644
--- a/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json
+++ b/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json
@@ -1,7 +1,7 @@
 {
     "queryDefinitionId": "549f0568-607c-4940-afef-437965094dat",
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "testExisting_query",
+    "key": "testExisting_query",
     "description": "updated on deploy",
     "queryText": "SELECT\n    SubscriberKey as testField\nFROM\n    _Subscribers\nWHERE\n    country IN ('test')\n",
     "targetName": "testExisting_dataExtension",
diff --git a/test/resources/9999999/automation/v1/queries/get-response.json b/test/resources/9999999/automation/v1/queries/get-response.json
index 13d3ba1f..4a7b047e 100644
--- a/test/resources/9999999/automation/v1/queries/get-response.json
+++ b/test/resources/9999999/automation/v1/queries/get-response.json
@@ -5,8 +5,8 @@
     "items": [
         {
             "queryDefinitionId": "549f0568-607c-4940-afef-437965094dat",
-            "name": "testExistingQuery",
-            "key": "testExistingQuery",
+            "name": "testExisting_query",
+            "key": "testExisting_query",
             "description": "bla bla",
             "queryText": "SELECT\n    SubscriberKey as testField\nFROM\n    _Subscribers\nWHERE\n    country IN ('test')\n",
             "targetName": "testExisting_dataExtension",
@@ -22,8 +22,8 @@
         },
         {
             "queryDefinitionId": "abcde-607c-4940-afef-437965094dat",
-            "name": "testExistingQuery2",
-            "key": "testExistingQuery2",
+            "name": "testExisting_query2",
+            "key": "testExisting_query2",
             "description": "bla bla",
             "queryText": "SELECT\n    SubscriberKey as testField\nFROM\n    _Subscribers\nWHERE\n    country IN ('test')\n",
             "targetName": "testExisting_dataExtension",
diff --git a/test/resources/9999999/automation/v1/queries/post-response.json b/test/resources/9999999/automation/v1/queries/post-response.json
index f858e8e3..e809ffc3 100644
--- a/test/resources/9999999/automation/v1/queries/post-response.json
+++ b/test/resources/9999999/automation/v1/queries/post-response.json
@@ -1,7 +1,7 @@
 {
     "queryDefinitionId": "549f0568-607c-4940-afef-437965094dae",
-    "name": "testNewQuery",
-    "key": "testNewQuery",
+    "name": "testNew_query",
+    "key": "testNew_query",
     "description": "created on deploy",
     "queryText": "SELECT\n    SubscriberKey as testField\nFROM\n    _Subscribers\n",
     "targetName": "testExisting_dataExtension",
diff --git a/test/resources/9999999/automation/v1/scripts/get-response.json b/test/resources/9999999/automation/v1/scripts/get-response.json
new file mode 100644
index 00000000..d5830148
--- /dev/null
+++ b/test/resources/9999999/automation/v1/scripts/get-response.json
@@ -0,0 +1,17 @@
+{
+    "count": 1,
+    "page": 1,
+    "pageSize": 500,
+    "items": [
+        {
+            "ssjsActivityId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
+            "name": "testExisting_script",
+            "key": "testExisting_script",
+            "description": "",
+            "script": "<script runat=\"server\">\n//dummy\n</script",
+            "categoryId": 290828,
+            "createdDate": "2022-10-20T00:41:26.163",
+            "modifiedDate": "2022-10-20T00:41:26.163"
+        }
+    ]
+}
diff --git a/test/resources/9999999/dataFolder/retrieve-ContentType=automations-response.xml b/test/resources/9999999/dataFolder/retrieve-ContentType=automations-response.xml
new file mode 100644
index 00000000..99565999
--- /dev/null
+++ b/test/resources/9999999/dataFolder/retrieve-ContentType=automations-response.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:f36f3303-3b5a-4641-8109-b26447634d91</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:33983968-28c4-4379-bb5f-f80ae32eb988</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-32ecc81b-6020-473c-9e99-4b5338921220">
+                <wsu:Created>2022-04-19T20:03:41Z</wsu:Created>
+                <wsu:Expires>2022-04-19T20:08:41Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>02cd5ccb-8f84-4651-826f-71169eeecf05</RequestID>
+            <Results xsi:type="DataFolder">
+                <Client>
+                    <ID>9999999</ID>
+                </Client>
+                <PartnerKey xsi:nil="true" />
+                <CreatedDate>2019-10-25T05:35:17.337</CreatedDate>
+                <ModifiedDate>2019-10-25T05:35:17.337</ModifiedDate>
+                <ID>290937</ID>
+                <ObjectID xsi:nil="true" />
+                <CustomerKey />
+                <ParentFolder>
+                    <PartnerKey xsi:nil="true" />
+                    <ID>0</ID>
+                    <ObjectID xsi:nil="true" />
+                </ParentFolder>
+                <Name>my automations</Name>
+                <Description />
+                <ContentType>automations</ContentType>
+                <IsActive>true</IsActive>
+                <IsEditable>true</IsEditable>
+                <AllowChildren>true</AllowChildren>
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
diff --git a/test/resources/9999999/dataFolder/retrieve-ContentType=queryactivity-response.xml b/test/resources/9999999/dataFolder/retrieve-ContentType=queryactivity-response.xml
new file mode 100644
index 00000000..668f4711
--- /dev/null
+++ b/test/resources/9999999/dataFolder/retrieve-ContentType=queryactivity-response.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:f36f3303-3b5a-4641-8109-b26447634d91</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:33983968-28c4-4379-bb5f-f80ae32eb988</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-32ecc81b-6020-473c-9e99-4b5338921220">
+                <wsu:Created>2022-04-19T20:03:41Z</wsu:Created>
+                <wsu:Expires>2022-04-19T20:08:41Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>02cd5ccb-8f84-4651-826f-71169eeecf05</RequestID>
+            <Results xsi:type="DataFolder">
+                <Client>
+                    <ID>9999999</ID>
+                </Client>
+                <PartnerKey xsi:nil="true" />
+                <CreatedDate>2016-07-22T11:52:20.407</CreatedDate>
+                <ModifiedDate>2016-07-22T11:52:20.407</ModifiedDate>
+                <ID>999</ID>
+                <ObjectID xsi:nil="true" />
+                <CustomerKey>queryactivity_default</CustomerKey>
+                <ParentFolder>
+                    <PartnerKey xsi:nil="true" />
+                    <ID>0</ID>
+                    <ObjectID xsi:nil="true" />
+                </ParentFolder>
+                <Name>Query</Name>
+                <Description />
+                <ContentType>queryactivity</ContentType>
+                <IsActive>true</IsActive>
+                <IsEditable>false</IsEditable>
+                <AllowChildren>true</AllowChildren>
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
diff --git a/test/resources/9999999/dataFolder/retrieve-response.xml b/test/resources/9999999/dataFolder/retrieve-response.xml
index e0ba6d20..29b1d38a 100644
--- a/test/resources/9999999/dataFolder/retrieve-response.xml
+++ b/test/resources/9999999/dataFolder/retrieve-response.xml
@@ -175,6 +175,28 @@
                 <IsEditable>false</IsEditable>
                 <AllowChildren>true</AllowChildren>
             </Results>
+            <Results xsi:type="DataFolder">
+                <Client>
+                    <ID>9999999</ID>
+                </Client>
+                <PartnerKey xsi:nil="true" />
+                <CreatedDate>2019-10-25T05:35:17.337</CreatedDate>
+                <ModifiedDate>2019-10-25T05:35:17.337</ModifiedDate>
+                <ID>290937</ID>
+                <ObjectID xsi:nil="true" />
+                <CustomerKey />
+                <ParentFolder>
+                    <PartnerKey xsi:nil="true" />
+                    <ID>0</ID>
+                    <ObjectID xsi:nil="true" />
+                </ParentFolder>
+                <Name>my automations</Name>
+                <Description />
+                <ContentType>automations</ContentType>
+                <IsActive>true</IsActive>
+                <IsEditable>true</IsEditable>
+                <AllowChildren>true</AllowChildren>
+            </Results>
         </RetrieveResponseMsg>
     </soap:Body>
 </soap:Envelope>
diff --git a/test/resources/9999999/emailSendDefinition/retrieve-response.xml b/test/resources/9999999/emailSendDefinition/retrieve-response.xml
new file mode 100644
index 00000000..88e1614f
--- /dev/null
+++ b/test/resources/9999999/emailSendDefinition/retrieve-response.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:e0ba7da7-7e82-42db-a166-42a488ac375b</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:17a3f405-6bd8-4b30-9230-44fea1749b96</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-96902d78-e86f-4361-855e-c37e2e3b4b58">
+                <wsu:Created>2023-06-01T12:04:17Z</wsu:Created>
+                <wsu:Expires>2023-06-01T12:09:17Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>687d0584-acbe-4bac-bfc2-4c41b73b5a32</RequestID>
+            <Results xsi:type="EmailSendDefinition">
+                <PartnerKey xsi:nil="true" />
+                <CreatedDate>2022-11-14T12:27:29.963</CreatedDate>
+                <ModifiedDate>2022-11-14T12:27:29.963</ModifiedDate>
+                <ObjectID>9b1c7bf9-4964-ed11-b849-48df37d1de8b</ObjectID>
+                <CustomerKey>testExisting_emailSend</CustomerKey>
+                <IsPlatformObject>false</IsPlatformObject>
+                <Name>testExisting_emailSend</Name>
+                <Description>some description</Description>
+                <CategoryID>290820</CategoryID>
+                <SendClassification>
+                    <PartnerKey xsi:nil="true" />
+                    <ObjectID xsi:nil="true" />
+                    <CustomerKey>test_send_classification</CustomerKey>
+                </SendClassification>
+                <SenderProfile>
+                    <PartnerKey xsi:nil="true" />
+                    <ObjectID xsi:nil="true" />
+                    <CustomerKey>Test_sender</CustomerKey>
+                </SenderProfile>
+                <DeliveryProfile>
+                    <PartnerKey xsi:nil="true" />
+                    <ObjectID xsi:nil="true" />
+                    <CustomerKey>Default</CustomerKey>
+                </DeliveryProfile>
+                <SuppressTracking>false</SuppressTracking>
+                <IsSendLogging>false</IsSendLogging>
+                <SendDefinitionList>
+                    <PartnerKey xsi:nil="true" />
+                    <ObjectID>9d1c7bf9-4964-ed11-b849-48df37d1de8b</ObjectID>
+                    <List>
+                        <PartnerKey xsi:nil="true" />
+                        <ID>32308</ID>
+                        <ObjectID xsi:nil="true" />
+                    </List>
+                    <SendDefinitionListType>SourceList</SendDefinitionListType>
+                    <CustomObjectID>2c19d707-743e-ed11-b848-48df37b24911</CustomObjectID>
+                    <DataSourceTypeID>CustomObject</DataSourceTypeID>
+                    <IsTestObject>false</IsTestObject>
+                    <SalesForceObjectID />
+                    <Name />
+                </SendDefinitionList>
+                <Email>
+                    <PartnerKey xsi:nil="true" />
+                    <ID>676709</ID>
+                    <ObjectID xsi:nil="true" />
+                </Email>
+                <BccEmail />
+                <AutoBccEmail />
+                <TestEmailAddr />
+                <EmailSubject>someSubject</EmailSubject>
+                <DynamicEmailSubject>someSubject</DynamicEmailSubject>
+                <IsMultipart>true</IsMultipart>
+                <IsWrapped>true</IsWrapped>
+                <DeduplicateByEmail>false</DeduplicateByEmail>
+                <ExclusionFilter />
+                <Additional />
+                <CCEmail />
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
\ No newline at end of file
diff --git a/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json b/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json
new file mode 100644
index 00000000..02c3b73d
--- /dev/null
+++ b/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/get-response.json
@@ -0,0 +1,21 @@
+{
+    "programId": "ZGQ4N2M2ZjEtYjJlZi00MDljLTg3MDctYzYwNWQ0MzdiYWI4OjI1OjA",
+    "workers": [
+        {
+            "programId": "ZGQ4N2M2ZjEtYjJlZi00MDljLTg3MDctYzYwNWQ0MzdiYWI4OjI1OjA",
+            "id": "YjA2NmVlODEtODllOS00NTE4LTkwYzYtMTY4Mzg2ZTk3MGE4OjEyOjA",
+            "notificationType": "Complete",
+            "definition": "complete@test.accenture.com",
+            "body": "",
+            "channelType": "Account"
+        },
+        {
+            "programId": "ZGQ4N2M2ZjEtYjJlZi00MDljLTg3MDctYzYwNWQ0MzdiYWI4OjI1OjA",
+            "id": "NGIzZGQ5N2EtMDI0ZS00MzFiLTg5ZWYtNTdjYTI4ODVjMjQ0OjEyOjA",
+            "notificationType": "Error",
+            "definition": "error@test.accenture.com",
+            "body": "test",
+            "channelType": "Account"
+        }
+    ]
+}
diff --git a/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/post-response.json b/test/resources/9999999/legacy/v1/beta/automations/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow/post-response.json
new file mode 100644
index 00000000..e69de29b
diff --git a/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json b/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json
new file mode 100644
index 00000000..bbf38898
--- /dev/null
+++ b/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json
@@ -0,0 +1,30 @@
+{
+    "startIndex": 0,
+    "itemsPerPage": 50,
+    "totalResults": 1,
+    "entry": [
+        {
+            "id": "RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoyNTow",
+            "key": "testExisting_automation",
+            "createdDate": "2022-01-12T08:41:35.773Z",
+            "name": "testExisting_automation",
+            "description": "bla bla",
+            "clientId": 9999999,
+            "status": "Building",
+            "createdBy": {
+                "id": "NzE3MzUzNDA1OjQ6MA",
+                "name": "Tom Tester",
+                "email": "tom.tester@accenture.com"
+            },
+            "modifiedDate": "2022-11-11T16:42:36.513Z",
+            "modifiedBy": {
+                "id": "NzE3MzUzNDA1OjQ6MA",
+                "name": "Tom Tester",
+                "email": "tom.tester@accenture.com"
+            },
+            "isPlatformObject": false,
+            "notifications": "https://mcxxxxx.rest.marketingcloudapis.com/legacy/v1/beta/hub/notifications/RkpOcE9qSVh2VUdnYTVJbWFfWW14dzoxMjow",
+            "automationType": "scheduled"
+        }
+    ]
+}
diff --git a/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation-response.xml b/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation-response.xml
new file mode 100644
index 00000000..16ba379b
--- /dev/null
+++ b/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation-response.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:60a72d4a-847e-4d9b-a4eb-a42951078298</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:0b59ed53-72ec-4481-ae06-4ee78912aef2</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-f95f3fd3-c763-4e2c-929f-33611e9d2eba">
+                <wsu:Created>2023-06-01T12:04:20Z</wsu:Created>
+                <wsu:Expires>2023-06-01T12:09:20Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>3b1c8cee-b270-49cb-b77b-e7b33934d1b6</RequestID>
+            <Results xsi:type="Program">
+                <PartnerKey xsi:nil="true" />
+                <ObjectID>08afb0e2-b00a-4c88-ad2e-1f7f8788c560</ObjectID>
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
\ No newline at end of file
diff --git a/test/resources/9999999/program/retrieve-CustomerKey=testNew_automation-response.xml b/test/resources/9999999/program/retrieve-CustomerKey=testNew_automation-response.xml
new file mode 100644
index 00000000..db925e14
--- /dev/null
+++ b/test/resources/9999999/program/retrieve-CustomerKey=testNew_automation-response.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:60a72d4a-847e-4d9b-a4eb-a42951078298</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:0b59ed53-72ec-4481-ae06-4ee78912aef2</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-f95f3fd3-c763-4e2c-929f-33611e9d2eba">
+                <wsu:Created>2023-06-01T12:04:20Z</wsu:Created>
+                <wsu:Expires>2023-06-01T12:09:20Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>3b1c8cee-b270-49cb-b77b-e7b33934d1b6</RequestID>
+            <Results xsi:type="Program">
+                <PartnerKey xsi:nil="true" />
+                <ObjectID>a8afb0e2-b00a-4c88-ad2e-1f7f8788c560</ObjectID>
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
\ No newline at end of file
diff --git a/test/resources/9999999/program/retrieve-Name=testExisting_automation-response.xml b/test/resources/9999999/program/retrieve-Name=testExisting_automation-response.xml
new file mode 100644
index 00000000..6d1b57ef
--- /dev/null
+++ b/test/resources/9999999/program/retrieve-Name=testExisting_automation-response.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:60a72d4a-847e-4d9b-a4eb-a42951078298</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:0b59ed53-72ec-4481-ae06-4ee78912aef2</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-f95f3fd3-c763-4e2c-929f-33611e9d2eba">
+                <wsu:Created>2023-06-01T12:04:20Z</wsu:Created>
+                <wsu:Expires>2023-06-01T12:09:20Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>3b1c8cee-b270-49cb-b77b-e7b33934d1b6</RequestID>
+            <Results xsi:type="Program">
+                <PartnerKey xsi:nil="true" />
+                <ObjectID>08afb0e2-b00a-4c88-ad2e-1f7f8788c560</ObjectID>
+                <Name>testExisting_automation</Name>
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
\ No newline at end of file
diff --git a/test/resources/9999999/program/retrieve-response.xml b/test/resources/9999999/program/retrieve-response.xml
new file mode 100644
index 00000000..67ede778
--- /dev/null
+++ b/test/resources/9999999/program/retrieve-response.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
+    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+    <soap:Header>
+        <wsa:Action>RetrieveResponse</wsa:Action>
+        <wsa:MessageID>urn:uuid:60a72d4a-847e-4d9b-a4eb-a42951078298</wsa:MessageID>
+        <wsa:RelatesTo>urn:uuid:0b59ed53-72ec-4481-ae06-4ee78912aef2</wsa:RelatesTo>
+        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
+        <wsse:Security>
+            <wsu:Timestamp wsu:Id="Timestamp-f95f3fd3-c763-4e2c-929f-33611e9d2eba">
+                <wsu:Created>2023-06-01T12:04:20Z</wsu:Created>
+                <wsu:Expires>2023-06-01T12:09:20Z</wsu:Expires>
+            </wsu:Timestamp>
+        </wsse:Security>
+    </soap:Header>
+    <soap:Body>
+        <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
+            <OverallStatus>OK</OverallStatus>
+            <RequestID>3b1c8cee-b270-49cb-b77b-e7b33934d1b6</RequestID>
+            <Results xsi:type="Program">
+                <PartnerKey xsi:nil="true" />
+                <ObjectID>08afb0e2-b00a-4c88-ad2e-1f7f8788c560</ObjectID>
+                <Name>testExisting_automation</Name><!--only retrieved for cache-->
+                <CustomerKey>testExisting_automation</CustomerKey><!--only retrieved for cache-->
+            </Results>
+        </RetrieveResponseMsg>
+    </soap:Body>
+</soap:Envelope>
\ No newline at end of file
diff --git a/test/resources/9999999/query/build-expected.json b/test/resources/9999999/query/build-expected.json
index c430bfb3..a7df6726 100644
--- a/test/resources/9999999/query/build-expected.json
+++ b/test/resources/9999999/query/build-expected.json
@@ -1,6 +1,6 @@
 {
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "testTemplated_query",
+    "key": "testTemplated_query",
     "description": "foobar",
     "targetKey": "testTemplated_dataExtension",
     "targetUpdateTypeName": "Overwrite",
diff --git a/test/resources/9999999/query/get-expected.json b/test/resources/9999999/query/get-expected.json
index 09e6c5ee..4cd60671 100644
--- a/test/resources/9999999/query/get-expected.json
+++ b/test/resources/9999999/query/get-expected.json
@@ -1,6 +1,6 @@
 {
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "testExisting_query",
+    "key": "testExisting_query",
     "description": "bla bla",
     "targetKey": "testExisting_dataExtension",
     "createdDate": "2022-04-26T15:21:16.453",
diff --git a/test/resources/9999999/query/get2-expected.json b/test/resources/9999999/query/get2-expected.json
index 0467c817..5e3955fa 100644
--- a/test/resources/9999999/query/get2-expected.json
+++ b/test/resources/9999999/query/get2-expected.json
@@ -1,6 +1,6 @@
 {
-    "name": "testExistingQuery2",
-    "key": "testExistingQuery2",
+    "name": "testExisting_query2",
+    "key": "testExisting_query2",
     "description": "bla bla",
     "targetKey": "testExisting_dataExtension",
     "createdDate": "2022-04-26T15:21:16.453",
diff --git a/test/resources/9999999/query/patch-expected.json b/test/resources/9999999/query/patch-expected.json
index 72ba5f15..421e918e 100644
--- a/test/resources/9999999/query/patch-expected.json
+++ b/test/resources/9999999/query/patch-expected.json
@@ -1,6 +1,6 @@
 {
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "testExisting_query",
+    "key": "testExisting_query",
     "description": "updated on deploy",
     "targetKey": "testExisting_dataExtension",
     "createdDate": "2022-04-26T15:21:16.453",
diff --git a/test/resources/9999999/query/post-expected.json b/test/resources/9999999/query/post-expected.json
index b2fc695a..7e4bdc09 100644
--- a/test/resources/9999999/query/post-expected.json
+++ b/test/resources/9999999/query/post-expected.json
@@ -1,6 +1,6 @@
 {
-    "name": "testNewQuery",
-    "key": "testNewQuery",
+    "name": "testNew_query",
+    "key": "testNew_query",
     "description": "created on deploy",
     "targetKey": "testExisting_dataExtension",
     "createdDate": "2022-04-26T15:21:16.453",
diff --git a/test/resources/9999999/query/template-expected.json b/test/resources/9999999/query/template-expected.json
index f1e53580..9f9bd280 100644
--- a/test/resources/9999999/query/template-expected.json
+++ b/test/resources/9999999/query/template-expected.json
@@ -1,6 +1,6 @@
 {
-    "name": "testExistingQuery",
-    "key": "testExistingQuery",
+    "name": "{{{prefix}}}query",
+    "key": "{{{prefix}}}query",
     "description": "{{{description}}}",
     "targetKey": "{{{prefix}}}dataExtension",
     "targetUpdateTypeName": "Overwrite",
diff --git a/test/type.automation.test.js b/test/type.automation.test.js
new file mode 100644
index 00000000..5f9dd60b
--- /dev/null
+++ b/test/type.automation.test.js
@@ -0,0 +1,259 @@
+const chai = require('chai');
+const chaiFiles = require('chai-files');
+
+chai.use(chaiFiles);
+
+const assert = chai.assert;
+const expect = chai.expect;
+const file = chaiFiles.file;
+const cache = require('../lib/util/cache');
+const testUtils = require('./utils');
+const handler = require('../lib/index');
+
+describe('type: automation', () => {
+    beforeEach(() => {
+        testUtils.mockSetup();
+    });
+    afterEach(() => {
+        testUtils.mockReset();
+    });
+    describe('Retrieve ================', () => {
+        it('Should retrieve a automation', async () => {
+            // WHEN
+            await handler.retrieve('testInstance/testBU', ['automation']);
+            // THEN
+            assert.equal(process.exitCode, false, 'retrieve should not have thrown an error');
+            // get results from cache
+            const result = cache.getCache();
+            assert.equal(
+                result.automation ? Object.keys(result.automation).length : 0,
+                1,
+                'only one automation expected'
+            );
+            assert.deepEqual(
+                await testUtils.getActualJson('testExisting_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'retrieve'),
+
+                'returned metadata was not equal expected'
+            );
+            // check if MD file was created and equals expectations
+            expect(file(testUtils.getActualDoc('testExisting_automation', 'automation'))).to.equal(
+                file(
+                    testUtils.getExpectedFile(
+                        '9999999',
+                        'automation',
+                        'retrieve-testExisting_automation',
+                        'md'
+                    )
+                )
+            );
+
+            assert.equal(
+                testUtils.getAPIHistoryLength(),
+                14,
+                'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+            );
+            return;
+        });
+    });
+    describe('Deploy ================', () => {
+        beforeEach(() => {
+            testUtils.mockSetup(true);
+        });
+        it('Should create & update a automation', async () => {
+            // WHEN
+            await handler.deploy('testInstance/testBU', ['automation']);
+            // THEN
+            assert.equal(process.exitCode, false, 'deploy should not have thrown an error');
+
+            // get results from cache
+            const result = cache.getCache();
+            assert.equal(
+                result.automation ? Object.keys(result.automation).length : 0,
+                2,
+                'two automations expected'
+            );
+            // insert
+            assert.deepEqual(
+                await testUtils.getActualJson('testNew_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'create'),
+                'returned metadata was not equal expected for create'
+            );
+            // update
+            assert.deepEqual(
+                await testUtils.getActualJson('testExisting_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'update'),
+                'returned metadata was not equal expected for update'
+            );
+            // check if MD file was created and equals expectations
+            expect(file(testUtils.getActualDoc('testExisting_automation', 'automation'))).to.equal(
+                file(
+                    testUtils.getExpectedFile(
+                        '9999999',
+                        'automation',
+                        'update-testExisting_automation',
+                        'md'
+                    )
+                )
+            );
+
+            // check if MD file was created and equals expectations
+            expect(file(testUtils.getActualDoc('testNew_automation', 'automation'))).to.equal(
+                file(
+                    testUtils.getExpectedFile(
+                        '9999999',
+                        'automation',
+                        'create-testNew_automation',
+                        'md'
+                    )
+                )
+            );
+
+            assert.equal(
+                testUtils.getAPIHistoryLength(),
+                15,
+                'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+            );
+            return;
+        });
+        it('Should change the key during update via --changeKeyValue');
+    });
+    describe('Templating ================', () => {
+        it('Should create a automation template via retrieveAsTemplate and build it', async () => {
+            // GIVEN there is a template
+            const result = await handler.retrieveAsTemplate(
+                'testInstance/testBU',
+                'automation',
+                ['testExisting_automation'],
+                'testSourceMarket'
+            );
+            assert.equal(
+                process.exitCode,
+                false,
+                'retrieveAsTemplate should not have thrown an error'
+            );
+
+            // WHEN
+            assert.equal(
+                result.automation ? Object.keys(result.automation).length : 0,
+                1,
+                'only one automation expected'
+            );
+            assert.deepEqual(
+                await testUtils.getActualTemplateJson('testExisting_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'template'),
+                'returned template was not equal expected'
+            );
+            // THEN
+            await handler.buildDefinition(
+                'testInstance/testBU',
+                'automation',
+                'testExisting_automation',
+                'testTargetMarket'
+            );
+            assert.equal(
+                process.exitCode,
+                false,
+                'buildDefinition should not have thrown an error'
+            );
+            assert.deepEqual(
+                await testUtils.getActualDeployJson('testTemplated_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'build'),
+                'returned deployment file was not equal expected'
+            );
+            assert.equal(
+                testUtils.getAPIHistoryLength(),
+                14,
+                'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+            );
+            return;
+        });
+        it('Should create a automation template via buildTemplate and build it', async () => {
+            // download first before we test buildTemplate
+            await handler.retrieve('testInstance/testBU', ['automation']);
+            // GIVEN there is a template
+            const result = await handler.buildTemplate(
+                'testInstance/testBU',
+                'automation',
+                ['testExisting_automation'],
+                'testSourceMarket'
+            );
+            assert.equal(process.exitCode, false, 'buildTemplate should not have thrown an error');
+            // WHEN
+            assert.equal(
+                result.automation ? Object.keys(result.automation).length : 0,
+                1,
+                'only one automation expected'
+            );
+            assert.deepEqual(
+                await testUtils.getActualTemplateJson('testExisting_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'template'),
+                'returned template was not equal expected'
+            );
+            // THEN
+            await handler.buildDefinition(
+                'testInstance/testBU',
+                'automation',
+                'testExisting_automation',
+                'testTargetMarket'
+            );
+            assert.equal(
+                process.exitCode,
+                false,
+                'buildDefinition should not have thrown an error'
+            );
+
+            assert.deepEqual(
+                await testUtils.getActualDeployJson('testTemplated_automation', 'automation'),
+                await testUtils.getExpectedJson('9999999', 'automation', 'build'),
+                'returned deployment file was not equal expected'
+            );
+            assert.equal(
+                testUtils.getAPIHistoryLength(),
+                14,
+                'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+            );
+            return;
+        });
+    });
+    describe('Delete ================', () => {
+        it('Should delete the item', async () => {
+            // WHEN
+            const result = await handler.deleteByKey('testInstance/testBU', 'automation', [
+                'testExisting_automation',
+            ]);
+            // THEN
+            assert.equal(process.exitCode, false, 'delete should not have thrown an error');
+
+            assert.equal(result, true, 'should have deleted the item');
+            return;
+        });
+    });
+    describe('CI/CD ================', () => {
+        it('Should return a list of files based on their type and key', async () => {
+            // WHEN
+            const fileList = await handler.getFilesToCommit('testInstance/testBU', 'automation', [
+                'testExisting_automation',
+            ]);
+            // THEN
+            assert.equal(
+                process.exitCode,
+                false,
+                'getFilesToCommit should not have thrown an error'
+            );
+            assert.equal(fileList.length, 2, 'expected only 2 file paths');
+
+            assert.equal(
+                fileList[0].split('\\').join('/'),
+                'retrieve/testInstance/testBU/automation/testExisting_automation.automation-meta.json',
+                'wrong JSON path'
+            );
+            assert.equal(
+                fileList[1].split('\\').join('/'),
+                'retrieve/testInstance/testBU/automation/testExisting_automation.automation-doc.md',
+                'wrong MD path'
+            );
+            return;
+        });
+    });
+});
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index 968a0d16..d1a06837 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -1,5 +1,8 @@
 const chai = require('chai');
 const chaiFiles = require('chai-files');
+
+chai.use(chaiFiles);
+
 const assert = chai.assert;
 const expect = chai.expect;
 const file = chaiFiles.file;
diff --git a/test/type.query.test.js b/test/type.query.test.js
index b64890ff..edaf7216 100644
--- a/test/type.query.test.js
+++ b/test/type.query.test.js
@@ -32,16 +32,16 @@ describe('type: query', () => {
             );
             // normal test
             assert.deepEqual(
-                await testUtils.getActualJson('testExistingQuery', 'query'),
+                await testUtils.getActualJson('testExisting_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'get'),
                 'returned metadata with correct key was not equal expected'
             );
-            expect(file(testUtils.getActualFile('testExistingQuery', 'query', 'sql'))).to.equal(
+            expect(file(testUtils.getActualFile('testExisting_query', 'query', 'sql'))).to.equal(
                 file(testUtils.getExpectedFile('9999999', 'query', 'get', 'sql'))
             );
             // check if targetKey was overwritten
             assert.deepEqual(
-                await testUtils.getActualJson('testExistingQuery2', 'query'),
+                await testUtils.getActualJson('testExisting_query2', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'get2'),
                 'returned metadata with wrong key was not equal expected'
             );
@@ -55,7 +55,7 @@ describe('type: query', () => {
         });
         it('Should retrieve one specific query', async () => {
             // WHEN
-            await handler.retrieve('testInstance/testBU', ['query'], ['testExistingQuery']);
+            await handler.retrieve('testInstance/testBU', ['query'], ['testExisting_query']);
             // THEN
             assert.equal(process.exitCode, false, 'retrieve should not have thrown an error');
             // get results from cache
@@ -66,11 +66,11 @@ describe('type: query', () => {
                 'only one query expected'
             );
             assert.deepEqual(
-                await testUtils.getActualJson('testExistingQuery', 'query'),
+                await testUtils.getActualJson('testExisting_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'get'),
                 'returned metadata was not equal expected'
             );
-            expect(file(testUtils.getActualFile('testExistingQuery', 'query', 'sql'))).to.equal(
+            expect(file(testUtils.getActualFile('testExisting_query', 'query', 'sql'))).to.equal(
                 file(testUtils.getExpectedFile('9999999', 'query', 'get', 'sql'))
             );
             assert.equal(
@@ -99,20 +99,20 @@ describe('type: query', () => {
             );
             // confirm created item
             assert.deepEqual(
-                await testUtils.getActualJson('testNewQuery', 'query'),
+                await testUtils.getActualJson('testNew_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'post'),
                 'returned metadata was not equal expected for insert query'
             );
-            expect(file(testUtils.getActualFile('testNewQuery', 'query', 'sql'))).to.equal(
+            expect(file(testUtils.getActualFile('testNew_query', 'query', 'sql'))).to.equal(
                 file(testUtils.getExpectedFile('9999999', 'query', 'post', 'sql'))
             );
             // confirm updated item
             assert.deepEqual(
-                await testUtils.getActualJson('testExistingQuery', 'query'),
+                await testUtils.getActualJson('testExisting_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'patch'),
                 'returned metadata was not equal expected for insert query'
             );
-            expect(file(testUtils.getActualFile('testExistingQuery', 'query', 'sql'))).to.equal(
+            expect(file(testUtils.getActualFile('testExisting_query', 'query', 'sql'))).to.equal(
                 file(testUtils.getExpectedFile('9999999', 'query', 'patch', 'sql'))
             );
             // check number of API calls
@@ -131,7 +131,7 @@ describe('type: query', () => {
             const result = await handler.retrieveAsTemplate(
                 'testInstance/testBU',
                 'query',
-                ['testExistingQuery'],
+                ['testExisting_query'],
                 'testSourceMarket'
             );
             // WHEN
@@ -146,18 +146,18 @@ describe('type: query', () => {
                 'only one query expected'
             );
             assert.deepEqual(
-                await testUtils.getActualTemplateJson('testExistingQuery', 'query'),
+                await testUtils.getActualTemplateJson('testExisting_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'template'),
                 'returned template JSON of retrieveAsTemplate was not equal expected'
             );
             expect(
-                file(testUtils.getActualTemplateFile('testExistingQuery', 'query', 'sql'))
+                file(testUtils.getActualTemplateFile('testExisting_query', 'query', 'sql'))
             ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'template', 'sql')));
             // THEN
             await handler.buildDefinition(
                 'testInstance/testBU',
                 'query',
-                'testExistingQuery',
+                'testExisting_query',
                 'testTargetMarket'
             );
             assert.equal(
@@ -167,13 +167,14 @@ describe('type: query', () => {
             );
 
             assert.deepEqual(
-                await testUtils.getActualDeployJson('testExistingQuery', 'query'),
+                await testUtils.getActualDeployJson('testTemplated_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'build'),
                 'returned deployment JSON was not equal expected'
             );
             expect(
-                file(testUtils.getActualDeployFile('testExistingQuery', 'query', 'sql'))
+                file(testUtils.getActualDeployFile('testTemplated_query', 'query', 'sql'))
             ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'build', 'sql')));
+
             assert.equal(
                 testUtils.getAPIHistoryLength(),
                 6,
@@ -188,7 +189,7 @@ describe('type: query', () => {
             const result = await handler.buildTemplate(
                 'testInstance/testBU',
                 'query',
-                ['testExistingQuery'],
+                ['testExisting_query'],
                 'testSourceMarket'
             );
             // WHEN
@@ -200,18 +201,18 @@ describe('type: query', () => {
                 'only one query expected'
             );
             assert.deepEqual(
-                await testUtils.getActualTemplateJson('testExistingQuery', 'query'),
+                await testUtils.getActualTemplateJson('testExisting_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'template'),
                 'returned template JSON of buildTemplate was not equal expected'
             );
             expect(
-                file(testUtils.getActualTemplateFile('testExistingQuery', 'query', 'sql'))
+                file(testUtils.getActualTemplateFile('testExisting_query', 'query', 'sql'))
             ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'template', 'sql')));
             // THEN
             await handler.buildDefinition(
                 'testInstance/testBU',
                 'query',
-                'testExistingQuery',
+                'testExisting_query',
                 'testTargetMarket'
             );
             assert.equal(
@@ -221,12 +222,12 @@ describe('type: query', () => {
             );
 
             assert.deepEqual(
-                await testUtils.getActualDeployJson('testExistingQuery', 'query'),
+                await testUtils.getActualDeployJson('testTemplated_query', 'query'),
                 await testUtils.getExpectedJson('9999999', 'query', 'build'),
                 'returned deployment JSON was not equal expected'
             );
             expect(
-                file(testUtils.getActualDeployFile('testExistingQuery', 'query', 'sql'))
+                file(testUtils.getActualDeployFile('testTemplated_query', 'query', 'sql'))
             ).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'build', 'sql')));
 
             assert.equal(
@@ -241,7 +242,7 @@ describe('type: query', () => {
         it('Should delete the item', async () => {
             // WHEN
             const result = await handler.deleteByKey('testInstance/testBU', 'query', [
-                'testExistingQuery',
+                'testExisting_query',
             ]);
             // THEN
             assert.equal(process.exitCode, false, 'delete should not have thrown an error');
@@ -254,7 +255,7 @@ describe('type: query', () => {
         it('Should return a list of files based on their type and key', async () => {
             // WHEN
             const fileList = await handler.getFilesToCommit('testInstance/testBU', 'query', [
-                'testExistingQuery',
+                'testExisting_query',
             ]);
             // THEN
             assert.equal(
@@ -266,15 +267,27 @@ describe('type: query', () => {
 
             assert.equal(
                 fileList[0].split('\\').join('/'),
-                'retrieve/testInstance/testBU/query/testExistingQuery.query-meta.json',
+                'retrieve/testInstance/testBU/query/testExisting_query.query-meta.json',
                 'wrong JSON path'
             );
             assert.equal(
                 fileList[1].split('\\').join('/'),
-                'retrieve/testInstance/testBU/query/testExistingQuery.query-meta.sql',
+                'retrieve/testInstance/testBU/query/testExisting_query.query-meta.sql',
                 'wrong JSON path'
             );
             return;
         });
     });
+    describe('Execute ================', () => {
+        it('Should start executing a query', async () => {
+            const execute = await handler.execute(
+                'testInstance/testBU',
+                ['query'],
+                ['testExisting_query']
+            );
+            assert.equal(process.exitCode, false, 'execute should not have thrown an error');
+            assert.equal(execute, true, 'query was supposed to be executed');
+            return;
+        });
+    });
 });
diff --git a/test/type.user.test.js b/test/type.user.test.js
index 697c5a5f..cb56fe09 100644
--- a/test/type.user.test.js
+++ b/test/type.user.test.js
@@ -7,6 +7,7 @@ const file = chaiFiles.file;
 const cache = require('../lib/util/cache');
 const testUtils = require('./utils');
 const handler = require('../lib/index');
+const File = require('../lib/util/file');
 
 describe('type: user', () => {
     beforeEach(() => {
@@ -35,9 +36,22 @@ describe('type: user', () => {
                 'returned metadata was not equal expected'
             );
             // check if MD file was created and equals expectations
-            expect(file(`./docs/user/testInstance.users.md`)).to.equal(
-                file(testUtils.getExpectedFile('1111111', 'user', 'retrieve', 'md'))
-            );
+            // ! this test needs to update the lastLoginDate counter because it changes with every passing day
+            const expectedFile = await File.readFile(
+                testUtils.getExpectedFile('1111111', 'user', 'retrieve', 'md'),
+                { encoding: 'utf8' }
+            );
+            const regexFindDaysSinceLogin =
+                /\| (\d*) (seconds|minutes|days|weeks|months|years){1} \|/gm;
+            // fetch expected time since last login
+            const expectedDaysSinceLogin = expectedFile.match(regexFindDaysSinceLogin);
+            // load actual file and replace days since last login with expected value
+            const actualFile = (
+                await File.readFile(`./docs/user/testInstance.users.md`, {
+                    encoding: 'utf8',
+                })
+            ).replaceAll(regexFindDaysSinceLogin, expectedDaysSinceLogin);
+            expect(actualFile).to.equal(expectedFile);
 
             assert.equal(
                 testUtils.getAPIHistoryLength(),
diff --git a/test/utils.js b/test/utils.js
index 6f0a628e..ded3e431 100644
--- a/test/utils.js
+++ b/test/utils.js
@@ -4,6 +4,7 @@ const axios = require('axios');
 const MockAdapter = require('axios-mock-adapter');
 const auth = require('../lib/util/auth');
 const Util = require('../lib/util/util');
+const handler = require('../lib/index');
 
 // for some reason doesnt realize below reference
 // eslint-disable-next-line no-unused-vars
@@ -28,7 +29,7 @@ exports.getActualJson = (customerKey, type, buName = 'testBU') =>
  * @param {string} customerKey of metadata
  * @param {string} type of metadata
  * @param {string} [buName] used when we need to test on ParentBU
- * @returns {Promise.<string>} file in string form
+ * @returns {string} file path
  */
 exports.getActualDoc = (customerKey, type, buName = 'testBU') =>
     `./retrieve/testInstance/${buName}/${type}/${customerKey}.${type}-doc.md`;
@@ -38,7 +39,7 @@ exports.getActualDoc = (customerKey, type, buName = 'testBU') =>
  * @param {string} customerKey of metadata
  * @param {string} type of metadata
  * @param {string} ext file extension
- * @returns {Promise.<string>} file in string form
+ * @returns {string} file path
  */
 exports.getActualFile = (customerKey, type, ext) =>
     `./retrieve/testInstance/testBU/${type}/${customerKey}.${type}-meta.${ext}`;
@@ -58,7 +59,7 @@ exports.getActualDeployJson = (customerKey, type, buName = 'testBU') =>
  * @param {string} customerKey of metadata
  * @param {string} type of metadata
  * @param {string} ext file extension
- * @returns {Promise.<string>} file in string form
+ * @returns {string} file path
  */
 exports.getActualDeployFile = (customerKey, type, ext) =>
     `./deploy/testInstance/testBU/${type}/${customerKey}.${type}-meta.${ext}`;
@@ -77,7 +78,7 @@ exports.getActualTemplateJson = (customerKey, type) =>
  * @param {string} customerKey of metadata
  * @param {string} type of metadata
  * @param {string} ext file extension
- * @returns {Promise.<string>} file in string form
+ * @returns {string} file path
  */
 exports.getActualTemplateFile = (customerKey, type, ext) =>
     `./template/${type}/${customerKey}.${type}-meta.${ext}`;
@@ -99,7 +100,7 @@ exports.getExpectedJson = (mid, type, action) =>
  * @param {string} type of metadata
  * @param {string} action of SOAP request
  * @param {string} ext file extension
- * @returns {Promise.<string>} file in string form
+ * @returns {string} file path
  */
 exports.getExpectedFile = (mid, type, action, ext) =>
     path.join('test', 'resources', mid, type, action + '-expected.' + ext);
@@ -111,7 +112,7 @@ exports.getExpectedFile = (mid, type, action, ext) =>
  */
 
 exports.mockSetup = (isDeploy) => {
-    Util.setLoggingLevel({ debug: true });
+    handler.setOptions({ debug: true, noLogFile: true });
     apimock = new MockAdapter(axios, { onNoMatch: 'throwException' });
     // set access_token to mid to allow for autorouting of mock to correct resources
     apimock.onPost(authResources.success.url).reply((config) => {