Compare commits

...

77 Commits

Author SHA1 Message Date
Ross Scroggs
28383c1391 Added option returnidonly to gam create|update printer 2026-03-01 19:52:51 -08:00
Jay Lee
7ab959f27c Fix command for printing user invitations in build.yml 2026-03-01 20:16:29 -05:00
Jay Lee
a877ca6139 Fix command syntax in build.yml for GAM commands 2026-03-01 20:00:28 -05:00
Jay Lee
33da8016a2 Update file paths in build.yml for GAM commands 2026-03-01 19:57:15 -05:00
Jay Lee
36b2849f20 Refactor gam command execution in build workflow 2026-03-01 19:40:52 -05:00
Jay Lee
377201614b Fix command substitution syntax in build.yml
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 19, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-03-01 19:05:30 -05:00
Jay Lee
ff11bf33d1 Fix command syntax for gam user query 2026-03-01 18:47:32 -05:00
Jay Lee
59463dcc9a Fix variable assignment syntax in build.yml 2026-03-01 18:35:34 -05:00
Jay Lee
23b5eb6fd6 Replace 'run_gam' with '$gam' in build.yml 2026-03-01 18:24:38 -05:00
Jay Lee
8f4aa19f13 Refactor GAM commands to use variable syntax 2026-03-01 18:01:25 -05:00
Jay Lee
6410691c0e Refactor GAM command execution and update workflows
Refactor GAM command executions to use a function for better readability and maintainability. Update artifact handling and VirusTotal scan steps.
2026-03-01 17:34:50 -05:00
Jay Lee
1ad1f9b96c Update artifact download and scan paths in build.yml 2026-03-01 12:43:30 -05:00
Ross Scroggs
636e8dd11e Updated gam-install.sh script for macOS/Linux #1883
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 19, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-27 18:18:43 -08:00
Ross Scroggs
caeab48dda Updated gam-install.sh script for macOS/Linux #1883
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 19, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2026-02-27 18:18:19 -08:00
Ross Scroggs
1364991e5d Fixed formatjson quotechar <Character> bug 2026-02-27 15:57:13 -08:00
Ross Scroggs
6bdea8fa54 Fixed formatjson quotechar <Character> bug 2026-02-27 15:56:55 -08:00
Ross Scroggs
da24220d87 Update Organizational-Units.md 2026-02-27 10:57:00 -08:00
Ross Scroggs
a7d537ebe2 Update Organizational-Units.md 2026-02-27 10:55:43 -08:00
Jay Lee
74b285959c actions: Add macOS 26 Intel, rebuild cache
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build x86_64 macOS 26, macos-26-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 14, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 18, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 19, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-27 05:48:39 -05:00
Jay Lee
c138bc44f0 [no ci] actions: more info about Python builds. 2026-02-27 05:31:25 -05:00
Jay Lee
13f56afcd2 [no ci] actions: archive types based on OS
Updated conditions for artifact archiving based on OS.
2026-02-27 05:23:27 -05:00
Jay Lee
ba8242f480 Change job dependency from 'merge' to 'build' 2026-02-27 04:39:00 -05:00
Jay Lee
01985d4381 actions: Refactor artifact archiving in build workflow 2026-02-27 04:37:35 -05:00
Jay Lee
77511b79c9 actions: use newer action versions 2026-02-27 04:07:31 -05:00
Ross Scroggs
06f653db8f Update Users-Photo.md
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-02-26 13:37:47 -08:00
Ross Scroggs
cea2099537 Updated gam <UserTypeEntity> update photo 2026-02-26 12:27:13 -08:00
Ross Scroggs
67a6d3f4de Updated gam <UserTypeEntity> update photo 2026-02-26 12:26:51 -08:00
Ross Scroggs
7987a94aab Update Users-Photo.md 2026-02-26 11:42:20 -08:00
Ross Scroggs
e6494b6747 Update Users-Photo.md 2026-02-26 11:40:42 -08:00
Ross Scroggs
401f5095e1 Update Users-Photo.md 2026-02-26 11:37:57 -08:00
Ross Scroggs
93323d12d3 Rebuild to avoid chardet induced error
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2026-02-24 18:26:01 -08:00
Ross Scroggs
c3e23fabf1 Update pyproject.toml 2026-02-24 17:22:59 -08:00
Ross Scroggs
95eb36c5c2 Update to avoid requests error 2026-02-24 15:56:30 -08:00
Ross Scroggs
17105d51f1 Initial guest user support 2026-02-24 15:45:47 -08:00
Ross Scroggs
8dbc455407 Initial guest user support 2026-02-24 14:45:03 -08:00
Ross Scroggs
7e7b8416a4 Define guest user fields 2026-02-24 14:10:49 -08:00
Ross Scroggs
ed81501bf2 Define guest user fields
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-24 14:10:13 -08:00
Ross Scroggs
428f8f5987 Added option copyfolderpermissions [<Boolean>] to gam <UserTypeEntity> copy|move drivefile
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2026-02-20 13:54:34 -08:00
Ross Scroggs
b9a489251b Added option copyfolderpermissions [<Boolean>] to gam <UserTypeEntity> copy|move drivefile 2026-02-20 13:54:14 -08:00
Ross Scroggs
3b9a9ba224 Update Users-Drive-Files-Display.md
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-20 08:34:59 -08:00
Ross Scroggs
0d63a85a45 Update Users-Gmail-Messages-Threads.md
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-02-18 09:49:00 -08:00
Ross Scroggs
a8ea30e19e Sort all events in gam report <ActivityApplictionName> 2026-02-18 09:08:56 -08:00
Ross Scroggs
660e9deb70 Sort all events in gam report <ActivityApplictionName> 2026-02-18 09:08:34 -08:00
Ross Scroggs
ad5ba656ee Improved create drivefileacl error handling
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-02-17 16:15:39 -08:00
Ross Scroggs
991b1aa33b Improved create drivefileacl error handling 2026-02-17 16:15:22 -08:00
Ross Scroggs
51fafdb735 Update Reports.md 2026-02-17 14:37:42 -08:00
Ross Scroggs
52f1e998fd Update Reports.md 2026-02-17 14:04:50 -08:00
Ross Scroggs
0f144b24d0 Update Reports.md 2026-02-17 13:54:08 -08:00
Ross Scroggs
52d0b0a84b Update course add external teacher|student error message
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-16 10:12:53 -08:00
Ross Scroggs
28224045b2 Update course add external teacher|student error message
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2026-02-16 10:12:28 -08:00
Jay Lee
3fbb261821 actions: rebuild to get Python 3.14.3
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025-vs2026) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2026-02-13 18:59:29 -05:00
Jay Lee
0b4a4a270e bump cryptography for security 2026-02-13 18:44:37 -05:00
Jay Lee
177f5f0792 Update build.yml 2026-02-13 18:35:48 -05:00
Ross Scroggs
57e0cc80af Mre fix typos 2026-02-13 15:33:14 -08:00
Ross Scroggs
1e67310f3d Fix typos 2026-02-13 15:31:36 -08:00
Jay Lee
e661641544 Update build.yml 2026-02-13 17:11:53 -05:00
Ross Scroggs
81aa9c6e16 Merge branch 'main' of https://github.com/GAM-team/GAM 2026-02-13 14:03:58 -08:00
Ross Scroggs
8c3b49a967 Update Users-Drive-Permissions.md 2026-02-13 14:03:54 -08:00
Jay Lee
13c6893b67 Update build.yml 2026-02-13 17:02:46 -05:00
Jay Lee
6702e4db30 [actions]: custom cryptography wheel for win arm64 2026-02-13 16:48:41 -05:00
Jay Lee
2ed23c8f55 Update build.yml 2026-02-13 16:30:11 -05:00
Jay Lee
24a58c8edc [actions] use VS Code 2026 on Win x64 2026-02-13 14:18:03 -05:00
Jay Lee
0112264291 [actions] update env variables for apply notary 2026-02-13 12:59:04 -05:00
Jay Lee
fa5af0ed1f [actions] switch Apple notary auth to using a key instead of ASP. 2026-02-13 12:46:15 -05:00
Ross Scroggs
15e3f50a3c Updated GAM to prevent unable to find the server errors 2026-02-13 09:17:34 -08:00
Ross Scroggs
24b7c65754 Updated GAM to prevent unable to find the server errors 2026-02-13 08:04:14 -08:00
Ross Scroggs
2429e99e18 Updated GAM to prevent unable to find the server errors
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-13 08:03:48 -08:00
Ross Scroggs
ff41390c85 Updated gam create|update adminrole
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-02-12 09:53:54 -08:00
Ross Scroggs
d8d68e8eb0 Updated gam create|update adminrole 2026-02-12 09:53:34 -08:00
Ross Scroggs
2196e70e7b Added variable csv_output_header_required to gam.cfg
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-11 16:19:28 -08:00
Ross Scroggs
4f79a29155 Added variable csv_output_header_required to gam.cfg
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-11 16:19:03 -08:00
Ross Scroggs
0290f0d0ce Replace teamdrive with shareddrive
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-10 21:31:07 -08:00
Ross Scroggs
b7c96a8172 Fixed bug in gam [<UserTypeEntity>] sendemail
Some checks failed
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
2026-02-10 14:01:06 -08:00
Ross Scroggs
fed1662eb4 Fixed bug in gam [<UserTypeEntity>] sendemail 2026-02-10 12:58:16 -08:00
Ross Scroggs
077747be99 Update No-Owner-Secondary-Calendars.md 2026-02-09 08:41:21 -08:00
Ross Scroggs
9eee475b4a Update No-Owner-Secondary-Calendars.md
Some checks failed
Check for Google Root CA Updates / check-certs (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2026-02-09 08:28:09 -08:00
Ross Scroggs
2636dd9827 Added hideinvitationssetting to <UserCalendarSettingsField>
Some checks failed
Build and test GAM / build (false, build, 1, Build Intel Ubuntu Jammy, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (false, build, 10, Build x86_64 macOS 15, macos-15-intel) (push) Has been cancelled
Build and test GAM / build (false, build, 11, Build Arm MacOS 26, macos-26) (push) Has been cancelled
Build and test GAM / build (false, build, 12, Build Intel Windows, windows-2025) (push) Has been cancelled
Build and test GAM / build (false, build, 13, Build Arm Windows, windows-11-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 2, Build Intel Ubuntu Noble, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (false, build, 3, Build Arm Ubuntu Noble, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 4, Build Arm Ubuntu Jammy, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (false, build, 5, Build Intel StaticX Legacy, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 6, Build Arm StaticX Legacy, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (false, build, 8, Build Arm MacOS 14, macos-14) (push) Has been cancelled
Build and test GAM / build (false, build, 9, Build Arm MacOS 15, macos-15) (push) Has been cancelled
Build and test GAM / build (false, test, 14, Test Python 3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (false, test, 15, Test Python 3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (false, test, 16, Test Python 3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (false, test, 17, Test Python 3.15-dev, ubuntu-24.04, 3.15-dev) (push) Has been cancelled
Build and test GAM / build (true, test, 18, Test Python 3.14 freethread, ubuntu-24.04, 3.14) (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
Check for Google Root CA Updates / check-certs (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
2026-02-07 06:55:26 -08:00
37 changed files with 1306 additions and 689 deletions

View File

@@ -86,18 +86,23 @@ jobs:
freethreaded: false freethreaded: false
goal: build goal: build
name: Build x86_64 macOS 15 name: Build x86_64 macOS 15
- os: macos-26 - os: macos-26-intel
jid: 11 jid: 11
freethreaded: false freethreaded: false
goal: build goal: build
name: Build Arm MacOS 26 name: Build x86_64 macOS 26
- os: windows-2025 - os: macos-26
jid: 12 jid: 12
freethreaded: false freethreaded: false
goal: build goal: build
name: Build Arm MacOS 26
- os: windows-2025-vs2026
jid: 13
freethreaded: false
goal: build
name: Build Intel Windows name: Build Intel Windows
- os: windows-11-arm - os: windows-11-arm
jid: 13 jid: 14
freethreaded: false freethreaded: false
goal: build goal: build
name: Build Arm Windows name: Build Arm Windows
@@ -105,36 +110,36 @@ jobs:
goal: test goal: test
python: "3.10" python: "3.10"
freethreaded: false freethreaded: false
jid: 14 jid: 15
name: Test Python 3.10 name: Test Python 3.10
- os: ubuntu-24.04 - os: ubuntu-24.04
goal: test goal: test
python: "3.11" python: "3.11"
freethreaded: false freethreaded: false
jid: 15 jid: 16
name: Test Python 3.11 name: Test Python 3.11
- os: ubuntu-24.04 - os: ubuntu-24.04
goal: test goal: test
python: "3.12" python: "3.12"
freethreaded: false freethreaded: false
jid: 16 jid: 17
name: Test Python 3.12 name: Test Python 3.12
- os: ubuntu-24.04 - os: ubuntu-24.04
goal: test goal: test
python: "3.15-dev" python: "3.15-dev"
freethreaded: false freethreaded: false
jid: 17 jid: 18
name: Test Python 3.15-dev name: Test Python 3.15-dev
- os: ubuntu-24.04 - os: ubuntu-24.04
goal: test goal: test
python: "3.14" python: "3.14"
freethreaded: true freethreaded: true
jid: 18 jid: 19
name: Test Python 3.14 freethread name: Test Python 3.14 freethread
steps: steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
@@ -148,12 +153,12 @@ jobs:
- name: Cache multiple paths - name: Cache multiple paths
if: matrix.goal == 'build' if: matrix.goal == 'build'
uses: actions/cache@638ed79f9dc94c1de1baef91bcab5edaa19451f4 # v4.2.4 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
id: cache-python-ssl id: cache-python-ssl
with: with:
path: | path: |
cache.tar.xz cache.tar.xz
key: gam-${{ matrix.jid }}-20260129 key: gam-${{ matrix.jid }}-20260227
- name: Untar Cache archive - name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true' if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@@ -163,7 +168,7 @@ jobs:
- name: Use pre-compiled Python for testing - name: Use pre-compiled Python for testing
if: matrix.python != '' if: matrix.python != ''
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
allow-prereleases: true allow-prereleases: true
@@ -247,7 +252,7 @@ jobs:
- name: MacOS import developer certificates for signing - name: MacOS import developer certificates for signing
if: runner.os == 'macOS' if: runner.os == 'macOS'
uses: apple-actions/import-codesign-certs@11e1bb2d3771ad8ffa8459dfe527bc26b2dd4b62 # v5.0.3 uses: apple-actions/import-codesign-certs@b610f78488812c1e56b20e6df63ec42d833f2d14 # v6.0.0
with: with:
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }} p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }} p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
@@ -471,7 +476,7 @@ jobs:
- name: Run Python - name: Run Python
run: | run: |
"${PYTHON}" -V "${PYTHON}" -VV
"${PYTHON}" -c "import ssl; print(f'Using {ssl.OPENSSL_VERSION}')" "${PYTHON}" -c "import ssl; print(f'Using {ssl.OPENSSL_VERSION}')"
- name: Create and use Python venv - name: Create and use Python venv
@@ -507,6 +512,8 @@ jobs:
"$PYTHON" -m pip list "$PYTHON" -m pip list
- name: Install pip requirements - name: Install pip requirements
env:
GH_TOKEN: ${{ github.token }}
run: | run: |
echo "before anything..." echo "before anything..."
"$PYTHON" -m pip list "$PYTHON" -m pip list
@@ -517,6 +524,12 @@ jobs:
echo "--pip debug verbose--" echo "--pip debug verbose--"
"$PYTHON" -m pip debug --verbose "$PYTHON" -m pip debug --verbose
echo "--------" echo "--------"
if ([ "$RUNNER_OS" == "Windows" ] && [ "$RUNNER_ARCH" == "ARM64" ]); then
# custom cryptography wheel for win arm64 since the project doesn't provide one:
# https://github.com/pyca/cryptography/issues/14293
gh release download --repo "jay0lee/cryptography-wheels" --pattern "*win_arm64.whl" --clobber
"$PYTHON" -m pip install cryptography-*.whl
fi
"$PYTHON" -m pip install -vvv --upgrade ..[yubikey] "$PYTHON" -m pip install -vvv --upgrade ..[yubikey]
echo "after everything..." echo "after everything..."
"$PYTHON" -m pip list "$PYTHON" -m pip list
@@ -625,13 +638,19 @@ jobs:
- name: MacOS send GAM binary for Apple notarization - name: MacOS send GAM binary for Apple notarization
if: runner.os == 'macOS' if: runner.os == 'macOS'
env: env:
ASP_NOTARIZE: ${{ secrets.ASP_NOTARIZE }} APPLE_KEY: ${{ secrets.APPLE_KEY }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
run: | run: |
# Apple wants some kind of "package" submitted so just add gam to a .zip # Apple wants some kind of "package" submitted so just add gam to a .zip
# name it something we can track and link in Apple's notarize process # name it something we can track and link in Apple's notarize process
zipfilename="./gam-${RUNNER_ARCH}-${GITHUB_RUN_ID}-${GITHUB_RUN_NUMBER}.zip" zipfilename="./gam-${RUNNER_ARCH}-${GITHUB_RUN_ID}-${GITHUB_RUN_NUMBER}.zip"
zip -r "$zipfilename" "$gampath" zip -r "$zipfilename" "$gampath"
xcrun notarytool submit --apple-id "jay0lee@gmail.com" --password "$ASP_NOTARIZE" --team-id GZ85H2DRLM "$zipfilename" export KEY_FILE="$(mktemp).p8"
trap 'rm -f "$KEY_FILE"' EXIT
echo "$APPLE_KEY" > "$KEY_FILE"
xcrun notarytool submit "$zipfilename" --key "$KEY_FILE" --key-id "$APPLE_KEY_ID" --issuer "$APPLE_ISSUER_ID"
rm -v "$KEY_FILE"
rm -v "$zipfilename" rm -v "$zipfilename"
- name: Basic Tests all jobs - name: Basic Tests all jobs
@@ -669,10 +688,9 @@ jobs:
if: runner.os == 'Windows' if: runner.os == 'Windows'
shell: pwsh shell: pwsh
run: | run: |
#$url = "https://files.certum.eu/software/SimplySignDesktop/Windows/9.3.2.67/SimplySignDesktop-9.3.2.67-64-bit-en.msi" #$url = "https://files.certum.eu/software/SimplySignDesktop/Windows/9.3.4.72/SimplySignDesktop-9.3.4.72-64-bit-en.msi"
#$file = "SimplySignDesktop-9.3.2.67-64-bit-en.msi" $url = "https://www.files.certum.eu/software/SimplySignDesktop/Windows/9.4.0.84/SimplySignDesktop-9.4.0.84-64-bit-en.msi"
$url = "https://files.certum.eu/software/SimplySignDesktop/Windows/9.3.4.72/SimplySignDesktop-9.3.4.72-64-bit-en.msi" $file = "SimplySignDesktop.msi"
$file = "SimplySignDesktop-9.3.4.72-64-bit-en.msi"
Invoke-WebRequest $url -OutFile $file Invoke-WebRequest $url -OutFile $file
$log = "install.log" $log = "install.log"
$procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru
@@ -719,7 +737,7 @@ jobs:
$gam create signjwtserviceaccount $gam create signjwtserviceaccount
- name: Attest gam executable was generated from this Action - name: Attest gam executable was generated from this Action
uses: actions/attest-build-provenance@0b6e9809265278d02c58acf52849a95818a5a306 # v3.0.0 uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
if: matrix.goal == 'build' if: matrix.goal == 'build'
with: with:
subject-path: ${{ env.gam }} subject-path: ${{ env.gam }}
@@ -783,7 +801,7 @@ jobs:
& 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:MSI_FILENAME" & 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:MSI_FILENAME"
- name: Attest that gam package files were generated from this Action - name: Attest that gam package files were generated from this Action
uses: actions/attest-build-provenance@0b6e9809265278d02c58acf52849a95818a5a306 # v3.0.0 uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal == 'build' if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal == 'build'
with: with:
subject-path: | subject-path: |
@@ -791,17 +809,32 @@ jobs:
gam*.zip gam*.zip
gam*.msi gam*.msi
- name: Archive production artifacts - name: Archive tar.xz artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
#if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal != 'test' if: runner.os != 'Windows'
if: always()
with: with:
name: gam-binaries-${{ env.GAMOS }}-${{ env.arch }}-${{ matrix.jid }} archive: false
if-no-files-found: ignore
path: | path: |
gam*.tar.xz gam*.tar.xz
- name: Archive zip artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
if: runner.os == 'Windows'
with:
archive: false
if-no-files-found: ignore
path: |
gam*.zip gam*.zip
- name: Archive msi artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
if: runner.os == 'Windows'
with:
archive: false
if-no-files-found: ignore
path: |
gam*.msi gam*.msi
*.png
- name: Basic Tests build jobs only - name: Basic Tests build jobs only
if: matrix.goal != 'test' && steps.cache-python-ssl.outputs.cache-hit != 'true' if: matrix.goal != 'test' && steps.cache-python-ssl.outputs.cache-hit != 'true'
@@ -826,19 +859,46 @@ jobs:
- name: Live API tests - name: Live API tests
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
run: | run: |
run_gam() {
local allowed_codes="0"
if [[ "$1" == "-a" ]]; then
allowed_codes="$2"
shift 2
fi
echo "::group::Executing: gam $*"
local exit_code=0
$gam "$@" || exit_code=$?
echo "::endgroup::"
allowed_codes="${allowed_codes//,/ }"
local passed=false
for code in $allowed_codes; do
if [ "$exit_code" -eq "$code" ]; then
passed=true
break
fi
done
if [ "$passed" = true ]; then
echo "| \`gam $*\` | 🟢 Pass | $exit_code |" >> $GITHUB_STEP_SUMMARY
return 0 # Mask the allowed non-zero exit code so GHA continues
else
echo "| \`gam $*\` | 🔴 Fail | $exit_code |" >> $GITHUB_STEP_SUMMARY
exit $exit_code # Hard fail the step for unapproved errors
fi
}
export gam_user="gam-gha-${JID}@pdl.jaylee.us" export gam_user="gam-gha-${JID}@pdl.jaylee.us"
echo "gam_user=${gam_user}" >> $GITHUB_ENV echo "gam_user=${gam_user}" >> $GITHUB_ENV
$gam config customer_id "C03uzfv2s" save run_gam config customer_id "C03uzfv2s" save
$gam config domain "pdl.jaylee.us" save run_gam config domain "pdl.jaylee.us" save
$gam config admin_email "${gam_user}" save run_gam config admin_email "${gam_user}" save
$gam config enable_dasa false save run_gam config enable_dasa false save
$gam oauth info run_gam oauth info
$gam oauth refresh run_gam oauth refresh
$gam config enable_dasa true save run_gam config enable_dasa true save
$gam checkconn run_gam checkconn
$gam user "$gam_user" check serviceaccount run_gam user "$gam_user" check serviceaccount
$gam info domain run_gam info domain
$gam info user run_gam info user
export tstamp=$($PYTHON -c "import time; print(time.time_ns())") export tstamp=$($PYTHON -c "import time; print(time.time_ns())")
export newbase="gha_test_${JID}_${tstamp}" export newbase="gha_test_${JID}_${tstamp}"
export newuser="${newbase}@pdl.jaylee.us" export newuser="${newbase}@pdl.jaylee.us"
@@ -847,24 +907,39 @@ jobs:
export newbuilding="${newbase}-building" export newbuilding="${newbase}-building"
export newresource="${newbase}-resource" export newresource="${newbase}-resource"
export newou="aaaGithub Actions/${newbase}" export newou="aaaGithub Actions/${newbase}"
echo "### GAM Execution Report" >> $GITHUB_STEP_SUMMARY
echo "| Command | Status |" >> $GITHUB_STEP_SUMMARY
echo "| :--- | :---: |" >> $GITHUB_STEP_SUMMARY
# cleanup old runs # cleanup old runs
$gam config enable_dasa false save run_gam config enable_dasa false save
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultholds | $gam csv - gam delete vaulthold "id:~~holdId~~" matter "id:~~matterId~~" || if [ $? != 55 ]; then exit $?; fi run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./vh.csv print vaultholds
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultmatters matterstate OPEN | $gam csv - gam update vaultmatter "id:~~matterId~~" action close run_gam -a "0 55" csv ./vh.csv gam delete vaulthold "id:~~holdId~~" matter "id:~~matterId~~"
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultmatters matterstate CLOSED | $gam csv - gam update vaultmatter "id:~~matterId~~" action delete run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./vm-open.csv print vaultmatters matterstate OPEN
$gam config csv_output_row_filter "Emails.1.address:regex:^gha_test-${JID}_" print contacts | $gam csv - gam delete contact ~ContactID run_gam csv ./vm-open.csv gam update vaultmatter "id:~~matterId~~" action close
$gam config enable_dasa true save run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./vm-closed.csv print vaultmatters matterstate CLOSED
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print features | $gam csv - gam delete feature ~name run_gam csv ./vm-closed.csv gam update vaultmatter "id:~~matterId~~" action delete
$gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" user $gam_user print shareddrives asadmin | $gam csv - gam user $gam_user delete shareddrive ~id nukefromorbit run_gam config csv_output_row_filter "Emails.1.address:regex:^gha_test-${JID}_" redirect csv ./contacts.csv print contacts
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail run_gam csv ./contacts.csv gam delete contact ~ContactID
$gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" print ous fromparent "aaaGithub Actions" | $gam csv - gam delete ou ~orgUnitId run_gam config enable_dasa true save
$gam config csv_output_row_filter "email:regex:^gha_test_${JID}_" print cigroups | $gam csv - gam delete cigroup ~email run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./features.csv print features
$gam config csv_output_row_filter "resourceId:regex:^gha_test_${JID}_" print resources | $gam csv - gam delete resource ~resourceId run_gam csv ./features.csv gam delete feature ~name
$gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" print buildings | $gam csv - gam delete building ~buildingId run_gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" redirect csv ./sd.csv user $gam_user print shareddrives asadmin
run_gam csv ./sd.csv gam user $gam_user delete shareddrive ~id nukefromorbit
run_gam redirect csv ./users.csv print users query "gha.jid=$JID"
run_gam csv ./users.csv gam delete user ~primaryEmail
run_gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" redirect csv ./ous.csv print ous fromparent "aaaGithub Actions"
run_gam csv ./ous.csv gam delete ou ~orgUnitId
run_gam config csv_output_row_filter "email:regex:^gha_test_${JID}_" redirect csv ./cigroups.csv print cigroups
run_gam csv ./cigroups.csv gam delete cigroup ~email
run_gam config csv_output_row_filter "resourceId:regex:^gha_test_${JID}_" redirect csv ./resources.csv print resources
run_gam csv ./resources.csv gam delete resource ~resourceId
run_gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" redirect csv ./buildings.csv print buildings
run_gam csv ./buildings.csv gam delete building ~buildingId
echo "Creating OrgUnit ${newou}" echo "Creating OrgUnit ${newou}"
$gam create ou "${newou}" run_gam create ou "${newou}"
export GAM_THREADS=5 export GAM_THREADS=5
echo email > sample.csv; echo email > sample.csv;
for i in {1..10}; do for i in {1..10}; do
@@ -872,156 +947,165 @@ jobs:
done done
driveid=$($gam user $gam_user add shareddrive "${newbase}" returnidonly) driveid=$($gam user $gam_user add shareddrive "${newbase}" returnidonly)
echo "Created shared drive ${driveid}" echo "Created shared drive ${driveid}"
$gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB- ou "${newou}" run_gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB- ou "${newou}"
$gam user $newuser add license workspaceenterpriseplus run_gam user $newuser add license workspaceenterpriseplus
$gam user $newuser update photo https://dummyimage.com/98x98/000/fff.jpg run_gam user $newuser update photo https://dummyimage.com/98x98/000/fff.jpg
$gam user $newuser get photo run_gam user $newuser get photo
$gam user $newuser delete photo run_gam user $newuser delete photo
$gam create alias $newalias user $newuser run_gam create alias $newalias user $newuser
$gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true run_gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true
$gam user $gam_user sendemail recipient dev-null@pdl.jaylee.us subject "test message $newbase" message "GHA test message" run_gam user $gam_user sendemail recipient dev-null@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
$gam config enable_dasa false save run_gam config enable_dasa false save
# don't expose policy output # don't expose policy output
$gam show policies > policies.csv run_gam show policies > policies.csv
$gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary run_gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary
$gam print contacts run_gam print contacts
$gam print privileges run_gam print privileges
$gam config enable_dasa true save run_gam config enable_dasa true save
$gam update cigroup $newgroup security memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()' run_gam update cigroup $newgroup security memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
$gam info cigroup $newgroup run_gam info cigroup $newgroup
$gam update group $newgroup add owner $gam_user run_gam update group $newgroup add owner $gam_user
$gam update group $newgroup add member $newuser run_gam update group $newgroup add member $newuser
$gam config enable_dasa false save run_gam config enable_dasa false save
# 9/17/24 temp disable due to Google API sluggishness to see new users for admin commands # 9/17/24 temp disable due to Google API sluggishness to see new users for admin commands
# $gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup # run_gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
# 9/13/25 temp disable due to hangs # 9/13/25 temp disable due to hangs
# $gam create admin $newgroup _HELP_DESK_ADMIN_ROLE org_unit "${newou}" # run_gam create admin $newgroup _HELP_DESK_ADMIN_ROLE org_unit "${newou}"
# $gam config csv_output_row_filter "assignedToUser:regex:${newuser}" print admins | $gam csv - gam delete admin "~roleAssignmentId" # run_gam config csv_output_row_filter "assignedToUser:regex:${newuser}" print admins | run_gam csv - gam delete admin "~roleAssignmentId"
# $gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | $gam csv - gam delete admin "~roleAssignmentId" # run_gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | run_gam csv - gam delete admin "~roleAssignmentId"
$gam config enable_dasa false save run_gam config enable_dasa false save
$gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID ou "${newou}" run_gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID ou "${newou}"
$gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random displayname "GitHub Actions Bulk ${JID}" run_gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random displayname "GitHub Actions Bulk ${JID}"
$gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail "" run_gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail ""
$gam config enable_dasa false save run_gam config enable_dasa false save
$gam csv sample.csv gam user ~email add license workspaceenterpriseplus run_gam csv sample.csv gam user ~email add license workspaceenterpriseplus
#$gam user $newuser add contactdelegate "${newbase}-bulkuser-1" #run_gam user $newuser add contactdelegate "${newbase}-bulkuser-1"
#$gam user $newuser print contactdelegates #run_gam user $newuser print contactdelegates
$gam config enable_dasa true save run_gam config enable_dasa true save
$gam csv sample.csv gam user $gam_user sendemail recipient ~~email~~@pdl.jaylee.us subject "test message $newbase" message "GHA test message" run_gam csv sample.csv gam user $gam_user sendemail recipient ~~email~~@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
$gam csv sample.csv gam update group $newgroup add member ~email run_gam csv sample.csv gam update group $newgroup add member ~email
$gam info group $newgroup run_gam info group $newgroup
$gam info cigroup $newgroup membertree run_gam info cigroup $newgroup membertree
# confirm mailbox is provisoned before continuing # confirm mailbox is provisoned before continuing
$gam user $newuser waitformailbox retries 50 run_gam user $newuser waitformailbox retries 50
$gam user $newuser imap on run_gam user $newuser imap on
$gam user $newuser show imap run_gam user $newuser show imap
$gam user $newuser show delegates run_gam user $newuser show delegates
export biohazard=$(echo -e '\xe2\x98\xa3') export biohazard=$(echo -e '\xe2\x98\xa3')
$gam user $newuser label "$biohazard unicode biohazard $biohazard" run_gam user $newuser label "$biohazard unicode biohazard $biohazard"
$gam user $newuser show labels run_gam user $newuser show labels
$gam user $newuser show labels > labels.txt run_gam user $newuser show labels > labels.txt
$gam user $gam_user importemail subject "GHA import $newbase" message "This is a test import" labels IMPORTANT,UNREAD,INBOX,STARRED run_gam user $gam_user importemail subject "GHA import $newbase" message "This is a test import" labels IMPORTANT,UNREAD,INBOX,STARRED
$gam user $gam_user insertemail subject "GHA insert $newbase" file gam.py labels INBOX,UNREAD # yep body is gam code run_gam user $gam_user insertemail subject "GHA insert $newbase" file gam.py labels INBOX,UNREAD # yep body is gam code
$gam user $gam_user sendemail recipient admin@pdl.jaylee.us subject "GHA send $gam_user $newbase" file gam.py run_gam user $gam_user sendemail recipient admin@pdl.jaylee.us subject "GHA send $gam_user $newbase" file gam.py
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test" run_gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
$gam csvfile sample.csv:email waitformailbox retries 20 run_gam csvfile sample.csv:email waitformailbox retries 20
$gam user $newuser delegate to "${newbase}-bulkuser-1" || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (delegation failed) run_gam user $newuser delegate to "${newbase}-bulkuser-1" || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (delegation failed)
$gam users "$gam_user $newbase-bulkuser-1 $newbase-bulkuser-2 $newbase-bulkuser-3" delete messages query in:anywhere maxtodelete 99999 doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages) run_gam -a "0 60" users "$gam_user $newbase-bulkuser-1 $newbase-bulkuser-2 $newbase-bulkuser-3" delete messages query in:anywhere maxtodelete 99999 doit
$gam users "$newbase-bulkuser-4 $newbase-bulkuser-5 $newbase-bulkuser-6" trash messages query in:anywhere maxtotrash 99999 doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages) run_gam -a "0 60" users "$newbase-bulkuser-4 $newbase-bulkuser-5 $newbase-bulkuser-6" trash messages query in:anywhere maxtotrash 99999 doit
$gam users "$newbase-bulkuser-7 $newbase-bulkuser-8 $newbase-bulkuser-9" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages) run_gam -a "0 60" users "$newbase-bulkuser-7 $newbase-bulkuser-8 $newbase-bulkuser-9" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit
$gam user $newuser delete label --ALL_LABELS-- run_gam user $newuser delete label --ALL_LABELS--
$gam config csv_output_row_filter "name:regex:gha-test-${JID}" print features | $gam csv - gam delete feature ~name run_gam config csv_output_row_filter "name:regex:gha-test-${JID}" redirect csv ./features.csv print features
$gam create feature name VC-$newbase run_gam csv ./features.csv gam delete feature ~name
$gam create feature name Whiteboard-$newbase run_gam create feature name VC-$newbase
$gam create building "My Building - $newbase" id $newbuilding floors 1,2,3,4,5,6,7,8,9,10,11,12,14,15 description "No 13th floor here..." run_gam create feature name Whiteboard-$newbase
$gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room run_gam create building "My Building - $newbase" id $newbuilding floors 1,2,3,4,5,6,7,8,9,10,11,12,14,15 description "No 13th floor here..."
$gam info resource $newresource run_gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room
$gam user $newuser add drivefile drivefilename "TPS Reports" mimetype gfolder run_gam info resource $newresource
$gam user $newuser show filelist run_gam user $newuser add drivefile drivefilename "TPS Reports" mimetype gfolder
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id # clear ACLs run_gam user $newuser show filelist
$gam calendar $gam_user add read domain run_gam redirect csv ./cal-acl.csv calendar $gam_user printacl
$gam calendar $gam_user add freebusy default run_gam csv ./cal-acl.csv gam calendar $gam_user delete ~id # clear ACLs
$gam calendar $gam_user add editor $newuser run_gam calendar $gam_user add read domain
$gam calendar $gam_user showacl run_gam calendar $gam_user add freebusy default
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id run_gam calendar $gam_user add editor $newuser
$gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all run_gam calendar $gam_user showacl
$gam calendar $gam_user printevents after -0d run_gam redirect csv ./cal-acl.csv calendar $gam_user printacl
$gam config enable_dasa false save run_gam csv ./cal-acl.csv gam calendar $gam_user delete ~id
run_gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all
run_gam calendar $gam_user printevents after -0d
run_gam config enable_dasa false save
matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" returnidonly) matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" returnidonly)
$gam create vaulthold matter $matterid name "GHA hold ${newbase}" corpus mail ou "$newou" run_gam create vaulthold matter "$matterid" name "GHA hold ${newbase}" corpus mail ou "$newou"
$gam print vaultmatters matterstate open run_gam print vaultmatters matterstate open
$gam print vaultholds matter $matterid run_gam print vaultholds matter $matterid
$gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser run_gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail ou "$newou" run_gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail ou "$newou"
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~ run_gam redirect csv ./exports.csv print exports matter $matterid
$gam config enable_dasa true save run_gam csv ./exports.csv gam info export $matterid id:~~id~~
$gam csv sample.csv gam user ~email add calendar id:$newresource run_gam config enable_dasa true save
$gam delete resource $newresource run_gam csv sample.csv gam user ~email add calendar id:$newresource
$gam delete feature Whiteboard-$newbase run_gam delete resource $newresource
$gam delete feature VC-$newbase run_gam delete feature Whiteboard-$newbase
$gam delete building $newbuilding run_gam delete feature VC-$newbase
$gam delete group $newgroup run_gam delete building $newbuilding
$gam config enable_dasa false save run_gam delete group $newgroup
run_gam config enable_dasa false save
echo start echo start
$gam user $newuser delete license workspaceenterpriseplus run_gam user $newuser delete license workspaceenterpriseplus
echo finish echo finish
$gam config enable_dasa true save run_gam config enable_dasa true save
$gam whatis $newuser || if [ $? != 20 ]; then exit $?; fi # expect a 20 return code (is a user) run_gam -a "0 20" whatis $newuser
$gam user $gam_user show tokens run_gam user $gam_user show tokens
$gam config enable_dasa false save run_gam config enable_dasa false save
download_dir="${RUNNER_TEMP}/TEMP_DELETE_ME" download_dir="${RUNNER_TEMP}/TEMP_DELETE_ME"
mkdir -v "$download_dir" mkdir -v "$download_dir"
$gam print exports matter $matterid | $gam csv - gam download export $matterid id:~~id~~ targetfolder "$download_dir" run_gam redirect csv ./exports.csv print exports matter $matterid
run_gam csv ./exports.csv gam download export $matterid id:~~id~~ targetfolder "$download_dir"
rm -rvf "$download_dir" rm -rvf "$download_dir"
$gam delete hold "GHA hold $newbase" matter $matterid run_gam delete hold "GHA hold $newbase" matter $matterid
$gam update matter $matterid action close run_gam update matter $matterid action close
$gam update matter $matterid action delete run_gam update matter $matterid action delete
# shakes off vault hold on user so we can delete # shakes off vault hold on user so we can delete
$gam print users query "email:${newuser}" orgunitpath | $gam csv - gam update user ~primaryEmail ou ~orgUnitPath run_gam redirect csv ./users.csv print users query "email:${newuser}" orgunitpath
$gam user $newuser show holds || if [ $? != 55 ]; then exit $?; fi # expect a 55 return code run_gam csv ./users.csv gam update user ~primaryEmail ou ~orgUnitPath
run_gam user $newuser show holds || if [ $? != 55 ]; then exit $?; fi # expect a 55 return code
export sn="$JID$JID$JID$JID-$(openssl rand -base64 32 | sed 's/[^a-zA-Z0-9]//g')" export sn="$JID$JID$JID$JID-$(openssl rand -base64 32 | sed 's/[^a-zA-Z0-9]//g')"
$gam create device serialnumber $sn devicetype android run_gam create device serialnumber $sn devicetype android
$gam delete contacts emailmatchpattern "^${newbase}@example.com$" run_gam delete contacts emailmatchpattern "^${newbase}@example.com$"
$gam config enable_dasa true save run_gam config enable_dasa true save
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (vault hold on user) run_gam redirect csv ./users.csv print users query "gha.jid=$JID"
$gam print mobile run_gam -a "0 50" csv ./users.csv gam delete user ~primaryEmail
$gam print devices clientstates run_gam print mobile
$gam print browsers run_gam print devices clientstates
$gam print cros allfields orderby serialnumber run_gam print browsers
$gam show crostelemetry storagepercentonly run_gam print cros allfields orderby serialnumber
$gam report usageparameters customer run_gam show crostelemetry storagepercentonly
$gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins run_gam report usageparameters customer
$gam report customer todrive tdnobrowser run_gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
#$gam report users fields accounts:is_less_secure_apps_access_allowed,gmail:last_imap_time,gmail:last_pop_time filters "accounts:last_login_time>2025-01-01T00:00:00.000Z" todrive tdnobrowser run_gam report customer todrive tdnobrowser
$gam report users todrive tdnobrowser #run_gam report users fields accounts:is_less_secure_apps_access_allowed,gmail:last_imap_time,gmail:last_pop_time filters "accounts:last_login_time>2025-01-01T00:00:00.000Z" todrive tdnobrowser
$gam report admin start -3d todrive tdnobrowser run_gam report users todrive tdnobrowser
$gam print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-" | $gam csv - gam delete device id ~name run_gam report admin start -3d todrive tdnobrowser
$gam config enable_dasa false save run_gam redirect csv ./devices.csv print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-"
$gam print userinvitations run_gam csv ./devices.csv gam delete device id ~name
$gam print userinvitations | $gam csv - gam send userinvitation ~name run_gam config enable_dasa false save
$gam config enable_dasa false save run_gam print userinvitations
$gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition run_gam redirect csv ./invitations.csv print userinvitations
$gam print caalevels run_gam csv ./invitations.csv gam send userinvitation ~name
$gam delete caalevel "zzz_${newbase}" run_gam config enable_dasa false save
$gam user $gam_user add drivefile localfile gam.py parentid "${driveid}" run_gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition
$gam user $gam_user update shareddrive "${driveid}" ou "${newou}" run_gam print caalevels
$gam user $gam_user show shareddrives asadmin run_gam delete caalevel "zzz_${newbase}"
$gam user $gam_user update shareddrive "${driveid}" ou "aaaGithub Actions" # so we can delete our OU... run_gam user $gam_user add drivefile localfile gam.py parentid "${driveid}"
$gam user $gam_user delete shareddrive "${driveid}" nukefromorbit run_gam user $gam_user update shareddrive "${driveid}" ou "${newou}"
ssoprofile=$($gam config debug_level 1 create inboundssoprofile name "El Goog ${newbase}" loginurl https://www.google.com logouturl https://www.google.com changepasswordurl https://www.google.com entityid ElGoog return_name_only) run_gam user $gam_user show shareddrives asadmin
run_gam user $gam_user update shareddrive "${driveid}" ou "aaaGithub Actions" # so we can delete our OU...
run_gam user $gam_user delete shareddrive "${driveid}" nukefromorbit
ssoprofile=$(run_gam config debug_level 1 create inboundssoprofile name "El Goog ${newbase}" loginurl https://www.google.com logouturl https://www.google.com changepasswordurl https://www.google.com entityid ElGoog return_name_only)
if [ ${ssoprofile} != 'inProgress' ]; then if [ ${ssoprofile} != 'inProgress' ]; then
$gam create inboundssocredential profile "id:${ssoprofile}" generate_key run_gam create inboundssocredential profile "id:${ssoprofile}" generate_key
#$gam create inboundssoassignment profile "id:${ssoprofile}" orgunit "${newou}" mode SAML_SSO #run_gam create inboundssoassignment profile "id:${ssoprofile}" orgunit "${newou}" mode SAML_SSO
#$gam delete inboundssoassignment "orgunit:${newou}" #run_gam delete inboundssoassignment "orgunit:${newou}"
$gam delete inboundssoprofile "id:${ssoprofile}" run_gam delete inboundssoprofile "id:${ssoprofile}"
fi fi
echo "printer model count:" echo "printer model count:"
$gam print printermodels | wc -l run_gam print printermodels | wc -l
$gam print printers run_gam print printers
printerid=$($gam create printer displayname "${newbase}" uri ipp://localhost:631 driverless description "made by ${gam_user}" ou "${newou}" nodetails | awk '{print substr($2, 1, length($2)-1)}') printerid=$($gam create printer displayname "${newbase}" uri ipp://localhost:631 driverless description "made by ${gam_user}" ou "${newou}" returnIdOnly)
$gam info printer "$printerid" run_gam info printer "$printerid"
$gam delete printer "$printerid" run_gam delete printer "$printerid"
$gam delete ou "${newou}" run_gam delete ou "${newou}"
- name: Tar Cache archive - name: Tar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true' if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
@@ -1035,24 +1119,10 @@ jobs:
echo '.git*' > ./excludes.txt echo '.git*' > ./excludes.txt
tar cJvvf cache.tar.xz --exclude-from=excludes.txt $tar_folders tar cJvvf cache.tar.xz --exclude-from=excludes.txt $tar_folders
merge:
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-24.04
needs: build
permissions:
contents: write
packages: write
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: gam-binaries
pattern: gam-binaries-*
publish: publish:
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
needs: merge needs: build
permissions: permissions:
contents: write contents: write
packages: write packages: write
@@ -1060,13 +1130,17 @@ jobs:
steps: steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # 5.0.0 uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
path: gam-binaries/
merge-multiple: true
skip-decompress: true
- name: VirusTotal Scan - name: VirusTotal Scan
uses: crazy-max/ghaction-virustotal@d34968c958ae283fe976efed637081b9f9dcf74f # 4.2.0 uses: crazy-max/ghaction-virustotal@d34968c958ae283fe976efed637081b9f9dcf74f # 4.2.0
@@ -1083,7 +1157,7 @@ jobs:
echo "dateversion=${dateversion}" >> $GITHUB_OUTPUT echo "dateversion=${dateversion}" >> $GITHUB_OUTPUT
- name: Publish draft release - name: Publish draft release
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3 uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with: with:
draft: true draft: true
prerelease: false prerelease: false

View File

@@ -11,8 +11,8 @@ authors = [
#significant compile dependencies. #significant compile dependencies.
dependencies = [ dependencies = [
"arrow>=1.3.0", "arrow>=1.3.0",
"chardet>=5.2.0", "chardet==5.2.0",
"cryptography==46.0.3", "cryptography>=46.0.5",
"distro; sys_platform=='linux'", "distro; sys_platform=='linux'",
"filelock>=3.18.0", "filelock>=3.18.0",
"google-api-python-client>=2.167.0", "google-api-python-client>=2.167.0",

View File

@@ -4568,8 +4568,8 @@ gam check ou|org <OrgUnitItem> [todrive <ToDriveAttribute>*]
usedriverlessconfig| usedriverlessconfig|
<PrinterFieldNameList> ::= "<PrinterFieldName>(,<PrinterFieldName>)*" <PrinterFieldNameList> ::= "<PrinterFieldName>(,<PrinterFieldName>)*"
gam create printer <PrinterAttribute>+ gam create printer <PrinterAttribute>+ [nodetails|returnidonly]
gam update printer <PrinterID> <PrinterAttribute>+ gam update printer <PrinterID> <PrinterAttribute>+ [nodetails|returnidonly]
gam delete printer gam delete printer
<PrinterIDList>| <PrinterIDList>|
<FileSelector>| <FileSelector>|
@@ -4662,6 +4662,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
[event|events <EventNameList>] [ip <String>] [event|events <EventNameList>] [ip <String>]
[gmaileventtypes <NumberRangeList>] [gmaileventtypes <NumberRangeList>]
[groupidfilter <String>] [resourcedetailsfilter <String>] [groupidfilter <String>] [resourcedetailsfilter <String>]
[notimesort]
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>] [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
[countsonly [bydate|summary] [eventrowfilter]] [countsonly [bydate|summary] [eventrowfilter]]
(addcsvdata <FieldName> <String>)* [shownoactivities] (addcsvdata <FieldName> <String>)* [shownoactivities]
@@ -5692,6 +5693,7 @@ gam download storagefile <StorageBucketObjectName>
fullname| fullname|
gender| gender|
givenname|firstname| givenname|firstname|
guestaccountinfo|
id| id|
ims|im| ims|im|
includeinglobaladdresslist|gal| includeinglobaladdresslist|gal|
@@ -5699,6 +5701,7 @@ gam download storagefile <StorageBucketObjectName>
isdelegatedadmin|admin|isadmin| isdelegatedadmin|admin|isadmin|
isenforcedin2sv|is2svenforced| isenforcedin2sv|is2svenforced|
isenrolledin2sv|is2svenrolled| isenrolledin2sv|is2svenrolled|
isguestuser|
ismailboxsetup| ismailboxsetup|
keyword|keywords| keyword|keywords|
language|languages| language|languages|
@@ -6906,6 +6909,7 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
[copyfilepermissions [<Boolean>]] [copyfilepermissions [<Boolean>]]
[copyfileinheritedpermissions [<Boolean>] [copyfileinheritedpermissions [<Boolean>]
[copyfilenoninheritedpermissions [<Boolean>] [copyfilenoninheritedpermissions [<Boolean>]
[copyfolderpermissions [<Boolean>]]
[copymergewithparentfolderpermissions [<Boolean>]] [copymergewithparentfolderpermissions [<Boolean>]]
[copymergedtopfolderpermissions [<Boolean>]] [copymergedtopfolderpermissions [<Boolean>]]
[copytopfolderpermissions [<Boolean>]] [copytopfolderpermissions [<Boolean>]]
@@ -6935,6 +6939,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
[createshortcutsfornonmovablefiles [<Boolean>]] [createshortcutsfornonmovablefiles [<Boolean>]]
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip] [duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
[duplicatefolders merge|duplicatename|uniquename|skip] [duplicatefolders merge|duplicatename|uniquename|skip]
[copyfolderpermissions [<Boolean>]]
[copymergewithparentfolderpermissions [<Boolean>]] [copymergewithparentfolderpermissions [<Boolean>]]
[copymergedtopfolderpermissions [<Boolean>]] [copymergedtopfolderpermissions [<Boolean>]]
[copytopfolderpermissions [<Boolean>]] [copytopfolderpermissions [<Boolean>]]

View File

@@ -1,3 +1,156 @@
7.34.12
Fixed build errors that prevented Windows zip files from being created.
Added option `returnidonly` to `gam create|update printer` that causes GAM to return just the ID
of the printer.
7.34.11
Updated gam-install.sh script for macOS/Linux to properly config GAM when the answer to the following question is No.
```
Can you run a full browser on this machine? (usually Y for macOS, N for Linux if you SSH into this machine)
```
7.34.10
Fixed bug where `formatjson quotechar <Character>` on the command line did not override `redirect csv <FileName> multiprocess quotechar <Character>`.
7.34.09
Updated `gam <UserTypeEntity> update photo` to delete the user's existing photo
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
7.34.08
Rebuild to avoid the following error:
```
requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
```
7.34.07
Added the following command to create a guest user.
* See: https://support.google.com/a/answer/16558545
```
gam create guestuser <EmailAddress>
```
Added the following items to `<UserFieldName>`:
* `guestaccountinfo` - Additional guest-related metadata fields
* `isguestuser` - Indicates if the inserted user is a guest
7.34.06
Added option `copyfolderpermissions [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`.
When `copyfolderpermissions false` is specified, no folder permissions are copied; this simplifies
disabling all folder permission copying.
When not specified or `copyfolderpermissions [true]` is specified, folder permissions are copied based on the following options:
```
copymergewithparentfolderpermissions [<Boolean>]
copymergedtopfolderpermissions [<Boolean>]
copytopfolderpermissions [<Boolean>]
copytopfolderiheritedpermissions [<Boolean>]
copytopfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
copymergedsubfolderpermissions [<Boolean>]
copysubfolderpermissions [<Boolean>]
copysubfolderinheritedpermissions [<Boolean>]
copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
```
7.34.05
Updated `gam report <ActivityApplictionName>` to perform a reverse chronological sort
on all rows across multiple users and/or event names; this is consistent with the behavior
in the Admin console. Use option `notimesort` to suppress this sort.
7.34.04
Updated `gam <UserTypeEntity> create drivefileacl <DriveFileEntity> user <UserItem> role owner` to better
handle the case where the current owner of a file is suspended. Previously, the command was displayed as an error
even though the ownership was changed.
```
gam user currentowner@domain.com add drivefileacl <DriveFileID> user newowner@domain.com role owner
User: currentowner@domain.com, Add 1 Drive File/Folder ACL
User: currentowner@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: newowner@domain.com, Add Failed: Sorry, the items were successfully shared but emails could not be sent to newowner@domain.com.
```
Now the command is displayed as a success with a note indicating that the ownership change email was not sent.
```
gam user currentowner@domain.com add drivefileacl <DriveFileID> user newowner@domain.com role owner
User: currentowner@domain.com, Add 1 Drive File/Folder ACL
User: currentowner@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: newowner@domain.com, Added: Sorry, the items were successfully shared but emails could not be sent to newowner@domain.com.
New Owner
id: 10834698115409747890
type: user
emailAddress: newowner@domain.com
domain: domain.com
role: owner
permissionDetails:
role: writer
type: file
inherited: True
inheritedFrom: Unknown
role: owner
type: file
inherited: False
deleted: False
pendingOwner: False
```
7.34.03
Updated to Python 3.14.3
Updated Cryptography to 46.0.5
Updated `gam course <CourseID> create student|teacher <EmailAddress>` error message when
`<EmailAddress>` is not in a trusted domain to remove suggestion about creating an invitation.
7.34.02
Updated GAM to prevent errors like the following:
```
ERROR: Unable to find the server at oauth2.googleapis.com
ERROR: Unable to find the server at gmail.googleapis.com
```
If you experience any unexpected errors, post a message to:
* The GAM Discussion Forum (google-apps-manager@googlegroups.com)
* The GAM Public Chat Room (https://chat.google.com/app/chat/AAAA4BULhWo)
7.34.01
Updated `gam create|update adminrole` to handle the following errors:
```
ERROR: 400: invalid - Invalid Role privileges
ERROR: 400: required - Required parameter: [resource.privileges[n].service_id]
```
7.34.00
Added variable `csv_output_header_required` to `gam.cfg` that is a comma separated list of `<Strings>`
that are required to be in the list of column headers in the CSV file written by a gam print command.
This will typically be used to specify headers that are required in subsequent commands that process
the CSV file even if the API didn't return any data for those columns.
Updated the following commands to not require the `Directory API - Domains` scope
unless the `internal` or `external` options are used to request the member category.
```
gam info|print groups
gam print|show group-members
gam info|print cigroups
gam print|show cigroup-members
gam <UserTypeEntity> print|show filesharecounts
```
7.33.03
Fixed bug in `gam [<UserTypeEntity>] sendemail ... from <EmailAddress> replyto <EmailAddress>`
where an `<EmailAddress>` of the form `Text <user@domain.com>` had the `Text` removed.
7.33.02 7.33.02
Added `hideinvitationssetting` to `<UserCalendarSettingsField>` used by Added `hideinvitationssetting` to `<UserCalendarSettingsField>` used by
@@ -1388,7 +1541,7 @@ Re-run the command specify a new service account name with: saname <ServiceAccou
Native support for Windows 11 Arm-based devices. Native support for Windows 11 Arm-based devices.
Renamed some MacOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64". Renamed some macOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".
7.06.05 7.06.05
@@ -1997,7 +2150,7 @@ for `[R] 35) Meet API (supports readonly)` as it is a special case.
7.00.39 7.00.39
Supported MacOS versions are now in the download filename. Supported macOS versions are now in the download filename.
Minor code fixes. Minor code fixes.
@@ -3800,11 +3953,11 @@ See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#fil
6.65.12 6.65.12
Additional updates on MacOS when a `gam csv` command is interrupted with a contol-C. Additional updates on macOS when a `gam csv` command is interrupted with a contol-C.
6.65.11 6.65.11
Updated multiprocessing to handle the following error that occurs on MacOS when a `gam csv` command Updated multiprocessing to handle the following error that occurs on macOS when a `gam csv` command
is interrupted with a contol-C. is interrupted with a contol-C.
``` ```
multiprocessing/resource_tracker.py:224: UserWarning: resource_tracker: There appear to be N leaked semaphore objects to clean up at shutdown multiprocessing/resource_tracker.py:224: UserWarning: resource_tracker: There appear to be N leaked semaphore objects to clean up at shutdown
@@ -5965,7 +6118,7 @@ Improved code for `gam [<UserTypeEntity>] create teamdrive <Name> ou <OrgUnitIte
6.29.04 6.29.04
Updated multiprocessing on MacOS to use `spawn` instead of `fork` when starting subprocesses Updated multiprocessing on macOS to use `spawn` instead of `fork` when starting subprocesses
as `fork` was unreliable when large numbers (>20) of threads were used; subprocesses would as `fork` was unreliable when large numbers (>20) of threads were used; subprocesses would
hang and never complete. hang and never complete.
@@ -6087,7 +6240,7 @@ then filters the list to only those in `<PeopleContactGroupItem>`; quota limits
6.28.03 6.28.03
Build MacOS x86_64 and arm64 executables. Build macOS x86_64 and arm64 executables.
6.28.02 6.28.02
@@ -6434,7 +6587,7 @@ Added command that allows checking if a user is a member of specific groups and
6.26.00 6.26.00
Build MacOS universal version. Build macOS universal version.
* Upgraded to OpenSSL 3.0.5 where possible. * Upgraded to OpenSSL 3.0.5 where possible.
@@ -11276,7 +11429,7 @@ ID of the created Team Drive as output. This will be useful in scripts that crea
want to perform subsequent GAM command on the Team Drive. This ID will only be valid when the return code want to perform subsequent GAM command on the Team Drive. This ID will only be valid when the return code
of the command is 0; program accordingly. of the command is 0; program accordingly.
``` ```
Linux/MacOS Linux/macOS
teamDriveId=`gam user user@domain.com create teamdrive ... returnidonly` teamDriveId=`gam user user@domain.com create teamdrive ... returnidonly`
Windows PowerShell Windows PowerShell
$teamDriveId = & gam user user@domain.com create teamdrive ... returnidonly` $teamDriveId = & gam user user@domain.com create teamdrive ... returnidonly`
@@ -11368,7 +11521,7 @@ file ID of the created file as output. This will be useful in scripts that creat
want to perform subsequent GAM command on the file. This file ID will only be valid when the return code want to perform subsequent GAM command on the file. This file ID will only be valid when the return code
of the command is 0; program accordingly. of the command is 0; program accordingly.
``` ```
Linux/MacOS Linux/macOS
fileId=`gam user user@domain.com create drivefile ... returnidonly` fileId=`gam user user@domain.com create drivefile ... returnidonly`
Windows PowerShell Windows PowerShell
$fileId = & gam user user@domain.com create drivefile ... returnidonly` $fileId = & gam user user@domain.com create drivefile ... returnidonly`
@@ -15451,7 +15604,7 @@ gam print group-members [todrive [<ToDriveAttribute>]]
4.55.44 4.55.44
Improve MacOS version of GAM's use of OpenSSL 1.0.2n. Improve macOS version of GAM's use of OpenSSL 1.0.2n.
Recode pyinstaller .spec files. Recode pyinstaller .spec files.
4.55.43 4.55.43
@@ -15478,7 +15631,7 @@ Fixed bug that made some gam print commands throw an exception.
4.55.40 4.55.40
Update MacOS version of GAM to use OpenSSL 1.0.2n. Update macOS version of GAM to use OpenSSL 1.0.2n.
4.55.39 4.55.39
@@ -18304,7 +18457,7 @@ Changed gam info user formatjson to show licenses in SKU ID (SKU Display Name) f
4.42.00 4.42.00
Fixed problem where control-C was not recognized when multiple processes were running via gam batch/csv. Fixed problem where control-C was not recognized when multiple processes were running via gam batch/csv.
Gam terminates cleanly on Linux/MacOS when you hit control-C in this situation; on Windows exceptions are Gam terminates cleanly on Linux/macOS when you hit control-C in this situation; on Windows exceptions are
thrown but Gam does terminate. thrown but Gam does terminate.
4.41.08 4.41.08

View File

@@ -10,7 +10,7 @@ OPTIONS:
-d Directory where gam folder will be installed. Default is \$HOME/bin/ -d Directory where gam folder will be installed. Default is \$HOME/bin/
-a Architecture to install (x86_64, arm64). Default is to detect your arch with "uname -m". -a Architecture to install (x86_64, arm64). Default is to detect your arch with "uname -m".
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s". -o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
-b OS version. Default is to detect on MacOS and Linux. -b OS version. Default is to detect on macOS and Linux.
-l Just upgrade GAM to latest version. Skips project creation and auth. -l Just upgrade GAM to latest version. Skips project creation and auth.
-p Profile update (true, false). Should script add gam command to environment. Default is true. -p Profile update (true, false). Should script add gam command to environment. Default is true.
-u Admin user email address to use with GAM. Default is to prompt. -u Admin user email address to use with GAM. Default is to prompt.
@@ -247,7 +247,7 @@ case $gamos in
archgrep="-arm64\|-aarch64" archgrep="-arm64\|-aarch64"
;; ;;
*) *)
echo_red "ERROR: this installer currently only supports x86_64 and arm64 MacOS. Looks like you're running on ${gamarch}. Exiting." echo_red "ERROR: this installer currently only supports x86_64 and arm64 macOS. Looks like you're running on ${gamarch}. Exiting."
exit exit
;; ;;
esac esac
@@ -256,19 +256,19 @@ case $gamos in
versionless_urls=$(echo -e "$gam_macos_urls" | \ versionless_urls=$(echo -e "$gam_macos_urls" | \
grep -e "-macos-") grep -e "-macos-")
if [ "$versionless_urls" == "" ]; then if [ "$versionless_urls" == "" ]; then
# versions after 7.00.38 include MacOS version info # versions after 7.00.38 include macOS version info
gam_macos_vers=$(echo -e "$gam_macos_urls" | \ gam_macos_vers=$(echo -e "$gam_macos_urls" | \
grep --only-matching -e '-macos[0-9\.]*' | \ grep --only-matching -e '-macos[0-9\.]*' | \
cut -c 7-10) cut -c 7-10)
for gam_mac_ver in $gam_macos_vers; do for gam_mac_ver in $gam_macos_vers; do
if version_gt $currentversion $gam_mac_ver; then if version_gt $currentversion $gam_mac_ver; then
download_url=$(echo -e "$gam_macos_urls" | grep "$gam_mac_ver") download_url=$(echo -e "$gam_macos_urls" | grep "$gam_mac_ver")
echo_green "You are running MacOS ${currentversion} Using GAM compiled against ${gam_mac_ver}" echo_green "You are running macOS ${currentversion} Using GAM compiled against ${gam_mac_ver}"
break break
fi fi
done done
if [ -z ${download_url+x} ]; then if [ -z ${download_url+x} ]; then
echo_red "Sorry, you are running MacOS ${osversion} but GAM on ${gamarch} requires MacOS ${gam_mac_ver} or newer. Exiting." echo_red "Sorry, you are running macOS ${osversion} but GAM on ${gamarch} requires macOS ${gam_mac_ver} or newer. Exiting."
exit exit
fi fi
else else
@@ -283,13 +283,13 @@ case $gamos in
esac esac
download_url=$(echo -e "$download_urls" | grep -e $archgrep) download_url=$(echo -e "$download_urls" | grep -e $archgrep)
if version_gt "$osversion" "$minimum_version"; then if version_gt "$osversion" "$minimum_version"; then
echo_green "You are running MacOS ${osversion}, good. Downloading GAM from ${download_url}." echo_green "You are running macOS ${osversion}, good. Downloading GAM from ${download_url}."
else else
echo_red "Sorry, you are running MacOS ${osversion} but GAM on ${gamarch} requires MacOS ${minimum_version}. Exiting." echo_red "Sorry, you are running macOS ${osversion} but GAM on ${gamarch} requires macOS ${minimum_version}. Exiting."
exit exit
fi fi
if [ -z ${download_url+x} ]; then if [ -z ${download_url+x} ]; then
echo_red "Sorry, you are running MacOS ${currentversion} but GAM on ${gamarch} requires MacOS ${minimum_version}. Exiting." echo_red "Sorry, you are running macOS ${currentversion} but GAM on ${gamarch} requires macOS ${minimum_version}. Exiting."
exit exit
fi fi
fi fi
@@ -302,7 +302,7 @@ case $gamos in
grep ".zip") grep ".zip")
;; ;;
*) *)
echo_red "Sorry, this installer currently only supports Linux and MacOS. Looks like you're running on ${gamos}. Exiting." echo_red "Sorry, this installer currently only supports Linux and macOS. Looks like you're running on ${gamos}. Exiting."
exit exit
;; ;;
esac esac
@@ -368,18 +368,15 @@ if [ "$upgrade_only" = true ]; then
exit exit
fi fi
# Set config command
#config_cmd="config no_browser false"
while true; do while true; do
read -p "Can you run a full browser on this machine? (usually Y for MacOS, N for Linux if you SSH into this machine) " yn read -p "Can you run a full browser on this machine? (usually Y for macOS, N for Linux if you SSH into this machine) " yn
case $yn in case $yn in
[Yy]*) [Yy]*)
"$target_gam" config no_browser false save
break break
;; ;;
[Nn]*) [Nn]*)
# config_cmd="config no_browser true" "$target_gam" config no_browser true save
touch "$target_folder/nobrowser.txt" > /dev/null 2>&1
break break
;; ;;
*) *)
@@ -397,7 +394,6 @@ while true; do
if [ "$adminuser" == "" ]; then if [ "$adminuser" == "" ]; then
read -p "Please enter your Google Workspace admin email address: " adminuser read -p "Please enter your Google Workspace admin email address: " adminuser
fi fi
# "$target_gam" $config_cmd create project $adminuser
"$target_gam" create project $adminuser "$target_gam" create project $adminuser
rc=$? rc=$?
if (( $rc == 0 )); then if (( $rc == 0 )); then
@@ -423,7 +419,6 @@ while $project_created; do
read -p "Are you ready to authorize GAM to perform Google Workspace management operations as your admin account? (yes or no) " yn read -p "Are you ready to authorize GAM to perform Google Workspace management operations as your admin account? (yes or no) " yn
case $yn in case $yn in
[Yy]*) [Yy]*)
# "$target_gam" $config_cmd oauth create $adminuser
"$target_gam" oauth create $adminuser "$target_gam" oauth create $adminuser
rc=$? rc=$?
if (( $rc == 0 )); then if (( $rc == 0 )); then
@@ -453,7 +448,6 @@ while $admin_authorized; do
read -p "Please enter the email address of a regular Google Workspace user: " regularuser read -p "Please enter the email address of a regular Google Workspace user: " regularuser
fi fi
echo_yellow "Great! Checking service account scopes.This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console." echo_yellow "Great! Checking service account scopes.This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console."
# "$target_gam" $config_cmd user $regularuser check serviceaccount
"$target_gam" user $regularuser check serviceaccount "$target_gam" user $regularuser check serviceaccount
rc=$? rc=$?
if (( $rc == 0 )); then if (( $rc == 0 )); then
@@ -475,7 +469,6 @@ while $admin_authorized; do
done done
echo_green "Here's information about your new GAM installation:" echo_green "Here's information about your new GAM installation:"
#"$target_gam" $config_cmd save version extended
"$target_gam" version extended "$target_gam" version extended
rc=$? rc=$?
if (( $rc != 0 )); then if (( $rc != 0 )); then

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
""" """
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>' __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.33.02' __version__ = '7.34.12'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
# pylint: disable=wrong-import-position # pylint: disable=wrong-import-position
@@ -1331,6 +1331,8 @@ def validateEmailAddressOrUID(emailAddressOrUID, checkPeople=True, ciGroupsAPI=F
return emailAddressOrUID return emailAddressOrUID
return emailAddressOrUID.find('@') != 0 and emailAddressOrUID.count('@') <= 1 return emailAddressOrUID.find('@') != 0 and emailAddressOrUID.count('@') <= 1
NAME_EMAIL_ADDRESS_PATTERN = re.compile(r'^(.*)<(.+)>$')
# Normalize user/group email address/uid # Normalize user/group email address/uid
# uid:12345abc -> 12345abc # uid:12345abc -> 12345abc
# foo -> foo@domain # foo -> foo@domain
@@ -1349,6 +1351,10 @@ def normalizeEmailAddressOrUID(emailAddressOrUID, noUid=False, checkForCustomerI
return cg.group(1) return cg.group(1)
if ciGroupsAPI and emailAddressOrUID.startswith('groups/'): if ciGroupsAPI and emailAddressOrUID.startswith('groups/'):
return emailAddressOrUID return emailAddressOrUID
if emailAddressOrUID.find('<') >= 0:
match = NAME_EMAIL_ADDRESS_PATTERN.match(emailAddressOrUID)
if match:
emailAddressOrUID = match.group(2)
atLoc = emailAddressOrUID.find('@') atLoc = emailAddressOrUID.find('@')
if atLoc == 0: if atLoc == 0:
return emailAddressOrUID[1:].lower() if not noLower else emailAddressOrUID[1:] return emailAddressOrUID[1:].lower() if not noLower else emailAddressOrUID[1:]
@@ -4147,7 +4153,7 @@ def SetGlobalVariables():
GC.Values[itemName] = _getCfgPassword(sectionName, itemName) GC.Values[itemName] = _getCfgPassword(sectionName, itemName)
elif varType == GC.TYPE_STRING: elif varType == GC.TYPE_STRING:
GC.Values[itemName] = _getCfgString(sectionName, itemName) GC.Values[itemName] = _getCfgString(sectionName, itemName)
elif varType in {GC.TYPE_STRINGLIST, GC.TYPE_HEADERFORCE, GC.TYPE_HEADERORDER}: elif varType in {GC.TYPE_STRINGLIST, GC.TYPE_HEADERFORCEREQUIRED, GC.TYPE_HEADERORDER}:
GC.Values[itemName] = _getCfgStringList(sectionName, itemName) GC.Values[itemName] = _getCfgStringList(sectionName, itemName)
elif varType == GC.TYPE_FILE: elif varType == GC.TYPE_FILE:
GC.Values[itemName] = _getCfgFile(sectionName, itemName) GC.Values[itemName] = _getCfgFile(sectionName, itemName)
@@ -4171,6 +4177,7 @@ def SetGlobalVariables():
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilter(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FILTER) GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilter(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FILTER)
GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER] = _getCfgHeaderFilter(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_DROP_FILTER) GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER] = _getCfgHeaderFilter(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_DROP_FILTER)
GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_ORDER) GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_ORDER)
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_REQUIRED)
GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = _getCfgRowFilter(outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER) GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = _getCfgRowFilter(outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER)
GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = _getCfgChoice(outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER_MODE) GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = _getCfgChoice(outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER_MODE)
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER] = _getCfgRowFilter(outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER) GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER] = _getCfgRowFilter(outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER)
@@ -4290,7 +4297,7 @@ def SetGlobalVariables():
if GM.Globals[GM.PID] == 0: if GM.Globals[GM.PID] == 0:
for itemName, itemEntry in sorted(GC.VAR_INFO.items()): for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE] varType = itemEntry[GC.VAR_TYPE]
if varType in {GC.TYPE_HEADERFILTER, GC.TYPE_HEADERFORCE, GC.TYPE_HEADERORDER, GC.TYPE_ROWFILTER}: if varType in {GC.TYPE_HEADERFILTER, GC.TYPE_HEADERFORCEREQUIRED, GC.TYPE_HEADERORDER, GC.TYPE_ROWFILTER}:
GM.Globals[GM.PARSER].set(sectionName, itemName, '') GM.Globals[GM.PARSER].set(sectionName, itemName, '')
elif (varType == GC.TYPE_INTEGER) and itemName in {GC.CSV_INPUT_ROW_LIMIT, GC.CSV_OUTPUT_ROW_LIMIT}: elif (varType == GC.TYPE_INTEGER) and itemName in {GC.CSV_INPUT_ROW_LIMIT, GC.CSV_OUTPUT_ROW_LIMIT}:
GM.Globals[GM.PARSER].set(sectionName, itemName, '0') GM.Globals[GM.PARSER].set(sectionName, itemName, '0')
@@ -4305,6 +4312,8 @@ def SetGlobalVariables():
GC.Values[GC.CSV_OUTPUT_HEADER_FORCE] = GM.Globals[GM.CSV_OUTPUT_HEADER_FORCE][:] GC.Values[GC.CSV_OUTPUT_HEADER_FORCE] = GM.Globals[GM.CSV_OUTPUT_HEADER_FORCE][:]
if not GC.Values[GC.CSV_OUTPUT_HEADER_ORDER]: if not GC.Values[GC.CSV_OUTPUT_HEADER_ORDER]:
GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = GM.Globals[GM.CSV_OUTPUT_HEADER_ORDER][:] GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = GM.Globals[GM.CSV_OUTPUT_HEADER_ORDER][:]
if not GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED]:
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = GM.Globals[GM.CSV_OUTPUT_HEADER_REQUIRED][:]
if not GC.Values[GC.CSV_OUTPUT_ROW_FILTER]: if not GC.Values[GC.CSV_OUTPUT_ROW_FILTER]:
GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER][:] GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER][:]
GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER_MODE] GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER_MODE]
@@ -5704,7 +5713,9 @@ def chooseSaAPI(api1, api2):
def buildGAPIServiceObject(api, user, i=0, count=0, displayError=True): def buildGAPIServiceObject(api, user, i=0, count=0, displayError=True):
userEmail = getSaUser(user) userEmail = getSaUser(user)
httpObj = getHttpObj(cache=GM.Globals[GM.CACHE_DIR]) if GM.Globals[GM.HTTP_OBJECT] is None:
GM.Globals[GM.HTTP_OBJECT] = getHttpObj(cache=GM.Globals[GM.CACHE_DIR])
httpObj = GM.Globals[GM.HTTP_OBJECT]
service = getService(api, httpObj) service = getService(api, httpObj)
credentials = getSvcAcctCredentials(api, userEmail) credentials = getSvcAcctCredentials(api, userEmail)
request = transportCreateRequest(httpObj) request = transportCreateRequest(httpObj)
@@ -6078,7 +6089,7 @@ def _checkMemberCategory(member, memberDisplayOptions):
if memberDisplayOptions['showCategory']: if memberDisplayOptions['showCategory']:
member['category'] = category member['category'] = category
if memberDisplayOptions['checkCategory']: if memberDisplayOptions['checkCategory']:
return True if memberDisplayOptions[category] else False return bool(memberDisplayOptions[category])
return True return True
def _checkCIMemberCategory(member, memberDisplayOptions): def _checkCIMemberCategory(member, memberDisplayOptions):
@@ -6091,7 +6102,7 @@ def _checkCIMemberCategory(member, memberDisplayOptions):
if memberDisplayOptions['showCategory']: if memberDisplayOptions['showCategory']:
member['category'] = category member['category'] = category
if memberDisplayOptions['checkCategory']: if memberDisplayOptions['checkCategory']:
return True if memberDisplayOptions[category] else False return bool(memberDisplayOptions[category])
return True return True
def getCIGroupMemberRoleFixType(member): def getCIGroupMemberRoleFixType(member):
@@ -7328,8 +7339,6 @@ def _addEmbeddedImagesToMessage(message, embeddedImages):
except (IOError, UnicodeDecodeError) as e: except (IOError, UnicodeDecodeError) as e:
usageErrorExit(f'{imageFilename}: {str(e)}') usageErrorExit(f'{imageFilename}: {str(e)}')
NAME_EMAIL_ADDRESS_PATTERN = re.compile(r'^.*<(.+)>$')
# Send an email # Send an email
def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msgFrom=None, msgReplyTo=None, def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msgFrom=None, msgReplyTo=None,
html=False, charset=UTF8, attachments=None, embeddedImages=None, html=False, charset=UTF8, attachments=None, embeddedImages=None,
@@ -7351,8 +7360,11 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
def cleanAddr(emailAddr): def cleanAddr(emailAddr):
match = NAME_EMAIL_ADDRESS_PATTERN.match(emailAddr) match = NAME_EMAIL_ADDRESS_PATTERN.match(emailAddr)
if match: if match:
return match.group(1) emailName = match.group(1)
return emailAddr emailAddr = normalizeEmailAddressOrUID(match.group(2), noUid=True, noLower=True)
return (f'{emailName} <{emailAddr}>', emailAddr)
emailAddr = normalizeEmailAddressOrUID(emailAddr, noUid=True, noLower=True)
return (emailAddr, emailAddr)
if msgFrom is None: if msgFrom is None:
msgFrom = _getAdminEmail() msgFrom = _getAdminEmail()
@@ -7372,9 +7384,9 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
if embeddedImages: if embeddedImages:
_addEmbeddedImagesToMessage(message, embeddedImages) _addEmbeddedImagesToMessage(message, embeddedImages)
message['Subject'] = msgSubject message['Subject'] = msgSubject
message['From'] = normalizeEmailAddressOrUID(cleanAddr(msgFrom), noUid=True, noLower=True) message['From'], msgFromAddr = cleanAddr(msgFrom)
if msgReplyTo is not None: if msgReplyTo is not None:
message['Reply-To'] = normalizeEmailAddressOrUID(cleanAddr(msgReplyTo), noUid=True, noLower=True) message['Reply-To'], _ = cleanAddr(msgReplyTo)
if ccRecipients: if ccRecipients:
message['Cc'] = ccRecipients.lower() message['Cc'] = ccRecipients.lower()
if bccRecipients: if bccRecipients:
@@ -7384,8 +7396,8 @@ def send_email(msgSubject, msgBody, msgTo, i=0, count=0, clientAccess=False, msg
if header not in {'Subject', 'From', 'To', 'Reply-To', 'Cc', 'Bcc'}: if header not in {'Subject', 'From', 'To', 'Reply-To', 'Cc', 'Bcc'}:
message[header] = value message[header] = value
if mailBox is None: if mailBox is None:
mailBox = msgFrom mailBox = msgFromAddr
mailBoxAddr = normalizeEmailAddressOrUID(cleanAddr(mailBox), noUid=True, noLower=True) _, mailBoxAddr = cleanAddr(mailBox)
action = Act.Get() action = Act.Get()
Act.Set(Act.SENDEMAIL) Act.Set(Act.SENDEMAIL)
if not GC.Values[GC.SMTP_HOST]: if not GC.Values[GC.SMTP_HOST]:
@@ -7915,6 +7927,7 @@ class CSVPrintFile():
self.JSONtitlesList = [] self.JSONtitlesList = []
self.sortHeaders = [] self.sortHeaders = []
self.SetHeaderForce(GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]) self.SetHeaderForce(GC.Values[GC.CSV_OUTPUT_HEADER_FORCE])
self.SetHeaderRequired(GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED])
if not self.headerForce and titles is not None: if not self.headerForce and titles is not None:
self.SetTitles(titles) self.SetTitles(titles)
self.SetJSONTitles(titles) self.SetJSONTitles(titles)
@@ -8631,6 +8644,9 @@ class CSVPrintFile():
self.SetTitles(headerForce) self.SetTitles(headerForce)
self.SetJSONTitles(headerForce) self.SetJSONTitles(headerForce)
def SetHeaderRequired(self, headerRequired):
self.headerRequired = headerRequired
def SetHeaderOrder(self, headerOrder): def SetHeaderOrder(self, headerOrder):
self.headerOrder = headerOrder self.headerOrder = headerOrder
@@ -9074,6 +9090,8 @@ class CSVPrintFile():
extrasaction = 'raise' extrasaction = 'raise'
if not self.formatJSON: if not self.formatJSON:
if not self.headerForce: if not self.headerForce:
if self.headerRequired:
self.AddTitles(self.headerRequired)
self.SortTitles() self.SortTitles()
self.SortIndexedTitles(self.titlesList) self.SortIndexedTitles(self.titlesList)
if self.fixPaths: if self.fixPaths:
@@ -9091,6 +9109,17 @@ class CSVPrintFile():
titlesList = self.titlesList titlesList = self.titlesList
else: else:
if not self.headerForce: if not self.headerForce:
if self.headerRequired:
for i, v in enumerate(self.JSONtitlesList):
if v.startswith('JSON'):
j = i
for title in self.headerRequired:
self.JSONtitlesList.insert(j, title)
self.JSONtitlesSet.add(title)
j += 1
break
else:
self.AddJSONTitles(self.headerRequired)
if self.fixPaths: if self.fixPaths:
self.FixPathsTitles(self.JSONtitlesList) self.FixPathsTitles(self.JSONtitlesList)
if not self.rows and self.nodataFields is not None: if not self.rows and self.nodataFields is not None:
@@ -9696,8 +9725,6 @@ def CSVFileQueueHandler(mpQueue, mpQueueStdout, mpQueueStderr, csvPF, datetimeNo
GC.Values[GC.TIMEZONE] = tzinfo GC.Values[GC.TIMEZONE] = tzinfo
GC.Values[GC.OUTPUT_TIMEFORMAT] = output_timeformat GC.Values[GC.OUTPUT_TIMEFORMAT] = output_timeformat
clearRowFilters = False clearRowFilters = False
# if sys.platform.startswith('win'):
# signal.signal(signal.SIGINT, signal.SIG_IGN)
if multiprocessing.get_start_method() != 'fork': if multiprocessing.get_start_method() != 'fork':
signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN)
Cmd = glclargs.GamCLArgs() Cmd = glclargs.GamCLArgs()
@@ -9747,7 +9774,7 @@ def CSVFileQueueHandler(mpQueue, mpQueueStdout, mpQueueStderr, csvPF, datetimeNo
GC.Values = dataItem GC.Values = dataItem
csvPF.SetColumnDelimiter(GC.Values[GC.CSV_OUTPUT_COLUMN_DELIMITER]) csvPF.SetColumnDelimiter(GC.Values[GC.CSV_OUTPUT_COLUMN_DELIMITER])
csvPF.SetNoEscapeChar(GC.Values[GC.CSV_OUTPUT_NO_ESCAPE_CHAR]) csvPF.SetNoEscapeChar(GC.Values[GC.CSV_OUTPUT_NO_ESCAPE_CHAR])
csvPF.SetQuoteChar(GC.Values[GC.CSV_OUTPUT_QUOTE_CHAR]) # csvPF.SetQuoteChar(GC.Values[GC.CSV_OUTPUT_QUOTE_CHAR])
csvPF.SetSortHeaders(GC.Values[GC.CSV_OUTPUT_SORT_HEADERS]) csvPF.SetSortHeaders(GC.Values[GC.CSV_OUTPUT_SORT_HEADERS])
csvPF.SetTimestampColumn(GC.Values[GC.CSV_OUTPUT_TIMESTAMP_COLUMN]) csvPF.SetTimestampColumn(GC.Values[GC.CSV_OUTPUT_TIMESTAMP_COLUMN])
csvPF.SetHeaderFilter(GC.Values[GC.CSV_OUTPUT_HEADER_FILTER]) csvPF.SetHeaderFilter(GC.Values[GC.CSV_OUTPUT_HEADER_FILTER])
@@ -9814,8 +9841,6 @@ def StdQueueHandler(mpQueue, stdtype, gmGlobals, gcValues):
except IOError as e: except IOError as e:
systemErrorExit(FILE_ERROR_RC, fdErrorMessage(fd, GM.Globals[stdtype][GM.REDIRECT_NAME], e)) systemErrorExit(FILE_ERROR_RC, fdErrorMessage(fd, GM.Globals[stdtype][GM.REDIRECT_NAME], e))
# if sys.platform.startswith('win'):
# signal.signal(signal.SIGINT, signal.SIG_IGN)
if multiprocessing.get_start_method() != 'fork': if multiprocessing.get_start_method() != 'fork':
signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN)
GM.Globals = gmGlobals.copy() GM.Globals = gmGlobals.copy()
@@ -9900,7 +9925,7 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
csvColumnDelimiter, csvNoEscapeChar, csvQuoteChar, csvColumnDelimiter, csvNoEscapeChar, csvQuoteChar,
csvSortHeaders, csvTimestampColumn, csvSortHeaders, csvTimestampColumn,
csvHeaderFilter, csvHeaderDropFilter, csvHeaderFilter, csvHeaderDropFilter,
csvHeaderForce, csvHeaderOrder, csvHeaderForce, csvHeaderOrder, csvHeaderRequired,
csvRowFilter, csvRowFilterMode, csvRowDropFilter, csvRowDropFilterMode, csvRowFilter, csvRowFilterMode, csvRowDropFilter, csvRowDropFilterMode,
csvRowLimit, csvRowLimit,
showGettings, showGettingsGotNL, showGettings, showGettingsGotNL,
@@ -9909,7 +9934,6 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
with mplock: with mplock:
initializeLogging() initializeLogging()
# if sys.platform.startswith('win'):
if multiprocessing.get_start_method() != 'fork': if multiprocessing.get_start_method() != 'fork':
signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN)
GM.Globals[GM.API_CALLS_RETRY_DATA] = {} GM.Globals[GM.API_CALLS_RETRY_DATA] = {}
@@ -9925,6 +9949,7 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
GM.Globals[GM.CSV_OUTPUT_HEADER_FILTER] = csvHeaderFilter[:] GM.Globals[GM.CSV_OUTPUT_HEADER_FILTER] = csvHeaderFilter[:]
GM.Globals[GM.CSV_OUTPUT_HEADER_FORCE] = csvHeaderForce[:] GM.Globals[GM.CSV_OUTPUT_HEADER_FORCE] = csvHeaderForce[:]
GM.Globals[GM.CSV_OUTPUT_HEADER_ORDER] = csvHeaderOrder[:] GM.Globals[GM.CSV_OUTPUT_HEADER_ORDER] = csvHeaderOrder[:]
GM.Globals[GM.CSV_OUTPUT_HEADER_REQUIRED] = csvHeaderRequired[:]
GM.Globals[GM.CSV_OUTPUT_QUOTE_CHAR] = csvQuoteChar GM.Globals[GM.CSV_OUTPUT_QUOTE_CHAR] = csvQuoteChar
GM.Globals[GM.CSV_OUTPUT_ROW_DROP_FILTER] = csvRowDropFilter[:] GM.Globals[GM.CSV_OUTPUT_ROW_DROP_FILTER] = csvRowDropFilter[:]
GM.Globals[GM.CSV_OUTPUT_ROW_DROP_FILTER_MODE] = csvRowDropFilterMode GM.Globals[GM.CSV_OUTPUT_ROW_DROP_FILTER_MODE] = csvRowDropFilterMode
@@ -10149,6 +10174,7 @@ def MultiprocessGAMCommands(items, showCmds):
GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER], GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER],
GC.Values[GC.CSV_OUTPUT_HEADER_FORCE], GC.Values[GC.CSV_OUTPUT_HEADER_FORCE],
GC.Values[GC.CSV_OUTPUT_HEADER_ORDER], GC.Values[GC.CSV_OUTPUT_HEADER_ORDER],
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED],
GC.Values[GC.CSV_OUTPUT_ROW_FILTER], GC.Values[GC.CSV_OUTPUT_ROW_FILTER],
GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE],
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER], GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER],
@@ -13798,7 +13824,9 @@ REPORT_ACTIVITIES_TIME_OBJECTS = {'time'}
# yesterday|today|thismonth|(previousmonths <Integer>)] # yesterday|today|thismonth|(previousmonths <Integer>)]
# [filter <String> (filtertime<String> <Time>)*] # [filter <String> (filtertime<String> <Time>)*]
# [event|events <EventNameList>] [ip <String>] # [event|events <EventNameList>] [ip <String>]
# [groupidfilter <String>] # [gmaileventtypes <NumberRangeList>]
# [groupidfilter <String>] [resourcedetailsfilter <String>]
# [notimesort]
# [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>] # [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
# [countsonly [bydate|summary] [eventrowfilter]] # [countsonly [bydate|summary] [eventrowfilter]]
# (addcsvdata <FieldName> <String>)* [shownoactivities] # (addcsvdata <FieldName> <String>)* [shownoactivities]
@@ -14113,6 +14141,7 @@ def doReport():
maxResults = 1000 maxResults = 1000
aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = countsByDate = countsSummary = \ aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = countsByDate = countsSummary = \
eventRowFilter = exitUserLoop = noAuthorizedApps = normalizeUsers = select = userCustomerRange = False eventRowFilter = exitUserLoop = noAuthorizedApps = normalizeUsers = select = userCustomerRange = False
sortAllTimes = True
limitDateChanges = -1 limitDateChanges = -1
allVerifyUser = userKey = 'all' allVerifyUser = userKey = 'all'
cd = orgUnit = orgUnitId = None cd = orgUnit = orgUnitId = None
@@ -14210,6 +14239,8 @@ def doReport():
eventNames.append(event) eventNames.append(event)
elif activityReports and myarg == 'ip': elif activityReports and myarg == 'ip':
actorIpAddress = getString(Cmd.OB_STRING) actorIpAddress = getString(Cmd.OB_STRING)
elif activityReports and myarg == 'notimesort':
sortAllTimes = False
elif activityReports and myarg == 'countsonly': elif activityReports and myarg == 'countsonly':
countsOnly = True countsOnly = True
elif activityReports and myarg == 'bydate': elif activityReports and myarg == 'bydate':
@@ -14675,6 +14706,8 @@ def doReport():
if addCSVData: if addCSVData:
row.update(addCSVData) row.update(addCSVData)
csvPF.WriteRowTitles(row) csvPF.WriteRowTitles(row)
elif sortAllTimes:
csvPF.SortRows('id.time', True)
else: else:
if eventRowFilter: if eventRowFilter:
csvPF.SetRowFilter([], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE]) csvPF.SetRowFilter([], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE])
@@ -16963,12 +16996,13 @@ def doCreateUpdateAdminRoles():
if not updateCmd: if not updateCmd:
result = callGAPI(cd.roles(), 'insert', result = callGAPI(cd.roles(), 'insert',
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.DUPLICATE], GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.DUPLICATE, GAPI.INVALID, GAPI.REQUIRED],
customer=GC.Values[GC.CUSTOMER_ID], body=body, fields=fieldsList) customer=GC.Values[GC.CUSTOMER_ID], body=body, fields=fieldsList)
else: else:
result = callGAPI(cd.roles(), 'patch', result = callGAPI(cd.roles(), 'patch',
throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND, throwReasons=[GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND,
GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION, GAPI.CONFLICT], GAPI.FORBIDDEN, GAPI.PERMISSION_DENIED]+[GAPI.NOT_FOUND, GAPI.FAILED_PRECONDITION,
GAPI.CONFLICT, GAPI.INVALID, GAPI.REQUIRED],
customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, body=body, fields=fieldsList) customer=GC.Values[GC.CUSTOMER_ID], roleId=roleId, body=body, fields=fieldsList)
if not csvPF: if not csvPF:
entityActionPerformed([Ent.ADMIN_ROLE, f"{result['roleName']}({result['roleId']})"]) entityActionPerformed([Ent.ADMIN_ROLE, f"{result['roleName']}({result['roleId']})"])
@@ -16986,7 +17020,7 @@ def doCreateUpdateAdminRoles():
row.update(addCSVData) row.update(addCSVData)
row['JSON'] = json.dumps(cleanJSON(result), ensure_ascii=False, sort_keys=True) row['JSON'] = json.dumps(cleanJSON(result), ensure_ascii=False, sort_keys=True)
csvPF.WriteRowNoFilter(row) csvPF.WriteRowNoFilter(row)
except GAPI.duplicate as e: except (GAPI.duplicate, GAPI.invalid, GAPI.required) as e:
entityActionFailedWarning([Ent.ADMIN_ROLE, f"{body['roleName']}"], str(e)) entityActionFailedWarning([Ent.ADMIN_ROLE, f"{body['roleName']}"], str(e))
except (GAPI.notFound, GAPI.failedPrecondition, GAPI.conflict) as e: except (GAPI.notFound, GAPI.failedPrecondition, GAPI.conflict) as e:
entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e)) entityActionFailedWarning([Ent.ADMIN_ROLE, roleId], str(e))
@@ -31622,6 +31656,7 @@ UPDATE_PRINTER_JSON_SKIP_FIELDS = ['id', 'name', 'createTime', 'orgUnitId', 'org
def _getPrinterAttributes(cd, jsonDeleteFields): def _getPrinterAttributes(cd, jsonDeleteFields):
'''get printer attributes for create/update commands''' '''get printer attributes for create/update commands'''
body = {} body = {}
returnIdOnly = False
showDetails = True showDetails = True
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
@@ -31640,13 +31675,15 @@ def _getPrinterAttributes(cd, jsonDeleteFields):
body['useDriverlessConfig'] = getBoolean() body['useDriverlessConfig'] = getBoolean()
elif myarg == 'nodetails': elif myarg == 'nodetails':
showDetails = False showDetails = False
elif myarg == 'returnidonly':
returnIdOnly = True
elif myarg == 'json': elif myarg == 'json':
body.update(getJSON(jsonDeleteFields)) body.update(getJSON(jsonDeleteFields))
else: else:
unknownArgumentExit() unknownArgumentExit()
if body.get('makeAndModel'): if body.get('makeAndModel'):
body.pop('useDriverlessConfig', None) body.pop('useDriverlessConfig', None)
return (body, showDetails) return (body, showDetails, returnIdOnly)
PRINTER_FIELDS_CHOICE_MAP = { PRINTER_FIELDS_CHOICE_MAP = {
'auxiliarymessages': 'auxiliaryMessages', 'auxiliarymessages': 'auxiliaryMessages',
@@ -31692,33 +31729,39 @@ def _showPrinter(cd, printer, FJQC, orgUnitId=None, showInherited=False, i=0, co
showJSON(None, printer, timeObjects=PRINTER_TIME_OBJECTS) showJSON(None, printer, timeObjects=PRINTER_TIME_OBJECTS)
Ind.Decrement() Ind.Decrement()
# gam create printer <PrinterAttribute>+ [nodetails] # gam create printer <PrinterAttribute>+ [nodetails|returnidonly]
def doCreatePrinter(): def doCreatePrinter():
cd = buildGAPIObject(API.DIRECTORY) cd = buildGAPIObject(API.DIRECTORY)
parent = _getCustomersCustomerIdWithC() parent = _getCustomersCustomerIdWithC()
body, showDetails = _getPrinterAttributes(cd, CREATE_PRINTER_JSON_SKIP_FIELDS) body, showDetails, returnIdOnly = _getPrinterAttributes(cd, CREATE_PRINTER_JSON_SKIP_FIELDS)
if not body.get('orgUnitId'): if not body.get('orgUnitId'):
missingArgumentExit('orgunit') missingArgumentExit('orgunit')
try: try:
printer = callGAPI(cd.customers().chrome().printers(), 'create', printer = callGAPI(cd.customers().chrome().printers(), 'create',
throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
parent=parent, body=body) parent=parent, body=body)
if returnIdOnly:
writeStdout(f"{printer['id']}\n")
return
entityActionPerformed([Ent.PRINTER, printer['id']]) entityActionPerformed([Ent.PRINTER, printer['id']])
if showDetails: if showDetails:
_showPrinter(cd, printer, None) _showPrinter(cd, printer, None)
except (GAPI.invalidArgument, GAPI.permissionDenied) as e: except (GAPI.invalidArgument, GAPI.permissionDenied) as e:
entityActionFailedWarning([Ent.PRINTER, None], str(e)) entityActionFailedWarning([Ent.PRINTER, None], str(e))
# gam update printer <PrinterID> <PrinterAttribute>+ [nodetails] # gam update printer <PrinterID> <PrinterAttribute>+ [nodetails|returnidonly]
def doUpdatePrinter(): def doUpdatePrinter():
name, printerId, cd = _getPrinterID() name, printerId, cd = _getPrinterID()
body, showDetails = _getPrinterAttributes(cd, UPDATE_PRINTER_JSON_SKIP_FIELDS) body, showDetails, returnIdOnly = _getPrinterAttributes(cd, UPDATE_PRINTER_JSON_SKIP_FIELDS)
updateMask = ','.join(list(body.keys())) updateMask = ','.join(list(body.keys()))
# note clearMask seems unnecessary. Updating field to '' clears it. # note clearMask seems unnecessary. Updating field to '' clears it.
try: try:
printer = callGAPI(cd.customers().chrome().printers(), 'patch', printer = callGAPI(cd.customers().chrome().printers(), 'patch',
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
name=name, updateMask=updateMask, body=body) name=name, updateMask=updateMask, body=body)
if returnIdOnly:
writeStdout(f"{printer['id']}\n")
return
entityActionPerformed([Ent.PRINTER, printerId]) entityActionPerformed([Ent.PRINTER, printerId])
if showDetails: if showDetails:
_showPrinter(cd, printer, None) _showPrinter(cd, printer, None)
@@ -34839,13 +34882,14 @@ def finalizeInternalDomains(cd, internalDomains):
return internalDomains return internalDomains
def finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, verifyAllowExternal): def finalizeIPSGMGroupRolesMemberDisplayOptions(cd, memberDisplayOptions, verifyAllowExternal):
memberDisplayOptions['internalDomains'] = finalizeInternalDomains(cd, memberDisplayOptions['internalDomains'])
if verifyAllowExternal: if verifyAllowExternal:
memberDisplayOptions['external'] = memberDisplayOptions['checkCategory'] = memberDisplayOptions['showCategory'] = True memberDisplayOptions['external'] = memberDisplayOptions['checkCategory'] = memberDisplayOptions['showCategory'] = True
memberDisplayOptions['internal'] = False memberDisplayOptions['internal'] = False
if memberDisplayOptions['showCategory']: if memberDisplayOptions['showCategory']:
memberDisplayOptions['gs'] = buildGAPIObject(API.GROUPSSETTINGS) memberDisplayOptions['gs'] = buildGAPIObject(API.GROUPSSETTINGS)
memberDisplayOptions['checkShowCategory'] = memberDisplayOptions['checkCategory'] or memberDisplayOptions['showCategory'] memberDisplayOptions['checkShowCategory'] = memberDisplayOptions['checkCategory'] or memberDisplayOptions['showCategory']
if memberDisplayOptions['checkShowCategory']:
memberDisplayOptions['internalDomains'] = finalizeInternalDomains(cd, memberDisplayOptions['internalDomains'])
return memberDisplayOptions['showCategory'], memberDisplayOptions['checkShowCategory'] return memberDisplayOptions['showCategory'], memberDisplayOptions['checkShowCategory']
GROUP_FIELDS_CHOICE_MAP = { GROUP_FIELDS_CHOICE_MAP = {
@@ -37791,7 +37835,7 @@ def doCreateUpdateCIPolicy():
updateCmd = Act.Get() == Act.UPDATE updateCmd = Act.Get() == Act.UPDATE
groupEmail = orgUnit = None groupEmail = orgUnit = None
checkArgumentPresent('json', True) checkArgumentPresent('json', True)
jsonData = getJSON(['type']) jsonData = getJSON(['customer', 'type'])
if updateCmd: if updateCmd:
pname = jsonData.pop('name', None) pname = jsonData.pop('name', None)
else: else:
@@ -45969,10 +46013,13 @@ def doCreateGuestUser():
checkForExtraneousArguments() checkForExtraneousArguments()
try: try:
result = callGAPI(cd.users(), 'createGuest', result = callGAPI(cd.users(), 'createGuest',
throwReasons=[GAPI.FAILED_PRECONDITION], throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.INVALID_ARGUMENT],
body=body) body=body)
entityActionPerformed([Ent.GUEST_USER, result['primaryGuestEmail']]) entityActionPerformed([Ent.GUEST_USER, body['primaryGuestEmail']])
except (GAPI.failedPrecondition) as e: Ind.Increment()
showJSON(None, result)
Ind.Decrement()
except (GAPI.failedPrecondition, GAPI.invalidArgument) as e:
entityActionFailedExit([Ent.GUEST_USER, body['primaryGuestEmail']], str(e)) entityActionFailedExit([Ent.GUEST_USER, body['primaryGuestEmail']], str(e))
# gam <UserTypeEntity> update user <UserAttribute>* # gam <UserTypeEntity> update user <UserAttribute>*
@@ -46584,8 +46631,9 @@ USER_FIELDS_CHOICE_MAP = {
'firstname': 'name.givenName', 'firstname': 'name.givenName',
'fullname': 'name.fullName', 'fullname': 'name.fullName',
'gal': 'includeInGlobalAddressList', 'gal': 'includeInGlobalAddressList',
'givenname': 'name.givenName',
'gender': ['gender.type', 'gender.customGender', 'gender.addressMeAs'], 'gender': ['gender.type', 'gender.customGender', 'gender.addressMeAs'],
'givenname': 'name.givenName',
'guestaccountinfo': 'guestAccountInfo',
'id': 'id', 'id': 'id',
'im': 'ims', 'im': 'ims',
'ims': 'ims', 'ims': 'ims',
@@ -46595,6 +46643,7 @@ USER_FIELDS_CHOICE_MAP = {
'isdelegatedadmin': ['isAdmin', 'isDelegatedAdmin'], 'isdelegatedadmin': ['isAdmin', 'isDelegatedAdmin'],
'isenforcedin2sv': 'isEnforcedIn2Sv', 'isenforcedin2sv': 'isEnforcedIn2Sv',
'isenrolledin2sv': 'isEnrolledIn2Sv', 'isenrolledin2sv': 'isEnrolledIn2Sv',
'isguestuser': 'isGuestUser',
'is2svenforced': 'isEnforcedIn2Sv', 'is2svenforced': 'isEnforcedIn2Sv',
'is2svenrolled': 'isEnrolledIn2Sv', 'is2svenrolled': 'isEnrolledIn2Sv',
'ismailboxsetup': 'isMailboxSetup', 'ismailboxsetup': 'isMailboxSetup',
@@ -51358,8 +51407,6 @@ def _batchAddItemsToCourse(croom, courseId, i, count, addItems, addType):
errMsg = getPhraseDNEorSNA(riItem) errMsg = getPhraseDNEorSNA(riItem)
else: else:
errMsg = getHTTPError(_ADD_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message) errMsg = getHTTPError(_ADD_PART_REASON_TO_MESSAGE_MAP, http_status, reason, message)
if (reason == GAPI.PERMISSION_DENIED) and (addType in {Ent.STUDENT, Ent.TEACHER}) and ('CannotDirectAddUser' in errMsg):
errMsg += f' Add external user with: gam user {riItem} create classroominvitation courses {ri[RI_ENTITY]} addType {Ent.Singular(addType)}'
entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionFailedWarning([Ent.COURSE, ri[RI_ENTITY], addType, riItem], errMsg, int(ri[RI_J]), int(ri[RI_JCOUNT]))
return return
waitOnFailure(1, 10, reason, message) waitOnFailure(1, 10, reason, message)
@@ -62027,6 +62074,7 @@ def initCopyMoveOptions(copyCmd):
'copyFilePermissions': False, 'copyFilePermissions': False,
'copyFileInheritedPermissions': True, 'copyFileInheritedPermissions': True,
'copyFileNonInheritedPermissions': COPY_NONINHERITED_PERMISSIONS_ALWAYS, 'copyFileNonInheritedPermissions': COPY_NONINHERITED_PERMISSIONS_ALWAYS,
'copyFolderPermissions': True,
'copyMergeWithParentFolderPermissions': False, 'copyMergeWithParentFolderPermissions': False,
'copyMergedTopFolderPermissions': copyCmd, 'copyMergedTopFolderPermissions': copyCmd,
'copyMergedSubFolderPermissions': copyCmd, 'copyMergedSubFolderPermissions': copyCmd,
@@ -62104,6 +62152,8 @@ def getCopyMoveOptions(myarg, copyMoveOptions):
copyMoveOptions['duplicateFiles'] = getChoice(DUPLICATE_FILE_CHOICES, mapChoice=True) copyMoveOptions['duplicateFiles'] = getChoice(DUPLICATE_FILE_CHOICES, mapChoice=True)
elif myarg == 'duplicatefolders': elif myarg == 'duplicatefolders':
copyMoveOptions['duplicateFolders'] = getChoice(DUPLICATE_FOLDER_CHOICES, mapChoice=True) copyMoveOptions['duplicateFolders'] = getChoice(DUPLICATE_FOLDER_CHOICES, mapChoice=True)
elif myarg == 'copyfolderpermissions':
copyMoveOptions['copyFolderPermissions'] = getBoolean()
elif myarg == 'copymergewithparentfolderpermissions': elif myarg == 'copymergewithparentfolderpermissions':
copyMoveOptions['copyMergeWithParentFolderPermissions'] = getBoolean() copyMoveOptions['copyMergeWithParentFolderPermissions'] = getBoolean()
elif myarg == 'copymergedtopfolderpermissions': elif myarg == 'copymergedtopfolderpermissions':
@@ -62782,6 +62832,7 @@ copyReturnItemMap = {
# [copyfilepermissions [<Boolean>]] # [copyfilepermissions [<Boolean>]]
# [copyfileinheritedpermissions [<Boolean>] # [copyfileinheritedpermissions [<Boolean>]
# [copyfilenoninheritedpermissions [<Boolean>] # [copyfilenoninheritedpermissions [<Boolean>]
# [copyfolderpermissions [<Boolean>]]
# [copymergewithparentfolderpermissions [<Boolean>]] # [copymergewithparentfolderpermissions [<Boolean>]]
# [copymergedtopfolderpermissions [<Boolean>]] # [copymergedtopfolderpermissions [<Boolean>]]
# [copytopfolderpermissions [<Boolean>]] # [copytopfolderpermissions [<Boolean>]]
@@ -62829,7 +62880,8 @@ def copyDriveFile(users):
_writeCSVData(user, folderName, folderId, newParentName, newParentId, MIMETYPE_GA_FOLDER) _writeCSVData(user, folderName, folderId, newParentName, newParentId, MIMETYPE_GA_FOLDER)
Act.Set(action) Act.Set(action)
_incrStatistic(statistics, STAT_FOLDER_MERGED) _incrStatistic(statistics, STAT_FOLDER_MERGED)
if (copyMoveOptions['copyMergeWithParentFolderPermissions'] and if (copyMoveOptions['copyFolderPermissions'] and
copyMoveOptions['copyMergeWithParentFolderPermissions'] and
copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT): copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT):
copyFolderNonInheritedPermissions =\ copyFolderNonInheritedPermissions =\
_getCopyFolderNonInheritedPermissions(copyMoveOptions, _getCopyFolderNonInheritedPermissions(copyMoveOptions,
@@ -62859,7 +62911,8 @@ def copyDriveFile(users):
_writeCSVData(user, folderName, folderId, newFolderName, newFolderId, MIMETYPE_GA_FOLDER) _writeCSVData(user, folderName, folderId, newFolderName, newFolderId, MIMETYPE_GA_FOLDER)
Act.Set(action) Act.Set(action)
_incrStatistic(statistics, STAT_FOLDER_MERGED) _incrStatistic(statistics, STAT_FOLDER_MERGED)
if (copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and if (copyMoveOptions['copyFolderPermissions'] and
copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and
(not atTop or copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT)): (not atTop or copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT)):
copyFolderNonInheritedPermissions =\ copyFolderNonInheritedPermissions =\
_getCopyFolderNonInheritedPermissions(copyMoveOptions, _getCopyFolderNonInheritedPermissions(copyMoveOptions,
@@ -62911,7 +62964,8 @@ def copyDriveFile(users):
else: else:
_writeCSVData(user, folderName, folderId, newFolderName, newFolderId, body['mimeType']) _writeCSVData(user, folderName, folderId, newFolderName, newFolderId, body['mimeType'])
_incrStatistic(statistics, STAT_FOLDER_COPIED_MOVED) _incrStatistic(statistics, STAT_FOLDER_COPIED_MOVED)
if copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]: if (copyMoveOptions['copyFolderPermissions'] and
copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]):
_copyPermissions(drive, user, i, count, j, jcount, _copyPermissions(drive, user, i, count, j, jcount,
Ent.DRIVE_FOLDER, folderId, folderName, newFolderId, newFolderName, Ent.DRIVE_FOLDER, folderId, folderName, newFolderId, newFolderName,
statistics, STAT_FOLDER_PERMISSIONS_FAILED, statistics, STAT_FOLDER_PERMISSIONS_FAILED,
@@ -63666,6 +63720,7 @@ def _recursiveUpdateMovePermissions(drive, user, i, count,
# [createshortcutsfornonmovablefiles [<Boolean>]] # [createshortcutsfornonmovablefiles [<Boolean>]]
# [duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip] # [duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
# [duplicatefolders merge|duplicatename|uniquename|skip] # [duplicatefolders merge|duplicatename|uniquename|skip]
# [copyfolderpermissions [<Boolean>]]
# [copymergewithparentfolderpermissions [<Boolean>]] # [copymergewithparentfolderpermissions [<Boolean>]]
# [copymergedtopfolderpermissions [<Boolean>]] # [copymergedtopfolderpermissions [<Boolean>]]
# [copytopfolderpermissions [<Boolean>]] # [copytopfolderpermissions [<Boolean>]]
@@ -63702,7 +63757,8 @@ def moveDriveFile(users):
entityPerformActionModifierItemValueList(kvList, Act.MODIFIER_CONTENTS_WITH, [Ent.DRIVE_FOLDER, newParentNameId], j, jcount) entityPerformActionModifierItemValueList(kvList, Act.MODIFIER_CONTENTS_WITH, [Ent.DRIVE_FOLDER, newParentNameId], j, jcount)
Act.Set(action) Act.Set(action)
_incrStatistic(statistics, STAT_FOLDER_MERGED) _incrStatistic(statistics, STAT_FOLDER_MERGED)
if (copyMoveOptions['copyMergeWithParentFolderPermissions'] and if (copyMoveOptions['copyFolderPermissions'] and
copyMoveOptions['copyMergeWithParentFolderPermissions'] and
copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT): copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT):
copyFolderNonInheritedPermissions =\ copyFolderNonInheritedPermissions =\
_getCopyFolderNonInheritedPermissions(copyMoveOptions, _getCopyFolderNonInheritedPermissions(copyMoveOptions,
@@ -63732,7 +63788,8 @@ def moveDriveFile(users):
entityModifierItemValueListActionPerformed(kvList, Act.MODIFIER_CONTENTS_WITH, [Ent.DRIVE_FOLDER, f'{newFolderName}({newFolderId})'], j, jcount) entityModifierItemValueListActionPerformed(kvList, Act.MODIFIER_CONTENTS_WITH, [Ent.DRIVE_FOLDER, f'{newFolderName}({newFolderId})'], j, jcount)
Act.Set(action) Act.Set(action)
_incrStatistic(statistics, STAT_FOLDER_MERGED) _incrStatistic(statistics, STAT_FOLDER_MERGED)
if (copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and if (copyMoveOptions['copyFolderPermissions'] and
copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and
(not atTop or copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT)): (not atTop or copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT)):
copyFolderNonInheritedPermissions =\ copyFolderNonInheritedPermissions =\
_getCopyFolderNonInheritedPermissions(copyMoveOptions, _getCopyFolderNonInheritedPermissions(copyMoveOptions,
@@ -63826,7 +63883,8 @@ def moveDriveFile(users):
j, jcount) j, jcount)
Act.Set(action) Act.Set(action)
_incrStatistic(statistics, STAT_FOLDER_COPIED_MOVED) _incrStatistic(statistics, STAT_FOLDER_COPIED_MOVED)
if copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]: if (copyMoveOptions['copyFolderPermissions'] and
copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]):
_copyPermissions(drive, user, i, count, j, jcount, _copyPermissions(drive, user, i, count, j, jcount,
Ent.DRIVE_FOLDER, folderId, folderName, newFolderId, newFolderName, Ent.DRIVE_FOLDER, folderId, folderName, newFolderId, newFolderName,
statistics, STAT_FOLDER_PERMISSIONS_FAILED, statistics, STAT_FOLDER_PERMISSIONS_FAILED,
@@ -66750,6 +66808,29 @@ def _checkFileIdEntityDomainAccess(fileIdEntity, useDomainAdminAccess):
# [sendemail|sendnotification] [emailmessage <String>] # [sendemail|sendnotification] [emailmessage <String>]
# [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])] # [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
def createDriveFileACL(users, useDomainAdminAccess=False): def createDriveFileACL(users, useDomainAdminAccess=False):
def _showResult(permission, showAction):
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET:
_updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, True, permission)
if csvPF:
baserow = {'Owner': user, 'id': fileId}
if showTitles:
baserow['name'] = fileName
row = baserow.copy()
_mapDrivePermissionNames(permission)
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
row = baserow.copy()
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
ensure_ascii=False, sort_keys=True)
csvPF.WriteRowNoFilter(row)
else:
if showAction:
entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount)
if showDetails:
_showDriveFilePermission(permission, printKeys, timeObjects)
moveToNewOwnersRoot = False moveToNewOwnersRoot = False
sendNotificationEmail = showTitles = _transferOwnership = updateSheetProtectedRanges = False sendNotificationEmail = showTitles = _transferOwnership = updateSheetProtectedRanges = False
roleLocation = withLinkLocation = expirationLocation = None roleLocation = withLinkLocation = expirationLocation = None
@@ -66859,35 +66940,30 @@ def createDriveFileACL(users, useDomainAdminAccess=False):
_, sheet = buildGAPIServiceObject(API.SHEETS, user, i, count) _, sheet = buildGAPIServiceObject(API.SHEETS, user, i, count)
if not sheet: if not sheet:
break break
permission = callGAPI(drive.permissions(), 'create', try:
bailOnInternalError=True, permission = callGAPI(drive.permissions(), 'create',
throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_CREATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE], bailOnInternalError=True,
moveToNewOwnersRoot=moveToNewOwnersRoot, throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+GAPI.DRIVE3_CREATE_ACL_THROW_REASONS+[GAPI.FILE_NEVER_WRITABLE],
useDomainAdminAccess=useDomainAdminAccess, moveToNewOwnersRoot=moveToNewOwnersRoot,
fileId=fileId, sendNotificationEmail=sendNotificationEmail, emailMessage=emailMessage, useDomainAdminAccess=useDomainAdminAccess,
transferOwnership=_transferOwnership, body=body, fields='*', supportsAllDrives=True) fileId=fileId, sendNotificationEmail=sendNotificationEmail, emailMessage=emailMessage,
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET: transferOwnership=_transferOwnership, body=body, fields='*', supportsAllDrives=True)
_updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, True, permission) _showResult(permission, True)
if csvPF: except GAPI.invalidSharingRequest as e:
baserow = {'Owner': user, 'id': fileId} errMsg = str(e)
if showTitles: if ('successfully shared but emails could not be sent' not in errMsg) or ('emailAddress' not in body):
baserow['name'] = fileName entityActionFailedWarning([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], errMsg, j, jcount)
row = baserow.copy() else:
_mapDrivePermissionNames(permission) if not csvPF:
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects) entityActionPerformedMessage([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], errMsg, j, jcount)
if not FJQC.formatJSON: tempPermId = getPermissionIdForEmail(user, i, count, body['emailAddress'])
csvPF.WriteRowTitles(row) permission = callGAPI(drive.permissions(), 'get',
elif csvPF.CheckRowTitles(row): throwReasons=GAPI.DRIVE_ACCESS_THROW_REASONS+[GAPI.BAD_REQUEST, GAPI.PERMISSION_NOT_FOUND, GAPI.INSUFFICIENT_ADMINISTRATOR_PRIVILEGES],
row = baserow.copy() useDomainAdminAccess=useDomainAdminAccess,
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects), fileId=fileId, permissionId=tempPermId, fields='*', supportsAllDrives=True)
ensure_ascii=False, sort_keys=True) _showResult(permission, False)
csvPF.WriteRowNoFilter(row)
else:
entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount)
if showDetails:
_showDriveFilePermission(permission, printKeys, timeObjects)
except (GAPI.badRequest, GAPI.invalid, GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, except (GAPI.badRequest, GAPI.invalid, GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError,
GAPI.cannotSetExpiration, GAPI.cannotSetExpirationOnAnyoneOrDomain, GAPI.permissionNotFound, GAPI.cannotSetExpiration, GAPI.cannotSetExpirationOnAnyoneOrDomain,
GAPI.expirationDateNotAllowedForSharedDriveMembers, GAPI.expirationDatesMustBeInTheFuture, GAPI.expirationDateNotAllowedForSharedDriveMembers, GAPI.expirationDatesMustBeInTheFuture,
GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.ownershipChangeAcrossDomainNotPermitted, GAPI.insufficientFilePermissions, GAPI.unknownError, GAPI.ownershipChangeAcrossDomainNotPermitted,
GAPI.teamDriveDomainUsersOnlyRestriction, GAPI.teamDriveTeamMembersOnlyRestriction, GAPI.teamDriveDomainUsersOnlyRestriction, GAPI.teamDriveTeamMembersOnlyRestriction,
@@ -66901,7 +66977,7 @@ def createDriveFileACL(users, useDomainAdminAccess=False):
GAPI.fileOrganizerOnNonTeamDriveNotSupported, GAPI.fileOrganizerOnNonTeamDriveNotSupported,
GAPI.cannotModifyInheritedPermission, GAPI.cannotModifyInheritedPermission,
GAPI.teamDrivesFolderSharingNotSupported, GAPI.invalidLinkVisibility, GAPI.teamDrivesFolderSharingNotSupported, GAPI.invalidLinkVisibility,
GAPI.invalidSharingRequest, GAPI.fileNeverWritable, GAPI.abusiveContentRestriction) as e: GAPI.fileNeverWritable, GAPI.abusiveContentRestriction) as e:
entityActionFailedWarning([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], str(e), j, jcount) entityActionFailedWarning([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], str(e), j, jcount)
except GAPI.notFound as e: except GAPI.notFound as e:
entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, fileName], str(e), j, jcount) entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE, fileName], str(e), j, jcount)
@@ -66920,6 +66996,29 @@ def doCreateDriveFileACL():
# [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]] # [updatesheetprotectedranges [<Boolean>]] [enforceexpansiveaccess [<Boolean>]]
# [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])] # [showtitles] [nodetails|(csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]])]
def updateDriveFileACLs(users, useDomainAdminAccess=False): def updateDriveFileACLs(users, useDomainAdminAccess=False):
def _showResult(permission, showAction):
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET:
_updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, True, permission)
if csvPF:
baserow = {'Owner': user, 'id': fileId}
if showTitles:
baserow['name'] = fileName
row = baserow.copy()
_mapDrivePermissionNames(permission)
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
row = baserow.copy()
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
ensure_ascii=False, sort_keys=True)
csvPF.WriteRowNoFilter(row)
else:
if showAction:
entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount)
if showDetails:
_showDriveFilePermission(permission, printKeys, timeObjects)
fileIdEntity = getDriveFileEntity() fileIdEntity = getDriveFileEntity()
isEmail, permissionId = getPermissionId() isEmail, permissionId = getPermissionId()
enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS] enforceExpansiveAccess = GC.Values[GC.ENFORCE_EXPANSIVE_ACCESS]
@@ -66999,26 +67098,7 @@ def updateDriveFileACLs(users, useDomainAdminAccess=False):
useDomainAdminAccess=useDomainAdminAccess, enforceExpansiveAccess=enforceExpansiveAccess, useDomainAdminAccess=useDomainAdminAccess, enforceExpansiveAccess=enforceExpansiveAccess,
fileId=fileId, permissionId=permissionId, removeExpiration=removeExpiration, fileId=fileId, permissionId=permissionId, removeExpiration=removeExpiration,
transferOwnership=body.get('role', '') == 'owner', body=body, fields='*', supportsAllDrives=True) transferOwnership=body.get('role', '') == 'owner', body=body, fields='*', supportsAllDrives=True)
if updateSheetProtectedRanges and mimeType == MIMETYPE_GA_SPREADSHEET: _showResult(permission, True)
_updateSheetProtectedRangesACLchange(sheet, user, i, count, j, jcount, fileId, fileName, True, permission)
if csvPF:
baserow = {'Owner': user, 'id': fileId}
if showTitles:
baserow['name'] = fileName
row = baserow.copy()
_mapDrivePermissionNames(permission)
flattenJSON({'permission': permission}, flattened=row, timeObjects=timeObjects)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
row = baserow.copy()
row['JSON'] = json.dumps(cleanJSON({'permission': permission}, timeObjects=timeObjects),
ensure_ascii=False, sort_keys=True)
csvPF.WriteRowNoFilter(row)
else:
entityActionPerformed([Ent.USER, user, entityType, fileName, Ent.PERMISSION_ID, permissionId], j, jcount)
if showDetails:
_showDriveFilePermission(permission, printKeys, timeObjects)
except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError, except (GAPI.fileNotFound, GAPI.forbidden, GAPI.internalError, GAPI.insufficientFilePermissions, GAPI.unknownError,
GAPI.cannotSetExpiration, GAPI.cannotSetExpirationOnAnyoneOrDomain, GAPI.cannotSetExpiration, GAPI.cannotSetExpirationOnAnyoneOrDomain,
GAPI.expirationDateNotAllowedForSharedDriveMembers, GAPI.expirationDatesMustBeInTheFuture, GAPI.expirationDateNotAllowedForSharedDriveMembers, GAPI.expirationDatesMustBeInTheFuture,
@@ -71264,6 +71344,13 @@ def updatePhoto(users):
continue continue
body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)} body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)}
try: try:
try:
callGAPI(cd.users().photos(), 'delete',
bailOnInternalError=True,
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.PHOTO_NOT_FOUND, GAPI.INTERNAL_ERROR],
userKey=user)
except (GAPI.photoNotFound, GAPI.internalError):
pass
callGAPI(cd.users().photos(), 'update', callGAPI(cd.users().photos(), 'update',
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT, GAPI.CONDITION_NOT_MET], throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT, GAPI.CONDITION_NOT_MET],
userKey=user, body=body, fields='') userKey=user, body=body, fields='')

View File

@@ -649,6 +649,16 @@ _SVCACCT_SCOPES = [
'api': CLOUDIDENTITY_DEVICES, 'api': CLOUDIDENTITY_DEVICES,
'subscopes': READONLY, 'subscopes': READONLY,
'scope': 'https://www.googleapis.com/auth/cloud-identity.devices'}, 'scope': 'https://www.googleapis.com/auth/cloud-identity.devices'},
# {'name': 'Cloud Identity API - Policy',
# 'api': CLOUDIDENTITY_POLICY,
# 'subscopes': READONLY,
# 'roByDefault': True,
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
# {'name': 'Cloud Identity API - Policy Beta',
# 'api': CLOUDIDENTITY_POLICY_BETA,
# 'subscopes': [],
# 'offByDefault': True,
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
# {'name': 'Cloud Identity User Invitations API', # {'name': 'Cloud Identity User Invitations API',
# 'api': CLOUDIDENTITY_USERINVITATIONS, # 'api': CLOUDIDENTITY_USERINVITATIONS,
# 'subscopes': READONLY, # 'subscopes': READONLY,

View File

@@ -123,6 +123,8 @@ CSV_OUTPUT_HEADER_DROP_FILTER = 'csv_output_header_drop_filter'
CSV_OUTPUT_HEADER_FORCE = 'csv_output_header_force' CSV_OUTPUT_HEADER_FORCE = 'csv_output_header_force'
# Orde output column headers # Orde output column headers
CSV_OUTPUT_HEADER_ORDER = 'csv_output_header_order' CSV_OUTPUT_HEADER_ORDER = 'csv_output_header_order'
# Required output column headers
CSV_OUTPUT_HEADER_REQUIRED = 'csv_output_header_required'
# Line terminator in CSV output file # Line terminator in CSV output file
CSV_OUTPUT_LINE_TERMINATOR = 'csv_output_line_terminator' CSV_OUTPUT_LINE_TERMINATOR = 'csv_output_line_terminator'
# Quote character in CSV output file # Quote character in CSV output file
@@ -329,6 +331,7 @@ CSV_INPUT_ROW_FILTER_ITEMS = {CSV_INPUT_ROW_FILTER, CSV_INPUT_ROW_FILTER_MODE,
CSV_OUTPUT_ROW_FILTER_ITEMS = {CSV_OUTPUT_HEADER_FILTER, CSV_OUTPUT_HEADER_DROP_FILTER, CSV_OUTPUT_ROW_FILTER_ITEMS = {CSV_OUTPUT_HEADER_FILTER, CSV_OUTPUT_HEADER_DROP_FILTER,
CSV_OUTPUT_HEADER_FORCE, CSV_OUTPUT_HEADER_ORDER, CSV_OUTPUT_HEADER_FORCE, CSV_OUTPUT_HEADER_ORDER,
CSV_OUTPUT_HEADER_REQUIRED,
CSV_OUTPUT_ROW_FILTER, CSV_OUTPUT_ROW_FILTER_MODE, CSV_OUTPUT_ROW_FILTER, CSV_OUTPUT_ROW_FILTER_MODE,
CSV_OUTPUT_ROW_DROP_FILTER, CSV_OUTPUT_ROW_DROP_FILTER_MODE, CSV_OUTPUT_ROW_DROP_FILTER, CSV_OUTPUT_ROW_DROP_FILTER_MODE,
CSV_OUTPUT_ROW_LIMIT} CSV_OUTPUT_ROW_LIMIT}
@@ -373,6 +376,7 @@ Defaults = {
CSV_OUTPUT_HEADER_DROP_FILTER: '', CSV_OUTPUT_HEADER_DROP_FILTER: '',
CSV_OUTPUT_HEADER_FORCE: '', CSV_OUTPUT_HEADER_FORCE: '',
CSV_OUTPUT_HEADER_ORDER: '', CSV_OUTPUT_HEADER_ORDER: '',
CSV_OUTPUT_HEADER_REQUIRED: '',
CSV_OUTPUT_LINE_TERMINATOR: 'lf', CSV_OUTPUT_LINE_TERMINATOR: 'lf',
CSV_OUTPUT_QUOTE_CHAR: '\'"\'', CSV_OUTPUT_QUOTE_CHAR: '\'"\'',
CSV_OUTPUT_ROW_FILTER: '', CSV_OUTPUT_ROW_FILTER: '',
@@ -487,7 +491,7 @@ TYPE_EMAIL_OPTIONAL = 'emao'
TYPE_FILE = 'file' TYPE_FILE = 'file'
TYPE_FLOAT = 'floa' TYPE_FLOAT = 'floa'
TYPE_HEADERFILTER = 'heaf' TYPE_HEADERFILTER = 'heaf'
TYPE_HEADERFORCE = 'hefo' TYPE_HEADERFORCEREQUIRED = 'hefr'
TYPE_HEADERORDER = 'heor' TYPE_HEADERORDER = 'heor'
TYPE_INTEGER = 'inte' TYPE_INTEGER = 'inte'
TYPE_LANGUAGE = 'lang' TYPE_LANGUAGE = 'lang'
@@ -544,8 +548,9 @@ VAR_INFO = {
CSV_OUTPUT_FIELD_DELIMITER: {VAR_TYPE: TYPE_CHARACTER}, CSV_OUTPUT_FIELD_DELIMITER: {VAR_TYPE: TYPE_CHARACTER},
CSV_OUTPUT_HEADER_FILTER: {VAR_TYPE: TYPE_HEADERFILTER}, CSV_OUTPUT_HEADER_FILTER: {VAR_TYPE: TYPE_HEADERFILTER},
CSV_OUTPUT_HEADER_DROP_FILTER: {VAR_TYPE: TYPE_HEADERFILTER}, CSV_OUTPUT_HEADER_DROP_FILTER: {VAR_TYPE: TYPE_HEADERFILTER},
CSV_OUTPUT_HEADER_FORCE: {VAR_TYPE: TYPE_HEADERFORCE}, CSV_OUTPUT_HEADER_FORCE: {VAR_TYPE: TYPE_HEADERFORCEREQUIRED},
CSV_OUTPUT_HEADER_ORDER: {VAR_TYPE: TYPE_HEADERORDER}, CSV_OUTPUT_HEADER_ORDER: {VAR_TYPE: TYPE_HEADERORDER},
CSV_OUTPUT_HEADER_REQUIRED: {VAR_TYPE: TYPE_HEADERFORCEREQUIRED},
CSV_OUTPUT_LINE_TERMINATOR: {VAR_TYPE: TYPE_CHOICE, VAR_CHOICES: {'cr': '\r', 'lf': '\n', 'crlf': '\r\n'}}, CSV_OUTPUT_LINE_TERMINATOR: {VAR_TYPE: TYPE_CHOICE, VAR_CHOICES: {'cr': '\r', 'lf': '\n', 'crlf': '\r\n'}},
CSV_OUTPUT_QUOTE_CHAR: {VAR_TYPE: TYPE_CHARACTER}, CSV_OUTPUT_QUOTE_CHAR: {VAR_TYPE: TYPE_CHARACTER},
CSV_OUTPUT_ROW_FILTER: {VAR_TYPE: TYPE_ROWFILTER}, CSV_OUTPUT_ROW_FILTER: {VAR_TYPE: TYPE_ROWFILTER},

View File

@@ -69,6 +69,8 @@ CSV_OUTPUT_HEADER_FILTER = 'cohf'
CSV_OUTPUT_HEADER_FORCE = 'cofh' CSV_OUTPUT_HEADER_FORCE = 'cofh'
# Order output column headers # Order output column headers
CSV_OUTPUT_HEADER_ORDER = 'coho' CSV_OUTPUT_HEADER_ORDER = 'coho'
# Required output column headers
CSV_OUTPUT_HEADER_REQUIRED = 'corh'
# No escape character in CSV output file # No escape character in CSV output file
CSV_OUTPUT_NO_ESCAPE_CHAR = 'cone' CSV_OUTPUT_NO_ESCAPE_CHAR = 'cone'
# Quote character in CSV output file # Quote character in CSV output file
@@ -127,6 +129,8 @@ GAM_CFG_SECTION_NAME = 'gcsn'
GAM_PATH = 'gpth' GAM_PATH = 'gpth'
# Python source, PyInstaller or StaticX? # Python source, PyInstaller or StaticX?
GAM_TYPE = 'gtyp' GAM_TYPE = 'gtyp'
# Shared Service Account HTTP Object
HTTP_OBJECT = 'http'
# Length of last Got message # Length of last Got message
LAST_GOT_MSG_LEN = 'lgml' LAST_GOT_MSG_LEN = 'lgml'
# License SKUs # License SKUs
@@ -248,6 +252,7 @@ Globals = {
CSV_OUTPUT_HEADER_FILTER: [], CSV_OUTPUT_HEADER_FILTER: [],
CSV_OUTPUT_HEADER_FORCE: [], CSV_OUTPUT_HEADER_FORCE: [],
CSV_OUTPUT_HEADER_ORDER: [], CSV_OUTPUT_HEADER_ORDER: [],
CSV_OUTPUT_HEADER_REQUIRED: [],
CSV_OUTPUT_NO_ESCAPE_CHAR: None, CSV_OUTPUT_NO_ESCAPE_CHAR: None,
CSV_OUTPUT_QUOTE_CHAR: None, CSV_OUTPUT_QUOTE_CHAR: None,
CSV_OUTPUT_ROW_DROP_FILTER: [], CSV_OUTPUT_ROW_DROP_FILTER: [],
@@ -279,6 +284,7 @@ Globals = {
GAM_CFG_SECTION_NAME: '', GAM_CFG_SECTION_NAME: '',
GAM_PATH: '.', GAM_PATH: '.',
GAM_TYPE: '', GAM_TYPE: '',
HTTP_OBJECT: None,
LAST_GOT_MSG_LEN: 0, LAST_GOT_MSG_LEN: 0,
LICENSE_SKUS: [], LICENSE_SKUS: [],
MAKE_BUILDING_ID_NAME_MAP: True, MAKE_BUILDING_ID_NAME_MAP: True,

View File

@@ -6,7 +6,7 @@
\deftab720 \deftab720
\pard\pardeftab720\sl276\slmult1\sa200\qc\partightenfactor0 \pard\pardeftab720\sl276\slmult1\sa200\qc\partightenfactor0
\f0\fs22 \cf0 Copyright 2025 Jay Lee\ \f0\fs22 \cf0 Copyright 2026 Jay Lee\
\pard\pardeftab720\sa200\qc\partightenfactor0 \pard\pardeftab720\sa200\qc\partightenfactor0
\f1\b \cf0 Licensed under the Apache License, Version 2.0 (the "License");\ \f1\b \cf0 Licensed under the Apache License, Version 2.0 (the "License");\

View File

@@ -14,8 +14,9 @@
There are seven values in `gam.cfg` that can be used to filter the output from `gam print` commands. There are seven values in `gam.cfg` that can be used to filter the output from `gam print` commands.
* `csv_output_header_filter` - A list of `<RegularExpressions>` used to select specific column headers to include * `csv_output_header_filter` - A list of `<RegularExpressions>` used to select specific column headers to include
* `csv_output_header_drop_filter` - A list of `<RegularExpressions>` used to select specific column headers to exclude * `csv_output_header_drop_filter` - A list of `<RegularExpressions>` used to select specific column headers to exclude
* `csv_output_header_force` - A list of <Strings> used to specify the exact column headers to include * `csv_output_header_force` - A list of `<Strings>` used to specify the exact column headers to include
* `csv_output_header_order` - A list of <Strings> used to specify the column header order; any headers in the file but not in the list will appear after the headers in the list. * `csv_output_header_order` - A list of `<Strings>` used to specify the column header order; any headers in the file but not in the list will appear after the header* `csv_output_header_required` - A list of `<Strings>` used to specify column headers that are included even if the print command doesn't return them
s in the list.
* `csv_output_row_filter` - A list or JSON dictionary used to include specific rows based on column values * `csv_output_row_filter` - A list or JSON dictionary used to include specific rows based on column values
* `csv_output_row_drop_filter` - A list or JSON dictionary used to exclude specific rows based on column values * `csv_output_row_drop_filter` - A list or JSON dictionary used to exclude specific rows based on column values
* `csv_output_row_limit` - A limit on the number of rows written * `csv_output_row_limit` - A limit on the number of rows written

View File

@@ -319,6 +319,8 @@ Data fields identified in a `csvkmd` argument.
(select <ProjectIDList> | <FileSelector> | <CSVFileSelector>) (select <ProjectIDList> | <FileSelector> | <CSVFileSelector>)
<PrinterIDEntity> ::= <PrinterIDEntity> ::=
<PrinterIDList> | <FileSelector> | <CSVFileSelector> <PrinterIDList> | <FileSelector> | <CSVFileSelector>
<QueryDriveFile> :: = <String> See: https://developers.google.com/workspace/drive/api/guides/search-files
<QuerySharedDrive> ::= <String> See: https://developers.google.com/workspace/drive/api/guides/search-shareddrives
<RecipientEntity> ::= <RecipientEntity> ::=
<EmailAddressEntity> | (select <UserTypeEntity>) <EmailAddressEntity> | (select <UserTypeEntity>)
<ResourceEntity> ::= <ResourceEntity> ::=
@@ -329,22 +331,22 @@ Data fields identified in a `csvkmd` argument.
<SerialNumberList> | <FileSelector> | <CSVFileSelector> <SerialNumberList> | <FileSelector> | <CSVFileSelector>
<SharedDriveIDEntity> ::= <SharedDriveIDEntity> ::=
<DriveFileItem> | <DriveFileItem> |
(teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
<SharedDriveNameEntity> ::= <SharedDriveNameEntity> ::=
(teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
<SharedDriveNameEntity> <SharedDriveNameEntity>
<SharedDriveAdminQueryEntity> ::= <SharedDriveAdminQueryEntity> ::=
(teamdriveadminquery <QueryTeamDrive>) | (teamdriveadminquery:<QueryTeamDrive>) (shareddriveadminquery <QuerySharedDrive>) | (shareddriveadminquery:<QuerySharedDrive>)
<SharedDriveEntityAdmin> ::= <SharedDriveEntityAdmin> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
<SharedDriveNameEntity>| <SharedDriveNameEntity>|
<SharedDriveAdminQueryEntity> <SharedDriveAdminQueryEntity>
<SharedDriveFileNameEntity> ::= <SharedDriveFileNameEntity> ::=
(teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
<SharedDriveFileQueryEntity> ::= <SharedDriveFileQueryEntity> ::=
(teamdrivequery <QueryDriveFile>) | (teamdrivequery:<QueryDriveFile>) (shareddrivequery <QueryDriveFile>) | (shareddrivequery:<QueryDriveFile>)
<SharedDriveFileQueryShortcut> ::= <SharedDriveFileQueryShortcut> ::=
all_files | all_folders | all_google_files | all_non_google_files | all_items all_files | all_folders | all_google_files | all_non_google_files | all_items
<SiteACLScopeEntity> ::= <SiteACLScopeEntity> ::=

View File

@@ -114,9 +114,9 @@ ous_and_children_na_ns
(anydrivefilename <DriveFileName>)|(anydrivefilename:<DriveFileName>) (anydrivefilename <DriveFileName>)|(anydrivefilename:<DriveFileName>)
<SharedDriveID> ::= <String> <SharedDriveID> ::= <String>
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveIDEntity> ::= (teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) <SharedDriveIDEntity> ::= (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
<SharedDriveNameEntity> ::= (teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) <SharedDriveNameEntity> ::= (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveFileNameEntity> ::= (teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) <SharedDriveFileNameEntity> ::= (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
<SharedDriveNameEntity> <SharedDriveNameEntity>
@@ -327,7 +327,7 @@ Use these options to select users for GAM commands.
* `ou_arch` - Archived users * `ou_arch` - Archived users
* `ou_ns` - Non-suspended users * `ou_ns` - Non-suspended users
* `ou_susp` - Suspended users * `ou_susp` - Suspended users
* `ou_na_ns` - Non-archived and nn-suspended users * `ou_na_ns` - Non-archived and non-suspended users
## Users in the Organization Unit `<OrgUnitItem>` and all of its sub Organization Units ## Users in the Organization Unit `<OrgUnitItem>` and all of its sub Organization Units
* `ou_and_children|ou_and_children_na|ou_and_children_arch|ou_and_children_ns|ou_and_children_susp|ou_and_children_na_ns <OrgUnitItem>` * `ou_and_children|ou_and_children_na|ou_and_children_arch|ou_and_children_ns|ou_and_children_susp|ou_and_children_na_ns <OrgUnitItem>`
@@ -336,7 +336,7 @@ Use these options to select users for GAM commands.
* `ou_and_children_arch` - Archived users * `ou_and_children_arch` - Archived users
* `ou_and_children_ns` - Non-suspended users * `ou_and_children_ns` - Non-suspended users
* `ou_and_children_susp` - Suspended users * `ou_and_children_susp` - Suspended users
* `ou_and_children_na_ns` - Non-archived and nn-suspended users * `ou_and_children_na_ns` - Non-archived and non-suspended users
## Users directly in the Organization Units `<OrgUnitList>` ## Users directly in the Organization Units `<OrgUnitList>`
* `ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns <OrgUnitList>` - Users directly in the Organization Units `<OrgUnitList>` * `ous|ous_na|ous_arch|ous_ns|ous_susp|ous_na_ns <OrgUnitList>` - Users directly in the Organization Units `<OrgUnitList>`
@@ -345,7 +345,7 @@ Use these options to select users for GAM commands.
* `ous_arch` - Archived users * `ous_arch` - Archived users
* `ous_ns` - Non-suspended users * `ous_ns` - Non-suspended users
* `ous_susp` - Suspended users * `ous_susp` - Suspended users
* `ous_na_ns` - Non-archived and nn-suspended users * `ous_na_ns` - Non-archived and non-suspended users
`<OrgUnitList>` may require special quoting based on whether the OUs contain spaces, commas or single quotes. `<OrgUnitList>` may require special quoting based on whether the OUs contain spaces, commas or single quotes.

View File

@@ -49,7 +49,8 @@
<DriveFolderID> ::= <String> <DriveFolderID> ::= <String>
<DriveFolderIDList> ::= "<DriveFolderID>(,<DriveFolderID>)*" <DriveFolderIDList> ::= "<DriveFolderID>(,<DriveFolderID>)*"
<DriveFolderName> ::= <String> <DriveFolderName> ::= <String>
<QueryDriveFile> :: = <String> See: https://developers.google.com/drive/api/v3/search-files <QueryDriveFile> :: = <String> See: https://developers.google.com/workspace/drive/api/guides/search-files
<QuerySharedDrive> ::= <String> See: https://developers.google.com/workspace/drive/api/guides/search-shareddrives
<DriveFileQueryEntity> ::= <DriveFileQueryEntity> ::=
(query <QueryDriveFile>) | (query:<QueryDriveFile>) (query <QueryDriveFile>) | (query:<QueryDriveFile>)
<DriveFileQueryShortcut> ::= <DriveFileQueryShortcut> ::=
@@ -90,15 +91,15 @@
<SharedDriveID> ::= <String> <SharedDriveID> ::= <String>
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveIDEntity> ::= (teamdriveid <SharedDriveID>) | (teamdriveid:<SharedDriveID>) <SharedDriveIDEntity> ::= (shareddriveid <SharedDriveID>) | (shareddriveid:<SharedDriveID>)
<SharedDriveNameEntity> ::= (teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) <SharedDriveNameEntity> ::= (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveFileNameEntity> ::= (teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) <SharedDriveFileNameEntity> ::= (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
<SharedDriveNameEntity> <SharedDriveNameEntity>
<SharedDriveAdminQueryEntity> ::= <SharedDriveAdminQueryEntity> ::=
(teamdriveadminquery <QueryTeamDrive>) | (teamdriveadminquery:<QueryTeamDrive>) (shareddriveadminquery <QuerySharedDrive>) | (shareddriveadminquery:<QuerySharedDrive>)
<SharedDriveFileQueryEntity> ::= <SharedDriveFileQueryEntity> ::=
(query <QueryDriveFile>) | (query:<QueryDriveFile>) (query <QueryDriveFile>) | (query:<QueryDriveFile>)
<SharedDriveFileQueryShortcut> ::= <SharedDriveFileQueryShortcut> ::=
@@ -335,13 +336,13 @@ Select a Shared Drive file by giving its unique ID.
``` ```
<SharedDriveIDEntity> ::= <SharedDriveIDEntity> ::=
<DriveFileItem> | <DriveFileItem> |
(teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
``` ```
### Examples ### Examples
``` ```
gam user testuser show fileinfo 1234ABCD gam user testuser show fileinfo 1234ABCD
gam user testuser show fileinfo id 1234ABCD gam user testuser show fileinfo id 1234ABCD
gam user testuser show fileinfo teamdriveid 1234ABCD gam user testuser show fileinfo shareddriveid 1234ABCD
``` ```
## Select Shared Drive file by name ## Select Shared Drive file by name
If you have the name, a search must be performed to find the ID that matches the name. If you have the name, a search must be performed to find the ID that matches the name.
@@ -350,16 +351,16 @@ You must specify the Shared Drive, either by ID or name, and the name of the fil
Remember, searching for a file by name may return several file IDs if you have multiple files with the same name. Remember, searching for a file by name may return several file IDs if you have multiple files with the same name.
``` ```
<SharedDriveIDEntity> ::= <SharedDriveIDEntity> ::=
(teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
<SharedDriveNameEntity> ::= <SharedDriveNameEntity> ::=
(teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveFileNameEntity> ::= <SharedDriveFileNameEntity> ::=
(teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
``` ```
### Examples ### Examples
``` ```
gam user testuser show fileinfo teamdriveid 1234ABCD teamdrivefilename "Test File" gam user testuser show fileinfo shareddriveid 1234ABCD shareddrivefilename "Test File"
gam user testuser show fileinfo teamdrive "Shared Drive 1" teamdrivefilename "Test File" gam user testuser show fileinfo shareddrive "Shared Drive 1" shareddrivefilename "Test File"
``` ```
## Select Shared Drive file by query ## Select Shared Drive file by query
You can use a query to find a file ID. You perform the query on all Shared Drives or a specific Shared Drive. You can use a query to find a file ID. You perform the query on all Shared Drives or a specific Shared Drive.
@@ -367,7 +368,7 @@ You can use a query to find a file ID. You perform the query on all Shared Drive
See: [Drive Query](https://developers.google.com/drive/api/v3/search-files) See: [Drive Query](https://developers.google.com/drive/api/v3/search-files)
``` ```
<SharedDriveFileQueryEntity> ::= <SharedDriveFileQueryEntity> ::=
(teamdrivequery <QueryDriveFile>) | (teamdrivequery:<QueryDriveFile>) (shareddrivequery <QueryDriveFile>) | (shareddrivequery:<QueryDriveFile>)
<SharedDriveFileQueryShortcut> ::= <SharedDriveFileQueryShortcut> ::=
all_files | all_folders | all_google_files | all_non_google_files | all_items all_files | all_folders | all_google_files | all_non_google_files | all_items
``` ```
@@ -380,32 +381,32 @@ Keyword to query mappings for `<DriveFileQueryShortcut>`:
### Examples ### Examples
``` ```
gam user testuser show fileinfo teamdrivequery "name='Test File'" gam user testuser show fileinfo shareddrivequery "name='Test File'"
gam user testuser show fileinfo teamdriveid 1234ABCD teamdrivequery "name='Test File'" gam user testuser show fileinfo shareddriveid 1234ABCD shareddrivequery "name='Test File'"
gam user testuser show fileinfo teamdrive teamdrive "Shared Drive 1" teamdrivequery "name='Test File'" gam user testuser show fileinfo shareddrive shareddrive "Shared Drive 1" shareddrivequery "name='Test File'"
gam user testuser show fileinfo teamdriveid 1234ABCD all_non_google_files gam user testuser show fileinfo shareddriveid 1234ABCD all_non_google_files
``` ```
## Select root folder of a Shared Drive by ID ## Select root folder of a Shared Drive by ID
The root folder of a Shared Drive is a folder, you select it by giving its unique ID. The root folder of a Shared Drive is a folder, you select it by giving its unique ID.
``` ```
<SharedDriveIDEntity> ::= <SharedDriveIDEntity> ::=
<DriveFileItem> | <DriveFileItem> |
(teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
``` ```
### Examples ### Examples
``` ```
gam user testuser show fileinfo 1234ABCD gam user testuser show fileinfo 1234ABCD
gam user testuser show fileinfo teamdriveid 1234ABCD gam user testuser show fileinfo shareddriveid 1234ABCD
``` ```
## Select root folder of a Shared Drive by name ## Select root folder of a Shared Drive by name
If you have a Shared Drive name, a search must be performed to find the ID that matches the name. If you have a Shared Drive name, a search must be performed to find the ID that matches the name.
``` ```
<SharedDriveNameEntity> ::= <SharedDriveNameEntity> ::=
(teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
``` ```
### Examples ### Examples
``` ```
gam user testuser show fileinfo teamdrive "Shared Drive 1" gam user testuser show fileinfo shareddrive "Shared Drive 1"
``` ```

View File

@@ -27,13 +27,13 @@
(anydrivefilename <DriveFileName>) | (anydrivefilename:<DriveFileName>) (anydrivefilename <DriveFileName>) | (anydrivefilename:<DriveFileName>)
<SharedDriveIDEntity> ::= <SharedDriveIDEntity> ::=
<DriveFileItem> | <DriveFileItem> |
(teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveNameEntity> ::= <SharedDriveNameEntity> ::=
(teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
<SharedDriveNameEntity> <SharedDriveNameEntity>
<SharedDriveFileNameEntity> ::= <SharedDriveFileNameEntity> ::=
(teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
``` ```

View File

@@ -10,6 +10,157 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
### 7.34.11
Updated gam-install.sh script for macOS/Linux to properly config GAM when the answer to the following question is No.
```
Can you run a full browser on this machine? (usually Y for macOS, N for Linux if you SSH into this machine)
```
### 7.34.10
Fixed bug where `formatjson quotechar <Character>` on the command line did not override `redirect csv <FileName> multiprocess quotechar <Character>`.
### 7.34.09
Updated `gam <UserTypeEntity> update photo` to delete the user's existing photo
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
### 7.34.08
Rebuild to avoid the following error:
```
requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
```
### 7.34.07
Added the following command to create a guest user.
* See: https://support.google.com/a/answer/16558545
```
gam create guestuser <EmailAddress>
```
Added the following items to `<UserFieldName>`:
* `guestaccountinfo` - Additional guest-related metadata fields
* `isguestuser` - Indicates if the inserted user is a guest
### 7.34.06
Added option `copyfolderpermissions [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`.
When `copyfolderpermissions false` is specified, no folder permissions are copied; this simplifies
disabling all folder permission copying.
When not specified or `copyfolderpermissions [true]` is specified, folder permissions are copied based on the following options:
```
copymergewithparentfolderpermissions [<Boolean>]
copymergedtopfolderpermissions [<Boolean>]
copytopfolderpermissions [<Boolean>]
copytopfolderiheritedpermissions [<Boolean>]
copytopfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
copymergedsubfolderpermissions [<Boolean>]
copysubfolderpermissions [<Boolean>]
copysubfolderinheritedpermissions [<Boolean>]
copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
```
### 7.34.05
Updated `gam report <ActivityApplictionName>` to perform a reverse chronological sort
on all rows across multiple users and/or event names; this is consistent with the behavior
in the Admin console. Use option `notimesort` to suppress this sort.
### 7.34.04
Updated `gam <UserTypeEntity> create drivefileacl <DriveFileEntity> user <UserItem> role owner` to better
handle the case where the current owner of a file is suspended. Previously, the command was displayed as an error
even though the ownership was changed.
```
gam user currentowner@domain.com add drivefileacl <DriveFileID> user newowner@domain.com role owner
User: currentowner@domain.com, Add 1 Drive File/Folder ACL
User: currentowner@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: newowner@domain.com, Add Failed: Sorry, the items were successfully shared but emails could not be sent to newowner@domain.com.
```
Now the command is displayed as a success with a note indicating that the ownership change email was not sent.
```
gam user currentowner@domain.com add drivefileacl <DriveFileID> user newowner@domain.com role owner
User: currentowner@domain.com, Add 1 Drive File/Folder ACL
User: currentowner@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: newowner@domain.com, Added: Sorry, the items were successfully shared but emails could not be sent to newowner@domain.com.
New Owner
id: 10834698115409747890
type: user
emailAddress: newowner@domain.com
domain: domain.com
role: owner
permissionDetails:
role: writer
type: file
inherited: True
inheritedFrom: Unknown
role: owner
type: file
inherited: False
deleted: False
pendingOwner: False
```
### 7.34.03
Updated to Python 3.14.3
Updated Cryptography to 46.0.5
Updated `gam course <CourseID> create student|teacher <EmailAddress>` error message when
`<EmailAddress>` is not in a trusted domain to remove suggestion about creating an invitation.
### 7.34.02
Updated GAM to prevent errors like the following:
```
ERROR: Unable to find the server at oauth2.googleapis.com
ERROR: Unable to find the server at gmail.googleapis.com
```
If you experience any unexpected errors, post a message to:
* The GAM Discussion Forum (google-apps-manager@googlegroups.com)
* The GAM Public Chat Room (https://chat.google.com/app/chat/AAAA4BULhWo)
### 7.34.01
Updated `gam create|update adminrole` to handle the following errors:
```
ERROR: 400: invalid - Invalid Role privileges
ERROR: 400: required - Required parameter: [resource.privileges[n].service_id]
```
### 7.34.00
Added variable `csv_output_header_required` to `gam.cfg` that is a comma separated list of `<Strings>`
that are required to be in the list of column headers in the CSV file written by a gam print command.
This will typically be used to specify headers that are required in subsequent commands that process
the CSV file even if the API didn't return any data for those columns.
Updated the following commands to not require the `Directory API - Domains` scope
unless the `internal` or `external` options are used to request the member category.
```
gam info|print groups
gam print|show group-members
gam info|print cigroups
gam print|show cigroup-members
gam <UserTypeEntity> print|show filesharecounts
```
### 7.33.03
Fixed bug in `gam [<UserTypeEntity>] sendemail ... from <EmailAddress> replyto <EmailAddress>`
where an `<EmailAddress>` of the form `Text <user@domain.com>` had the `Text` removed.
### 7.33.02
Added `hideinvitationssetting` to `<UserCalendarSettingsField>` used by
`gam <UserTypeEntity> print|show calsettings`.
### 7.33.01 ### 7.33.01
Added option `shownopolicy` to `gam print chromepolicies` that will display output like the following Added option `shownopolicy` to `gam print chromepolicies` that will display output like the following

View File

@@ -9,30 +9,30 @@ and all necessary authentications.
## Linux and MacOS and Google Cloud Shell ## Linux and MacOS and Google Cloud Shell
In these examples, your Google Super admin is shown as admin@domain.com; replace with the In these examples, your Google Super admin is shown as gamteam@domain.com; replace with the
actual email adddress. actual email adddress.
In these examples, the user home folder is shown as /Users/admin; adjust according to your In these examples, the user home folder is shown as /Users/gamteam; adjust according to your
specific situation; e.g., /home/administrator. specific situation; e.g., /home/administrator.
This example assumes that GAM7 has been installed in /Users/admin/bin/gam7. This example assumes that GAM7 has been installed in /Users/gamteam/bin/gam7.
If you've installed GAM7 in another directory, substitute that value in the directions. If you've installed GAM7 in another directory, substitute that value in the directions.
### Set a configuration directory ### Set a configuration directory
The default GAM configuration directory is /Users/admin/.gam; for more flexibility you The default GAM configuration directory is /Users/gamteam/.gam; for more flexibility you
probably want to select a non-hidden location. This example assumes that the GAM probably want to select a non-hidden location. This example assumes that the GAM
configuration directory will be /Users/admin/GAMConfig; If you've chosen another directory, configuration directory will be /Users/gamteam/GAMConfig; If you've chosen another directory,
substitute that value in the directions. substitute that value in the directions.
Make the directory: Make the directory:
``` ```
admin@server:/Users/admin$ mkdir -p /Users/admin/GAMConfig gamteam@server:/Users/gamteam$ mkdir -p /Users/gamteam/GAMConfig
``` ```
Add the following line: Add the following line:
``` ```
export GAMCFGDIR="/Users/admin/GAMConfig" export GAMCFGDIR="/Users/gamteam/GAMConfig"
``` ```
to one of these files based on your shell: to one of these files based on your shell:
``` ```
@@ -44,34 +44,34 @@ to one of these files based on your shell:
Issue the following command replacing `<Filename>` with the name of the file you edited: Issue the following command replacing `<Filename>` with the name of the file you edited:
``` ```
admin@server:/Users/admin$ source <Filename> gamteam@server:/Users/gamteam$ source <Filename>
``` ```
You need to make sure the GAM configuration directory actually exists. Test that like this: You need to make sure the GAM configuration directory actually exists. Test that like this:
``` ```
admin@server:/Users/admin$ ls -l $GAMCFGDIR gamteam@server:/Users/gamteam$ ls -l $GAMCFGDIR
``` ```
### Set a working directory ### Set a working directory
You should establish a GAM working directory; you will store your GAM related You should establish a GAM working directory; you will store your GAM related
data in this folder and execute GAM commands from this folder. You should not use data in this folder and execute GAM commands from this folder. You should not use
/Users/admin/bin/gam7 or /Users/admin/GAMConfig for this purpose. /Users/gamteam/bin/gam7 or /Users/gamteam/GAMConfig for this purpose.
This example assumes that the GAM working directory will be /Users/admin/GAMWork; If you've chosen This example assumes that the GAM working directory will be /Users/gamteam/GAMWork; If you've chosen
another directory, substitute that value in the directions. another directory, substitute that value in the directions.
Make the directory: Make the directory:
``` ```
admin@server:/Users/admin$ mkdir -p /Users/admin/GAMWork gamteam@server:/Users/gamteam$ mkdir -p /Users/gamteam/GAMWork
``` ```
### Set an alias ### Set an alias
You should set an alias to point to /Users/admin/bin/gam7/gam so you can operate from the /Users/admin/GAMWork directory. You should set an alias to point to /Users/gamteam/bin/gam7/gam so you can operate from the /Users/gamteam/GAMWork directory.
Aliases aren't available in scripts, so you may want to set a symlink instead, see below. Aliases aren't available in scripts, so you may want to set a symlink instead, see below.
Add the following line: Add the following line:
``` ```
alias gam="/Users/admin/bin/gam7/gam" alias gam="/Users/gamteam/bin/gam7/gam"
``` ```
to one of these files based on your shell: to one of these files based on your shell:
``` ```
@@ -84,48 +84,48 @@ to one of these files based on your shell:
Issue the following command replacing `<Filename>` with the name of the file you edited: Issue the following command replacing `<Filename>` with the name of the file you edited:
``` ```
admin@server:/Users/admin$ source <Filename> gamteam@server:/Users/gamteam$ source <Filename>
``` ```
### Set a symlink ### Set a symlink
Set a symlink in `/usr/local/bin` (or some other location on $PATH) to point to GAM. Set a symlink in `/usr/local/bin` (or some other location on $PATH) to point to GAM.
``` ```
admin@server:/Users/admin$ ln -s "/Users/admin/bin/gam7/gam" /usr/local/bin/gam gamteam@server:/Users/gamteam$ ln -s "/Users/gamteam/bin/gam7/gam" /usr/local/bin/gam
``` ```
### Initialize GAM7; this should be the first GAM7 command executed. ### Initialize GAM7; this should be the first GAM7 command executed.
``` ```
admin@server:/Users/admin$ gam config drive_dir /Users/admin/GAMWork verify gamteam@server:/Users/gamteam$ gam config drive_dir /Users/gamteam/GAMWork verify
Created: /Users/admin/GAMConfig Created: /Users/gamteam/GAMConfig
Created: /Users/admin/GAMConfig/gamcache Created: /Users/gamteam/GAMConfig/gamcache
Config File: /Users/admin/GAMConfig/gam.cfg, Initialized Config File: /Users/gamteam/GAMConfig/gam.cfg, Initialized
Section: DEFAULT Section: DEFAULT
... ...
cache_dir = /Users/admin/GAMConfig/gamcache cache_dir = /Users/gamteam/GAMConfig/gamcache
... ...
config_dir = /Users/admin/GAMConfig config_dir = /Users/gamteam/GAMConfig
... ...
drive_dir = /Users/admin/GAMWork drive_dir = /Users/gamteam/GAMWork
... ...
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Verify initialization, this was a successful installation. ### Verify initialization, this was a successful installation.
``` ```
admin@server:/Users/admin$ ls -l $GAMCFGDIR gamteam@server:/Users/gamteam$ ls -l $GAMCFGDIR
total 48 total 48
-rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg -rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg
drwxr-x---+ 2 admin staff 68 Mar 3 09:23 gamcache drwxr-x---+ 2 admin staff 68 Mar 3 09:23 gamcache
-rw-rw-rw-+ 1 admin staff 0 Mar 3 09:23 oauth2.txt.lock -rw-rw-rw-+ 1 admin staff 0 Mar 3 09:23 oauth2.txt.lock
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Create your project with local browser ### Create your project with local browser
``` ```
admin@server:/Users/admin$ gam create project gamteam@server:/Users/gamteam$ gam create project
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: client_secrets_json, Value: /Users/admin/GAMConfig/client_secrets.json, Not Found WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Item: client_secrets_json, Value: /Users/gamteam/GAMConfig/client_secrets.json, Not Found
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: oauth2service_json, Value: /Users/admin/GAMConfig/oauth2service.json, Not Found WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Item: oauth2service_json, Value: /Users/gamteam/GAMConfig/oauth2service.json, Not Found
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gamteam@domain.com
Your browser has been opened to visit: Your browser has been opened to visit:
@@ -167,7 +167,7 @@ Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-p
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded
Service Account OAuth2 File: /Users/admin/GAMConfig/oauth2service.json, Service Account Key: SVCACCTKEY, Updated Service Account OAuth2 File: /Users/gamteam/GAMConfig/oauth2service.json, Service Account Key: SVCACCTKEY, Updated
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key
Please go to: Please go to:
@@ -185,16 +185,16 @@ Enter your Client Secret: CLIENTSECRET
6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open. 6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open.
That's it! Your GAM Project is created and ready to use. That's it! Your GAM Project is created and ready to use.
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Create your project without local browser (Google Cloud Shell for instance) ### Create your project without local browser (Google Cloud Shell for instance)
``` ```
admin@server:/Users/admin$ gam config no_browser true save gamteam@server:/Users/gamteam$ gam config no_browser true save
admin@server:/Users/admin$ gam create project gamteam@server:/Users/gamteam$ gam create project
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: client_secrets_json, Value: /Users/admin/GAMConfig/client_secrets.json, Not Found WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Item: client_secrets_json, Value: /Users/gamteam/GAMConfig/client_secrets.json, Not Found
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: oauth2service_json, Value: /Users/admin/GAMConfig/oauth2service.json, Not Found WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Item: oauth2service_json, Value: /Users/gamteam/GAMConfig/oauth2service.json, Not Found
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gamteam@domain.com
Go to the following link in a browser on other computer: Go to the following link in a browser on other computer:
@@ -235,7 +235,7 @@ Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-p
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded
Service Account OAuth2 File: /Users/admin/GAMConfig/oauth2service.json, Service Account Key: SVCACCTKEY, Updated Service Account OAuth2 File: /Users/gamteam/GAMConfig/oauth2service.json, Service Account Key: SVCACCTKEY, Updated
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key
Please go to: Please go to:
@@ -253,7 +253,7 @@ Enter your Client Secret: CLIENTSECRET
6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open. 6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open.
That's it! Your GAM Project is created and ready to use. That's it! Your GAM Project is created and ready to use.
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Enable GAM7 client access ### Enable GAM7 client access
@@ -261,7 +261,7 @@ You select a list of scopes, GAM uses a browser to get final authorization from
writes the credentials into the file oauth2.txt. writes the credentials into the file oauth2.txt.
``` ```
admin@server:/Users/admin$ gam oauth create gamteam@server:/Users/gamteam$ gam oauth create
[*] 0) Calendar API (supports readonly) [*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly) [*] 1) Chrome Browser Cloud Management API (supports readonly)
@@ -328,7 +328,7 @@ Continue to authorization by entering a 'c'
Please enter 0-50[a|r] or s|u|e|c: c Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com Enter your Google Workspace admin email address? gamteam@domain.com
Go to the following link in a browser on this computer or on another computer: Go to the following link in a browser on this computer or on another computer:
@@ -340,16 +340,16 @@ click the Allow button, paste "Unable to connect" URL from other computer (only
Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required): Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required):
The authentication flow has completed. The authentication flow has completed.
Client OAuth2 File: /Users/admin/GAMConfig/oauth2.txt, Created Client OAuth2 File: /Users/gamteam/GAMConfig/oauth2.txt, Created
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
If clicking on the link in the instructions does not work (i.e. you get a 404 or 400 error message, instead of something about 'unable to connect') the URL in the link is too long. Most likely, you have selected all scopes. Try again with fewer scopes until it works. (there is no harm in repeatedly trying) If clicking on the link in the instructions does not work (i.e. you get a 404 or 400 error message, instead of something about 'unable to connect') the URL in the link is too long. Most likely, you have selected all scopes. Try again with fewer scopes until it works. (there is no harm in repeatedly trying)
### Enable GAM7 service account access. ### Enable GAM7 service account access.
``` ```
admin@server:/Users/admin$ gam user admin@domain.com update serviceaccount gamteam@server:/Users/gamteam$ gam user gamteam@domain.com update serviceaccount
[*] 0) AlertCenter API [*] 0) AlertCenter API
[*] 1) Analytics API - read only [*] 1) Analytics API - read only
[*] 2) Analytics Admin API - read only [*] 2) Analytics Admin API - read only
@@ -413,7 +413,7 @@ Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ FAIL (1/38) https://mail.google.com/ FAIL (1/38)
https://sites.google.com/feeds FAIL (2/38) https://sites.google.com/feeds FAIL (2/38)
https://www.googleapis.com/auth/analytics.readonly FAIL (3/38) https://www.googleapis.com/auth/analytics.readonly FAIL (3/38)
@@ -464,7 +464,7 @@ Click AUTHORIZE
When the box closes you're done When the box closes you're done
After authorizing it may take some time for this test to pass so wait a few moments and then try this command again. After authorizing it may take some time for this test to pass so wait a few moments and then try this command again.
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
The link shown in the error message should take you directly to the authorization screen. The link shown in the error message should take you directly to the authorization screen.
If not, make sure that you are logged in as a domain admin, then re-enter the link. If not, make sure that you are logged in as a domain admin, then re-enter the link.
@@ -474,14 +474,14 @@ If not, make sure that you are logged in as a domain admin, then re-enter the li
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
for the authorization to complete. for the authorization to complete.
``` ```
admin@server:/Users/admin$ gam user admin@domain.com check serviceaccount gamteam@server:/Users/gamteam$ gam user gamteam@domain.com check serviceaccount
System time status System time status
Your system time differs from admin.googleapis.com by less than 1 second PASS Your system time differs from admin.googleapis.com by less than 1 second PASS
Service Account Private Key Authentication Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ PASS (1/38) https://mail.google.com/ PASS (1/38)
https://sites.google.com/feeds PASS (2/38) https://sites.google.com/feeds PASS (2/38)
https://www.googleapis.com/auth/analytics.readonly PASS (3/38) https://www.googleapis.com/auth/analytics.readonly PASS (3/38)
@@ -524,14 +524,14 @@ All scopes PASSED!
Service Account Client name: SVCACCTID is fully authorized. Service Account Client name: SVCACCTID is fully authorized.
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Update gam.cfg with some basic values ### Update gam.cfg with some basic values
* `customer_id` - Having this data keeps Gam from having to make extra API calls * `customer_id` - Having this data keeps Gam from having to make extra API calls
* `domain` - This allows you to omit the domain portion of email addresses * `domain` - This allows you to omit the domain portion of email addresses
* `timezone local` - Gam will convert all UTC times to your local timezone * `timezone local` - Gam will convert all UTC times to your local timezone
``` ```
admin@server:/Users/admin$ gam info domain gamteam@server:/Users/gamteam$ gam info domain
Customer ID: C01234567 Customer ID: C01234567
Primary Domain: domain.com Primary Domain: domain.com
Customer Creation Time: 2007-06-06T15:47:55.444Z Customer Creation Time: 2007-06-06T15:47:55.444Z
@@ -539,8 +539,8 @@ Primary Domain Verified: True
Default Language: en Default Language: en
... ...
admin@server:/Users/admin$ gam config customer_id C01234567 domain domain.com timezone local save verify gamteam@server:/Users/gamteam$ gam config customer_id C01234567 domain domain.com timezone local save verify
Config File: /Users/admin/GAMConfig/gam.cfg, Saved Config File: /Users/gamteam/GAMConfig/gam.cfg, Saved
Section: DEFAULT Section: DEFAULT
... ...
customer_id = C01234567 customer_id = C01234567
@@ -550,12 +550,12 @@ Section: DEFAULT
timezone = local timezone = local
... ...
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
## Windows ## Windows
In these examples, your Google Super admin is shown as admin@domain.com; replace with the In these examples, your Google Super admin is shown as gamteam@domain.com; replace with the
actual email adddress. actual email adddress.
This example assumes that GAM7 has been installed in C:\GAM7; if you've installed This example assumes that GAM7 has been installed in C:\GAM7; if you've installed
@@ -645,7 +645,7 @@ C:\>gam create project
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: client_secrets_json, Value: C:\GAMConfig\client_secrets.json, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Item: client_secrets_json, Value: C:\GAMConfig\client_secrets.json, Not Found
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: oauth2service_json, Value: C:\GAMConfig\oauth2service.json, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Item: oauth2service_json, Value: C:\GAMConfig\oauth2service.json, Not Found
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gamteam@domain.com
Your browser has been opened to visit: Your browser has been opened to visit:
@@ -714,7 +714,7 @@ C:\>gam create project
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: client_secrets_json, Value: C:\GAMConfig\client_secrets.json, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Item: client_secrets_json, Value: C:\GAMConfig\client_secrets.json, Not Found
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: oauth2service_json, Value: C:\GAMConfig\oauth2service.json, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Item: oauth2service_json, Value: C:\GAMConfig\oauth2service.json, Not Found
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gamteam@domain.com
Go to the following link in a browser on other computer: Go to the following link in a browser on other computer:
@@ -848,7 +848,7 @@ Continue to authorization by entering a 'c'
Please enter 0-50[a|r] or s|u|e|c: c Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com Enter your Google Workspace admin email address? gamteam@domain.com
Go to the following link in a browser on this computer or on another computer: Go to the following link in a browser on this computer or on another computer:
@@ -866,7 +866,7 @@ C:\>
``` ```
### Enable GAM7 service account access. ### Enable GAM7 service account access.
``` ```
C:\>gam user admin@domain.com update serviceaccount C:\>gam user gamteam@domain.com update serviceaccount
[*] 0) AlertCenter API [*] 0) AlertCenter API
[*] 1) Analytics API - read only [*] 1) Analytics API - read only
[*] 2) Analytics Admin API - read only [*] 2) Analytics Admin API - read only
@@ -930,7 +930,7 @@ Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ FAIL (1/38) https://mail.google.com/ FAIL (1/38)
https://sites.google.com/feeds FAIL (2/38) https://sites.google.com/feeds FAIL (2/38)
https://www.googleapis.com/auth/analytics.readonly FAIL (3/38) https://www.googleapis.com/auth/analytics.readonly FAIL (3/38)
@@ -991,14 +991,14 @@ If not, make sure that you are logged in as a domain admin, then re-enter the li
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
for the authorization to complete. for the authorization to complete.
``` ```
C:\>gam user admin@domain.com check serviceaccount C:\>gam user gamteam@domain.com check serviceaccount
System time status System time status
Your system time differs from admin.googleapis.com by less than 1 second PASS Your system time differs from admin.googleapis.com by less than 1 second PASS
Service Account Private Key Authentication Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ PASS (1/38) https://mail.google.com/ PASS (1/38)
https://sites.google.com/feeds PASS (2/38) https://sites.google.com/feeds PASS (2/38)
https://www.googleapis.com/auth/analytics.readonly PASS (3/38) https://www.googleapis.com/auth/analytics.readonly PASS (3/38)

View File

@@ -10,30 +10,30 @@ and all necessary authentications.
## Linux and MacOS and Google Cloud Shell ## Linux and MacOS and Google Cloud Shell
In these examples, your Google Super admin is shown as admin@domain.com; replace with the In these examples, your Google Super admin is shown as gamteam@domain.com; replace with the
actual email adddress. actual email adddress.
In these examples, the user home folder is shown as /Users/admin; adjust according to your In these examples, the user home folder is shown as /Users/gamteam; adjust according to your
specific situation; e.g., /home/administrator. specific situation; e.g., /home/administrator.
This example assumes that GAM7 has been installed in /Users/admin/bin/gam7. This example assumes that GAM7 has been installed in /Users/gamteam/bin/gam7.
If you've installed GAM7 in another directory, substitute that value in the directions. If you've installed GAM7 in another directory, substitute that value in the directions.
### Set a configuration directory ### Set a configuration directory
The default GAM configuration directory is /Users/admin/.gam; for more flexibility you The default GAM configuration directory is /Users/gamteam/.gam; for more flexibility you
probably want to select a non-hidden location. This example assumes that the GAM probably want to select a non-hidden location. This example assumes that the GAM
configuration directory will be /Users/admin/GAMConfig; If you've chosen another directory, configuration directory will be /Users/gamteam/GAMConfig; If you've chosen another directory,
substitute that value in the directions. substitute that value in the directions.
Make the directory: Make the directory:
``` ```
admin@server:/Users/admin$ mkdir -p /Users/admin/GAMConfig gamteam@server:/Users/gamteam$ mkdir -p /Users/gamteam/GAMConfig
``` ```
Add the following line: Add the following line:
``` ```
export GAMCFGDIR="/Users/admin/GAMConfig" export GAMCFGDIR="/Users/gamteam/GAMConfig"
``` ```
to one of these files based on your shell: to one of these files based on your shell:
``` ```
@@ -45,34 +45,34 @@ to one of these files based on your shell:
Issue the following command replacing `<Filename>` with the name of the file you edited: Issue the following command replacing `<Filename>` with the name of the file you edited:
``` ```
admin@server:/Users/admin$ source <Filename> gamteam@server:/Users/gamteam$ source <Filename>
``` ```
You need to make sure the GAM configuration directory actually exists. Test that like this: You need to make sure the GAM configuration directory actually exists. Test that like this:
``` ```
admin@server:/Users/admin$ ls -l $GAMCFGDIR gamteam@server:/Users/gamteam$ ls -l $GAMCFGDIR
``` ```
### Set a working directory ### Set a working directory
You should establish a GAM working directory; you will store your GAM related You should establish a GAM working directory; you will store your GAM related
data in this folder and execute GAM commands from this folder. You should not use data in this folder and execute GAM commands from this folder. You should not use
/Users/admin/bin/gam7 or /Users/admin/GAMConfig for this purpose. /Users/gamteam/bin/gam7 or /Users/gamteam/GAMConfig for this purpose.
This example assumes that the GAM working directory will be /Users/admin/GAMWork; If you've chosen This example assumes that the GAM working directory will be /Users/gamteam/GAMWork; If you've chosen
another directory, substitute that value in the directions. another directory, substitute that value in the directions.
Make the directory: Make the directory:
``` ```
admin@server:/Users/admin$ mkdir -p /Users/admin/GAMWork gamteam@server:/Users/gamteam$ mkdir -p /Users/gamteam/GAMWork
``` ```
### Set an alias ### Set an alias
You should set an alias to point to /Users/admin/bin/gam7/gam so you can operate from the /Users/admin/GAMWork directory. You should set an alias to point to /Users/gamteam/bin/gam7/gam so you can operate from the /Users/gamteam/GAMWork directory.
Aliases aren't available in scripts, so you may want to set a symlink instead, see below. Aliases aren't available in scripts, so you may want to set a symlink instead, see below.
Add the following line: Add the following line:
``` ```
alias gam="/Users/admin/bin/gam7/gam" alias gam="/Users/gamteam/bin/gam7/gam"
``` ```
to one of these files based on your shell: to one of these files based on your shell:
``` ```
@@ -85,62 +85,62 @@ to one of these files based on your shell:
If you already have an alias for legacy GAM but are no longer going to run it, delete these lines: If you already have an alias for legacy GAM but are no longer going to run it, delete these lines:
``` ```
function gam() { "/Users/admin/bin/gam/gam" "$@" ; }" function gam() { "/Users/gamteam/bin/gam/gam" "$@" ; }"
alias gam="/Users/admin/bin/gam/gam" alias gam="/Users/gamteam/bin/gam/gam"
``` ```
If you already have an alias for legacy GAM and want to run it and GAM7, give your old alias a different name: If you already have an alias for legacy GAM and want to run it and GAM7, give your old alias a different name:
``` ```
function gamstd() { "/Users/admin/bin/gam/gam" "$@" ; }" function gamstd() { "/Users/gamteam/bin/gam/gam" "$@" ; }"
alias gamstd="/Users/admin/bin/gam/gam" alias gamstd="/Users/gamteam/bin/gam/gam"
``` ```
Issue the following command replacing `<Filename>` with the name of the file you edited: Issue the following command replacing `<Filename>` with the name of the file you edited:
``` ```
admin@server:/Users/admin$ source <Filename> gamteam@server:/Users/gamteam$ source <Filename>
``` ```
### Set a symlink ### Set a symlink
Set a symlink in `/usr/local/bin` (or some other location on $PATH) to point to GAM. Set a symlink in `/usr/local/bin` (or some other location on $PATH) to point to GAM.
``` ```
admin@server:/Users/admin$ ln -s "/Users/admin/bin/gam7/gam" /usr/local/bin/gam gamteam@server:/Users/gamteam$ ln -s "/Users/gamteam/bin/gam7/gam" /usr/local/bin/gam
``` ```
Set environment variable OLDGAMPATH to point to the existing Gam directory; /Users/admin/bin/gam will be used in this example. Set environment variable OLDGAMPATH to point to the existing Gam directory; /Users/gamteam/bin/gam will be used in this example.
If your existing Gam is in another directory, substitute that value in the directions. If your existing Gam is in another directory, substitute that value in the directions.
``` ```
admin@server:/Users/admin$ export OLDGAMPATH=/Users/admin/bin/gam gamteam@server:/Users/gamteam$ export OLDGAMPATH=/Users/gamteam/bin/gam
``` ```
Verify that OLDGAMPATH points to the correct location. Verify that OLDGAMPATH points to the correct location.
``` ```
admin@server:/Users/admin$ ls -l $OLDGAMPATH/*.json gamteam@server:/Users/gamteam$ ls -l $OLDGAMPATH/*.json
-rw-r-----@ 1 admin staff 553 Feb 26 10:39 /Users/admin/bin/gam/client_secrets.json -rw-r-----@ 1 admin staff 553 Feb 26 10:39 /Users/gamteam/bin/gam/client_secrets.json
-rw-r-----@ 1 admin staff 2377 Feb 26 10:39 /Users/admin/bin/gam/oauth2service.json -rw-r-----@ 1 admin staff 2377 Feb 26 10:39 /Users/gamteam/bin/gam/oauth2service.json
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Initialize GAM7; this should be the first GAM7 command executed. ### Initialize GAM7; this should be the first GAM7 command executed.
``` ```
admin@server:/Users/admin$ gam config drive_dir /Users/admin/GAMWork verify gamteam@server:/Users/gamteam$ gam config drive_dir /Users/gamteam/GAMWork verify
Created: /Users/admin/GAMConfig Created: /Users/gamteam/GAMConfig
Created: /Users/admin/GAMConfig/gamcache Created: /Users/gamteam/GAMConfig/gamcache
Copied: /Users/admin/bin/gam/oauth2service.json, To: /Users/admin/GAMConfig/oauth2service.json Copied: /Users/gamteam/bin/gam/oauth2service.json, To: /Users/gamteam/GAMConfig/oauth2service.json
Copied: /Users/admin/bin/gam/oauth2.txt, To: /Users/admin/GAMConfig/oauth2.txt Copied: /Users/gamteam/bin/gam/oauth2.txt, To: /Users/gamteam/GAMConfig/oauth2.txt
Copied: /Users/admin/bin/gam/client_secrets.json, To: /Users/admin/GAMConfig/client_secrets.json Copied: /Users/gamteam/bin/gam/client_secrets.json, To: /Users/gamteam/GAMConfig/client_secrets.json
Config File: /Users/admin/GAMConfig/gam.cfg, Initialized Config File: /Users/gamteam/GAMConfig/gam.cfg, Initialized
Section: DEFAULT Section: DEFAULT
... ...
cache_dir = /Users/admin/GAMConfig/gamcache cache_dir = /Users/gamteam/GAMConfig/gamcache
... ...
config_dir = /Users/admin/GAMConfig config_dir = /Users/gamteam/GAMConfig
... ...
drive_dir = /Users/admin/GAMWork drive_dir = /Users/gamteam/GAMWork
... ...
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Verify initialization, this was a successful installation. ### Verify initialization, this was a successful installation.
``` ```
admin@server:/Users/admin$ ls -l $GAMCFGDIR gamteam@server:/Users/gamteam$ ls -l $GAMCFGDIR
total 48 total 48
-rw-r-----+ 1 admin staff 553 Mar 3 09:23 client_secrets.json -rw-r-----+ 1 admin staff 553 Mar 3 09:23 client_secrets.json
-rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg -rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg
@@ -149,21 +149,21 @@ drwxr-x---+ 2 admin staff 68 Mar 3 09:23 gamcache
-rw-r-----+ 1 admin staff 5104 Mar 3 09:23 oauth2.txt -rw-r-----+ 1 admin staff 5104 Mar 3 09:23 oauth2.txt
-rw-rw-rw-+ 1 admin staff 0 Mar 3 09:23 oauth2.txt.lock -rw-rw-rw-+ 1 admin staff 0 Mar 3 09:23 oauth2.txt.lock
-rw-r-----+ 1 admin staff 2377 Mar 3 09:23 oauth2service.json -rw-r-----+ 1 admin staff 2377 Mar 3 09:23 oauth2service.json
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
If the verification looks like this, then you'll have to copy client_secrets.json and oauth2service.json manually. If the verification looks like this, then you'll have to copy client_secrets.json and oauth2service.json manually.
``` ```
admin@server:/Users/admin$ ls -l $GAMCFGDIR gamteam@server:/Users/gamteam$ ls -l $GAMCFGDIR
total 40 total 40
-rw-r-----+ 1 admin admin 1427 Nov 1 11:38 gam.cfg -rw-r-----+ 1 admin admin 1427 Nov 1 11:38 gam.cfg
drwxr-x---+ 16 admin admin 544 Nov 2 07:25 gamcache drwxr-x---+ 16 admin admin 544 Nov 2 07:25 gamcache
-rw-r--r--+ 1 admin admin 10 Nov 2 15:31 lastupdatecheck.txt -rw-r--r--+ 1 admin admin 10 Nov 2 15:31 lastupdatecheck.txt
-rw-rw-rw-+ 1 admin admin 0 Sep 19 17:28 oauth2.txt.lock -rw-rw-rw-+ 1 admin admin 0 Sep 19 17:28 oauth2.txt.lock
admin@server:/Users/admin$ cp -p $OLDGAMPATH/client_secrets.json $GAMCFGDIR/ gamteam@server:/Users/gamteam$ cp -p $OLDGAMPATH/client_secrets.json $GAMCFGDIR/
admin@server:/Users/admin$ cp -p $OLDGAMPATH/oauth2service.json $GAMCFGDIR/ gamteam@server:/Users/gamteam$ cp -p $OLDGAMPATH/oauth2service.json $GAMCFGDIR/
admin@server:/Users/admin$ cp -p $OLDGAMPATH/oauth2.txt $GAMCFGDIR/ gamteam@server:/Users/gamteam$ cp -p $OLDGAMPATH/oauth2.txt $GAMCFGDIR/
admin@server:/Users/admin$ ls -l $GAMCFGDIR gamteam@server:/Users/gamteam$ ls -l $GAMCFGDIR
total 40 total 40
-rw-r-----+ 1 admin staff 553 Mar 3 09:23 client_secrets.json -rw-r-----+ 1 admin staff 553 Mar 3 09:23 client_secrets.json
-rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg -rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg
@@ -175,9 +175,9 @@ drwxr-x---+ 2 admin staff 68 Mar 3 09:23 gamcache
``` ```
### Update your project with local browser to include the additional APIs that GAM7 uses. ### Update your project with local browser to include the additional APIs that GAM7 uses.
``` ```
admin@server:/Users/admin$ gam update project gamteam@server:/Users/gamteam$ gam update project
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? gamteam@domain.com
Your browser has been opened to visit: Your browser has been opened to visit:
@@ -205,14 +205,14 @@ Enable 3 APIs
API: groupsmigration.googleapis.com, Enabled (2/3) API: groupsmigration.googleapis.com, Enabled (2/3)
API: sheets.googleapis.com, Enabled (3/3) API: sheets.googleapis.com, Enabled (3/3)
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Update your project without local browser (Google Cloud Shell for instance) to include the additional APIs that GAM7 uses ### Update your project without local browser (Google Cloud Shell for instance) to include the additional APIs that GAM7 uses
``` ```
admin@server:/Users/admin$ gam config no_browser true save gamteam@server:/Users/gamteam$ gam config no_browser true save
admin@server:/Users/admin$ gam update project gamteam@server:/Users/gamteam$ gam update project
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? gamteam@domain.com
Go to the following link in a browser on other computer: Go to the following link in a browser on other computer:
@@ -239,7 +239,7 @@ Enable 3 APIs
API: groupsmigration.googleapis.com, Enabled (2/3) API: groupsmigration.googleapis.com, Enabled (2/3)
API: sheets.googleapis.com, Enabled (3/3) API: sheets.googleapis.com, Enabled (3/3)
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Enable GAM7 client access ### Enable GAM7 client access
@@ -249,17 +249,17 @@ You select a list of scopes, GAM uses a browser to get final authorization from
writes the credentials into the file oauth2.txt. writes the credentials into the file oauth2.txt.
``` ```
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt gamteam@server:/Users/gamteam$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
admin@server:/Users/admin$ gam version gamteam@server:/Users/gamteam$ gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/gamteam/GAMConfig/oauth2.txt, Not Found
GAM 7.33.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.34.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.2 64-bit final Python 3.14.3 64-bit final
macOS Tahoe 26.2 x86_64 macOS Tahoe 26.3 arm64
Path: /Users/admin/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
admin@server:/Users/admin$ gam oauth create gamteam@server:/Users/gamteam$ gam oauth create
[*] 0) Calendar API (supports readonly) [*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly) [*] 1) Chrome Browser Cloud Management API (supports readonly)
@@ -326,7 +326,7 @@ Continue to authorization by entering a 'c'
Please enter 0-50[a|r] or s|u|e|c: c Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com Enter your Google Workspace admin email address? gamteam@domain.com
Go to the following link in a browser on this computer or on another computer: Go to the following link in a browser on this computer or on another computer:
@@ -338,13 +338,13 @@ click the Allow button, paste "Unable to connect" URL from other computer (only
Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required): Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required):
The authentication flow has completed. The authentication flow has completed.
Client OAuth2 File: /Users/admin/GAMConfig/oauth2.txt, Created Client OAuth2 File: /Users/gamteam/GAMConfig/oauth2.txt, Created
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Enable GAM7 service account access. ### Enable GAM7 service account access.
``` ```
admin@server:/Users/admin$ gam user admin@domain.com update serviceaccount gamteam@server:/Users/gamteam$ gam user gamteam@domain.com update serviceaccount
[*] 0) AlertCenter API [*] 0) AlertCenter API
[*] 1) Analytics API - read only [*] 1) Analytics API - read only
[*] 2) Analytics Admin API - read only [*] 2) Analytics Admin API - read only
@@ -408,7 +408,7 @@ Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ PASS (1/38) https://mail.google.com/ PASS (1/38)
https://sites.google.com/feeds FAIL (2/38) https://sites.google.com/feeds FAIL (2/38)
https://www.googleapis.com/auth/analytics.readonly FAIL (3/38) https://www.googleapis.com/auth/analytics.readonly FAIL (3/38)
@@ -459,7 +459,7 @@ Click AUTHORIZE
When the box closes you're done When the box closes you're done
After authorizing it may take some time for this test to pass so wait a few moments and then try this command again. After authorizing it may take some time for this test to pass so wait a few moments and then try this command again.
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
The link shown in the error message should take you directly to the authorization screen. The link shown in the error message should take you directly to the authorization screen.
If not, make sure that you are logged in as a domain admin, then re-enter the link. If not, make sure that you are logged in as a domain admin, then re-enter the link.
@@ -469,7 +469,7 @@ If not, make sure that you are logged in as a domain admin, then re-enter the li
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
for the authorization to complete. for the authorization to complete.
``` ```
admin@server:/Users/admin$ gam user admin@domain.com check serviceaccount gamteam@server:/Users/gamteam$ gam user gamteam@domain.com check serviceaccount
System time status System time status
Your system time differs from admin.googleapis.com by less than 1 second PASS Your system time differs from admin.googleapis.com by less than 1 second PASS
@@ -477,7 +477,7 @@ Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ PASS (1/38) https://mail.google.com/ PASS (1/38)
https://sites.google.com/feeds PASS (2/38) https://sites.google.com/feeds PASS (2/38)
https://www.googleapis.com/auth/analytics.readonly PASS (3/38) https://www.googleapis.com/auth/analytics.readonly PASS (3/38)
@@ -519,14 +519,14 @@ Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38
All scopes PASSED! All scopes PASSED!
Service Account Client name: SVCACCTID is fully authorized. Service Account Client name: SVCACCTID is fully authorized.
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
### Update gam.cfg with some basic values ### Update gam.cfg with some basic values
* `customer_id` - Having this data keeps Gam from having to make extra API calls * `customer_id` - Having this data keeps Gam from having to make extra API calls
* `domain` - This allows you to omit the domain portion of email addresses * `domain` - This allows you to omit the domain portion of email addresses
* `timezone local` - Gam will convert all UTC times to your local timezone * `timezone local` - Gam will convert all UTC times to your local timezone
``` ```
admin@server:/Users/admin$ gam info domain gamteam@server:/Users/gamteam$ gam info domain
Customer ID: C01234567 Customer ID: C01234567
Primary Domain: domain.com Primary Domain: domain.com
Customer Creation Time: 2007-06-06T15:47:55.444Z Customer Creation Time: 2007-06-06T15:47:55.444Z
@@ -534,8 +534,8 @@ Primary Domain Verified: True
Default Language: en Default Language: en
... ...
admin@server:/Users/admin$ gam config customer_id C01234567 domain domain.com timezone local save verify gamteam@server:/Users/gamteam$ gam config customer_id C01234567 domain domain.com timezone local save verify
Config File: /Users/admin/GAMConfig/gam.cfg, Saved Config File: /Users/gamteam/GAMConfig/gam.cfg, Saved
Section: DEFAULT Section: DEFAULT
activity_max_results = 100 activity_max_results = 100
admin_email = '' admin_email = ''
@@ -546,18 +546,18 @@ Section: DEFAULT
bail_on_internal_error_tries = 2 bail_on_internal_error_tries = 2
batch_size = 50 batch_size = 50
cacerts_pem = '' cacerts_pem = ''
cache_dir = /Users/admin/GAMConfig/gamcache cache_dir = /Users/gamteam/GAMConfig/gamcache
cache_discovery_only = true cache_discovery_only = true
channel_customer_id = '' channel_customer_id = ''
charset = utf-8 charset = utf-8
chat_max_results = 100 chat_max_results = 100
classroom_max_results = 0 classroom_max_results = 0
client_secrets_json = client_secrets.json ; /Users/admin/GAMConfig/client_secrets.json client_secrets_json = client_secrets.json ; /Users/gamteam/GAMConfig/client_secrets.json
clock_skew_in_seconds = 10 clock_skew_in_seconds = 10
cmdlog = '' cmdlog = ''
cmdlog_max_backups = 5 cmdlog_max_backups = 5
cmdlog_max_kilo_bytes = 1000 cmdlog_max_kilo_bytes = 1000
config_dir = /Users/admin/GAMConfig config_dir = /Users/gamteam/GAMConfig
contact_max_results = 100 contact_max_results = 100
csv_input_column_delimiter = , csv_input_column_delimiter = ,
csv_input_no_escape_char = true csv_input_no_escape_char = true
@@ -574,6 +574,7 @@ Section: DEFAULT
csv_output_header_filter = '' csv_output_header_filter = ''
csv_output_header_force = '' csv_output_header_force = ''
csv_output_header_order = '' csv_output_header_order = ''
csv_output_header_required = ''
csv_output_line_terminator = lf csv_output_line_terminator = lf
csv_output_no_escape_char = false csv_output_no_escape_char = false
csv_output_quote_char = '"' csv_output_quote_char = '"'
@@ -593,7 +594,7 @@ Section: DEFAULT
developer_preview_apis = '' developer_preview_apis = ''
device_max_results = 200 device_max_results = 200
domain = domain.com domain = domain.com
drive_dir = /Users/admin/GAMWork drive_dir = /Users/gamteam/GAMWork
drive_max_results = 1000 drive_max_results = 1000
email_batch_size = 50 email_batch_size = 50
enable_dasa = false enable_dasa = false
@@ -621,8 +622,8 @@ Section: DEFAULT
no_verify_ssl = false no_verify_ssl = false
num_tbatch_threads = 2 num_tbatch_threads = 2
num_threads = 5 num_threads = 5
oauth2_txt = oauth2.txt ; /Users/admin/GAMConfig/oauth2.txt oauth2_txt = oauth2.txt ; /Users/gamteam/GAMConfig/oauth2.txt
oauth2service_json = oauth2service.json ; /Users/admin/GAMConfig/oauth2service.json oauth2service_json = oauth2service.json ; /Users/gamteam/GAMConfig/oauth2service.json
output_dateformat = '' output_dateformat = ''
output_timeformat = '' output_timeformat = ''
people_max_results = 100 people_max_results = 100
@@ -673,12 +674,12 @@ Section: DEFAULT
user_max_results = 500 user_max_results = 500
user_service_account_access_only = false user_service_account_access_only = false
admin@server:/Users/admin$ gamteam@server:/Users/gamteam$
``` ```
## Windows ## Windows
In these examples, your Google Super admin is shown as admin@domain.com; replace with the In these examples, your Google Super admin is shown as gamteam@domain.com; replace with the
actual email adddress. actual email adddress.
This example assumes that GAM7 has been installed in C:\GAM7; if you've installed This example assumes that GAM7 has been installed in C:\GAM7; if you've installed
@@ -797,6 +798,7 @@ Section: DEFAULT
csv_output_header_filter = '' csv_output_header_filter = ''
csv_output_header_force = '' csv_output_header_force = ''
csv_output_header_order = '' csv_output_header_order = ''
csv_output_header_required = ''
csv_output_line_terminator = lf csv_output_line_terminator = lf
csv_output_no_escape_char = false csv_output_no_escape_char = false
csv_output_quote_char = '"' csv_output_quote_char = '"'
@@ -963,7 +965,7 @@ C:\>dir %GAMCFGDIR%
``` ```
C:\>gam update project C:\>gam update project
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? gamteam@domain.com
Your browser has been opened to visit: Your browser has been opened to visit:
@@ -995,7 +997,7 @@ C:\>
C:\>gam config no_browser true save C:\>gam config no_browser true save
C:\>gam update project C:\>gam update project
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? admin@domain.com Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? gamteam@domain.com
Go to the following link in a browser on other computer: Go to the following link in a browser on other computer:
@@ -1034,9 +1036,9 @@ writes the credentials into the file oauth2.txt.
C:\>del C:\GAMConfig\oauth2.txt C:\>del C:\GAMConfig\oauth2.txt
C:\>gam version C:\>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAM 7.33.01 - https://github.com/GAM-team/GAM - pythonsource GAM 7.34.11 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.2 64-bit final Python 3.14.3 64-bit final
Windows 11 10.0.26200 AMD64 Windows 11 10.0.26200 AMD64
Path: C:\GAM7 Path: C:\GAM7
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -1108,7 +1110,7 @@ Continue to authorization by entering a 'c'
Please enter 0-50[a|r] or s|u|e|c: c Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com Enter your Google Workspace admin email address? gamteam@domain.com
Go to the following link in a browser on this computer or on another computer: Go to the following link in a browser on this computer or on another computer:
@@ -1127,7 +1129,7 @@ C:\>
### Enable GAM7 service account access. ### Enable GAM7 service account access.
``` ```
C:\>gam user admin@domain.com update serviceaccount C:\>gam user gamteam@domain.com update serviceaccount
[*] 0) AlertCenter API [*] 0) AlertCenter API
[*] 1) Analytics API - read only [*] 1) Analytics API - read only
[*] 2) Analytics Admin API - read only [*] 2) Analytics Admin API - read only
@@ -1191,7 +1193,7 @@ Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ PASS (1/38) https://mail.google.com/ PASS (1/38)
https://sites.google.com/feeds FAIL (2/38) https://sites.google.com/feeds FAIL (2/38)
https://www.googleapis.com/auth/analytics.readonly FAIL (3/38) https://www.googleapis.com/auth/analytics.readonly FAIL (3/38)
@@ -1252,14 +1254,14 @@ If not, make sure that you are logged in as a domain admin, then re-enter the li
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
for the authorization to complete. for the authorization to complete.
``` ```
C:\>gam user admin@domain.com check serviceaccount C:\>gam user gamteam@domain.com check serviceaccount
System time status System time status
Your system time differs from admin.googleapis.com by less than 1 second PASS Your system time differs from admin.googleapis.com by less than 1 second PASS
Service Account Private Key Authentication Service Account Private Key Authentication
Authentication PASS Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 1 day WARN Service Account Private Key age: 1 day WARN
Domain-wide Delegation authentication:, User: admin@domain.com, Scopes: 38 Domain-wide Delegation authentication:, User: gamteam@domain.com, Scopes: 38
https://mail.google.com/ PASS (1/38) https://mail.google.com/ PASS (1/38)
https://sites.google.com/feeds PASS (2/38) https://sites.google.com/feeds PASS (2/38)
https://www.googleapis.com/auth/analytics.readonly PASS (3/38) https://www.googleapis.com/auth/analytics.readonly PASS (3/38)
@@ -1357,6 +1359,7 @@ Section: DEFAULT
csv_output_header_filter = '' csv_output_header_filter = ''
csv_output_header_force = '' csv_output_header_force = ''
csv_output_header_order = '' csv_output_header_order = ''
csv_output_header_required = ''
csv_output_line_terminator = lf csv_output_line_terminator = lf
csv_output_no_escape_char = false csv_output_no_escape_char = false
csv_output_quote_char = '"' csv_output_quote_char = '"'

View File

@@ -56,6 +56,7 @@ The only `<VariableNames>` recognized in this `<Section>` are:
* `csv_output_header_drop_filter` * `csv_output_header_drop_filter`
* `csv_output_header_force` * `csv_output_header_force`
* `csv_output_header_order` * `csv_output_header_order`
* `csv_output_header_required`
* `csv_output_row_filter` * `csv_output_row_filter`
* `csv_output_row_filter_mode` * `csv_output_row_filter_mode`
* `csv_output_row_drop_filter` * `csv_output_row_drop_filter`

View File

@@ -7,7 +7,7 @@ Save the CSV file that Google sent you as NoOwnerSecCals.csv
Get calendar description and summary for non-owned secondary calendars. Get calendar description and summary for non-owned secondary calendars.
* There will be one row per calendar. * There will be one row per calendar.
``` ```
gam config num_threads 10 redirect csv ./NOSC_Details.csv multiprocess redirect stderr - multiprocess csv NoOwnerSecCals.csv gam calendar "~Secondary calendar email" print settings fields description,summary gam config num_threads 10 csv_output_header_force "calendarId,description,summary" redirect csv ./NOSC_Details.csv multiprocess redirect stderr - multiprocess csv NoOwnerSecCals.csv gam calendar "~Secondary calendar email" print settings fields description,summary
``` ```
Get event counts for non-owned secondary calendars. Get event counts for non-owned secondary calendars.
@@ -23,12 +23,12 @@ gam config num_threads 10 redirect csv ./NOSC_Summary.csv multiprocess redirect
``` ```
You can add an owner. You can add an owner.
* Replace `admin@domain.com` with the super admin from: `gam oauth info` * Replace `admin@domain.com` with a super admin other than the one from: `gam oauth info`
``` ```
gam config num_threads 10 redirect stdout ./Add_NOSC_Owner.txt multiprocess redirect stderr stdout csv NoOwnerSecCals.csv gam calendar "~Secondary calendar email" add acls owner admin@domain.com gam config num_threads 10 redirect stdout ./Add_NOSC_Owner.txt multiprocess redirect stderr stdout csv NoOwnerSecCals.csv gam calendar "~Secondary calendar email" add acls owner admin@domain.com sendnotifications false
``` ```
After inspecting NOSC_Summary.csv, you can delete the calendars if desired. After inspecting NOSC_Summary.csv, you can delete the calendars if desired.
* Replace `admin@domain.com` with the super admin from: `gam oauth info` * Replace `admin@domain.com` with the super admin specified in the previous step
``` ```
gam config num_threads 10 redirect stdout ./Delete_NOSC.txt multiprocess redirect stderr stdout csv NoOwnerSecCals.csv gam user admin@domain.com remove calendar "~Secondary calendar email" gam config num_threads 10 redirect stdout ./Delete_NOSC.txt multiprocess redirect stderr stdout csv NoOwnerSecCals.csv gam user admin@domain.com remove calendar "~Secondary calendar email"
`` ``

View File

@@ -1,6 +1,7 @@
# Organizational Units # Organizational Units
- [API documentation](#api-documentation) - [API documentation](#api-documentation)
- [Definitions](#definitions) - [Definitions](#definitions)
- [Special character issues](#special-character-issues)
- [Special quoting](#special-quoting) - [Special quoting](#special-quoting)
- [Manage organizational units](#manage-organizational-units) - [Manage organizational units](#manage-organizational-units)
- [Add users to an organizational unit](#add-users-to-an-organizational-unit) - [Add users to an organizational unit](#add-users-to-an-organizational-unit)
@@ -50,6 +51,15 @@ For `<UserTypeEntity>`, see: [Collections of Users](Collections-Of-Users)
For `<CrOSTypeEntity>`, see: [Collections of ChromeOS Devices](Collections-of-ChromeOS-Devices) For `<CrOSTypeEntity>`, see: [Collections of ChromeOS Devices](Collections-of-ChromeOS-Devices)
## Special character issues
If an organizational unit name contains a `#` or a `+`, these commands will not work due to a bug
that Google does not plan to fix.
```
gam update org|ou <OrgUnitPath>
gam delete org|ou <OrgUnitPath>
gam info org|ou <OrgUnitPath>
```
## Special quoting ## Special quoting
You specify a single organizational unit with `org <OrgUnitPath>` and a list of organizationsl units with `orgs <OrgUnitList>`. You specify a single organizational unit with `org <OrgUnitPath>` and a list of organizationsl units with `orgs <OrgUnitList>`.
As organizational unit paths can contain spaces, some care must be used when entering `<OrgUnitPath>` and `<OrgUnitList>`. As organizational unit paths can contain spaces, some care must be used when entering `<OrgUnitPath>` and `<OrgUnitList>`.

View File

@@ -14,17 +14,17 @@
## API documentation ## API documentation
* [Activity Data Sources](https://support.google.com/a/answer/11482175) * [Activity Data Sources](https://support.google.com/a/answer/11482175)
Changes starting 2025-10-29.
* [Reports API - Admin log event changes](https://support.google.com/a/answer/16601511)
Changes starting 2025-12-20 Changes starting 2025-12-20
* [Reports API - Admin log enhancements](https://workspaceupdates.googleblog.com/2025/12/google-workspace-audit-log-api.html) * [Reports API - Admin log enhancements](https://workspaceupdates.googleblog.com/2025/12/google-workspace-audit-log-api.html)
These pages show event/parameter names; scroll down in the left column to: Reports. Changes starting 2026-02-17.
* [Reports API - Admin log event changes](https://support.google.com/a/answer/16601511)
* [Reports API - Activities](https://developers.google.com/admin-sdk/reports/v1/reference/activities) These pages show event/parameter names:
* [Reports API - Customer Usage](https://developers.google.com/admin-sdk/reports/v1/reference/customerUsageReports) * [Reports API - Admin Activities](https://developers.google.com/workspace/admin/reports/v1/appendix/activity/admin-event-names)
* [Reports API - User Usage](https://developers.google.com/admin-sdk/reports/v1/reference/userUsageReport) * [Reports API - Activities](https://developers.google.com/workspace/admin/reports/v1/appendix/activity/access-transparency)
* [Reports API - Customer Usage](https://developers.google.com/workspace/admin/reports/v1/appendix/usage/customer)
* [Reports API - User Usage](https://developers.google.com/workspace/admin/reports/v1/appendix/usage/user)
## Definitions ## Definitions
``` ```
@@ -99,6 +99,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
[event|events <EventNameList>] [ip <String>] [event|events <EventNameList>] [ip <String>]
[gmaileventtypes <NumberRangeList>] [gmaileventtypes <NumberRangeList>]
[groupidfilter <String>] [resourcedetailsfilter <String>] [groupidfilter <String>] [resourcedetailsfilter <String>]
[notimesort]
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>] [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
[countsonly [bydate|summary] [eventrowfilter]] [countsonly [bydate|summary] [eventrowfilter]]
(addcsvdata <FieldName> <String>)* [shownoactivities] (addcsvdata <FieldName> <String>)* [shownoactivities]
@@ -176,6 +177,9 @@ show the most recent activity/event; this can be useful when reporting drive act
Add additional columns of data from the command line to the output. Add additional columns of data from the command line to the output.
* `addcsvdata <FieldName> <String>` * `addcsvdata <FieldName> <String>`
By default, a reverse chronological sort is performed on all rows across multiple users and/or event names;
this is consistent with the behavior in the Admin console. Use option `notimesort` to suppress this sort.
Display a row with a key value of `NoActivities` when there are no activities to report. Display a row with a key value of `NoActivities` when there are no activities to report.
* `shownoactivities` * `shownoactivities`

View File

@@ -171,7 +171,7 @@
withlink withlink
<DrivePermissionsFieldNameList> ::= "<DrivePermissionsFieldName>(,<DrivePermissionsFieldName>)*" <DrivePermissionsFieldNameList> ::= "<DrivePermissionsFieldName>(,<DrivePermissionsFieldName>)*"
<QueryTeamDrive> ::= <String> See: https://developers.google.com/drive/api/v3/search-parameters <QuerySharedDrive> ::= <String> See: https://developers.google.com/workspace/drive/api/guides/search-shareddrives
<SharedDriveACLRole> ::= <SharedDriveACLRole> ::=
manager|organizer|owner| manager|organizer|owner|
contentmanager|fileorganizer| contentmanager|fileorganizer|
@@ -183,8 +183,8 @@
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveID>| <SharedDriveID>|
(teamdriveid <SharedDriveID>)|(teamdriveid:<SharedDriveID>)| (shareddriveid <SharedDriveID>)|(shareddriveid:<SharedDriveID>)|
(teamdrive <SharedDriveName>)|(teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>)|(shareddrive:<SharedDriveName>)
<SharedDriveFieldName> ::= <SharedDriveFieldName> ::=
backgroundimagefile| backgroundimagefile|
@@ -199,11 +199,11 @@
<SharedDriveFieldNameList> ::= "<SharedDriveFieldName>(,<SharedDriveFieldName>)*" <SharedDriveFieldNameList> ::= "<SharedDriveFieldName>(,<SharedDriveFieldName>)*"
<SharedDriveIDEntity> ::= <SharedDriveIDEntity> ::=
<DriveFileItem>|(teamdriveid <DriveFileItem>)|(teamdriveid:<DriveFileItem>) <DriveFileItem>|(shareddriveid <DriveFileItem>)|(shareddriveid:<DriveFileItem>)
<SharedDriveNameEntity> ::= <SharedDriveNameEntity> ::=
(teamdrive <SharedDriveName>)|(teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>)|(shareddrive:<SharedDriveName>)
<SharedDriveAdminQueryEntity> ::= <SharedDriveAdminQueryEntity> ::=
(teamdriveadminquery <QueryTeamDrive>)|(teamdriveadminquery:<QueryTeamDrive>) (shareddriveadminquery <QuerySharedDrive>)|(shareddriveadminquery:<QuerySharedDrive>)
<SharedDriveEntityAdmin> ::= <SharedDriveEntityAdmin> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
@@ -327,11 +327,11 @@ When either of these options is chosen, no infomation about Shared Drive restric
To retrieve the Shared Drive ID with `returnidonly`: To retrieve the Shared Drive ID with `returnidonly`:
``` ```
Linux/MacOS Linux/MacOS
teamDriveId=$(gam create shareddrive ... returnidonly) shareddriveId=$(gam create shareddrive ... returnidonly)
Windows PowerShell Windows PowerShell
$teamDriveId = & gam create shareddrive ... returnidonly $shareddriveId = & gam create shareddrive ... returnidonly
Windows Command Prompt Windows Command Prompt
for /f "delims=" %a in ('gam create shareddrive ... returnidonly') do set teamDriveId=%a for /f "delims=" %a in ('gam create shareddrive ... returnidonly') do set shareddriveId=%a
``` ```
## Bulk Create Shared Drives ## Bulk Create Shared Drives
@@ -422,14 +422,14 @@ By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format. * `formatjson` - Display the fields in JSON format.
``` ```
gam [<UserTypeEntity>] show shareddrives gam [<UserTypeEntity>] show shareddrives
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>] [adminaccess|asadmin] [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
[fields <SharedDriveFieldNameList>] [fields <SharedDriveFieldNameList>]
[showwebviewlink text|hyperlink] [showwebviewlink text|hyperlink]
[formatjson] [formatjson]
``` ```
By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives: By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern. * `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
@@ -441,14 +441,14 @@ By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format. * `formatjson` - Display the fields in JSON format.
``` ```
gam [<UserTypeEntity>] print shareddrives [todrive <ToDriveAttribute>*] gam [<UserTypeEntity>] print shareddrives [todrive <ToDriveAttribute>*]
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>] [adminaccess|asadmin] [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
[fields <SharedDriveFieldNameList>] [fields <SharedDriveFieldNameList>]
[showwebviewlink text|hyperlink] [showwebviewlink text|hyperlink]
[formatjson [quotechar <Character>]] [formatjson [quotechar <Character>]]
``` ```
By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives: By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern. * `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
@@ -498,7 +498,7 @@ Options `shareddriveadminquery|query` and `shareddrives|teamdrives` are mutually
Options `shareddriveadminquery|query` and `orgunit|org|ou` require `adminaccess|asadmin`. Options `shareddriveadminquery|query` and `orgunit|org|ou` require `adminaccess|asadmin`.
By default, organizers for all Shared Drives are displayed; use the following options to select a subset of Shared Drives: By default, organizers for all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `shareddrives|teamdrives <SharedDriveIDList>` - Select the Shared Drive IDs specified in `<SharedDriveIDList>` * `shareddrives|teamdrives <SharedDriveIDList>` - Select the Shared Drive IDs specified in `<SharedDriveIDList>`
* `shareddrives|teamdrives select <FileSelector>|<CSVFileSelector>` - Select the Shared Drive IDs specified in `<FileSelector>|<CSVFileSelector>` * `shareddrives|teamdrives select <FileSelector>|<CSVFileSelector>` - Select the Shared Drive IDs specified in `<FileSelector>|<CSVFileSelector>`
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
@@ -535,12 +535,12 @@ gam print shareddrives query "organizerCount = 0"
Display the number of Shared Drives. Display the number of Shared Drives.
``` ```
gam [<UserTypeEntity>] show|print shareddrives gam [<UserTypeEntity>] show|print shareddrives
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>] [adminaccess|asadmin] [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
showitemcountonly showitemcountonly
``` ```
By default, all Shared Drives are counted; use the following options to select a subset of Shared Drives: By default, all Shared Drives are counted; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern. * `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
@@ -758,7 +758,7 @@ gam config csv_output_header_drop_filter "User,createdTime,permission.photoLink,
## Display Shared Drive access for selected Shared Drives ## Display Shared Drive access for selected Shared Drives
``` ```
gam [<UserTypeEntity>] show shareddriveacls gam [<UserTypeEntity>] show shareddriveacls
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>] [adminaccess|asadmin] [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)* [user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
<PermissionMatch>* [<PermissionMatchAction>] [pmselect] <PermissionMatch>* [<PermissionMatchAction>] [pmselect]
@@ -767,7 +767,7 @@ gam [<UserTypeEntity>] show shareddriveacls
[formatjson] [formatjson]
gam [<UserTypeEntity>] print shareddriveacls [todrive <ToDriveAttribute>*] gam [<UserTypeEntity>] print shareddriveacls [todrive <ToDriveAttribute>*]
[adminaccess|asadmin] [teamdriveadminquery|query <QueryTeamDrive>] [adminaccess|asadmin] [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)* [user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
<PermissionMatch>* [<PermissionMatchAction>] [pmselect] <PermissionMatch>* [<PermissionMatchAction>] [pmselect]
@@ -777,7 +777,7 @@ gam [<UserTypeEntity>] print shareddriveacls [todrive <ToDriveAttribute>*]
``` ```
By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives: By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern. * `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
* `<PermissionMatch>* [<PermissionMatchAction>] pmselect` - Use permission matching to select Shared Drives; all ACLs are displayed for the selected Shared Drives * `<PermissionMatch>* [<PermissionMatchAction>] pmselect` - Use permission matching to select Shared Drives; all ACLs are displayed for the selected Shared Drives
@@ -927,12 +927,12 @@ gam redirect stdout ./DeleteSharedDrives.txt multiprocess redirect stderr stdout
## Delete old empty Shared Drives ## Delete old empty Shared Drives
``` ```
# Get a list of Shared Drives organizers for Shared Drives created before one year ago; alter date<-1y as required. # Get a list of Shared Drives organizers for Shared Drives created before one year ago; alter date<-1y as required.
gam config csv_output_row_filter "createdTime:date<-1y" redirect csv ./TeamDriveOrganizers.csv print shareddriveorganizers domainlist mydomain.com includetypes user oneorganizer shownoorganizerdrives gam config csv_output_row_filter "createdTime:date<-1y" redirect csv ./ShareddriveOrganizers.csv print shareddriveorganizers domainlist mydomain.com includetypes user oneorganizer shownoorganizerdrives
# Inspect shareddriveOrganizers.csv, you'll have to deal with Shared Drives with no organizer/manager # Inspect shareddriveOrganizers.csv, you'll have to deal with Shared Drives with no organizer/manager
# Get old empty Shared Drives # Get old empty Shared Drives
gam config num_threads 10 csv_input_row_filter "organizers:regex:^.+$" csv_output_row_filter "Total:count=0" redirect csv ./OldEmptySharedDrives.csv multiprocess redirect stderr - multiprocess csv ./TeamDriveOrganizers.csv gam user "~organizers" print filecounts select shareddriveid "~id" showsize gam config num_threads 10 csv_input_row_filter "organizers:regex:^.+$" csv_output_row_filter "Total:count=0" redirect csv ./OldEmptySharedDrives.csv multiprocess redirect stderr - multiprocess csv ./ShareddriveOrganizers.csv gam user "~organizers" print filecounts select shareddriveid "~id" showsize
# Inspect OldEmptySharedDrives.csv, if you're confident of the results, proceed # Inspect OldEmptySharedDrives.csv, if you're confident of the results, proceed

View File

@@ -101,6 +101,7 @@
defaulteventlength| defaulteventlength|
format24hourtime| format24hourtime|
hideinvitations| hideinvitations|
hideinvitationssetting|
hideweekends| hideweekends|
locale| locale|
remindonrespondedeventsonly| remindonrespondedeventsonly|

View File

@@ -18,8 +18,8 @@
<SharedDriveID> ::= <String> <SharedDriveID> ::= <String>
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveID>|(teamdriveid <SharedDriveID>)|(teamdriveid:<SharedDriveID>)| <SharedDriveID>|(shareddriveid <SharedDriveID>)|(shareddriveid:<SharedDriveID>)|
(teamdrive <SharedDriveName>)|(teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>)|(shareddrive:<SharedDriveName>)
``` ```
## Display empty folders ## Display empty folders
``` ```

View File

@@ -68,10 +68,10 @@
(parentid <DriveFolderID>)| (parentid <DriveFolderID>)|
(parentname <DriveFolderName>)| (parentname <DriveFolderName>)|
(anyownerparentname <DriveFolderName>)| (anyownerparentname <DriveFolderName>)|
(teamdriveparentid <DriveFolderID>)| (shareddriveparentid <DriveFolderID>)|
(teamdriveparent <SharedDriveName>)| (shareddriveparent <SharedDriveName>)|
(teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>)| (shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>)|
(teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>) (shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>)
<DriveFileCopyAttribute> ::= <DriveFileCopyAttribute> ::=
(contentrestrictions readonly false)| (contentrestrictions readonly false)|
@@ -120,6 +120,7 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
[copyfilepermissions [<Boolean>]] [copyfilepermissions [<Boolean>]]
[copyfileinheritedpermissions [<Boolean>] [copyfileinheritedpermissions [<Boolean>]
[copyfilenoninheritedpermissions [<Boolean>] [copyfilenoninheritedpermissions [<Boolean>]
[copyfolderpermissions [<Boolean>]]
[copymergewithparentfolderpermissions [<Boolean>]] [copymergewithparentfolderpermissions [<Boolean>]]
[copymergedtopfolderpermissions [<Boolean>]] [copymergedtopfolderpermissions [<Boolean>]]
[copytopfolderpermissions [<Boolean>]] [copytopfolderpermissions [<Boolean>]]
@@ -231,10 +232,10 @@ and "Template" is replaced by "NewCustomer" in all copied sub files and folders
* `parentid <DriveFolderID>` - The target folder is identified by `<DriveFolderID>` which must be writable by `<UserTypeEntity>`. * `parentid <DriveFolderID>` - The target folder is identified by `<DriveFolderID>` which must be writable by `<UserTypeEntity>`.
* `parentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by `<UserTypeEntity>`. * `parentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by `<UserTypeEntity>`.
* `anyownerparentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by any user but must be writable by `<UserTypeEntity>`. * `anyownerparentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by any user but must be writable by `<UserTypeEntity>`.
* `teamdriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specific Shared Drive folder. * `shareddriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specific Shared Drive folder.
* `teamdriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive. * `shareddriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive.
* `teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive. * `shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive.
* `teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive. * `shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive.
* If none of the parent options are specified, the copied file/folder will be located in the source folder. * If none of the parent options are specified, the copied file/folder will be located in the source folder.
### Duplicate files ### Duplicate files
@@ -294,6 +295,8 @@ When a folder is copied, its permissions are not copied; these options control c
of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed. of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
When copied, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions. When copied, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions.
* `copyfolderpermissions false` - The permissions of the source folders are not copied to the target folder.
* `copyfolderpermissions true` - The permissions of the source folders are copied to the target folder based on the following options; this is the default action.
When `mergewithparent` is `true`: When `mergewithparent` is `true`:
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action. * `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
@@ -414,15 +417,15 @@ Specify the target location on the Shared Drive, either the ID of the Shared Dri
Files/folders in root of My Drive will be merged into `<DriveFolderID>` Files/folders in root of My Drive will be merged into `<DriveFolderID>`
``` ```
gam user user@domain.com copy drivefile root recursive teamdriveparentid <DriveFolderID> mergewithparent true gam user user@domain.com copy drivefile root recursive shareddriveparentid <DriveFolderID> mergewithparent true
``` ```
Files/folders in root of My Drive will be in a new folder named `My Drive` created in `<DriveFolderID>` Files/folders in root of My Drive will be in a new folder named `My Drive` created in `<DriveFolderID>`
``` ```
gam user user@domain.com copy drivefile root recursive teamdriveparentid <DriveFolderID> mergewithparent false gam user user@domain.com copy drivefile root recursive shareddriveparentid <DriveFolderID> mergewithparent false
``` ```
Files/folders in root of My Drive will be in a new folder named `<String>` created in `<DriveFolderID>` Files/folders in root of My Drive will be in a new folder named `<String>` created in `<DriveFolderID>`
``` ```
gam user user@domain.com copy drivefile root recursive teamdriveparentid <SharedDriveID> mergewithparent false newfilename <String> gam user user@domain.com copy drivefile root recursive shareddriveparentid <SharedDriveID> mergewithparent false newfilename <String>
``` ```
### Copy content of a Shared Drive to another Shared Drive ### Copy content of a Shared Drive to another Shared Drive
@@ -438,7 +441,7 @@ The example is assuming that the target drive is empty.
* Non-inherited sub folder permissions are copied. * Non-inherited sub folder permissions are copied.
* Non-inherited file permissions are copied. * Non-inherited file permissions are copied.
``` ```
gam user user@domain.com copy drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX mergewithparent recursive gam user user@domain.com copy drivefile shareddriveid 0AC_1AB shareddriveparentid 0AE_9ZX mergewithparent recursive
copymergewithparentfolderpermissions true copymergewithparentfolderpermissions true
copytopfolderinheritedpermissions false copytopfolderinheritedpermissions false
copytopfoldernoninheritedpermissions always copytopfoldernoninheritedpermissions always
@@ -458,7 +461,7 @@ Suppose that the source drive has been updated and you want to refresh the targe
* Non-inherited file permissions are copied. * Non-inherited file permissions are copied.
* Files and folders that have been deleted from the source drive will remain on the target drive * Files and folders that have been deleted from the source drive will remain on the target drive
``` ```
gam user user@domain.com copy drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX mergewithparent recursive gam user user@domain.com copy drivefile shareddriveid 0AC_1AB shareddriveparentid 0AE_9ZX mergewithparent recursive
copymergewithparentfolderpermissions true copymergewithparentfolderpermissions true
copytopfolderinheritedpermissions false copytopfolderinheritedpermissions false
copytopfoldernoninheritedpermissions syncallfolders copytopfoldernoninheritedpermissions syncallfolders
@@ -478,7 +481,7 @@ gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 0AC
``` ```
Copy the top level items to target Shared Drive; append desired permission options Copy the top level items to target Shared Drive; append desired permission options
``` ```
gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive teamdriveparentid 0AE_9ZX gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive shareddriveparentid 0AE_9ZX
``` ```
### Copy content of a source Shared Drive folder to a target Shared Drive with parallel Processing ### Copy content of a source Shared Drive folder to a target Shared Drive with parallel Processing
@@ -488,31 +491,31 @@ gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx
``` ```
Create a folder on target Shared Drive with ID 0AE_9ZX, replace "New Folder Name" as desired. Create a folder on target Shared Drive with ID 0AE_9ZX, replace "New Folder Name" as desired.
``` ```
gam user user@domain.com create drivefile mimetype gfolder teamdriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly gam user user@domain.com create drivefile mimetype gfolder shareddriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly
``` ```
Copy the folder top level items to target Shared Drive folder, assume ID 2CY-45G was returned in previous step Copy the folder top level items to target Shared Drive folder, assume ID 2CY-45G was returned in previous step
``` ```
gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive teamdriveparentid 2CY-45G gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive shareddriveparentid 2CY-45G
``` ```
You can script the steps: You can script the steps:
Linux/MacOS Linux/MacOS
``` ```
gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx-8W3 fields id,name,mimetype depth 0 gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx-8W3 fields id,name,mimetype depth 0
targetFolderId=$(gam user user@domain.com create drivefile mimetype gfolder teamdriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly) targetFolderId=$(gam user user@domain.com create drivefile mimetype gfolder shareddriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly)
gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive teamdriveparentid $targetFolderId gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive shareddriveparentid $targetFolderId
``` ```
Windows PowerShell Windows PowerShell
``` ```
gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx-8W3 fields id,name,mimetype depth 0 gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx-8W3 fields id,name,mimetype depth 0
$targetFolderId = & gam user user@domain.com create drivefile mimetype gfolder teamdriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly $targetFolderId = & gam user user@domain.com create drivefile mimetype gfolder shareddriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly
gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive teamdriveparentid $targetFolderId gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive shareddriveparentid $targetFolderId
``` ```
Windows Command Prompt Windows Command Prompt
``` ```
gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx-8W3 fields id,name,mimetype depth 0 gam redirect csv ./TopSDItems.csv user user@domain.com print filelist select 1Bx-8W3 fields id,name,mimetype depth 0
for /f "delims=" %a in ('gam user user@domain.com create drivefile mimetype gfolder teamdriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly') do set taregtFolderId=%a for /f "delims=" %a in ('gam user user@domain.com create drivefile mimetype gfolder shareddriveparentid 0AE-9ZX drivefilename "New Folder Name" returnidonly') do set taregtFolderId=%a
gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive teamdriveparentid %targetFolderId% gam redirect stdout ./CopySharedDrive.txt multiprocess redirect stderr stdout csv TopSDItems.csv gam user user@domain.com copy drivefile "~id" recursive shareddriveparentid %targetFolderId%
``` ```
## Move files and folders ## Move files and folders
@@ -571,6 +574,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
[createshortcutsfornonmovablefiles [<Boolean>]] [createshortcutsfornonmovablefiles [<Boolean>]]
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip] [duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
[duplicatefolders merge|duplicatename|uniquename|skip] [duplicatefolders merge|duplicatename|uniquename|skip]
[copyfolderpermissions [<Boolean>]]
[copymergewithparentfolderpermissions [<Boolean>]] [copymergewithparentfolderpermissions [<Boolean>]]
[copymergedtopfolderpermissions [<Boolean>]] [copymergedtopfolderpermissions [<Boolean>]]
[copytopfolderpermissions [<Boolean>]] [copytopfolderpermissions [<Boolean>]]
@@ -614,10 +618,10 @@ This is the default mode.
* `parentid <DriveFolderID>` - The target folder is identified by `<DriveFolderID>` which must be writable by `<UserTypeEntity>`. * `parentid <DriveFolderID>` - The target folder is identified by `<DriveFolderID>` which must be writable by `<UserTypeEntity>`.
* `parentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by `<UserTypeEntity>`. * `parentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by `<UserTypeEntity>`.
* `anyownerparentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by any user but must be writable by `<UserTypeEntity>`. * `anyownerparentname <DriveFolderName>` - A search is performed for a folder named `<DriveFolderName>` owned by any user but must be writable by `<UserTypeEntity>`.
* `teamdriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specific Shared Drive folder. * `shareddriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specific Shared Drive folder.
* `teamdriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive. * `shareddriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive.
* `teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive. * `shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive.
* `teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive. * `shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive.
* If none of the parent options are specified, the moved file/folder will be located in the source folder. * If none of the parent options are specified, the moved file/folder will be located in the source folder.
### Duplicate files ### Duplicate files
@@ -660,6 +664,8 @@ When a folder is moved by recreating it, its permissions are not copied by the D
For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed. For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions; When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions;
* `copyfolderpermissions false` - The permissions of the source folders are not copied to the target folder.
* `copyfolderpermissions true` - The permissions of the source folders are copied to the target folder based on the following options; this is the default action.
When `mergewithparent` is `true`: When `mergewithparent` is `true`:
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action. * `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
@@ -761,14 +767,14 @@ The following command will change the parents of the top level files and folders
* No permissions are processed. * No permissions are processed.
``` ```
gam user user@domain.com move drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX mergewithparent gam user user@domain.com move drivefile shareddriveid 0AC_1AB shareddriveparentid 0AE_9ZX mergewithparent
``` ```
If you want the source Shared Drive with ID 0AC_1AB to be contained in a top level folder of the target Shared Drive with ID 0AE_9ZX, omit the `mergewithparent` argument. If you want the source Shared Drive with ID 0AC_1AB to be contained in a top level folder of the target Shared Drive with ID 0AE_9ZX, omit the `mergewithparent` argument.
The folder on the target Shared Drive will have the same name as the name of the source Shared Drive; use the `newfilename <DriveFileName>` to use a different name. The folder on the target Shared Drive will have the same name as the name of the source Shared Drive; use the `newfilename <DriveFileName>` to use a different name.
``` ```
gam user user@domain.com move drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX gam user user@domain.com move drivefile shareddriveid 0AC_1AB shareddriveparentid 0AE_9ZX
gam user user@domain.com move drivefile teamdriveid 0AC_1AB teamdriveparentid 0AE_9ZX newfilename "Copy of source Shared Drive" gam user user@domain.com move drivefile shareddriveid 0AC_1AB shareddriveparentid 0AE_9ZX newfilename "Copy of source Shared Drive"
``` ```
### Inter-workspace moves ### Inter-workspace moves
@@ -778,7 +784,7 @@ Due to a restructuring, you want to move data from Shared Drive A in domaina.com
* `user@domaina.com` is a manager of both Shared Drives. * `user@domaina.com` is a manager of both Shared Drives.
``` ```
$ gam user user@domaina move drivefile teamdriveid <SharedDriveAID> teamdriveparentid <SharedDriveBID> mergewithparent $ gam user user@domaina move drivefile shareddriveid <SharedDriveAID> shareddriveparentid <SharedDriveBID> mergewithparent
User: user@domaina.com, Move 1 Drive File/Folder User: user@domaina.com, Move 1 Drive File/Folder
User: user@domaina.com, Drive Folder: Shared Drive A(<SharedDriveAID>), Move(Merge) contents with Drive Folder: Shared Drive B(<SharedDriveBID>) User: user@domaina.com, Drive Folder: Shared Drive A(<SharedDriveAID>), Move(Merge) contents with Drive Folder: Shared Drive B(<SharedDriveBID>)
User: user@domaina.com, Drive File: Filename(<FileID>), Move Failed: Bad Request. User message: "shareOutNotPermitted" User: user@domaina.com, Drive File: Filename(<FileID>), Move Failed: Bad Request. User message: "shareOutNotPermitted"
@@ -794,13 +800,13 @@ The following command will change the parents of the top level files and folders
* No permissions are processed. * No permissions are processed.
``` ```
gam user user@domain.com move drivefile teamdriveid 0AC_1AB parentid root mergewithparent gam user user@domain.com move drivefile shareddriveid 0AC_1AB parentid root mergewithparent
``` ```
If you want the contents of Shared Drive with ID 0AC_1AB to be contained in a top level folder of the My Drive, omit the `mergewithparent` argument. If you want the contents of Shared Drive with ID 0AC_1AB to be contained in a top level folder of the My Drive, omit the `mergewithparent` argument.
The folder on the My Drive will have the same name as the name of the Shared Drive; use the `newfilename <DriveFileName>` to use a different name. The folder on the My Drive will have the same name as the name of the Shared Drive; use the `newfilename <DriveFileName>` to use a different name.
``` ```
gam user user@domain.com move drivefile teamdriveid 0AC_1AB parentid root gam user user@domain.com move drivefile shareddriveid 0AC_1AB parentid root
gam user user@domain.com move drivefile teamdriveid 0AC_1AB parentid root newfilename "Copy of Shared Drive" gam user user@domain.com move drivefile shareddriveid 0AC_1AB parentid root newfilename "Copy of Shared Drive"
``` ```

View File

@@ -65,9 +65,9 @@
<SharedDriveID> ::= <String> <SharedDriveID> ::= <String>
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveIDEntity> ::= (teamdriveid <SharedDriveID>) | (teamdriveid:<SharedDriveID>) <SharedDriveIDEntity> ::= (shareddriveid <SharedDriveID>) | (shareddriveid:<SharedDriveID>)
<SharedDriveNameEntity> ::= (teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) <SharedDriveNameEntity> ::= (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveFileNameEntity> ::= (teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) <SharedDriveFileNameEntity> ::= (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveIDEntity> | <SharedDriveIDEntity> |
@@ -315,8 +315,8 @@
size| size|
spaces| spaces|
starred| starred|
teamdriveid| shareddriveid|
teamdrivename| shareddrivename|
thumbnaillink| thumbnaillink|
thumbnailversion| thumbnailversion|
title| title|
@@ -619,8 +619,10 @@ This option is not available for `print|show filetree`.
``` ```
((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)* ((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*
``` ```
GAM initializes the query to `'me' in owners`.
* `query "xxx"` - ` and xxx` is appended to the current query; you can repeat the query argument to build up a longer query. * `query "xxx"` - ` and xxx` is appended to the current query; you can repeat the query argument to build up a longer query.
* `fullquery "xxx"` - The query is set to `xxx` eliminating the initial `'me' in owners`. * `fullquery "xxx"` - The query is set to `xxx` eliminating the initial `'me' in owners`. You must also use `showownedby any|others` as desired.
* `<DriveFileQueryShortcut>` - Predefined queries * `<DriveFileQueryShortcut>` - Predefined queries
Use the `querytime<String> <Time>` option to allow times, usually relative, to be substituted into the `query <QueryDriveFile>` option. Use the `querytime<String> <Time>` option to allow times, usually relative, to be substituted into the `query <QueryDriveFile>` option.

View File

@@ -149,10 +149,10 @@
(parentid <DriveFolderID>)| (parentid <DriveFolderID>)|
(parentname <DriveFolderName>)| (parentname <DriveFolderName>)|
(anyownerparentname <DriveFolderName>)| (anyownerparentname <DriveFolderName>)|
(teamdriveparentid <DriveFolderID>)| (shareddriveparentid <DriveFolderID>)|
(teamdriveparent <SharedDriveName>)| (shareddriveparent <SharedDriveName>)|
(teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>)| (shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>)|
(teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>) (shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>)
<DriveFileCreateAttribute> ::= <DriveFileCreateAttribute> ::=
<DriveFileAttribute>| <DriveFileAttribute>|
@@ -196,10 +196,10 @@ You can specify where the new file is to be located:
* `parentid <DriveFolderID>` - Folder ID. * `parentid <DriveFolderID>` - Folder ID.
* `parentname <DriveFolderName>` - Folder name; the folder must be owned by `<UserTypeEntity>`. * `parentname <DriveFolderName>` - Folder name; the folder must be owned by `<UserTypeEntity>`.
* `anyownerparentname <DriveFolderName>` - Folder name; the folder can be owned by any user, `<UserTypeEntity>` must be able to write to the folder. * `anyownerparentname <DriveFolderName>` - Folder name; the folder can be owned by any user, `<UserTypeEntity>` must be able to write to the folder.
* `teamdriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specfic Shared Drive folder. * `shareddriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specfic Shared Drive folder.
* `teamdriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive. * `shareddriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive.
* `teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive. * `shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive.
* `teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive. * `shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive.
* If none of the parent options are specified, the parent folder is the root folder. * If none of the parent options are specified, the parent folder is the root folder.
By default, Google assigns the current time to the attributes `createdTime` and `modifiedTime`; you can assign your own values By default, Google assigns the current time to the attributes `createdTime` and `modifiedTime`; you can assign your own values
@@ -290,7 +290,7 @@ This will create a three column CSV file SharedDriveNamesIDs.csv with columns: U
You are building student folders on a Shared Drive as an admin and want to add ACLs to the folders You are building student folders on a Shared Drive as an admin and want to add ACLs to the folders
allowing the student write access and you want a shortcut on the student's My Drive pointing to the folder. allowing the student write access and you want a shortcut on the student's My Drive pointing to the folder.
By adding the student's primary email address to the CSV output, it can be used in subsequent commands. By adding the student's primary email address to the CSV output, it can be used in subsequent commands.
Sustitute for admin@domain.com and `<TeamDriveID>`. Sustitute for admin@domain.com and `<SharedDriveID>`.
``` ```
Students.csv Students.csv
primaryEmail,Name primaryEmail,Name
@@ -299,7 +299,7 @@ mary@domain.com, Mary Smith
... ...
# Create the student folders on the Shared Drive # Create the student folders on the Shared Drive
gam redirect csv ./StudentFolders.csv multiprocess csv Students.csv gam user admin@domain.com create drivefile mimetype gfolder drivefilename "~~Name~~ Digital Portfolio" parentid <TeamDriveID> csv addcsvdata primaryEmail "~primaryEmail" gam redirect csv ./StudentFolders.csv multiprocess csv Students.csv gam user admin@domain.com create drivefile mimetype gfolder drivefilename "~~Name~~ Digital Portfolio" parentid <SharedDriveID> csv addcsvdata primaryEmail "~primaryEmail"
# Add ACLs granting the students write access to their folders; "~User" refers to admin@domain.com # Add ACLs granting the students write access to their folders; "~User" refers to admin@domain.com
gam csv StudentFolders.csv gam user "~User" add drivefileacl "~id" user "~primaryEmail" role fileorganizer gam csv StudentFolders.csv gam user "~User" add drivefileacl "~id" user "~primaryEmail" role fileorganizer
# Add a shortcut to the folder on the student's My Drive # Add a shortcut to the folder on the student's My Drive
@@ -389,7 +389,7 @@ User: user@domain.com, Drive Folder Path:, Create
Build in a Shared Drive Folder Build in a Shared Drive Folder
``` ```
gam user user@domain.com create drivefolderpath path "Top Folder/Middle Folder/Bottom Folder/Sub Folder" teamdriveparent "TS Shared Drive" teamdriveparentname "TS SD6 Folder" gam user user@domain.com create drivefolderpath path "Top Folder/Middle Folder/Bottom Folder/Sub Folder" shareddriveparent "TS Shared Drive" shareddriveparentname "TS SD6 Folder"
Getting all Drive Files/Folders that match query (mimeType = 'application/vnd.google-apps.folder' and name = 'TS SD6 Folder' and trashed = false) for user@domain.com Getting all Drive Files/Folders that match query (mimeType = 'application/vnd.google-apps.folder' and name = 'TS SD6 Folder' and trashed = false) for user@domain.com
Got 1 Drive File/Folder that matched query (mimeType = 'application/vnd.google-apps.folder' and name = 'TS SD6 Folder' and trashed = false) for user@domain.com... Got 1 Drive File/Folder that matched query (mimeType = 'application/vnd.google-apps.folder' and name = 'TS SD6 Folder' and trashed = false) for user@domain.com...
User: user@domain.com, Drive Folder Path:, Create User: user@domain.com, Drive Folder Path:, Create
@@ -495,10 +495,10 @@ You can change where the new file is to be located; this removes all other paren
* `parentid <DriveFolderID>` - Folder ID. * `parentid <DriveFolderID>` - Folder ID.
* `parentname <DriveFolderName>` - Folder name; the folder must be owned by `<UserTypeEntity>`. * `parentname <DriveFolderName>` - Folder name; the folder must be owned by `<UserTypeEntity>`.
* `anyownerparentname <DriveFolderName>` - Folder name; the folder can be owned by any user, `<UserTypeEntity>` must be able to write to the folder. * `anyownerparentname <DriveFolderName>` - Folder name; the folder can be owned by any user, `<UserTypeEntity>` must be able to write to the folder.
* `teamdriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specfic Shared Drive folder. * `shareddriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specfic Shared Drive folder.
* `teamdriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive. * `shareddriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive.
* `teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive. * `shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive.
* `teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive. * `shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive.
You can add/remove parent folders without affecting other parent folders. You can add/remove parent folders without affecting other parent folders.
* `addparents|removeparents <DriveFolderIDList>` - Specify the parent folders by ID. * `addparents|removeparents <DriveFolderIDList>` - Specify the parent folders by ID.

View File

@@ -30,13 +30,13 @@
(parentid <DriveFolderID>)| (parentid <DriveFolderID>)|
(parentname <DriveFolderName>)| (parentname <DriveFolderName>)|
(anyownerparentname <DriveFolderName>)| (anyownerparentname <DriveFolderName>)|
(teamdriveparentid <DriveFolderID>)| (shareddriveparentid <DriveFolderID>)|
(teamdriveparent <SharedDriveName>)| (shareddriveparent <SharedDriveName>)|
(teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>)| (shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>)|
(teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>))| (shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>))|
(teamdriveparentid <DriveFolderID>)|(teamdriveparent <SharedDriveName>)| (shareddriveparentid <DriveFolderID>)|(shareddriveparent <SharedDriveName>)|
(teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>)| (shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>)|
(teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>) (shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>)
<DriveOrderByFieldName> ::= <DriveOrderByFieldName> ::=
createddate|createdtime| createddate|createdtime|

View File

@@ -15,6 +15,7 @@
- [Remove domainCanFind-domainWithLink ACLs for internal domain](#remove-domaincanfind-domainwithlink-acls-for-internal-domain) - [Remove domainCanFind-domainWithLink ACLs for internal domain](#remove-domaincanfind-domainwithlink-acls-for-internal-domain)
- [Remove My Drive ACLs for external domains](#remove-my-drive-acls-for-external-domains) - [Remove My Drive ACLs for external domains](#remove-my-drive-acls-for-external-domains)
- [Remove anyoneCanFind-anyoneWithLink ACLs](#remove-anyonecanfind-anyonewithlink-acls) - [Remove anyoneCanFind-anyoneWithLink ACLs](#remove-anyonecanfind-anyonewithlink-acls)
- [Target Audiences](#target-audiences)
## API documentation ## API documentation
* [Drive API - Permissions](https://developers.google.com/drive/api/v3/reference/permissions) * [Drive API - Permissions](https://developers.google.com/drive/api/v3/reference/permissions)
@@ -143,6 +144,7 @@ specify `basicpermissions` and additional permission fields, e.g., `permissions.
<FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector> <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
``` ```
## GUI API permission name mapping ## GUI API permission name mapping
| GUI setting | API setting | | GUI setting | API setting |
@@ -357,8 +359,8 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
For example, to get the ACLs for your Team Drives with the Team Drive name included in the output: For example, to get the ACLs for your Team Drives with the Team Drive name included in the output:
``` ```
gam redirect csv ./TeamDrives.csv print teamdrives gam redirect csv ./SharedDrives.csv print shareddrives
gam redirect csv ./TeamDriveACLs.csv multiprocess csv ./TeamDrives.csv gam print drivefileacls teamdriveid "~id" addtitle "~name" fields id,domain,emailaddress,role,type,deleted gam redirect csv ./SharedDriveACLs.csv multiprocess csv ./SharedDrives.csv gam print drivefileacls shareddriveid "~id" addtitle "~name" fields id,domain,emailaddress,role,type,deleted
``` ```
## Delete all ACLs except owner from a file ## Delete all ACLs except owner from a file
@@ -616,3 +618,51 @@ Delete those Shared Drive ACLs.
``` ```
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~" gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
``` ```
## Target Audiences
* See: https://support.google.com/a/answer/9934697
You can manage target audiences in the admin console at Directory/Target audiences.
If you click on a target audience the URL will look like this: `https://admin.google.com/ac/targetaudiences/02xcytpi0xrdqxi`
You can add this target audience to a file with:
```
gam user user@domain.com create drivefileacl <DriveFileID> domain 02xcytpi0xrdqxi.audience.googledomains.com role reader
User: user@domain.com, Add 1 Drive File/Folder ACL
User: user@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: 02xcytpi0xrdqxi.audience.googledomains.com, Added
Test Audience
id: 02897912034288871303
type: domain
domain: 02xcytpi0xrdqxi.audience.googledomains.com
role: reader
permissionDetails:
role: reader
type: file
inherited: False
allowFileDiscovery: False
```
You can update the target audience role with:
```
gam user user@domain.com update drivefileacl <DriveFileID> id:02897912034288871303 role writer
User: user@domain.com, Update 1 Drive File/Folder ACL
User: user@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: 02897912034288871303, Updated
Test Audience
id: 02897912034288871303
type: domain
domain: 02xcytpi0xrdqxi.audience.googledomains.com
role: writer
permissionDetails:
role: writer
type: file
inherited: False
allowFileDiscovery: False
```
You can delete the target audience from a file with:
```
gam user user@domain.com delete drivefileacl <DriveFileID> id:02897912034288871303
User: user@domain.com, Delete 1 Drive File/Folder ACL
User: user@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: 02897912034288871303, Deleted
```

View File

@@ -26,10 +26,10 @@
(parentid <DriveFolderID>)| (parentid <DriveFolderID>)|
(parentname <DriveFolderName>)| (parentname <DriveFolderName>)|
(anyownerparentname <DriveFolderName>)| (anyownerparentname <DriveFolderName>)|
(teamdriveparentid <DriveFolderID>)| (shareddriveparentid <DriveFolderID>)|
(teamdriveparent <SharedDriveName>)| (shareddriveparent <SharedDriveName>)|
(teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>)| (shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>)|
(teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>) (shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>)
``` ```
## Create shortcuts ## Create shortcuts
@@ -48,10 +48,10 @@ There are two modes of operaton:
* `parentid <DriveFolderID>` - Folder ID. * `parentid <DriveFolderID>` - Folder ID.
* `parentname <DriveFolderName>` - Folder name; the folder must be owned by `<UserTypeEntity>`. * `parentname <DriveFolderName>` - Folder name; the folder must be owned by `<UserTypeEntity>`.
* `anyownerparentname <DriveFolderName>` - Folder name; the folder can be owned by any user, `<UserTypeEntity>` must be able to write to the folder. * `anyownerparentname <DriveFolderName>` - Folder name; the folder can be owned by any user, `<UserTypeEntity>` must be able to write to the folder.
* `teamdriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specfic Shared Drive folder. * `shareddriveparentid <DriveFolderID>` - Shared Drive folder ID; when used alone, this indicates a specfic Shared Drive folder.
* `teamdriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive. * `shareddriveparent <SharedDriveName>` - Shared Drive name; when used alone, this indicates the root level of the Shared Drive.
* `teamdriveparentid <SharedDriveID> teamdriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive. * `shareddriveparentid <SharedDriveID> shareddriveparentname <DriveFolderName>` - A Shared Drive ID and a folder name on that Shared Drive.
* `teamdriveparent <SharedDriveName> teamdriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive. * `shareddriveparent <SharedDriveName> shareddriveparentname <DriveFolderName>` - A Shared Drive name and a folder name on that Shared Drive.
* `convertparents` - Convert all but the last parent reference in `<DriveFileEntity>` to shortcuts. My testing shows that as parents are added to a file, they are added to the front of the parents list; thus, the last parent is the original parent. * `convertparents` - Convert all but the last parent reference in `<DriveFileEntity>` to shortcuts. My testing shows that as parents are added to a file, they are added to the front of the parents list; thus, the last parent is the original parent.
If neither `<DriveFileParentAttribute>` nor `convertparents` are specified, the shortcut is placed in the root folder (My Drive). If neither `<DriveFileParentAttribute>` nor `convertparents` are specified, the shortcut is placed in the root folder (My Drive).
@@ -142,6 +142,6 @@ gam csv Shortcuts.csv matchfield code 4 gam user "~owner" create drivefileshortc
## Check shortcut validity on Shared Drives ## Check shortcut validity on Shared Drives
``` ```
gam redirect csv ./TDShortcuts.csv user organizer@domain.com print filelist select teamdriveid <SharedDriveID> showmimetype gshortcut fields id gam redirect csv ./TDShortcuts.csv user organizer@domain.com print filelist select shareddriveid <SharedDriveID> showmimetype gshortcut fields id
gam redirect csv ./Shortcuts.csv user organizer@domain.com check drivefileshortcut csvfile TDShortcuts.csv:id csv gam redirect csv ./Shortcuts.csv user organizer@domain.com check drivefileshortcut csvfile TDShortcuts.csv:id csv
``` ```

View File

@@ -404,7 +404,7 @@ Messages are archived to the group specified by `<GroupItem>`.
### Archive a selected set of messages ### Archive a selected set of messages
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages * `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs. * `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
* `max_to_archive <Number>` - Limit the number of messages that will be archived; use a value of 0 for no limit * `max_to_archive <Number>` - Limit the number of messages that will be archived; use a value of 0 for no limit
* `doit` - No messages are archived unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations. * `doit` - No messages are archived unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations.
When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query. When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query.
@@ -430,8 +430,6 @@ user@domain.com,18e9fc6581b9acab,Archived,
user@domain.com,18e9fc58c5491f4c,Archived, user@domain.com,18e9fc58c5491f4c,Archived,
``` ```
See below for message selection.
## Export messages/threads ## Export messages/threads
Export messages in EML format. Export messages in EML format.
``` ```
@@ -464,7 +462,18 @@ By default, when exporting a message, an existing local file will not be overwri
* `overwrite true` - Overwite an existing file * `overwrite true` - Overwite an existing file
* `overwrite false` - Do not overwite an existing file; add a numeric prefix and create a new file * `overwrite false` - Do not overwite an existing file; add a numeric prefix and create a new file
See below for message selection. ### Export a specific set of messages
* `ids <MessageIDEntity>` - A list of message ids
### Export a selected set of messages
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
* `max_to_export <Number>` - Limit the number of messages that will be exported; use a value of 0 for no limit
When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query.
```
&()"|{}/
```
## Forward messages/threads ## Forward messages/threads
``` ```
@@ -492,7 +501,19 @@ If `addorigfieldstosubject` is specified, GAM appends the original `from`, `to`
Fwd: Ross to TestUser (Original From: Ross Scroggs <ross.scroggs@gmail.com> To: testuser@domain.com Date: Thu, 23 Nov 2023 07:01:59 -0800) Fwd: Ross to TestUser (Original From: Ross Scroggs <ross.scroggs@gmail.com> To: testuser@domain.com Date: Thu, 23 Nov 2023 07:01:59 -0800)
``` ```
See below for message selection. ### Forward a specific set of messages
* `ids <MessageIDEntity>` - A list of message ids
### Forward a selected set of messages
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
* `max_to_forward <Number>` - Limit the number of messages that will be forwarded; use a value of 0 for no limit
* `doit` - No messages are processed unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations.
When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query.
```
&()"|{}/
```
## Manage messages/threads ## Manage messages/threads
``` ```

View File

@@ -1,5 +1,6 @@
# Users - Photo # Users - Photo
- [API documentation](#api-documentation) - [API documentation](#api-documentation)
- [Notes](#notes)
- [Definitions](#definitions) - [Definitions](#definitions)
- [Upload a user's photo from a default file](#upload-a-users-photo-from-a-default-file) - [Upload a user's photo from a default file](#upload-a-users-photo-from-a-default-file)
- [Upload a user's photo specifying file name](#upload-a-users-photo-specifying-file-name) - [Upload a user's photo specifying file name](#upload-a-users-photo-specifying-file-name)
@@ -7,11 +8,16 @@
- [Upload a user's photo specifying a Google Drive owner and file name](#upload-a-users-photo-specifying-a-google-drive-owner-and-file-name) - [Upload a user's photo specifying a Google Drive owner and file name](#upload-a-users-photo-specifying-a-google-drive-owner-and-file-name)
- [Download a user's photo](#download-a-users-photo) - [Download a user's photo](#download-a-users-photo)
- [Delete a user's photo](#delete-a-users-photo) - [Delete a user's photo](#delete-a-users-photo)
- [Update photo fails to change user's photo](#update-photo-fails-to-change-users-photo)
- [Download a user's profile photo](Users-Profile-Photo) - [Download a user's profile photo](Users-Profile-Photo)
## API documentation ## API documentation
* [Directory API - Users Photos](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users.photos) * [Directory API - Users Photos](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users.photos)
## Notes
As of version 7.34.09, `gam <UserTypeEntity> update photo` was updated to delete the user's existing photo
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
## Definitions ## Definitions
* [`<DriveFileEntity>`](Drive-File-Selection) * [`<DriveFileEntity>`](Drive-File-Selection)
* [`<UserTypeEntity>`](Collections-of-Users) * [`<UserTypeEntity>`](Collections-of-Users)
@@ -81,3 +87,7 @@ By default, the Base64 encoded data is dumped to stdout.
``` ```
gam <UserTypeEntity> delete|del photo gam <UserTypeEntity> delete|del photo
``` ```
## Update photo fails to change user's photo
If you use `gam <UserTypeEntity> update photo ...` to change a user's photo and the command succeeds
but the photo doesn't change, use `gam <UserTypeEntity> delete photo` first and then do the update.

View File

@@ -148,6 +148,8 @@
<CSVkmdSelector> | <CSVkmdSelector> |
<CSVDataSelector> <CSVDataSelector>
<QuerySharedDrive> ::= <String> See: https://developers.google.com/workspace/drive/api/guides/search-shareddrives
<SharedDriveACLRole> ::= <SharedDriveACLRole> ::=
manager|organizer|owner| manager|organizer|owner|
contentmanager|fileorganizer| contentmanager|fileorganizer|
@@ -159,8 +161,8 @@
<SharedDriveName> ::= <String> <SharedDriveName> ::= <String>
<SharedDriveEntity> ::= <SharedDriveEntity> ::=
<SharedDriveID>| <SharedDriveID>|
(teamdriveid <SharedDriveID>)|(teamdriveid:<SharedDriveID>)| (shareddriveid <SharedDriveID>)|(shareddriveid:<SharedDriveID>)|
(teamdrive <SharedDriveName>)|(teamdrive:<SharedDriveName>) (shareddrive <SharedDriveName>)|(shareddrive:<SharedDriveName>)
<SharedDriveFieldName> ::= <SharedDriveFieldName> ::=
backgroundimagefile| backgroundimagefile|
@@ -174,10 +176,10 @@
themeid themeid
<SharedDriveFieldNameList> ::= "<SharedDriveFieldName>(,<SharedDriveFieldName>)*" <SharedDriveFieldNameList> ::= "<SharedDriveFieldName>(,<SharedDriveFieldName>)*"
<SharedDriveIDEntity> ::= (teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>) <SharedDriveIDEntity> ::= (shareddriveid <DriveFileItem>) | (shareddriveid:<DriveFileItem>)
<SharedDriveNameEntity> ::= (teamdrive <SharedDriveName>) | (teamdrive:<SharedDriveName>) <SharedDriveNameEntity> ::= (shareddrive <SharedDriveName>) | (shareddrive:<SharedDriveName>)
<SharedDriveFileNameEntity> ::= (teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>) <SharedDriveFileNameEntity> ::= (shareddrivefilename <DriveFileName>) | (shareddrivefilename:<DriveFileName>)
<SharedDriveFileQueryEntity> ::= (teamdrivequery <QueryDriveFile>) | (teamdrivequery:<QueryDriveFile>) <SharedDriveFileQueryEntity> ::= (shareddrivequery <QueryDriveFile>) | (shareddrivequery:<QueryDriveFile>)
<SharedDriveFileQueryShortcut> ::= <SharedDriveFileQueryShortcut> ::=
all_files | all_folders | all_google_files | all_non_google_files | all_items all_files | all_folders | all_google_files | all_non_google_files | all_items
@@ -291,11 +293,11 @@ When either of these options is chosen, no infomation about Shared Drive restric
To retrieve the Shared Drive ID with `returnidonly`: To retrieve the Shared Drive ID with `returnidonly`:
``` ```
Linux/MacOS Linux/MacOS
teamDriveId=$(gam user user@domain.com create shareddrive ... returnidonly) shareddriveId=$(gam user user@domain.com create shareddrive ... returnidonly)
Windows PowerShell Windows PowerShell
$teamDriveId = & gam user user@domain.com create shareddrive ... returnidonly $shareddriveId = & gam user user@domain.com create shareddrive ... returnidonly
Windows Command Prompt Windows Command Prompt
for /f "delims=" %a in ('gam user user@domain.com create shareddrive ... returnidonly') do set teamDriveId=%a for /f "delims=" %a in ('gam user user@domain.com create shareddrive ... returnidonly') do set shareddriveId=%a
``` ```
## Bulk Create Shared Drives ## Bulk Create Shared Drives
@@ -417,12 +419,12 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
Display the number of Shared Drives. Display the number of Shared Drives.
``` ```
gam <UserTypeEntity> show|print shareddrives gam <UserTypeEntity> show|print shareddrives
[teamdriveadminquery|query <QueryTeamDrive>] [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
showitemcountonly showitemcountonly
``` ```
By default, all Shared Drives are counted; use the following options to select a subset of Shared Drives: By default, all Shared Drives are counted; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern. * `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
@@ -466,7 +468,7 @@ Options `shareddriveadminquery|query` and `shareddrives|teamdrives` are mutually
Options `shareddriveadminquery|query` and `orgunit|org|ou` require `adminaccess|asadmin`. Options `shareddriveadminquery|query` and `orgunit|org|ou` require `adminaccess|asadmin`.
By default, organizers for all Shared Drives are displayed; use the following options to select a subset of Shared Drives: By default, organizers for all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives
* `shareddrives|teamdrives <SharedDriveIDList>` - Select the Shared Drive IDs specified in `<SharedDriveIDList>` * `shareddrives|teamdrives <SharedDriveIDList>` - Select the Shared Drive IDs specified in `<SharedDriveIDList>`
* `shareddrives|teamdrives select <FileSelector>|<CSVFileSelector>` - Select the Shared Drive IDs specified in `<FileSelector>|<CSVFileSelector>` * `shareddrives|teamdrives select <FileSelector>|<CSVFileSelector>` - Select the Shared Drive IDs specified in `<FileSelector>|<CSVFileSelector>`
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
@@ -486,7 +488,7 @@ To select organizers from any domain, use: `domainlist ""`
For example, to get a single user organizer from your domain for all Shared Drives including no organizer drives: For example, to get a single user organizer from your domain for all Shared Drives including no organizer drives:
``` ```
gam redirect csv ./TeamDriveOrganizers.csv print shareddriveorganizers gam redirect csv ./ShareddriveOrganizers.csv print shareddriveorganizers
``` ```
## Manage Shared Drive access ## Manage Shared Drive access
@@ -596,14 +598,14 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
## Display Shared Drive access for selected Shared Drives ## Display Shared Drive access for selected Shared Drives
``` ```
gam <UserTypeEntity> show shareddriveacls gam <UserTypeEntity> show shareddriveacls
adminaccess [teamdriveadminquery|query <QueryTeamDrive>] adminaccess [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)* [user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
<PermissionMatch>* [<PermissionMatchAction>] [pmselect] <PermissionMatch>* [<PermissionMatchAction>] [pmselect]
[oneitemperrow] [<DrivePermissionsFieldName>*|(fields <DrivePermissionsFieldNameList>)] [oneitemperrow] [<DrivePermissionsFieldName>*|(fields <DrivePermissionsFieldNameList>)]
[formatjson [quotechar <Character>]] [formatjson [quotechar <Character>]]
gam <UserTypeEntity> print shareddriveacls [todrive <ToDriveAttribute>*] gam <UserTypeEntity> print shareddriveacls [todrive <ToDriveAttribute>*]
adminaccess [teamdriveadminquery|query <QueryTeamDrive>] adminaccess [shareddriveadminquery|query <QuerySharedDrive>]
[matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>] [matchname <REMatchPattern>] [orgunit|org|ou <OrgUnitPath>]
[user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)* [user|group <EmailAddress> [checkgroups]] (role|roles <SharedDriveACLRoleList>)*
<PermissionMatch>* [<PermissionMatchAction>] [pmselect] <PermissionMatch>* [<PermissionMatchAction>] [pmselect]
@@ -615,7 +617,7 @@ Shared Drives in the workspace, `<UserTypeEntity>` should specify a super admin
option shoud be used. option shoud be used.
By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives: By default, all Shared Drives are displayed; use the following options to select a subset of Shared Drives:
* `teamdriveadminquery|query <QueryTeamDrive>` - Use a query to select Shared Drives * `shareddriveadminquery|query <QuerySharedDrive>` - Use a query to select Shared Drives
* `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern. * `matchname <REMatchPattern>` - Retrieve Shared Drives with names that match a pattern.
* `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected * `orgunit|org|ou <OrgUnitPath>` - Only Shared Drives in the specified Org Unit are selected
* `<PermissionMatch>* [<PermissionMatchAction>] pmselect` - Use permission matching to select Shared Drives * `<PermissionMatch>* [<PermissionMatchAction>] pmselect` - Use permission matching to select Shared Drives

View File

@@ -40,6 +40,7 @@
- [Print user list](#print-user-list) - [Print user list](#print-user-list)
- [Display user counts](#display-user-counts) - [Display user counts](#display-user-counts)
- [Verify domain membership](#verify-domain-membership) - [Verify domain membership](#verify-domain-membership)
- [Guest Users](#guest-users)
## API documentation ## API documentation
* [Directory API - Users](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users) * [Directory API - Users](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users)
@@ -169,6 +170,7 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
fullname| fullname|
gender| gender|
givenname|firstname| givenname|firstname|
guestaccountinfo|
id| id|
ims|im| ims|im|
includeinglobaladdresslist|gal| includeinglobaladdresslist|gal|
@@ -176,6 +178,7 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
isdelegatedadmin|admin|isadmin| isdelegatedadmin|admin|isadmin|
isenforcedin2sv|is2svenforced| isenforcedin2sv|is2svenforced|
isenrolledin2sv|is2svenrolled| isenrolledin2sv|is2svenrolled|
isguestuser|
ismailboxsetup| ismailboxsetup|
keyword|keywords| keyword|keywords|
language|languages| language|languages|
@@ -1384,3 +1387,11 @@ testuser1@domain.com,118080758787650801331,True,Test User 1
testuserxxx@domain.com,,False,Test User XXX testuserxxx@domain.com,,False,Test User XXX
testuser2@domain.com,107344800159717682514,True,Test User 2 testuser2@domain.com,107344800159717682514,True,Test User 2
``` ```
## Guest Users
* See: https://support.google.com/a/answer/16558545
```
gam create guestuser <EmailAddress>
```
Guest users are in the OU "/Workspace guests".

View File

@@ -3,23 +3,23 @@
Print the current version of Gam with details Print the current version of Gam with details
``` ```
gam version gam version
GAM 7.33.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.34.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.2 64-bit final Python 3.14.3 64-bit final
macOS Tahoe 26.2 x86_64 macOS Tahoe 26.3 arm64
Path: /Users/Admin/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2025-12-23T13:57:00-08:00 Time: 2026-02-15T07:51:00-08:00
``` ```
Print the current version of Gam with details and time offset information Print the current version of Gam with details and time offset information
``` ```
gam version timeoffset gam version timeoffset
GAM 7.33.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.34.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.2 64-bit final Python 3.14.3 64-bit final
macOS Tahoe 26.2 x86_64 macOS Tahoe 26.3 arm64
Path: /Users/Admin/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Your system time differs from www.googleapis.com by less than 1 second Your system time differs from www.googleapis.com by less than 1 second
``` ```
@@ -27,29 +27,29 @@ Your system time differs from www.googleapis.com by less than 1 second
Print the current version of Gam with extended details and SSL information Print the current version of Gam with extended details and SSL information
``` ```
gam version extended gam version extended
GAM 7.33.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.34.11 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.2 64-bit final Python 3.14.3 64-bit final
macOS Tahoe 26.2 x86_64 macOS Tahoe 26.3 arm64
Path: /Users/Admin/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2025-12-23T13:57:00-08:00 Time: 2026-02-15T07:51:00-08:00
Your system time differs from admin.googleapis.com by less than 1 second Your system time differs from admin.googleapis.com by less than 1 second
OpenSSL 3.6.1 27 Jan 2026 OpenSSL 3.6.1 27 Jan 2026
arrow 1.3.0 arrow 1.4.0
chardet 5.2.0 chardet 5.2.0
cryptography 46.0.1 cryptography 46.0.5
filelock 3.19.1 filelock 3.21.2
google-api-python-client 2.182.0 google-api-python-client 2.190.0
google-auth-httplib2 0.2.0 google-auth-httplib2 0.3.0
google-auth-oauthlib 1.2.2 google-auth-oauthlib 1.2.4
google-auth 2.40.3 google-auth 2.48.0
lxml 6.0.1 lxml 6.0.2
httplib2 0.31.0 httplib2 0.31.2
passlib 1.7.4 passlib 1.7.4
pathvalidate 3.3.1 pathvalidate 3.3.1
pyscard 2.3.0 pyscard 2.3.1
yubikey-manager 5.8.0 yubikey-manager 5.9.0
admin.googleapis.com connects using TLSv1.3 TLS_AES_256_GCM_SHA384 admin.googleapis.com connects using TLSv1.3 TLS_AES_256_GCM_SHA384
``` ```
@@ -65,10 +65,10 @@ google-api-python-client 2.77.0
httplib2 0.16.0 httplib2 0.16.0
oauth2client 4.1.3 oauth2client 4.1.3
MacOS High Sierra 10.13.6 x86_64 MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gam7 Path: /Users/gamteam/bin/gam7
Version Check: Version Check:
Current: 5.35.08 Current: 5.35.08
Latest: 7.33.01 Latest: 7.34.11
echo $? echo $?
1 1
``` ```
@@ -76,7 +76,7 @@ echo $?
Print the current version number without details Print the current version number without details
``` ```
gam version simple gam version simple
7.33.01 7.34.11
``` ```
In Linux/MacOS you can do: In Linux/MacOS you can do:
``` ```
@@ -86,13 +86,13 @@ echo $VER
Print the current version of Gam and address of this Wiki Print the current version of Gam and address of this Wiki
``` ```
gam help gam help
GAM 7.33.01 - https://github.com/GAM-team/GAM GAM 7.34.11 - https://github.com/GAM-team/GAM
GAM Team <google-apps-manager@googlegroups.com> GAM Team <google-apps-manager@googlegroups.com>
Python 3.14.2 64-bit final Python 3.14.3 64-bit final
macOS Tahoe 26.2 x86_64 macOS Tahoe 26.3 arm64
Path: /Users/Admin/bin/gam7 Path: /Users/gamteam/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2025-12-23T13:57:00-08:00 Time: 2026-02-15T07:51:00-08:00
Help: Syntax in file /Users/Admin/bin/gam7/GamCommands.txt Help: Syntax in file /Users/gamteam/bin/gam7/GamCommands.txt
Help: Documentation is at https://github.com/GAM-team/GAM/wiki Help: Documentation is at https://github.com/GAM-team/GAM/wiki
``` ```

View File

@@ -232,6 +232,11 @@ csv_output_header_order
Any headers in the file but not in the list will appear after Any headers in the file but not in the list will appear after
the headers in the list the headers in the list
Default: '' Default: ''
csv_output_header_required
A list of <Strings> used to specify column headers
for inclusion in the CSV file written by a gam print command
even if the API didn't return any data for those columns.
Default: ''
csv_output_line_terminator csv_output_line_terminator
Allowed values: cr, lf, crlf Allowed values: cr, lf, crlf
Designates character(s) used to terminate the lines of a CSV file. Designates character(s) used to terminate the lines of a CSV file.
@@ -730,6 +735,8 @@ Section: DEFAULT
csv_output_header_drop_filter = '' csv_output_header_drop_filter = ''
csv_output_header_filter = '' csv_output_header_filter = ''
csv_output_header_force = '' csv_output_header_force = ''
csv_output_header_order = ''
csv_output_header_required = ''
csv_output_line_terminator = lf csv_output_line_terminator = lf
csv_output_no_escape_char = false csv_output_no_escape_char = false
csv_output_quote_char = '"' csv_output_quote_char = '"'
@@ -976,6 +983,7 @@ csv_output_header_drop_filter = ''
csv_output_header_filter = '' csv_output_header_filter = ''
csv_output_header_force = '' csv_output_header_force = ''
csv_output_header_order = '' csv_output_header_order = ''
csv_output_header_required = ''
csv_output_line_terminator = lf csv_output_line_terminator = lf
csv_output_no_escape_char = false csv_output_no_escape_char = false
csv_output_quote_char = '"' csv_output_quote_char = '"'