# A360 Bot Package Version Audit Report
This process produces an audit spreadsheet showing, for every automation ("bot") in a chosen Control Room folder — or for a specific list of bots — which reusable code libraries ("packages") each bot depends on, which version of each package the bot is locked to, which version the Control Room currently treats as default, and which version ships as standard in A360 v24. Each line is flagged with whether action is required before a v24 upgrade. The output is a single Excel workbook plus a timestamped log, both written to an operator-supplied output folder. The report exists to support upgrade planning: it identifies bots pinned to package versions that differ from the v24 baseline.
## At a glance
| | |
|---|---|
| **Trigger** | Manual, parameterised run. The operator supplies the Control Room URL, credentials/API key, output folder, and *either* a folder ID *or* a list of bot IDs. No schedule or work-queue feed appears anywhere in the source. |
| **Frequency** | Not recorded in the source |
| **Systems used** | Automation Anywhere Control Room REST API; Microsoft Excel; a Python helper script (`BotPackagesReportLogicV2.py`); a plain-text log file |
| **Inputs** | `iStr3_CRURL` (Control Room base URL), `iStr4_CRUserName`, `iStr5_APIKey`, `iStr1_PublicFolderIDs`, `iStr2_PublicBotIDs` (comma-separated), `iStr6_OuputFolderPath`; reference workbook `v24PackagesList.xlsx` |
| **Outputs** | `<output folder>\BotPackagesReport.xlsx` (sheet **BotPackagesReport**); `<output folder>\botPackagesReportLogs.log`; an on-screen message box on invalid input or failure |
| **Typical run** | Not recorded in the source (no volume or duration figures) |
| **Owner** | Not recorded in the source |
## Before you start
- **Control Room access.** A Control Room user name and API key with rights to read the bot repository (`/v2/repository/files/...`) and to query package versions (`/v2/packages/package/version/list`). The automation defaults its authentication type to `BASIC`; a separate sub-automation (referred to in the error text as the "GetToken Subbot") exchanges these credentials for a session token.
- **Decide the scope before launching.** You must supply exactly one of: a public folder ID, or a comma-separated list of bot IDs. Supplying both, or neither, aborts the run immediately.
- **Reference workbook in place.** `v24PackagesList.xlsx` must exist in the Control Room repository at `Automation Anywhere/Bots/SIKHA/BotPackagesReport/`. It holds the A360 v24 baseline: package name in the first column, and the v24 default version in the third column. The automation reads it with a header row and reads every row.
- **Report template in place.** `BotPackagesReport.xlsx` must exist at the same repository location and contain a worksheet named `BotPackagesReport`. It is opened for editing and written from cell A1.
- **Python helper in place.** `BotPackagesReportLogicV2.py` at the same repository location. It provides `getAllTaskBotsByFolderID` (enumerates bots under a folder) and `compare_versions` (produces the ActionRequired verdict). Python 3 must be available to the running machine.
- **Output folder must exist and be writable.** Both the report and the log are written there, and any existing `BotPackagesReport.xlsx` in that folder will be overwritten without prompting.
- **Excel must be available** on the machine — the automation opens and saves workbooks through Microsoft Excel, not through a file-only library.
- **Interactive session.** Failures and invalid input are surfaced as message boxes that wait for a human to dismiss them, so the run should be attended.
## Procedure
### Stage 1 — Validate the scope you were given
1. Check the folder ID and the bot ID list.
2. **If both are empty, then**: display a message box titled *Automation Anywhere Enterprise Client* reading "Please provide either PublicFolderID or PublicBotIDs", append `Both PublicFolderID and PublicBotIDs values are empty.` to `<output folder>\botPackagesReportLogs.log`, and stop the run.
3. **If both are populated, then**: display the same message box, append `Both PublicFolderID and PublicBotIDs have values` to the log, and stop the run.
4. Otherwise continue. Every log entry throughout the run is appended with a timestamp; nothing is overwritten.
### Stage 2 — Set up the report layout in memory
1. Build the header row for the results table with these seven columns, in this order:
| Column | Meaning |
|---|---|
| BotID | Control Room internal ID of the bot |
| BotPath | Repository path of the bot |
| PackageName | Name of the package the bot depends on |
| Bot-PackageVersion | Version the bot is pinned to |
| CR-Default-PackageVersion | Version this Control Room currently treats as default |
| A360-v24-Default-PackageVersion | Version that ships as standard in v24 (from the baseline workbook) |
| ActionRequired | Verdict from the version comparison |
2. Insert that header row as the first row of the results table.
3. Build a second, two-column table (`packagename`, `crdefaultpackageversion`) with a header row. This acts as a running cache: once the Control Room's default version for a package has been looked up, it is remembered so the same package is never queried twice in one run.
### Stage 3 — Load the A360 v24 baseline
1. Open `repository:///Automation Anywhere/Bots/SIKHA/BotPackagesReport/v24PackagesList.xlsx` in Excel, for editing, treating the first row as headers.
2. Read **all** rows, as displayed text, into memory.
3. Close the workbook (saving). No changes are intentionally made to this file — it is a read-only reference in practice.
### Stage 4 — Get a Control Room session token
1. Run the token sub-automation. The developer's note at this point reads: *"Generate an auth token and fetch the bot files. Each request will retrieve 100 bots."*
2. **If the returned token text contains the word `Error`, then** raise a failure with the message `Eroor from GetToken Subbot : <returned text>`. This is caught by the run-level handler in Stage 10, which still writes out whatever has been collected.
*Ambiguity: the outline does not name the sub-automation, its endpoint, or whether it uses the API key or a password. Treat the token step as a black box that returns either a token or text containing "Error".*
### Stage 5 — Build the list of bots to inspect
**If a folder ID was supplied, then:**
1. Assemble the inputs for the Python helper, in this order: folder ID, Control Room URL, session token, output folder path.
2. Log `BEFORE THE PYTHON SCRIPT CALL.`
3. Load `repository:///Automation Anywhere/Bots/SIKHA/BotPackagesReport/BotPackagesReportLogicV2.py` and call its `getAllTaskBotsByFolderID` function with those inputs.
4. Log `AFTER THE PYTHON SCRIPT CALL.`
5. Convert the Python-style `True`/`False` literals in the returned text to their JSON equivalents so the result can be parsed, then read the `list` node. Each entry in that list carries a bot's `id`, `name` and `path`.
**If a bot ID list was supplied, then:**
1. Split the supplied string on commas to produce the list of bot IDs to process.
Finally, log `BEFORE BOT Loop`.
### Stage 6 — For each bot: establish its identity
Repeat Stages 6 to 9 for every entry in the list built above.
1. **If working from a folder ID, then** read the bot's `id`, `name` and `path` straight from the list entry, and log `Started Processing BotID : <id>`.
2. **If working from a bot ID list, then** the entry *is* the bot ID. Log `Started Processing BotID : <id>`, then call `GET <CRURL>/v2/repository/files/<botId>` and read `name` and `path` from the response.
3. **If that call fails, then** re-run the token sub-automation (the failure is treated as an expired session), check the new token for `Error` as in Stage 4, and retry the same call once.
### Stage 7 — For each bot: read its package dependencies
1. Call `GET <CRURL>/v2/repository/files/<botId>/content`.
2. **If the call fails, then** refresh the token as in Stage 6 step 3 and retry once.
3. From the returned bot definition, read the `packages` node — the list of packages the bot depends on, each with a `name` and a `version`.
*Note: a developer comment immediately above this step reads "Check if the bot contains endpoints (v1/Authentication or v1/Authentication/token or v1/usermanagement)". No such check exists in the steps; this comment appears to be left over from a different automation and should be ignored.*
### Stage 8 — For each package: gather the three versions
Repeat for every package in the current bot. Each package is processed inside its own error boundary, so one bad package does not stop the bot or the run.
1. Log the raw package detail: `BotID : <botId> : Package details : <raw package JSON>`.
2. Read the package `name` and `version`.
3. Record the bot ID, bot path and package name into the working row.
4. **v24 baseline lookup** — search the baseline table loaded in Stage 3 for the package name, **case-sensitive**.
- **If found, then** take the matched row number and read the v24 default version from the **third** column of that row.
- **If not found, then** log `ERROR : Unable to retrive Package details from v24packages list` together with the package name and version, and leave the v24 version at its reset value `0.0.0`.
5. **Control Room default lookup** — search the cache table from Stage 2 for the package name, **case-insensitive**.
- **If found, then** log `Found the this package details in default datatable.` and read the cached default version.
- **If not found, then** log `unable to find the this package details in default datatable . so calling API.` and call `POST <CRURL>/v2/packages/package/version/list` (JSON request). Read the `list` node from the response and take `packageVersion` from its **first** entry. Add the package name and that version to the cache so it is not queried again.
- **If the POST fails, then** refresh the token as in Stage 6 step 3 and retry once.
*Ambiguity: the outline does not show the body sent to `/v2/packages/package/version/list`, nor how the session token is attached (the call is configured with no built-in authentication, implying a header set elsewhere).*
### Stage 9 — For each package: decide whether action is required, and record the row
1. Write the v24 default version into the working row.
2. Normalise the bot's package version: split it on `-` and keep the part before the hyphen (so a build suffix is discarded).
3. Call the Python helper's `compare_versions` function with two values in this order: the normalised bot package version, then the v24 default version. The value it returns becomes **ActionRequired** for this row. The variable's initial value is `No`.
4. Write the bot package version, the Control Room default version and ActionRequired into the working row, and append the completed row to the bottom of the results table.
5. Reset the v24 version holder to `0.0.0` and clear the per-package working lists, so nothing leaks into the next package.
6. **If anything in this stage or Stage 8 fails for this package, then** log `ERROR: while processing Bot : <botId> . : <message> at line number: <line>` and move on to the next package. The row for that package will be missing from the report — the log is the only record.
### Stage 10 — Publish the report
1. Log `AFTER THE BOT LOOP`.
2. Run a final Python step. *The outline names no function for it; its purpose is unclear — most plausibly closing down the Python session.*
3. Open `repository:///Automation Anywhere/Bots/SIKHA/BotPackagesReport/BotPackagesReport.xlsx` in Excel for editing.
4. Write the entire results table to the worksheet named `BotPackagesReport`, starting at cell **A1**.
5. Save the workbook as `<output folder>\BotPackagesReport.xlsx`, overwriting any file already there.
6. Close the workbook.
The whole run from Stage 1 to Stage 10 sits inside a run-level error boundary. If anything not otherwise handled goes wrong, the automation still performs steps 3–6 above, so the report always contains everything collected up to the point of failure. The developer's note is explicit: *"write excel from datatable action inside the catch block as well, to write the current datatable content incase of error hanpppened."*
## Exceptions and recovery
| Condition | What the automation does | What a human should do |
|---|---|---|
| Both folder ID and bot ID list empty | Message box "Please provide either PublicFolderID or PublicBotIDs"; logs `Both PublicFolderID and PublicBotIDs values are empty.`; stops | Re-launch with exactly one scope parameter filled in |
| Both folder ID and bot ID list supplied | Same message box; logs `Both PublicFolderID and PublicBotIDs have values`; stops | Clear one of the two parameters and re-launch |
| Token sub-automation returns text containing `Error` | Raises `Eroor from GetToken Subbot : <text>`; caught at run level, so a partial report is still written and a message box is shown | Check the Control Room URL, user name and API key, and that the account is not locked or expired; then re-run |
| A repository call fails — `GET /v2/repository/files/<botId>` (bot details) or `GET /v2/repository/files/<botId>/content` (bot content) | Re-runs the token sub-automation, verifies the new token, and retries the same call **once**. A second failure is not caught locally, so it escalates to the run-level handler: the run stops after writing the rows collected so far | Check Control Room availability and the log, then re-run. Treat the saved workbook as partial |
| `POST /v2/packages/package/version/list` (Control Room default package version) fails | Re-runs the token sub-automation, verifies the new token, and retries the same call **once**. A second failure is absorbed by the per-package handler: it is logged as `ERROR: while processing Bot : <botId> . : <message> at line number: <line>` and processing continues with the next package — only that one package's row is lost, the run does not stop | Review the log for skipped packages and re-run for the affected bots if those rows matter |
| Package name not present in `v24PackagesList.xlsx` | Logs `ERROR : Unable to retrive Package details from v24packages list` with the package name and version; the row is still written but with `0.0.0` as the v24 version | Treat any `0.0.0` in the A360-v24-Default-PackageVersion column as "no baseline on file", not as a real version. Add the missing package to the baseline workbook and re-run if the row matters. Note the lookup is case-sensitive, so a casing mismatch will also cause this |
| Error while processing one package inside a bot | Logs `ERROR: while processing Bot : <botId> . : <message> at line number: <line>` and continues with the next package | Review the log after the run for skipped packages; those bots' reports are incomplete |
| Any other unhandled error in the run | Logs `outer: <message> <line number>`, writes the rows collected so far to sheet `BotPackagesReport`, saves `BotPackagesReport.xlsx` to the output folder, then shows the error in a message box | Dismiss the message box, read the log, fix the cause, and re-run. Treat the saved workbook as partial — verify the bot count before circulating it |
## Data handled
| Item | Holds | Source |
|---|---|---|
| `iStr3_CRURL` | Control Room base URL, used as the prefix for every API call | Run parameter |
| `iStr4_CRUserName`, `iStr5_APIKey` | Control Room credentials; authentication type defaults to `BASIC` | Run parameters |
| `iStr1_PublicFolderIDs` | Folder ID to scan; mutually exclusive with the bot ID list | Run parameter |
| `iStr2_PublicBotIDs` | Comma-separated bot IDs; mutually exclusive with the folder ID | Run parameter |
| `iStr6_OuputFolderPath` | Destination folder for `BotPackagesReport.xlsx` and `botPackagesReportLogs.log` | Run parameter |
| `iStrCrToken` | Control Room session token, refreshed on any API failure | Token sub-automation |
| `v24PackagesData` | The whole A360 v24 baseline table: package name in column 1, v24 default version read from column index `[2]` (third column) | `v24PackagesList.xlsx`, all rows, read as text |
| `pStrNodeLists` | The work list for the run — either bot records (id/name/path) from the Python folder scan, or bare bot IDs from the split input | Stage 5 |
| `pStrBotID`, `pStrBotName`, `pStrBotPath` | Identity of the bot currently being processed | Folder list entry, or `GET /v2/repository/files/{botId}` |
| `pStrBotContent` / `packages` | The bot's definition and the `packages` node extracted from it | `GET /v2/repository/files/{botId}/content` |
| `packageName_`, `packageVersion_` | Name and version of the package currently being processed; the version is truncated at the first `-` before comparison | Each entry in the `packages` node |
| `V24PackageVesrion` | v24 baseline version for the current package; reset to `0.0.0` after each package, so `0.0.0` in the report means "not found in the baseline" | `v24PackagesData` lookup |
| `DefaultPkgVersionInCR` | The Control Room's current default version for the current package | Cache table, or `POST /v2/packages/package/version/list` |
| `CRDefaultPackageVersions` | Two-column cache (`packagename`, `crdefaultpackageversion`) preventing repeat API calls for the same package within a run | Built during Stage 8 |
| `ActionRequired` | Verdict for the row; initial value `No` | Python `compare_versions` |
| `botpackagerecord` | The row under construction — one row per bot/package pair | Assembled in Stages 8–9 |
| `DT_BotsandPackages` | The complete results table, header row plus one row per bot/package pair; written to sheet `BotPackagesReport` | Accumulated across the run |
## Not determinable from the source
- Schedule and run frequency — no trigger information exists in the source.
- Who runs the process and who consumes `BotPackagesReport.xlsx` downstream; upgrade planning is implied but never stated.
- The token sub-automation's internals: which endpoint it calls, whether it uses the API key or a password, and how the `BASIC` authentication type is applied.
- The request body sent to `POST /v2/packages/package/version/list` (a filter on package name is implied but not shown), and how the session token is attached given the call is configured with no built-in authentication.
- The exact logic and possible return values of Python `compare_versions`, i.e. what values can appear in the ActionRequired column beyond the default `No`.
- The full column layout of `v24PackagesList.xlsx` beyond package name and the version in the third column, and how and by whom that baseline is maintained.
- The purpose of the unnamed Python step after the bot loop, and of a disabled Python step in the folder-ID branch.
- Whether the note "Each request will retrieve 100 bots" implies a pagination limit — offset variables exist in the automation but no paging loop appears in the outline, so folders with more than 100 bots may be truncated.
- Volumes: how many bots and packages are typically processed, and expected runtime.
- Whether the repository copy of `BotPackagesReport.xlsx` is a template that must be cleared between runs — it is opened for editing and written from A1, which may leave stale rows below the new data if a previous run was longer.
How this SOP was checked
Generated from the project's source files and audited against them. Audit verdict: minor issues, confidence high.
Stage sequence matches the outline end to end: input validation with stop, in-memory header rows for the results table and the CR-default cache, loading v24PackagesList.xlsx (all rows, as text), token sub-bot call and 'Error' check, folder-ID branch via Python getAllTaskBotsByFolderID vs comma-split bot-ID branch, per-bot identity/content GETs with token-refresh-and-retry catches, per-package v24 (case-sensitive) and CR-default (case-insensitive, cached, POST /v2/packages/package/version/list) lookups, compare_versions, row append, resets, and the dual write of BotPackagesReport.xlsx in both the normal path and the outer catch. Log strings, paths, sheet name, endpoints and thresholds are preserved accurately. Genuinely unsupported items (token sub-bot internals, POST body, compare_versions return values, purpose of the unnamed/disabled Python steps, pagination) are correctly declared undeterminable.
1 correction from the audit was applied to the procedure above.
Remaining minor notes, not corrected:
- Stage 2, step 1 column table / Data handled — The header text actually written for the bot-version column is 'PackageVersion' (Update Column columnName=Bot-PackageVersion but typeStringVal=PackageVersion); all other columns write text identical to their names. The SOP presents 'Bot-PackageVersion' as the spreadsheet heading. (Note that the internal column is Bot-PackageVersion but the heading cell in BotPackagesReport.xlsx reads 'PackageVersion'.)
- Before you start – 'Reference workbook in place'; Data handled – v24PackagesData — Asserts package name is in the first column of v24PackagesList.xlsx. The source only searches the whole table for the value and then reads column index [2] of the matched row; the matching column is never checked. (State only what is traceable: the workbook is searched (case-sensitive) for the package name anywhere in the table, and the v24 version is read from the third column of the matched row; the exact layout of the name column is not determinable.)
- Stage 8 ambiguity note / 'Not determinable' list — Token-attachment ambiguity is raised only for the POST, but all REST calls in the outline (both /v2/repository/files GETs and the POST) are configured with authenticationMode=NoAuthentication. (Extend the caveat: none of the REST steps show how $iStrCrToken$ is attached, including the two repository GETs.)
- Stage 1, steps 2–3 — The 'both empty' / 'both populated' readings are stated as fact, but the outline exposes only a partial condition on $iStr1_PublicFolderIDs$ (operator EQ, no value shown) and gives no condition text for the Else-If branch. (Keep the reading (it is supported by the log messages) but flag that the exact comparison logic for the two branches is not visible in the source.)