Repository navigation
Releases: PaulOgier/GoogleWorkspaceScripts
Release list
gam-script-checker-v0.4.6
GAM Script Checker v0.4.6
A .sh, .bash or .zsh file, or a file whose first line is a sh, bash, zsh, ksh or dash shebang, is now always read as a shell script. Before, a shell script with batch-looking text in it, such as printf '%s|%s', could be read as a Windows batch file: its # comments were then read as commands (a comment ending . Still opens ... showed as running a script called Still), and the mode reading added in 0.4.5 was skipped. A paste with no file name or shebang is still guessed from its text.
A shell assignment whose value is only spaces (X=" ") no longer stops the check with an error.
Tested on Linux (Python 3.14), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
SHA256
a745de2f65d6fa20d436fd3bb1584b4bac20df02af6d66e4071619fbbd857db0 gam-script-checker-v0.4.6.zip
c3c235d64a743744c3f36fd42d83b652e423059b6239f73715b6d528a5478ef7 gamcheck.py
a1a66d32b34608c2c23fd8362abd6754e13a921b3a7b4011388b5c9c4e4f9647 verbs/gam7.json
c9eb70fb3c7f2aa08fb838679387ee19192f07e4d1af21cb52a06a1bb5b8a87a verbs/gamadv-xtd3.json
a9251216bbe39581dd2723acdfa7652ee463c067128f95a549ba586e178988ec verbs/legacy-gam.json
55178dbb0bf90bc85e0862568f1677b408d655eff0f880a605cdccbf75e9f46f verbs/wiki.json
gam-script-checker-v0.4.5
GAM Script Checker v0.4.5
A pasted line that runs a shell script with a mode word, such as bash runbook.sh check, is now judged by the lines that mode runs. When the script reads its mode from the first argument (MODE="${1:-check}", or $1 itself) and picks a branch with a plain compare (if [ "$MODE" = "check" ], elif, else, or case "$MODE" in check)), the gam lines in the other branches are listed under NOT RUN IN THIS MODE and are not counted. A read-only mode of a script that also creates or deletes users now reads READ-ONLY. With no mode word, the default after :- is used.
If the mode is tested any other way, every line counts and a NOTE says why. That includes a pattern or a variable as the compared word, && in the test, a second assignment, shift, printf -v, read, nocasematch, a fallthrough (;&), a test inside a function, or a mode decided at runtime. A one-line guard (case "$MODE" in check|apply) ;; *) exit 1;; esac) counts its own line and does not block the reading.
A script checked on its own (gamcheck.py runbook.sh) still gets the whole-file verdict.
Tested on Linux (Python 3.14), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
SHA256
696cd88888ea8822492738b0df8ebb325c7cec5ef66f00a598192b6042c4c002 gam-script-checker-v0.4.5.zip
1f31b166324e0a03d3282ced4b6f3a6f7cdeb4ff99bd1dd6c45508ca73f76816 gamcheck.py
a1a66d32b34608c2c23fd8362abd6754e13a921b3a7b4011388b5c9c4e4f9647 verbs/gam7.json
c9eb70fb3c7f2aa08fb838679387ee19192f07e4d1af21cb52a06a1bb5b8a87a verbs/gamadv-xtd3.json
a9251216bbe39581dd2723acdfa7652ee463c067128f95a549ba586e178988ec verbs/legacy-gam.json
55178dbb0bf90bc85e0862568f1677b408d655eff0f880a605cdccbf75e9f46f verbs/wiki.json
offboard-v5.7.2
Scorched earth no longer deletes the account when the leaver's Shared Drive list cannot be read or parsed. It refuses with exit 2, as it already did when a drive's membership could not be read, so an account that may be the sole organizer of a Shared Drive is never deleted unchecked.
A --user given as an alias is resolved to its primary address before any change. Before, the alias moved to the successor during the run, and the commands after it (licence removal, suspension) could reach the successor's account.
A missing or unreadable GYB message database now fails backup verification and holds the licence. Before, it passed as an empty backup, and the check could create the missing file.
The update check reads the GoogleWorkspaceScripts repository.
Tested on dev on Linux: an alias given as --user, and a scorched-earth run with the Shared Drive listing forced to fail. 243 tests pass on Linux (Python 3.14), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
Google Workspace Security Audit v1.7.2: incomplete scans held for review
A --run-dir holding another customer's run is refused at preflight. Before, a resume against a different tenant skipped the completed modules and reported the saved data under the current tenant's name.
A Shared Drive scan that left drives unscanned is now partial: the report is held for review, the run exits 2, and those drives are no longer listed as checked and clean. Run with --grant-temp-access to cover drives the admin is not a member of.
A check that fails to run now holds the report and exits 2, instead of leaving only an INFO finding.
With --grant-temp-access, a temporary organizer grant that could not be removed now holds the report and exits 2. The QA report names the drive and the admin to remove.
Also in this release (v1.7.1, not released separately): the report no longer needs JavaScript to open, so a viewer that blocks scripts shows it instead of a blank page; the header and footer credit the tool and link to the repository; the update check reads the GoogleWorkspaceScripts repository.
Tested on dev on Linux: a partial Shared Drive scan held for review, and a resume against a run directory carrying another customer ID refused. 294 tests pass on Linux (Python 3.14), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
gam-script-checker-v0.4.4
GAM Script Checker v0.4.4
Code handed to Python's exec or compile as a string is now read like the rest of the script, so exec("os.system('gam delete user ...')") is DESTRUCTIVE instead of being skipped. Text that cannot be read that way, and eval of a string, is CANNOT TELL.
A command substitution inside echo, printf and similar commands is now checked as a command: echo "$(gam delete user ...)" is DESTRUCTIVE. Single-quoted text and echo "gam delete user ..." without a substitution are still read as text.
Before, either form beside a read-only command gave the whole script READ-ONLY.
The adversarial test runner now exits 1 on an under-warning or a crash, so it can fail a release.
Tested on Linux (Python 3.14), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
SHA256
f2ee862aed6fa0b12816294d8051238b0c7d73a3516e8ecf88675307e8f51ec4 gam-script-checker-v0.4.4.zip
7b5350706d7bca04634c60fe3a91775da0eb0cc1a644b3c6649058b945b4bdad gamcheck.py
a1a66d32b34608c2c23fd8362abd6754e13a921b3a7b4011388b5c9c4e4f9647 verbs/gam7.json
c9eb70fb3c7f2aa08fb838679387ee19192f07e4d1af21cb52a06a1bb5b8a87a verbs/gamadv-xtd3.json
a9251216bbe39581dd2723acdfa7652ee463c067128f95a549ba586e178988ec verbs/legacy-gam.json
55178dbb0bf90bc85e0862568f1677b408d655eff0f880a605cdccbf75e9f46f verbs/wiki.json
Google Workspace Security Audit v1.7.0: month-to-month comparison
New findings: files made public or shared outside the organisation in the last 30 days (from the Drive audit log), domain-wide delegation granted in the last 30 days, Gmail filters that match business-email-compromise patterns, super admins without a phishing-resistant second factor, files shared with target audiences, and settings below the CISA SCuBA Google Workspace baseline (MEDIUM and INFO, each row citing its CISA requirement). Settings the Policy API omits because they were never changed are now judged at Google's documented default and marked "Set by: Google default".
Each run is compared with the last completed run of the same customer: resolved findings, findings and rows new this month, and a posture score with a six-run trend. A finding whose data was incomplete in either run is reported as not compared, never as resolved. findings_evidence.csv carries every row with a stable ID.
--tenants, --tenant and --all audit tenants from a tenants file, each stopping if gam info domain answers with a different customer ID. Break-glass admins are excluded from the dormancy checks. qa_report.html says whether the report is ready to send. Exit codes: 0 complete, 1 preflight failed or wrong tenant, 2 some modules could not run, 130 interrupted; modules that do not apply to the tenant (Classroom without an Education licence) do not count.
The Shared Drive scan reads permissions only for items shared beyond the drive's members, about ten times faster with the same results. Gmail filters run in the default audit.
Tested on the dev and Education test tenants, on Linux (Python 3.13), macOS (Python 3.9) and Windows (Python 3.14).
gam-script-checker-v0.4.3
GAM Script Checker v0.4.3
Checked against GAM7 7.48.20. gam print chromebrowsers is recognised, and Looker Studio commands are recognised under both the lookerstudio and datastudio spellings and described as Looker Studio assets and sharing.
A stderr redirect is no longer read as an argument: gam info domain 2>&1 is "shows details of domain", not "shows details of domain 2".
A gam path or a variable named for GAM, given to a command that takes file paths ([[ -x $GAMDIR/gam ]], cp -a "$GAMDIR" ..., ls, rm, Copy-Item and similar), is no longer reported as CANNOT TELL. bash -c "gam ..." and $(gam ...) still are.
The purge events warning added in 0.4.2 now cites the GAM bug report, GAM-team/GAM#1997.
Tested on Linux (Python 3.13), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
SHA256
5b09343331e2d679e99cf74628fc340ace1e20659539145a6dfd7f77238a557a gam-script-checker-v0.4.3.zip
a2c03193bbb461d863f03af94a49f164eecf65b136f32939a1828d510d67ec67 gamcheck.py
a1a66d32b34608c2c23fd8362abd6754e13a921b3a7b4011388b5c9c4e4f9647 verbs/gam7.json
c9eb70fb3c7f2aa08fb838679387ee19192f07e4d1af21cb52a06a1bb5b8a87a verbs/gamadv-xtd3.json
a9251216bbe39581dd2723acdfa7652ee463c067128f95a549ba586e178988ec verbs/legacy-gam.json
55178dbb0bf90bc85e0862568f1677b408d655eff0f880a605cdccbf75e9f46f verbs/wiki.json
gam-script-checker-v0.4.2
GAM Script Checker v0.4.2
purge events now reads as DESTRUCTIVE with or without doit. 0.4.1 reported it as a dry run without doit. GAM skips its own delete step, then moves the matched events into a temporary calendar and deletes that calendar, so the events are destroyed while GAM prints "Not Deleted: Use the doit argument". Tested on a live event.
A Cloud Identity device or device user named by its ID (gam delete device devices/..., gam wipe deviceuser ...) now reads as a change, not a dry run. As with mobile devices in 0.4.1, GAM only waits for doit when the devices are picked by query or devicesn.
gam user ... forward messages|threads is read as forwarding existing mail to another address: a dry run without doit when picked by query, a SECURITY line either way. 0.4.1 read it as turning on mail forwarding.
Changes now name what they act on: deletes user account bob@example.com, deletes group staff@example.com, changes org unit /Staff, transfers drive to <new owner>.
Switching something off no longer reads as switching it on: suspended off says it unsuspends the account, and forward off says it turns forwarding off with no SECURITY line.
Moving a user to another OU carries a note that its policies and licences can change. gam all users_ns and similar say "non-suspended users" instead of GAM's suffix. A CSV loop with matchfield or skipfield gives the row count as "before filtering".
A script or paste that makes a change with no gam info domain check above it gets a NOTE under the verdict.
The test suite gains invariant checks that run over every fixture and the blind set: no narrowed command is described as tenant-wide, every change names its target, every doit-gated command is checked in its named and query forms, and on/off pairs read differently.
Tested on Linux (Python 3.13), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
SHA256
474359d5b18b6b3c2883e869ad34ca8882f2add64b104f0d086471121ce72708 gam-script-checker-v0.4.2.zip
f70e0a952179ad3666915d2e938aed7bc9f5c1bc3b3cbcbc1a24ad9699ae460c gamcheck.py
94635da34181f137871ed32c03101c08d9c036f0aebd4f5de28ae6949d03903c verbs/gam7.json
c9eb70fb3c7f2aa08fb838679387ee19192f07e4d1af21cb52a06a1bb5b8a87a verbs/gamadv-xtd3.json
a9251216bbe39581dd2723acdfa7652ee463c067128f95a549ba586e178988ec verbs/legacy-gam.json
2d9995ae1eb5c83c9a76aa510c69bf869850adac91a5f530f2d75e1dd7d4a1c6 verbs/wiki.json
gam-script-checker-v0.4.1
GAM Script Checker v0.4.1
gam update mobile <device> action wipe and gam delete mobile <device> now read as DESTRUCTIVE. 0.4.0 reported them as a dry run because no doit was given, but GAM only asks for doit when the devices are picked by query. A device named by its ID is wiped or deleted straight away. The query form still reads as a dry run until doit is added.
gam report now says who it covers: one user for user <email>, the users in an OU for ou <path>, the selected users for select <entity>, and the whole tenant only when nothing narrows it or for user all and customer reports. 0.4.0 described every report as "for the whole tenant".
gam version, list, sendemail, whatis, checkconn, comment and help no longer end with "for the whole tenant".
Tested on Linux (Python 3.13), macOS (Python 3.9 and 3.14) and Windows (Python 3.14).
SHA256
db554e9ea76c501ac01b4e1fb5c7bc9945e1361927d3a53b78cb5136b527def8 gam-script-checker-v0.4.1.zip
19a4047aa553ec6a077b6403b25d34e05ef14fe76f4ac1dc6c4183d78d5b245d gamcheck.py
94635da34181f137871ed32c03101c08d9c036f0aebd4f5de28ae6949d03903c verbs/gam7.json
c9eb70fb3c7f2aa08fb838679387ee19192f07e4d1af21cb52a06a1bb5b8a87a verbs/gamadv-xtd3.json
a9251216bbe39581dd2723acdfa7652ee463c067128f95a549ba586e178988ec verbs/legacy-gam.json
2d9995ae1eb5c83c9a76aa510c69bf869850adac91a5f530f2d75e1dd7d4a1c6 verbs/wiki.json
tenant-audit-v1.6.2
Shared drives are now scanned as one of their own active members, managers first. The audit no longer has to add the admin to each drive, and it works when the audit admin holds no Workspace licence. A new shareddrive.scannedAs column says whose view each drive was read through. A member whose Drive is switched off is skipped for the next member, instead of the drive being reported as empty and clean. A scan sees what that member sees, so a limited-access folder they are kept out of is not covered.
--grant-temp-access is now only a fallback for a drive that none of its members can list. If Google refuses the grant, the report gives Google's reason. Resuming a run re-scans any shared drive left unscanned, and the My Drive scan limit is now 4 hours instead of 1.
Admin accounts with app passwords are rated High instead of Critical. An app password cannot sign in to the Admin console, but it lets a mail, calendar or contacts app reach the mailbox without 2-step verification. Files shared to a target audience are no longer reported as shared with an external domain.
Tested on Linux, macOS and Windows.