Compare commits

...

85 Commits

Author SHA1 Message Date
Ross Scroggs
23b0b0f203 Added option countsonly to gam <UserTypeEntity> print|show notes 2024-04-04 11:37:41 -07:00
Ross Scroggs
83d464d167 Updated commands that send emails to not downshift 'First Last<firstlast@domain.com>' 2024-04-02 10:38:35 -07:00
Ross Scroggs
1ba9f73fbd Update sendemail and notify email address lists 2024-04-01 19:36:12 -07:00
Ross Scroggs
0a21f2c959 Cleaned up code for all commands that display Chat objects. 2024-03-30 09:37:43 -07:00
Ross Scroggs
62b7b5d84b Added commands to display Chat events. 2024-03-29 20:06:07 -07:00
Ross Scroggs
7e12a8f0a7 Fixed bug in gam <UserTypeEntity> create chatspace that caused a trap. 2024-03-28 08:00:58 -07:00
Ross Scroggs
d347c65fcb Updated gam delete admin <RoleAssignmentId> 2024-03-25 20:01:38 -07:00
Ross Scroggs
51f109ffa7 Improved commands to display drive file comments. 2024-03-24 08:44:22 -07:00
Ross Scroggs
a5e7d6ff6c Added commands to display drive file comments 2024-03-22 15:52:44 -07:00
Ross Scroggs
2260e7df50 Updated <CrOSFieldName> to include cpuinfo and backlightinfo. 2024-03-21 11:42:12 -07:00
Ross Scroggs
08fc3bdb6f Added depth column to output of gam <UserTypeEntity> print diskusage <DriveFileEntity> 2024-03-17 18:39:39 -07:00
Ross Scroggs
0754a9b176 Updated gam <UserTypeEntity> create|update sendas <EmailAddress> ... replyto <EmailAddress>
to allow uppercase letters in `sendas <EmailAddress>` and `replyto <EmailAddress>`.
2024-03-17 12:05:27 -07:00
Ross Scroggs
448d58f9ba Updated gam create project to handle the following error:
ERROR: 403: permissionDenied - Authentication error: 7; Error Details: User not allowed to access GCP services.
2024-03-13 15:13:46 -07:00
Ross Scroggs
bdc330405e Show new label name on update 2024-03-11 17:04:05 -07:00
Ross Scroggs
abe1d5381d Added a command to update a Gmail label's settings by specifying it's ID rather than it's name. 2024-03-11 16:41:47 -07:00
Ross Scroggs
be0eff7e14 Updated <UserMultiAttribute>.location.buildingid <String> to allow non-validated building IDs 2024-03-09 07:06:45 -08:00
Ross Scroggs
f88a125966 Update WIX toolset version 2024-03-06 18:35:45 -08:00
Ross Scroggs
623ff1fae9 Added option showmimetype category <MimeTypeNameList> to gam <UserTypeEntity> print|show filecounts|filelist|filetree 2024-03-06 17:13:01 -08:00
Ross Scroggs
63d7b5568b Added option addcsvdata <FieldName> <String> to gam print cros 2024-03-05 16:14:18 -08:00
Ross Scroggs
7c8a87673a Reverted change made in 6.71.09 to gam <UserTypeEntity> print filelist 2024-03-04 10:41:43 -08:00
Ross Scroggs
a3b814f758 Improved the performance of gam <UserTypeEntity> print filelist when showmimetype and filepath|fullpath are both specified. 2024-03-03 14:18:17 -08:00
Ross Scroggs
1989d72f4f Added option oneitemperrow to 'gam print admins|adminroles` 2024-03-01 15:10:42 -08:00
Ross Scroggs
63b1ca7e30 Added command to upload changes to Google Docs. 2024-02-29 22:08:17 -08:00
Ross Scroggs
a328ac8ea9 Add licenses, thanks to Jay 2024-02-29 14:15:11 -08:00
Ross Scroggs
2188bfa704 Merge branch 'main' of https://github.com/GAM-team/GAM 2024-02-29 14:03:36 -08:00
Ross Scroggs
0f5adbe211 Added additional error handling to Gmail Client Side Encryption commands. 2024-02-29 14:03:29 -08:00
Jay Lee
d0251182de Education Endpoint SKU 2024-02-29 19:42:30 +00:00
Ross Scroggs
a04345fb10 Include missing gamlib updates 2024-02-29 11:09:35 -08:00
Ross Scroggs
80440255ab Many updates/fixes
Gmail CSE updates

Added todrive options: tdalert, tdfrom, tdsubject

Added CSV output row sorting

Fixed audit monitor create
2024-02-29 10:58:46 -08:00
Ross Scroggs
7b3cc6d819 Update documentation YouTube API off by default 2024-02-26 11:30:12 -08:00
Ross Scroggs
76d3ead61b Updated gam oauth create and gam <UserTypeEntity> update serviceaccount 2024-02-26 10:58:25 -08:00
Ross Scroggs
21ca008a47 Updated gam info users <UserTypeEntity> to not include group tree infornation unless option grouptree is specified. 2024-02-25 10:24:06 -08:00
Ross Scroggs
96aa4f3bd2 Added commands to create|delete|display Drive Label permissions. 2024-02-24 16:56:16 -08:00
Ross Scroggs
883979f5f5 Added options showvalidcolumn and addcsvdata to `gam print use 2024-02-23 14:41:45 -08:00
Ross Scroggs
b03a43777d Update DuetAI licenses to Gemini 2024-02-22 08:33:53 -08:00
Ross Scroggs
a0e4be4b50 Use gam.cfg/use_course_owner_access in course copyfrom. 2024-02-21 14:20:40 -08:00
Ross Scroggs
115caf2486 Added support for Gmail Client Side Encryption 2024-02-21 11:32:00 -08:00
Ross Scroggs
d5255615fd Added use_classroom_owner_access Boolean variable to gam.cfg 2024-02-18 20:59:58 -08:00
Ross Scroggs
d949ca2cad permissionDetails improvements 2024-02-15 18:24:47 -08:00
Ross Scroggs
4b0533ff0e Merge branch 'main' of https://github.com/GAM-team/GAM 2024-02-14 08:34:53 -08:00
Ross Scroggs
d1e87df2df Updated gam info user ... locations formatjson to include the buildingName field in the locations entries. 2024-02-14 08:34:39 -08:00
Jay Lee
dc8f6c3b5e actions: upgrade various action versions 2024-02-13 19:12:46 -05:00
Ross Scroggs
70640c1ddb Bug fix/enhancement copy|more drive file 2024-02-13 13:08:20 -08:00
Ross Scroggs
a72b81f99e Limit testing so jobs complete 2024-02-12 19:58:32 -08:00
Ross Scroggs
89a7c86840 Try multi artifact build - 2 2024-02-12 18:08:19 -08:00
Ross Scroggs
a086c1c2a8 Try multi artifact build 2024-02-12 18:02:57 -08:00
Ross Scroggs
be3c6f10c7 Updated gam print groups ... ciallfields|(cifields <CIGroupFieldNameList>) to account for an API shortcoming that failed to get all of the Cloud Identity fields. 2024-02-12 11:28:09 -08:00
Ross Scroggs
1c9f65f7ca Fix for delete artifacts failing? Try 2 2024-02-11 15:20:46 -08:00
Ross Scroggs
b023ecf8ce Fix for delete artifacts failing? 2024-02-11 15:16:48 -08:00
Ross Scroggs
0a0cb2a18b Back to macos-14 for universal2 build 2024-02-10 19:56:54 -08:00
Ross Scroggs
a02afe76fc Add missing lines
Build universal2 with macos-12, doesn't run with macos-14
2024-02-10 19:27:05 -08:00
Ross Scroggs
0b24beca30 Make artifact names unique with jid 2024-02-10 18:16:39 -08:00
Ross Scroggs
7dfa236bc1 Use v4 actions 2024-02-10 15:29:36 -08:00
Ross Scroggs
b7400b9010 run format cleanup, fix typo line 594 2024-02-09 16:03:11 -08:00
Jay Lee
50c5986c3e actions: fix Windows cache 2024-02-09 15:08:16 -05:00
Ross Scroggs
fff892300b Update glmsgs.py 2024-02-09 10:29:32 -08:00
Ross Scroggs
adbee45073 Added option skiprows <Integer> to gam csv|loop 2024-02-09 10:00:33 -08:00
Ross Scroggs
2d091c8ca0 Fixed bug in gam <UserTypeEntity> create drivefileacl that caused a trap. 2024-02-09 07:26:39 -08:00
Jay Lee
933fc19379 actions: reduce cache sizes by only caching necessary path for OS 2024-02-09 06:23:20 -05:00
Jay Lee
2bb2684165 actions: fix jid numbering 2024-02-08 14:29:33 -05:00
Jay Lee
868e5e1ab6 actions: expire cache to ensure all builds are correct 2024-02-08 14:25:55 -05:00
Jay Lee
d537067908 [no ci] actions: build arm64 and universal2 on github hosted runner 2024-02-08 14:23:17 -05:00
Jay Lee
a9b8a14d8e actions: cleanup brew installs for macOS 2024-02-08 14:18:24 -05:00
Ross Scroggs
f3d654fc76 Upgraded to Python 3.12.2 where possible. 2024-02-08 10:27:41 -08:00
Ross Scroggs
62a01bbcfd Added options restricted|(audience <String>) to gam <UserTypeEntity> create|update chatspace 2024-02-08 10:15:29 -08:00
Jay Lee
e60e1e939b [actions] github hosted Apple silicon (sweet) 2024-02-08 10:55:44 -05:00
Jay Lee
5305f1bda0 actions: rebuild for Python 3.12.2 2024-02-08 08:47:24 -05:00
Ross Scroggs
6126e6ac67 Fixed <PermissionMatch> bug for real. 2024-02-07 12:18:08 -08:00
Ross Scroggs
58e2f74700 Fixed <PermissionMatch> bug introduced in 6.67.35 2024-02-07 09:04:47 -08:00
Ross Scroggs
dcaf892e95 Added option wait <Integer> <Integer> to gam create datatransfer 2024-02-06 18:20:54 -08:00
Ross Scroggs
e8b2dee02d Added option tdnotify [<Boolean>] to <ToDriveAttribute> 2024-02-06 13:46:53 -08:00
Ross Scroggs
267d63fcd6 Fixed bug in gam <UserTypeEntity> show messages ... showattachments to avoid a trap when text/plain attachments in character sets other than UTF-8 are displayed. 2024-02-03 21:14:16 -08:00
Ross Scroggs
566a0c0345 Added sleep <Integer> to batch commands 2024-02-03 17:33:36 -08:00
Ross Scroggs
6ed3f8ebfc Added the following options to <PermissionMatch> that allow more powerful matching.
Added the following options to `<PermissionMatch>` that allow more powerful matching.
```
nottype	<DriveFileACLType>
typelist <DriveFileACLTypeList>
nottypelist <DriveFileACLTypeList>
rolelist <DriveFileACLRoleList>
notrolelist <DriveFileACLRoleList>
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Permission-Matches#define-a-match
2024-02-03 12:09:09 -08:00
Ross Scroggs
51c7a542e3 Shared Drive fixes/updates 2024-02-02 16:00:43 -08:00
Ross Scroggs
ee68669652 Fixed bug in gam <UserTypeEntity> print shareddrives where role was improperly displayed as unknown 2024-02-01 15:40:18 -08:00
Ross Scroggs
e7e653d395 Updated <ToDriveAttribute> to allow multiple tdshare <EmailAddress> commenter|reader|writer options. 2024-02-01 13:28:43 -08:00
Ross Scroggs
e6a4eb7fd9 Merge branch 'main' of https://github.com/GAM-team/GAM 2024-01-31 10:41:39 -08:00
Ross Scroggs
25cdf2e544 Multiple updates 2024-01-31 10:41:36 -08:00
Jay Lee
5e1702018c [actions] bump actions for OpenSSL 3.2.1 2024-01-30 13:04:12 -05:00
Ross Scroggs
a404af0582 Fixed bug that caused HTML password notification email messages to be displayed in raw form. 2024-01-22 09:52:26 -08:00
Ross Scroggs
741b69ff2d Update __init__.py 2024-01-20 10:23:17 -08:00
Ross Scroggs
da1f808c06 Use local copy of googleapiclient to remove static discovery documents to improve performance. 2024-01-20 10:01:04 -08:00
Ross Scroggs
39a8bf9485 Two updates
Added `permissionidlist <PermissionIDList>` to `<PermissionMatch>`

Added option `exportlinkeddrivefiles <Boolean>` to `gam create vaultexport`
2024-01-19 14:31:47 -08:00
Ross Scroggs
53d1ce5ddb Updated gam remove aliases <EmailAddress> user|group <EmailAddressEntity> 2024-01-19 08:12:27 -08:00
72 changed files with 11127 additions and 1594 deletions

View File

@@ -34,11 +34,13 @@ jobs:
goal: build
arch: x86_64
openssl_archs: linux-x86_64
fullGamTest: yes
- os: [self-hosted, linux, arm64]
jid: 2
goal: build
arch: aarch64
openssl_archs: linux-aarch64
fullGamTest: yes
- os: ubuntu-20.04
jid: 3
goal: build
@@ -56,21 +58,24 @@ jobs:
goal: build
arch: x86_64
openssl_archs: darwin64-x86_64
- os: [self-hosted, macOS, ARM64]
jid: 7
fullGamTest: yes
- os: macos-14
jid: 6
goal: build
arch: aarch64
openssl_archs: darwin64-arm64
- os: [self-hosted, macOS, ARM64]
jid: 12
fullGamTest: yes
- os: macos-14
jid: 7
goal: build
arch: universal2
openssl_archs: darwin64-arm64 darwin64-x86_64
- os: windows-2022
jid: 6
jid: 8
goal: build
arch: Win64
openssl_archs: VC-WIN64A
fullGamTest: yes
- os: ubuntu-22.04
goal: test
python: "3.8"
@@ -94,37 +99,36 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- id: auth
name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/297925809119/locations/global/workloadIdentityPools/gha-pool/providers/gha-provider
service_account: github-actions-testing-for-gam@gam-project-wyo-lub-ivl.iam.gserviceaccount.com
- name: Cache multiple paths
if: matrix.goal == 'build'
uses: actions/cache@v3
uses: actions/cache@v4
id: cache-python-ssl
with:
path: |
bin.tar.xz
src/cpython
key: gam-${{ matrix.jid }}-20231212
cache.tar.xz
key: gam-${{ matrix.jid }}-20240210
- name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
working-directory: ${{ github.workspace }}
run: |
tar xvvf bin.tar.xz
tar xvvf cache.tar.xz
- name: Use pre-compiled Python for testing
if: matrix.python != ''
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
allow-prereleases: true
@@ -155,19 +159,30 @@ jobs:
fi
echo "GAMCFGDIR=${GAMCFGDIR}" >> $GITHUB_ENV
echo "GAMCFGDIR is: ${GAMCFGDIR}"
if [[ "${RUNNER_OS}" == "macOS" ]]; then
GAMOS="macos"
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
GAMOS="linux"
elif [[ "${RUNNER_OS}" == "Windows" ]]; then
GAMOS="windows"
else
GAMOS='unknown'
fi
echo "GAMOS=${GAMOS}" >> $GITHUB_ENV
echo "GAMOS is: ${GAMOS}"
- name: Set env variables for test
if: matrix.goal == 'test'
run: |
export PYTHON=$(which python3)
export PIP=$(which pip3)
export gam="${PYTHON} -m gam"
export gampath="$(readlink -e .)"
echo -e "PYTHON: ${PYTHON}\nPIP: ${PIP}\gam: ${gam}\ngampath: ${gampath}"
echo "PYTHON=${PYTHON}" >> $GITHUB_ENV
echo "PIP=${PIP}" >> $GITHUB_ENV
echo "gam=${gam}" >> $GITHUB_ENV
echo "gampath=${gampath}" >> $GITHUB_ENV
export PYTHON=$(which python3)
export PIP=$(which pip3)
export gam="${PYTHON} -m gam"
export gampath="$(readlink -e .)"
echo -e "PYTHON: ${PYTHON}\nPIP: ${PIP}\gam: ${gam}\ngampath: ${gampath}"
echo "PYTHON=${PYTHON}" >> $GITHUB_ENV
echo "PIP=${PIP}" >> $GITHUB_ENV
echo "gam=${gam}" >> $GITHUB_ENV
echo "gampath=${gampath}" >> $GITHUB_ENV
- name: Install necessary Github-hosted Linux packages
if: runner.os == 'Linux' && runner.arch == 'X64'
@@ -177,15 +192,15 @@ jobs:
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev
- name: MacOS install tools
if: runner.os == 'macOS' && runner.arch == 'x86_64'
if: runner.os == 'macOS'
run: |
# Install latest Rust
curl $curl_retry -fsS -o rust.sh https://sh.rustup.rs
bash ./rust.sh -y
source $HOME/.cargo/env
# needed for Rust to compile cryptography Python package for universal2
# not needed since MacOS ARM and universal will be on self-hosted
#rustup target add aarch64-apple-darwin
# Install needed packages
brew update
brew install gpg swig
- name: Windows Configure VCode
uses: ilammy/msvc-dev-cmd@v1
@@ -215,14 +230,11 @@ jobs:
CHOC_OPS="--forcex86"
fi
if [[ "${RUNNER_OS}" == "macOS" ]]; then
#brew install coreutils
#brew install bash
MAKE=make
MAKEOPT="-j$(sysctl -n hw.logicalcpu)"
PERL=perl
echo "MACOSX_DEPLOYMENT_TARGET=10.15" >> $GITHUB_ENV
echo "PYTHON=${PYTHON_INSTALL_PATH}/bin/python3" >> $GITHUB_ENV
#echo "PIP_ARGS=--no-binary=:all:" >> $GITHUB_ENV
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
MAKE=make
MAKEOPT="-j$(nproc)"
@@ -444,39 +456,39 @@ jobs:
- name: Install pip requirements
run: |
echo "before anything..."
"${PYTHON}" -m pip list
if ([ "${RUNNER_OS}" == "macOS" ] && [ "$arch" == "universal2" ]); then
# cffi is a dep of cryptography and doesn't ship
# a universal2 wheel so we must build one ourself :-/
export CFLAGS="-arch x86_64 -arch arm64"
export ARCHFLAGS="-arch x86_64 -arch arm64"
"${PYTHON}" -m pip install --upgrade --force-reinstall --no-binary :all: \
--no-cache-dir --no-deps --use-pep517 \
--use-feature=no-binary-enable-wheel-cache \
cffi
echo "before cryptography..."
"${PYTHON}" -m pip list
# cryptography has a universal2 wheel but getting it installed
# on x86-64 MacOS is a royal pain in the keester.
"${PYTHON}" -m pip download --only-binary :all: \
--dest . \
--no-cache \
--no-deps \
--platform macosx_10_15_universal2 \
cryptography
"${PYTHON}" -m pip install --force-reinstall --no-deps cryptography*.whl
echo "after cryptography..."
"${PYTHON}" -m pip list
"${PYTHON}" -m pip install --upgrade --no-binary :all: -r requirements.txt
else
"${PYTHON}" -m pip install --upgrade -r requirements.txt
echo "after requirements..."
"${PYTHON}" -m pip list
"${PYTHON}" -m pip install --force-reinstall --no-deps --upgrade cryptography
fi
echo "after everything..."
"${PYTHON}" -m pip list
echo "before anything..."
"${PYTHON}" -m pip list
if ([ "${RUNNER_OS}" == "macOS" ] && [ "$arch" == "universal2" ]); then
# cffi is a dep of cryptography and doesn't ship
# a universal2 wheel so we must build one ourself :-/
export CFLAGS="-arch x86_64 -arch arm64"
export ARCHFLAGS="-arch x86_64 -arch arm64"
"${PYTHON}" -m pip install --upgrade --force-reinstall --no-binary :all: \
--no-cache-dir --no-deps --use-pep517 \
--use-feature=no-binary-enable-wheel-cache \
cffi
echo "before cryptography..."
"${PYTHON}" -m pip list
# cryptography has a universal2 wheel but getting it installed
# on x86-64 MacOS is a royal pain in the keester.
"${PYTHON}" -m pip download --only-binary :all: \
--dest . \
--no-cache \
--no-deps \
--platform macosx_10_15_universal2 \
cryptography
"${PYTHON}" -m pip install --force-reinstall --no-deps cryptography*.whl
echo "after cryptography..."
"${PYTHON}" -m pip list
"${PYTHON}" -m pip install --upgrade --no-binary :all: -r requirements.txt
else
"${PYTHON}" -m pip install --upgrade -r requirements.txt
echo "after requirements..."
"${PYTHON}" -m pip list
"${PYTHON}" -m pip install --force-reinstall --no-deps --upgrade cryptography
fi
echo "after everything..."
"${PYTHON}" -m pip list
- name: Install PyInstaller
if: matrix.goal == 'build'
@@ -514,34 +526,34 @@ jobs:
- name: Build GAM with PyInstaller
if: matrix.goal != 'test'
run: |
if [[ "${staticx}" == "yes" ]]; then
export distpath="./dist/gam"
export gampath="${distpath}"
else
export distpath="./dist"
export gampath="${distpath}/gam"
fi
mkdir -p -v "${gampath}"
if [[ "${RUNNER_OS}" == "macOS" ]]; then
export gampath=$($PYTHON -c "import os; print(os.path.realpath('$gampath'))")
elif [[ "${RUNNER_OS}" == "Windows" ]]; then
# Work around issue where PyInstaller picks up python3.dll from other Python versions
# https://github.com/pyinstaller/pyinstaller/issues/7102
export PATH="/usr/bin"
else
export gampath=$(realpath "${gampath}")
fi
export gam="${gampath}/gam"
echo "gampath=${gampath}" >> $GITHUB_ENV
echo "gam=${gam}" >> $GITHUB_ENV
echo -e "GAM: ${gam}\nGAMPATH: ${gampath}"
# TEMP force everything back to one file.
export PYINSTALLER_BUILD_ONEFILE="yes"
export distpath="./dist/gam"
export gampath="${distpath}"
"${PYTHON}" -m PyInstaller --clean --noconfirm --distpath="${distpath}" gam.spec
cat build/gam/warn-gam.txt
if [[ "${staticx}" == "yes" ]]; then
export distpath="./dist/gam"
export gampath="${distpath}"
else
export distpath="./dist"
export gampath="${distpath}/gam"
fi
mkdir -p -v "${gampath}"
if [[ "${RUNNER_OS}" == "macOS" ]]; then
export gampath=$($PYTHON -c "import os; print(os.path.realpath('$gampath'))")
elif [[ "${RUNNER_OS}" == "Windows" ]]; then
# Work around issue where PyInstaller picks up python3.dll from other Python versions
# https://github.com/pyinstaller/pyinstaller/issues/7102
export PATH="/usr/bin"
else
export gampath=$(realpath "${gampath}")
fi
export gam="${gampath}/gam"
echo "gampath=${gampath}" >> $GITHUB_ENV
echo "gam=${gam}" >> $GITHUB_ENV
echo -e "GAM: ${gam}\nGAMPATH: ${gampath}"
# TEMP force everything back to one file.
export PYINSTALLER_BUILD_ONEFILE="yes"
export distpath="./dist/gam"
export gampath="${distpath}"
"${PYTHON}" -m PyInstaller --clean --noconfirm --distpath="${distpath}" gam.spec
cat build/gam/warn-gam.txt
- name: Copy extra package files
if: matrix.goal == 'build'
run: |
@@ -578,11 +590,11 @@ jobs:
- name: Basic Tests all jobs
id: basictests
run: |
$PYTHON -m unittest discover --start-directory ./ --pattern "*_test.py" --buffer || if [ $? != 5 ]; then exit $?; fi # exit 5 is no tests
$gam version extended nooffseterror
export GAMVERSION=$($gam version simple)
echo "GAM Version ${GAMVERSION}"
echo "GAMVERSION=${GAMVERSION}" >> $GITHUB_ENV
$PYTHON -m unittest discover --start-directory ./ --pattern "*_test.py" --buffer || if [ $? != 5 ]; then exit $?; fi # exit 5 is no tests
$gam version extended nooffseterror
export GAMVERSION=$($gam version simple)
echo "GAM Version ${GAMVERSION}"
echo "GAMVERSION=${GAMVERSION}" >> $GITHUB_ENV
- name: Linux/MacOS package
if: runner.os != 'Windows' && matrix.goal == 'build'
@@ -595,7 +607,7 @@ jobs:
else
libver="glibc$(ldd --version | awk '/ldd/{print $NF}')"
fi
GAM_ARCHIVE="gam-${GAMVERSION}-linux-$(arch)-$libver}.tar.xz"
GAM_ARCHIVE="gam-${GAMVERSION}-linux-$(arch)-${libver}.tar.xz"
fi
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
@@ -606,8 +618,8 @@ jobs:
GAM_ARCHIVE="../gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.zip"
/c/Program\ Files/7-Zip/7z.exe a -tzip $GAM_ARCHIVE gam "-xr@${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" -bb3
cd ..
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.11/bin/candle.exe -arch "${WIX_ARCH}" gam.wxs
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.11/bin/light.exe -ext /c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.11/bin/WixUIExtension.dll gam.wixobj -o "gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.msi" || true;
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/candle.exe -arch "${WIX_ARCH}" gam.wxs
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/light.exe -ext /c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/WixUIExtension.dll gam.wixobj -o "gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.msi" || true;
rm -v -f *.wixpdb
- name: Basic Tests build jobs only
@@ -631,227 +643,248 @@ jobs:
echo "We successfully compiled Python ${this_python} and OpenSSL ${this_openssl}"
- name: Live API tests push only
if: github.event_name == 'push' || github.event_name == 'schedule'
if: (github.event_name == 'push' || github.event_name == 'schedule') && matrix.fullGamTest == 'yes'
env:
PASSCODE: ${{ secrets.PASSCODE }}
run: |
if ([ "${RUNNER_OS}" == "macOS" ] && which gpg > /dev/null); then
brew install gnupg
fi
source ../.github/actions/decrypt.sh ../.github/actions/creds.tar.xz.gpg creds.tar.xz "${GAMCFGDIR}"
mv -v "${GAMCFGDIR}/oauth2.txt-gam-gha-${JID}" "${GAMCFGDIR}/oauth2.txt"
rm -v $GAMCFGDIR/oauth2.txt-gam*
export gam_user="gam-gha-${JID}@pdl.jaylee.us"
echo "gam_user=${gam_user}" >> $GITHUB_ENV
$gam config customer_id "C03uzfv2s" save
$gam config domain "pdl.jaylee.us" save
$gam config admin_email "${gam_user}" save
$gam config enable_dasa false save
$gam oauth info
$gam oauth refresh
$gam config enable_dasa true save
$gam create signjwtserviceaccount
$gam checkconn
$gam user "$gam_user" check serviceaccount
$gam info domain
$gam info user
export tstamp=$($PYTHON -c "import time; print(time.time_ns())")
export newbase="gha_test_${JID}_${tstamp}"
export newuser="${newbase}@pdl.jaylee.us"
export newgroup="${newbase}-group@pdl.jaylee.us"
export newalias="${newbase}-alias@pdl.jaylee.us"
export newbuilding="${newbase}-building"
export newresource="${newbase}-resource"
export newou="aaaGithub Actions/${newbase}"
# cleanup old runs
$gam config enable_dasa false save
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultholds || if [ $? != 55 ]; then exit $?; fi | $gam csv - gam delete vaulthold "id:~~holdId~~" matter "id:~~matterId~~"
$gam config enable_dasa true save
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print features | $gam csv - gam delete feature ~name
$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
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail
$gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" print ous fromparent "aaaGithub Actions" | $gam csv - gam delete ou ~orgUnitId
$gam config csv_output_row_filter "email:regex:^gha_test_${JID}_" print cigroups | $gam csv - gam delete cigroup ~email
$gam config csv_output_row_filter "resourceId:regex:^gha_test_${JID}_" print resources | $gam csv - gam delete resource ~resourceId
$gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" print buildings | $gam csv - gam delete building ~buildingId
$gam config csv_output_row_filter "Emails.1.address:regex:^gha_test-${JID}_" print contacts | $gam csv - gam delete contact ~ContactID
source ../.github/actions/decrypt.sh ../.github/actions/creds.tar.xz.gpg creds.tar.xz "${GAMCFGDIR}"
mv -v "${GAMCFGDIR}/oauth2.txt-gam-gha-${JID}" "${GAMCFGDIR}/oauth2.txt"
rm -v $GAMCFGDIR/oauth2.txt-gam*
export gam_user="gam-gha-${JID}@pdl.jaylee.us"
echo "gam_user=${gam_user}" >> $GITHUB_ENV
$gam config customer_id "C03uzfv2s" save
$gam config domain "pdl.jaylee.us" save
$gam config admin_email "${gam_user}" save
$gam config enable_dasa false save
$gam oauth info
$gam oauth refresh
$gam config enable_dasa true save
$gam create signjwtserviceaccount
$gam checkconn
$gam user "$gam_user" check serviceaccount
$gam info domain
$gam info user
export tstamp=$($PYTHON -c "import time; print(time.time_ns())")
export newbase="gha_test_${JID}_${tstamp}"
export newuser="${newbase}@pdl.jaylee.us"
export newgroup="${newbase}-group@pdl.jaylee.us"
export newalias="${newbase}-alias@pdl.jaylee.us"
export newbuilding="${newbase}-building"
export newresource="${newbase}-resource"
export newou="aaaGithub Actions/${newbase}"
# cleanup old runs
$gam config enable_dasa false save
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultholds || if [ $? != 55 ]; then exit $?; fi | $gam csv - gam delete vaulthold "id:~~holdId~~" matter "id:~~matterId~~"
$gam config enable_dasa true save
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print features | $gam csv - gam delete feature ~name
$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
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail
$gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" print ous fromparent "aaaGithub Actions" | $gam csv - gam delete ou ~orgUnitId
$gam config csv_output_row_filter "email:regex:^gha_test_${JID}_" print cigroups | $gam csv - gam delete cigroup ~email
$gam config csv_output_row_filter "resourceId:regex:^gha_test_${JID}_" print resources | $gam csv - gam delete resource ~resourceId
$gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" print buildings | $gam csv - gam delete building ~buildingId
$gam config csv_output_row_filter "Emails.1.address:regex:^gha_test-${JID}_" print contacts | $gam csv - gam delete contact ~ContactID
echo "Creating OrgUnit ${newou}"
$gam create ou "${newou}"
export GAM_THREADS=5
echo email > sample.csv;
for i in {1..10}; do
echo "${newbase}-bulkuser-$i" >> sample.csv;
done
driveid=$($gam user $gam_user add shareddrive "${newbase}" returnidonly)
echo "Created shared drive ${driveid}"
$gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random ou "${newou}" recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB-
$gam user $newuser update photo https://dummyimage.com/400x600/000/fff
$gam user $newuser get photo
$gam user $newuser delete photo
$gam create alias $newalias user $newuser
$gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true
$gam user $gam_user sendemail recipient $newuser subject "test message $newbase" message "GHA test message"
$gam user $gam_user sendemail recipient exchange@pdl.jaylee.us subject "test ${tstamp}" message "test message"
$gam config enable_dasa false save
$gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary
$gam print contacts
$gam user $newuser add license workspaceenterpriseplus
$gam print privileges
$gam config enable_dasa true save
$gam update cigroup $newgroup security memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
$gam info cigroup $newgroup
$gam update group $newgroup add owner $gam_user
$gam update group $newgroup add member $newuser
$gam config enable_dasa false save
$gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
$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"
$gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
$gam config enable_dasa false save
$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}"
$gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail ""
$gam config enable_dasa false save
$gam csv sample.csv gam user ~email add license workspaceenterpriseplus
$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"
$gam csv sample.csv gam update group $newgroup add member ~email
$gam info group $newgroup
$gam info cigroup $newgroup membertree
# confirm mailbox is provisoned before continuing
$gam user $newuser waitformailbox
$gam user $newuser imap on
$gam user $newuser show imap
$gam user $newuser show delegates
#$gam user $newuser add contactdelegate "${newbase}-bulkuser-1"
#$gam user $newuser print contactdelegates
export biohazard=$(echo -e '\xe2\x98\xa3')
$gam user $newuser label "$biohazard unicode biohazard $biohazard"
$gam user $newuser show labels
$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
$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 subject "GHA send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
$gam csvfile sample.csv:email waitformailbox
$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)
$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)
$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)
$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
$gam create feature name VC-$newbase
$gam create feature name Whiteboard-$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..."
$gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room
$gam info resource $newresource
$gam user $newuser add drivefile drivefilename "TPS Reports" mimetype gfolder
$gam user $newuser show filelist
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id # clear ACLs
$gam calendar $gam_user add read domain
$gam calendar $gam_user add freebusy default
$gam calendar $gam_user add editor $newuser
$gam calendar $gam_user showacl
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id
$gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all
$gam calendar $gam_user printevents after -0d
$gam config enable_dasa false save
matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" collaborators $newuser returnidonly)
$gam create vaulthold matter $matterid name "GHA hold $newbase" corpus mail accounts $newuser
$gam print vaultmatters matterstate open
$gam print vaultholds matter $matterid
$gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail accounts $newuser
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~
$gam config enable_dasa true save
$gam csv sample.csv gam user ~email add calendar id:$newresource
$gam delete resource $newresource
$gam delete feature Whiteboard-$newbase
$gam delete feature VC-$newbase
$gam delete building $newbuilding
$gam delete group $newgroup
$gam config enable_dasa false save
echo start
$gam user $newuser delete license workspaceenterpriseplus
echo finish
$gam config enable_dasa true save
$gam whatis $newuser || if [ $? != 20 ]; then exit $?; fi # expect a 20 return code (is a user)
$gam user $gam_user show tokens
$gam config enable_dasa false save
download_dir="${RUNNER_TEMP}/TEMP_DELETE_ME"
mkdir -v "$download_dir"
$gam print exports matter $matterid | $gam csv - gam download export $matterid id:~~id~~ targetfolder "$download_dir"
rm -rvf "$download_dir"
$gam delete hold "GHA hold $newbase" matter $matterid
$gam update matter $matterid action close
$gam update matter $matterid action 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
$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')"
$gam create device serialnumber $sn devicetype android
$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)
$gam delete contacts emailmatchpattern "^${newbase}@example.com$"
$gam print mobile
$gam print devices
$gam print browsers
$gam print cros allfields orderby serialnumber
$gam show crostelemetry storagepercentonly
$gam report usageparameters customer
$gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
$gam report customer todrive tdnobrowser
#$gam report users fields accounts:is_less_secure_apps_access_allowed,gmail:last_imap_time,gmail:last_pop_time filters "accounts:last_login_time>2019-01-01T00:00:00.000Z" todrive tdnobrowser
$gam report users todrive tdnobrowser
$gam report admin start -3d todrive tdnobrowser
$gam print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-" | $gam csv - gam delete device id ~name
$gam config enable_dasa false save
$gam print userinvitations
$gam print userinvitations | $gam csv - gam send userinvitation ~name
$gam config enable_dasa false save
$gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition
$gam print caalevels
$gam delete caalevel "zzz_${newbase}"
$gam user $gam_user add drivefile localfile gam.py parentid "${driveid}"
$gam user $gam_user update shareddrive "${driveid}" ou "${newou}"
$gam user $gam_user show shareddrives asadmin
$gam user $gam_user update shareddrive "${driveid}" ou "aaaGithub Actions" # so we can delete our OU...
$gam user $gam_user delete shareddrive "${driveid}" nukefromorbit
echo "printer model count:"
ssoprofile=$($gam 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)
$gam create inboundssocredential profile "id:${ssoprofile}" generate_key
#$gam create inboundssoassignment profile "id:${ssoprofile}" orgunit "${newou}" mode SAML_SSO
#$gam delete inboundssoassignment "orgunit:${newou}"
$gam delete inboundssoprofile "id:${ssoprofile}"
$gam print printermodels | wc -l
$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)}')
$gam info printer "$printerid"
$gam delete printer "$printerid"
$gam delete ou "${newou}"
- name: Archive production artifacts
uses: actions/upload-artifact@v3
if: (github.event_name == 'push' || github.event_name == 'schedule') && matrix.goal != 'test'
with:
name: gam-binaries
path: |
src/*.tar.xz
src/*.zip
src/*.msi
echo "Creating OrgUnit ${newou}"
$gam create ou "${newou}"
export GAM_THREADS=5
echo email > sample.csv;
for i in {1..10}; do
echo "${newbase}-bulkuser-$i" >> sample.csv;
done
driveid=$($gam user $gam_user add shareddrive "${newbase}" returnidonly)
echo "Created shared drive ${driveid}"
$gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random ou "${newou}" recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB-
$gam user $newuser update photo https://dummyimage.com/400x600/000/fff
$gam user $newuser get photo
$gam user $newuser delete photo
$gam create alias $newalias user $newuser
$gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true
$gam user $gam_user sendemail recipient $newuser subject "test message $newbase" message "GHA test message"
$gam user $gam_user sendemail recipient exchange@pdl.jaylee.us subject "test ${tstamp}" message "test message"
$gam config enable_dasa false save
$gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary
$gam print contacts
$gam user $newuser add license workspaceenterpriseplus
$gam print privileges
$gam config enable_dasa true save
$gam update cigroup $newgroup security memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
$gam info cigroup $newgroup
$gam update group $newgroup add owner $gam_user
$gam update group $newgroup add member $newuser
$gam config enable_dasa false save
$gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
$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"
$gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
$gam config enable_dasa false save
$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}"
$gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail ""
$gam config enable_dasa false save
$gam csv sample.csv gam user ~email add license workspaceenterpriseplus
$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"
$gam csv sample.csv gam update group $newgroup add member ~email
$gam info group $newgroup
$gam info cigroup $newgroup membertree
# confirm mailbox is provisoned before continuing
$gam user $newuser waitformailbox
$gam user $newuser imap on
$gam user $newuser show imap
$gam user $newuser show delegates
#$gam user $newuser add contactdelegate "${newbase}-bulkuser-1"
#$gam user $newuser print contactdelegates
export biohazard=$(echo -e '\xe2\x98\xa3')
$gam user $newuser label "$biohazard unicode biohazard $biohazard"
$gam user $newuser show labels
$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
$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 subject "GHA send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
$gam csvfile sample.csv:email waitformailbox
$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)
$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)
$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)
$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
$gam create feature name VC-$newbase
$gam create feature name Whiteboard-$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..."
$gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room
$gam info resource $newresource
$gam user $newuser add drivefile drivefilename "TPS Reports" mimetype gfolder
$gam user $newuser show filelist
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id # clear ACLs
$gam calendar $gam_user add read domain
$gam calendar $gam_user add freebusy default
$gam calendar $gam_user add editor $newuser
$gam calendar $gam_user showacl
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id
$gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all
$gam calendar $gam_user printevents after -0d
$gam config enable_dasa false save
matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" collaborators $newuser returnidonly)
$gam create vaulthold matter $matterid name "GHA hold $newbase" corpus mail accounts $newuser
$gam print vaultmatters matterstate open
$gam print vaultholds matter $matterid
$gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail accounts $newuser
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~
$gam config enable_dasa true save
$gam csv sample.csv gam user ~email add calendar id:$newresource
$gam delete resource $newresource
$gam delete feature Whiteboard-$newbase
$gam delete feature VC-$newbase
$gam delete building $newbuilding
$gam delete group $newgroup
$gam config enable_dasa false save
echo start
$gam user $newuser delete license workspaceenterpriseplus
echo finish
$gam config enable_dasa true save
$gam whatis $newuser || if [ $? != 20 ]; then exit $?; fi # expect a 20 return code (is a user)
$gam user $gam_user show tokens
$gam config enable_dasa false save
download_dir="${RUNNER_TEMP}/TEMP_DELETE_ME"
mkdir -v "$download_dir"
$gam print exports matter $matterid | $gam csv - gam download export $matterid id:~~id~~ targetfolder "$download_dir"
rm -rvf "$download_dir"
$gam delete hold "GHA hold $newbase" matter $matterid
$gam update matter $matterid action close
$gam update matter $matterid action 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
$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')"
$gam create device serialnumber $sn devicetype android
$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)
$gam delete contacts emailmatchpattern "^${newbase}@example.com$"
$gam print mobile
$gam print devices
$gam print browsers
$gam print cros allfields orderby serialnumber
$gam show crostelemetry storagepercentonly
$gam report usageparameters customer
$gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
$gam report customer todrive tdnobrowser
#$gam report users fields accounts:is_less_secure_apps_access_allowed,gmail:last_imap_time,gmail:last_pop_time filters "accounts:last_login_time>2019-01-01T00:00:00.000Z" todrive tdnobrowser
$gam report users todrive tdnobrowser
$gam report admin start -3d todrive tdnobrowser
$gam print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-" | $gam csv - gam delete device id ~name
$gam config enable_dasa false save
$gam print userinvitations
$gam print userinvitations | $gam csv - gam send userinvitation ~name
$gam config enable_dasa false save
$gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition
$gam print caalevels
$gam delete caalevel "zzz_${newbase}"
$gam user $gam_user add drivefile localfile gam.py parentid "${driveid}"
$gam user $gam_user update shareddrive "${driveid}" ou "${newou}"
$gam user $gam_user show shareddrives asadmin
$gam user $gam_user update shareddrive "${driveid}" ou "aaaGithub Actions" # so we can delete our OU...
$gam user $gam_user delete shareddrive "${driveid}" nukefromorbit
echo "printer model count:"
ssoprofile=$($gam 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)
$gam create inboundssocredential profile "id:${ssoprofile}" generate_key
#$gam create inboundssoassignment profile "id:${ssoprofile}" orgunit "${newou}" mode SAML_SSO
#$gam delete inboundssoassignment "orgunit:${newou}"
$gam delete inboundssoprofile "id:${ssoprofile}"
$gam print printermodels | wc -l
$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)}')
$gam info printer "$printerid"
$gam delete printer "$printerid"
$gam delete ou "${newou}"
- name: Tar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
working-directory: ${{ github.workspace }}
run: |
tar cJvvf bin.tar.xz bin/
if [[ "${RUNNER_OS}" == "Windows" ]]; then
tar_folders="src/cpython/ bin/ssl"
else
tar_folders="bin/"
fi
tar cJvvf cache.tar.xz $tar_folders
- name: Archive production artifacts
uses: actions/upload-artifact@v4
if: (github.event_name == 'push' || github.event_name == 'schedule') && matrix.goal != 'test'
with:
name: gam-binaries-${{ env.GAMOS }}-${{ env.arch }}-${{ matrix.jid }}
path: |
src/*.tar.xz
src/*.zip
src/*.msi
merge:
if: (github.event_name == 'push' || github.event_name == 'schedule')
runs-on: ubuntu-latest
needs: build
permissions:
contents: write
packages: write
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
with:
name: gam-binaries
pattern: gam-binaries-*
# - name: Delete Artifacts
# uses: geekyeggo/delete-artifact@v4
# with:
# name: gam-binaries-*
publish:
if: github.event_name == 'push'
runs-on: ubuntu-latest
needs: build
needs: merge
permissions:
contents: write
packages: write
@@ -859,16 +892,16 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
- name: VirusTotal Scan
uses: crazy-max/ghaction-virustotal@v3
uses: crazy-max/ghaction-virustotal@v4
with:
vt_api_key: ${{ secrets.VT_API_KEY }}
files: |

View File

@@ -851,11 +851,15 @@ gam delete adminrole <RoleItem>
## Display administrative roles
```
gam info adminrole <RoleItem> [privileges]
gam print adminroles|roles [todrive <ToDriveAttribute>*] [privileges]
gam print adminroles|roles [todrive <ToDriveAttribute>*]
[privileges] [oneitemperrow]
gam show adminroles|roles [todrive <ToDriveAttribute>*] [privileges]
```
* `privileges` - Display privileges associated with each role
By default, all privileges for a role are shown on one row as a repeating item.
When `oneitemperrow` is specified, each privilege is output on a separate row/line with the other role fields.
## Create an administrator
Add an administrator role to an administrator.
```
@@ -877,7 +881,8 @@ gam delete admin <RoleAssignmentId>
## Display administrators
```
gam print admins [todrive <ToDriveAttribute>*]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition]
[privileges] [oneitemperrow]
gam show admins
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
```
@@ -889,6 +894,9 @@ options to limit the display:
* `condition` - Display any conditions associated with a role assignment
* `privileges` - Display privileges associated with each role assignment
By default, all role privileges for an admin are shown on one row as a repeating item.
When `oneitemperrow` is specified, each role privilege is output on a separate row/line with the other admin fields.
In versions prior to 6.07.01, specification of both `user <UserItem>`
and `role <RoleItem>` generated no output due to an undocumented API rule that disallows both.

View File

@@ -85,7 +85,7 @@ gam <UserTypeEntity> delete aliases
```
## Display aliases
Display a specific alise.
Display a specific alias.
```
gam info alias|aliases <EmailAddressEntity>
```

View File

@@ -89,15 +89,6 @@ If you run a Google Workspace Education SKU, verify that the super admin you'll
* Choose "All users are 18 or older"
* Click "SAVE"
Verify whether the super admin you'll be using is in an OU where reauthentication is required.
* Access the admin console and go to Security -> Overview
* Scroll down and open Google Cloud session control section
* Select the OU containing the super admin
* If Require reauthentication is selected and Exempt Trusted apps is not checked, you'll have to do `gam oauth create` at whatever frequency is specified
* If that sounds unappealing, check Exempt Trusted apps
* Click "OVERRIDE"
* Follow the steps below to mark GAM as a trusted app
Based on your domain policies, you may have to mark GAM as a trusted app. These steps are performed after a project is created.
* Access the admin console and go to Security -> Access and data control -> API controls
* Check Trust internal, domain-owned apps
@@ -114,6 +105,19 @@ Based on your domain policies, you may have to mark GAM as a trusted app. These
* Click Next/Continue
* Click Finish
Verify whether the super admin you'll be using is in an OU where reauthentication is required.
* Access the admin console and go to Security -> Overview
* Scroll down and open Google Cloud session control section
* Select the OU containing the super admin
* If Require reauthentication is selected and Exempt Trusted apps is not checked, you'll have to do `gam oauth create` at whatever frequency is specified
* If that sounds unappealing, check Exempt Trusted apps
* Click "OVERRIDE"
* Follow the steps below to mark GAM as a trusted app
Additional steps may be required if errors are encountered.
* [Authorize a super admin to create projects](#authorize-a-super-admin-to-create-projects)
* [Authorize GAM to create projects](#authorize-gam-to-create-projects)
## Headless computers and Cloud Shells
With many thanks to Jay, `gam oauth create` now uses a new client access authentication flow
as required by Google for headless computers/cloud shells; this is required as of February 28, 2022.
@@ -404,60 +408,70 @@ writes the credentials into the file oauth2.txt.
```
gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - Telemetry read only
[*] 3) Chrome Management API - read only
[*] 4) Chrome Policy API (supports readonly)
[*] 5) Chrome Printer Management API (supports readonly)
[*] 6) Chrome Version History API
[*] 7) Classroom API - Course Announcements (supports readonly)
[*] 8) Classroom API - Course Topics (supports readonly)
[*] 9) Classroom API - Course Work/Materials (supports readonly)
[*] 10) Classroom API - Course Work/Submissions (supports readonly)
[*] 11) Classroom API - Courses (supports readonly)
[*] 12) Classroom API - Profile Emails
[*] 13) Classroom API - Profile Photos
[*] 14) Classroom API - Rosters (supports readonly)
[*] 15) Classroom API - Student Guardians (supports readonly)
[*] 16) Cloud Identity Groups API (supports readonly)
[*] 17) Cloud Storage (Vault Export - read only)
[*] 18) Contact Delegation API (supports readonly)
[*] 19) Contacts API - Domain Shared and Users and GAL
[*] 20) Data Transfer API (supports readonly)
[*] 21) Directory API - Chrome OS Devices (supports readonly)
[*] 22) Directory API - Customers (supports readonly)
[*] 23) Directory API - Domains (supports readonly)
[*] 24) Directory API - Groups (supports readonly)
[*] 25) Directory API - Mobile Devices Directory (supports readonly and action)
[*] 26) Directory API - Organizational Units (supports readonly)
[*] 27) Directory API - Resource Calendars (supports readonly)
[*] 28) Directory API - Roles (supports readonly)
[*] 29) Directory API - User Schemas (supports readonly)
[*] 30) Directory API - User Security
[*] 31) Directory API - Users (supports readonly)
[*] 32) Email Audit API
[*] 33) Groups Migration API
[*] 34) Groups Settings API
[*] 35) License Manager API
[*] 36) People API (supports readonly)
[*] 37) People Directory API - read only
[ ] 38) Pub / Sub API
[*] 39) Reports API - Audit Reports
[*] 40) Reports API - Usage Reports
[ ] 41) Reseller API
[*] 42) Site Verification API
[*] 43) Sites API
[*] 44) Vault API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
[*] 3) Chrome Management API - Telemetry read only
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
[*] 11) Classroom API - Course Work/Submissions (supports readonly)
[*] 12) Classroom API - Courses (supports readonly)
[*] 13) Classroom API - Profile Emails
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
[*] 21) Cloud Identity User Invitations API (supports readonly)
[ ] 22) Cloud Storage API (Read Only, Vault/Takeout Download, Cloud Storage)
[ ] 23) Cloud Storage API (Read/Write, Vault/Takeout Copy/Download, Cloud Storage)
[*] 24) Contact Delegation API (supports readonly)
[*] 25) Contacts API - Domain Shared Contacts and GAL
[*] 26) Data Transfer API (supports readonly)
[*] 27) Directory API - Chrome OS Devices (supports readonly)
[*] 28) Directory API - Customers (supports readonly)
[*] 29) Directory API - Domains (supports readonly)
[*] 30) Directory API - Groups (supports readonly)
[*] 31) Directory API - Mobile Devices Directory (supports readonly and action)
[*] 32) Directory API - Organizational Units (supports readonly)
[*] 33) Directory API - Resource Calendars (supports readonly)
[*] 34) Directory API - Roles (supports readonly)
[*] 35) Directory API - User Schemas (supports readonly)
[*] 36) Directory API - User Security
[*] 37) Directory API - Users (supports readonly)
[ ] 38) Email Audit API
[*] 39) Groups Migration API
[*] 40) Groups Settings API
[*] 41) License Manager API
[*] 42) People API (supports readonly)
[*] 43) People Directory API - read only
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Please enter 0-42[a|r] or s|u|e|c:
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com
@@ -487,60 +501,70 @@ writes the credentials into the file `oauth2.txt`.
```
gam oauth update
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - Telemetry read only
[*] 3) Chrome Management API - read only
[*] 4) Chrome Policy API (supports readonly)
[*] 5) Chrome Printer Management API (supports readonly)
[*] 6) Chrome Version History API
[*] 7) Classroom API - Course Announcements (supports readonly)
[*] 8) Classroom API - Course Topics (supports readonly)
[*] 9) Classroom API - Course Work/Materials (supports readonly)
[*] 10) Classroom API - Course Work/Submissions (supports readonly)
[*] 11) Classroom API - Courses (supports readonly)
[*] 12) Classroom API - Profile Emails
[*] 13) Classroom API - Profile Photos
[*] 14) Classroom API - Rosters (supports readonly)
[*] 15) Classroom API - Student Guardians (supports readonly)
[*] 16) Cloud Identity Groups API (supports readonly)
[*] 17) Cloud Storage (Vault Export - read only)
[*] 18) Contact Delegation API (supports readonly)
[*] 19) Contacts API - Domain Shared and Users and GAL
[*] 20) Data Transfer API (supports readonly)
[*] 21) Directory API - Chrome OS Devices (supports readonly)
[*] 22) Directory API - Customers (supports readonly)
[*] 23) Directory API - Domains (supports readonly)
[*] 24) Directory API - Groups (supports readonly)
[*] 25) Directory API - Mobile Devices Directory (supports readonly and action)
[*] 26) Directory API - Organizational Units (supports readonly)
[*] 27) Directory API - Resource Calendars (supports readonly)
[*] 28) Directory API - Roles (supports readonly)
[*] 29) Directory API - User Schemas (supports readonly)
[*] 30) Directory API - User Security
[*] 31) Directory API - Users (supports readonly)
[*] 32) Email Audit API
[*] 33) Groups Migration API
[*] 34) Groups Settings API
[*] 35) License Manager API
[*] 36) People API (supports readonly)
[*] 37) People Directory API - read only
[ ] 38) Pub / Sub API
[*] 39) Reports API - Audit Reports
[*] 40) Reports API - Usage Reports
[ ] 41) Reseller API
[*] 42) Site Verification API
[*] 43) Sites API
[*] 44) Vault API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
[*] 3) Chrome Management API - Telemetry read only
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
[*] 11) Classroom API - Course Work/Submissions (supports readonly)
[*] 12) Classroom API - Courses (supports readonly)
[*] 13) Classroom API - Profile Emails
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
[*] 21) Cloud Identity User Invitations API (supports readonly)
[ ] 22) Cloud Storage API (Read Only, Vault/Takeout Download, Cloud Storage)
[ ] 23) Cloud Storage API (Read/Write, Vault/Takeout Copy/Download, Cloud Storage)
[*] 24) Contact Delegation API (supports readonly)
[*] 25) Contacts API - Domain Shared Contacts and GAL
[*] 26) Data Transfer API (supports readonly)
[*] 27) Directory API - Chrome OS Devices (supports readonly)
[*] 28) Directory API - Customers (supports readonly)
[*] 29) Directory API - Domains (supports readonly)
[*] 30) Directory API - Groups (supports readonly)
[*] 31) Directory API - Mobile Devices Directory (supports readonly and action)
[*] 32) Directory API - Organizational Units (supports readonly)
[*] 33) Directory API - Resource Calendars (supports readonly)
[*] 34) Directory API - Roles (supports readonly)
[*] 35) Directory API - User Schemas (supports readonly)
[*] 36) Directory API - User Security
[*] 37) Directory API - Users (supports readonly)
[ ] 38) Email Audit API
[*] 39) Groups Migration API
[*] 40) Groups Settings API
[*] 41) License Manager API
[*] 42) People API (supports readonly)
[*] 43) People Directory API - read only
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Please enter 0-42[a|r] or s|u|e|c:
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com
@@ -817,24 +841,38 @@ By default, the following scopes are verified:
```
https://mail.google.com/
https://sites.google.com/feeds
https://www.google.com/m8/feeds
https://www.googleapis.com/auth/analytics.readonly
https://www.googleapis.com/auth/apps.alerts
https://www.googleapis.com/auth/calendar
https://www.googleapis.com/auth/chat.delete
https://www.googleapis.com/auth/chat.memberships
https://www.googleapis.com/auth/chat.messages
https://www.googleapis.com/auth/chat.spaces
https://www.googleapis.com/auth/classroom.announcements
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.courseworkmaterials
https://www.googleapis.com/auth/classroom.profile.emails
https://www.googleapis.com/auth/classroom.profile.photos
https://www.googleapis.com/auth/classroom.rosters
https://www.googleapis.com/auth/classroom.topics
https://www.googleapis.com/auth/cloud-identity
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/cloudprint
https://www.googleapis.com/auth/contacts
https://www.googleapis.com/auth/contacts.other.readonly
https://www.googleapis.com/auth/datastudio
https://www.googleapis.com/auth/directory.readonly
https://www.googleapis.com/auth/documents
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.activity
https://www.googleapis.com/auth/drive.admin.labels
https://www.googleapis.com/auth/drive.labels
https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.settings.basic
https://www.googleapis.com/auth/gmail.settings.sharing
https://www.googleapis.com/auth/keep
https://www.googleapis.com/auth/spreadsheets
https://www.googleapis.com/auth/tasks
https://www.googleapis.com/auth/userinfo.profile
```
This scope is verified when `user_service_account_access_only = true` in `gam.cfg`.
```
@@ -862,6 +900,118 @@ gam <UserTypeEntity> update serviceaccount (scope|scopes <APIScopeURLList>)*
* `<UserTypeEntity>` - Typically `user <EmailAddress>`, a non-Google Workspace administrator.
* `scopes <APIScopeURLList>` - Verify/enable service account access for a set of specific scopes rather than selecting the scopes.
```
gam user user@domain.com update serviceaccount
[*] 0) AlertCenter API
[*] 1) Analytics API - read only
[*] 2) Analytics Admin API - read only
[*] 3) Calendar API (supports readonly)
[*] 4) Chat API - Memberships (supports readonly)
[*] 5) Chat API - Messages (supports readonly)
[*] 6) Chat API - Spaces (supports readonly)
[*] 7) Chat API - Spaces Delete
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
[*] 11) Classroom API - Course Work/Submissions (supports readonly)
[*] 12) Classroom API - Profile Emails
[*] 13) Classroom API - Profile Photos
[*] 14) Classroom API - Rosters (supports readonly)
[*] 15) Cloud Identity Devices API (supports readonly)
[*] 16) Cloud Resource Manager API v3
[*] 17) Docs API (supports readonly)
[*] 18) Drive API (supports readonly)
[*] 19) Drive API - todrive
[*] 20) Drive Activity API v2 - must pair with Drive API
[*] 21) Drive Labels API v2beta - Admin (supports readonly)
[*] 22) Drive Labels API v2beta - User (supports readonly)
[*] 23) Forms API
[*] 24) Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read
[*] 25) Gmail API - Full Access (Labels, Messages)
[*] 26) Gmail API - Full Access (Labels, Messages) except delete message
[ ] 27) Gmail API - Full Access - read only
[ ] 28) Gmail API - Send Messages - including todrive
[*] 29) Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
[*] 30) Identity and Access Management API
[*] 31) Keep API (supports readonly)
[*] 32) Looker Studio API (supports readonly)
[*] 33) OAuth2 API
[*] 34) People API (supports readonly)
[*] 35) People API - Other Contacts - read only
[*] 36) People Directory API - read only
[*] 37) Sheets API (supports readonly)
[*] 38) Sheets API - todrive
[*] 39) Sites API
[*] 40) Tasks API (supports readonly)
[ ] 41) Youtube API - read only
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Please enter 0-41[a|r] or s|u|e|c: c
System time status
Your system time differs from admin.googleapis.com by less than 1 second PASS
Service Account Private Key Authentication
Authentication PASS
Service Account Private Key age; Google recommends rotating keys on a routine basis
Service Account Private Key age: 364 days WARN
Domain-wide Delegation authentication:, User: user@domain.com, Scopes: 34
https://mail.google.com/ PASS (1/34)
https://sites.google.com/feeds PASS (2/34)
https://www.googleapis.com/auth/analytics.readonly PASS (3/34)
https://www.googleapis.com/auth/apps.alerts PASS (4/34)
https://www.googleapis.com/auth/calendar PASS (5/34)
https://www.googleapis.com/auth/chat.delete PASS (6/34)
https://www.googleapis.com/auth/chat.memberships PASS (7/34)
https://www.googleapis.com/auth/chat.messages PASS (8/34)
https://www.googleapis.com/auth/chat.spaces PASS (9/34)
https://www.googleapis.com/auth/classroom.announcements PASS (10/34)
https://www.googleapis.com/auth/classroom.coursework.students PASS (11/34)
https://www.googleapis.com/auth/classroom.courseworkmaterials PASS (12/34)
https://www.googleapis.com/auth/classroom.profile.emails PASS (13/34)
https://www.googleapis.com/auth/classroom.profile.photos PASS (14/34)
https://www.googleapis.com/auth/classroom.rosters PASS (15/34)
https://www.googleapis.com/auth/classroom.topics PASS (16/34)
https://www.googleapis.com/auth/cloud-identity PASS (17/34)
https://www.googleapis.com/auth/cloud-platform PASS (18/34)
https://www.googleapis.com/auth/contacts PASS (19/34)
https://www.googleapis.com/auth/contacts.other.readonly PASS (20/34)
https://www.googleapis.com/auth/datastudio PASS (21/34)
https://www.googleapis.com/auth/directory.readonly PASS (22/34)
https://www.googleapis.com/auth/documents PASS (23/34)
https://www.googleapis.com/auth/drive PASS (24/34)
https://www.googleapis.com/auth/drive.activity PASS (25/34)
https://www.googleapis.com/auth/drive.admin.labels FAIL (26/34)
https://www.googleapis.com/auth/drive.labels FAIL (27/34)
https://www.googleapis.com/auth/gmail.modify PASS (28/34)
https://www.googleapis.com/auth/gmail.settings.basic PASS (29/34)
https://www.googleapis.com/auth/gmail.settings.sharing PASS (30/34)
https://www.googleapis.com/auth/keep PASS (31/34)
https://www.googleapis.com/auth/spreadsheets PASS (32/34)
https://www.googleapis.com/auth/tasks PASS (33/34)
https://www.googleapis.com/auth/userinfo.profile PASS (34/34)
Some scopes Failed!
To authorize them, please go to the following link in your browser:
https://admin.google.com/ac/owl/domainwidedelegation?clientScopeToAdd=https://mail.google.com/,...
You will be directed to the Google Workspace admin console Security > API Controls > Domain-wide Delegation page
The "Add a new Client ID" box will open
Make sure that "Overwrite existing client ID" is checked
Click AUTHORIZE
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.
```
## Configure Limited access
You can configure GAM to allow users limited access to your domain via GAM.
You can limit both client and service account access.

View File

@@ -119,7 +119,7 @@
#7a4706|#8a1c0a|#994a64|#ffffff
<LanguageCode> ::=
ach|af|ag|ak|am|ar|az|be|bem|bg|bn|br|bs|ca|chr|ckb|co|crs|cs|cy|da|de|
ee|el|en|en-gb|en-us|eo|es|es-419|et|eu|fa|fi|fil|fo|fr|fr-ca|fy|
ee|el|en|en-ca|en-gb|en-us|eo|es|es-419|et|eu|fa|fi|fil|fo|fr|fr-ca|fy|
ga|gaa|gd|gl|gn|gu|ha|haw|he|hi|hr|ht|hu|hy|ia|id|ig|in|is|it|iw|ja|jw|
ka|kg|kk|km|kn|ko|kri|ku|ky|la|lg|ln|lo|loz|lt|lua|lv|
mfe|mg|mi|mk|ml|mn|mo|mr|ms|mt|my|ne|nl|nn|no|nso|ny|nyn|oc|om|or|
@@ -222,72 +222,6 @@
shortcut
<MimeTypeName> ::= application|audio|font|image|message|model|multipart|text|video
<MimeType> ::= <MimeTypeShortcut>|(<MimeTypeName>/<String>)
<ProductID> ::=
nv:<String> |
101001 |
101005 |
101031 |
101033 |
101034 |
101035 |
101036 |
101037 |
101039 |
101040 |
Google-Apps |
Google-Chrome-Device-Management |
Google-Drive-storage |
Google-Vault
<SKUID> ::=
nv:<String>:<String> |
20gb | drive20gb | googledrivestorage20gb | Google-Drive-storage-20GB |
50gb | drive50gb | googledrivestorage50gb | Google-Drive-storage-50GB |
200gb | drive200gb | googledrivestorage200gb | Google-Drive-storage-200GB |
400gb | drive400gb | googledrivestorage400gb | Google-Drive-storage-400GB |
1tb | drive1tb | googledrivestorage1tb | Google-Drive-storage-1TB |
2tb | drive2tb | googledrivestorage2tb | Google-Drive-storage-2TB |
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
assuredcontrols | 1010390001 |
bce | beyondcorp | beyondcorpenterprise | 1010400001 |
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
cloudidentity | identity | 1010010001 |
cloudidentitypremium | identitypremium | 1010050001 |
cloudsearch | 1010350001 |
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 |
gsuitegov | gafg | gsuitegovernment | Google-Apps-For-Government |
gsuitelite | gal | gsl | lite | Google-Apps-Lite |
gwep | workspaceeducationplus | 1010310008 |
gwepstaff | workspaceeducationplusstaff | 1010310009 |
gwepstudent | workspaceeducationplusstudent | 1010310010 |
gwes | workspaceeducationstandard | 1010310005 |
gwesstaff | workspaceeducationstandardstaff | 1010310006 |
gwesstudent | workspaceeducationstandardstudent | 1010310007 |
gwetlu | workspaceeducationupgrade | 1010370001 |
meetdialing | googlemeetglobaldialing | 1010360001 |
postini | gams | gsuitegams | gsuitepostini | gsuitemessagesecurity | Google-Apps-For-Postini |
standard | free | Google-Apps |
vault | googlevault | Google-Vault |
vfe | googlevaultformeremployee | Google-Vault-Former-Employee |
voicepremier | gvpremier | googlevoicepremier | 1010330002 |
voicestandard | gvstandard | googlevoicestandard | 1010330004 |
voicestarter | gvstarter | googlevoicestarter | 1010330003 |
wsbizplus | workspacebusinessplus | 1010020025 |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 |
wsbizstan | workspacebusinessstandard | 1010020028 |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 |
wsentess | workspaceenterpriseessentials | 1010060003 |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 |
wsentstan | workspaceenterprisestandard | 1010020026 |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030
```
## Items built from primitives
```
@@ -346,7 +280,7 @@
<ChannelCustomerID> ::= <String>
<ChatMember> ::= spaces/<String>/members/<String>
<ChatMessage> ::= spaces/<String>/messages/<String>
<ChatSpace> ::= spaces/<String> | <String>
<ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
<ChatThread> ::= spaces/<String>/threads/<String>
<ClassroomInvitationID> ::= <String>
<ClientID> ::= <String>
@@ -421,6 +355,7 @@
<DriveLabelFieldID> ::= <String>
<DriveLabelSelectionID> ::= <String>
<DriveLabelName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]
<DriveLabelPermissionName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]/permissions/(audiences|groups|people)/<String>
<EmailAddress> ::= <String>@<DomainName>
<EmailItem> ::= <EmailAddress>|<UniqueID>|<String>
<EmailReplacement> ::= <String>
@@ -456,6 +391,11 @@
<Marker> ::= <String>
<MatterItem> ::= <UniqueID>|<String>
<MatterState> ::= open|closed|deleted
<MessageContent> ::=
(message|textmessage|htmlmessage <String>)|
(file|textfile|htmlfile <FileName> [charset <Charset>])|
(gdoc|ghtml <UserGoogleDoc>)|
(gcsdoc|gcshtml <StorageBucketObjectName>)
<MessageID> ::= <String>
<Namespace> ::= <String>
<NotesName> ::= notes/<String>
@@ -529,7 +469,7 @@
<ServiceAccountDisplayName> ::= <String>
Maximum of 100 characters
<ServiceAccountDescrition> ::= <String>
Maximumof 256 chcracters
Maximum of 256 chcracters
<ServiceAccountEmail> ::= <ServiceAccountName>@<ProjectID>.iam.gserviceaccount.com
<ServiceAccountUniqueID> ::= <Number>
<ServiceAccountKey> ::= <String>
@@ -584,8 +524,10 @@
(tdlocale <Locale>)|
(tdnobrowser [<Boolean>])|
(tdnoemail [<Boolean>])|
(tdnoescapechar [<Boolean>])|
(tdparent (id:<DriveFolderID>)|<DriveFolderName>)|
(tdshare <EmailAddress> commenter|reader|writer)|
(tdretaintitle [<Boolean>])|
(tdshare <EmailAddress> commenter|reader|writer)*|
(tdsheet (id:<Number>)|<String>)|
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>])
(tdsheettitle <String>)|

View File

@@ -41,6 +41,7 @@ Batch files can contain the following types of lines:
* GAM waits for all running GAM commands to complete
* GAM prints \<String\> and waits for the user to press any key
* GAM continues
* sleep \<Integer\> - Batch processing will suspend for \<Integer\> seconds before the next command line is processed
* print \<String\> - Print \<String\> on stderr
* set \<KeywordString\> \<ValueString\>
* Subsequent lines will have %\<KeywordString\>% replaced with \<ValueString\>
@@ -71,13 +72,13 @@ gam redirect stdout ./NewStudents.out redirect stderr ./NewStudents.err tbatch N
gam csv <FileName>|-|(gsheet <UserGoogleSheet>)|(gdoc <UserGoogleDoc>) [charset <Charset>] [warnifnodata]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [fields <FieldNameList>]
(matchfield|skipfield <FieldName> <RegularExpression>)* [showcmds [<Boolean>]]
[maxrows <Integer>]
[skiprows <Integer>] [maxrows <Integer>]
gam <GAMArgumentList>
gam loop <FileName>|-|(gsheet <UserGoogleSheet>)|(gdoc <UserGoogleDoc>) [charset <Charset>] [warnifnodata]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [fields <FieldNameList>]
(matchfield|skipfield <FieldName> <RegularExpression>)* [showcmds [<Boolean>]]
[maxrows <Integer>]
[skiprows <Integer>] [maxrows <Integer>]
gam <GAMArgumentList>
```
* `gam csv` - Use parallel processing
@@ -92,7 +93,10 @@ gam loop <FileName>|-|(gsheet <UserGoogleSheet>)|(gdoc <UserGoogleDoc>) [charset
* `fields <FieldNameList>` - The column headings of a CSV file that does not contain column headings.
* `(matchfield|skipfield <FieldName> <RegularExpression>)*` - The criteria to select rows from the CSV file; can be used multiple times; if not specified, all rows are selected
* `showcmds` - Write `timestamp,command number/number of commands,command` to stderr when each command starts; write `timestamp, command number/numberof commands,complete` to stderr when command completes
* `maxrows <Integer>` - Limit the number of filtered rows processed from the CSV file/Google Sheet.
* `skiprows <Integer>` - Skip filtered rows from the CSV file/Google Sheet.
* `skiprows 0` - All rows are processed, this is the default
* `skiprows N` - The first N filtered rows are skipped
* `maxrows <Integer>` - Limit the number of filtered rows processed from the CSV file/Google Sheet after any skipped rows.
* `maxrows 0` - All rows are processed, this is the default
* `maxrows N` - N filtered rows are processed

View File

@@ -105,7 +105,9 @@ The second form is backwards compatible with Standard GAM and selection with `<C
annotatedlocation|location|
annotateduser|user|
autoupdateexpiration|
backlightinfo|
bootmode|
cpuinfo|
cpustatusreports|
deprovisionreason|
devicefiles|
@@ -551,6 +553,7 @@ gam print cros [todrive <ToDriveAttribute>*]
[start <Date>] [end <Date>] [listlimit <Number>]
[reverselists <CrOSListFieldNameList>]
[timerangeorder ascending|descending] [showdvrsfp]
(addcsvdata <FieldName> <String>)*
[sortheaders]
[formatjson [quotechar <Character>]]
```
@@ -593,6 +596,9 @@ otherwise, the remaining field names will appear in the order specified.
- `timerangeorder descending` - Change the `activetimeranges` order from ascending (oldest to newest) to descending (newest to oldest); this makes it easy to get the `N` most recent values with `timeranges listlimit N timerangeorder descending`.
- `showdvrsfp` - Display a field `diskVolumeReports.volumeInfo.storageFreePercentage` which is calculated as: `(diskVolumeReports.volumeInfo.storageFree/diskVolumeReports.volumeInfo.storageTotal)*100`
Add additional columns of data from the command line to the output
* `addcsvdata <FieldName> <String>`
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format:
- `formatjson` - Display the fields in JSON format.
@@ -615,6 +621,7 @@ gam <CrOSTypeEntity> print cros [todrive <ToDriveAttribute>*]
[start <Date>] [end <Date>] [listlimit <Number>]
[reverselists <CrOSListFieldNameList>]
[timerangeorder ascending|descending] [showdvrsfp]
(addcsvdata <FieldName> <String>)*
[sortheaders]
[formatjson [quotechar <Character>]]
@@ -643,6 +650,9 @@ otherwise, the remaining field names will appear in the order specified.
- `timerangeorder descending` - Change the `activetimeranges` order from ascending (oldest to newest) to descending (newest to oldest); this makes it easy to get the `N` most recent values with `timeranges listlimit N timerangeorder descending`.
- `showdvrsfp` - Display a field `diskVolumeReports.volumeInfo.storageFreePercentage` which is calculated as: `(diskVolumeReports.volumeInfo.storageFree/diskVolumeReports.volumeInfo.storageTotal)*100`
Add additional columns of data from the command line to the output
* `addcsvdata <FieldName> <String>`
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format:
- `formatjson` - Display the fields in JSON format.

View File

@@ -3,9 +3,10 @@
- [Notes](#notes)
- [Definitions](#definitions)
- [Create classroom invitations](#create-classroom-invitations)
- [Accept classroom invitations](#accept-classroom-invitations)
- [Delete classroom invitations](#delete-classroom-invitations)
- [Accept classroom invitations by user](#accept-classroom-invitations-by-user)
- [Delete classroom invitations by user](#delete-classroom-invitations-by-user)
- [Display classroom invitations by user](#display-classroom-invitations-by-user)
- [Delete classroom invitations by course](#delete-classroom-invitations-by-course)
- [Display classroom invitations by course](#display-classroom-invitations-by-course)
## API documentation
@@ -24,8 +25,6 @@ Scope: https://www.googleapis.com/auth/classroom.rosters , Checked: FA
```
Follow the directions to authorize the Service Account scopes.
The Classroom API does not support inviting users from outside your domain.
## Definitions
```
<DomainName> ::= <String>(.<String>)+
@@ -49,12 +48,18 @@ The Classroom API does not support inviting users from outside your domain.
Invite users to classes.
```
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
[adminaccess|asadmin] [csvformat] [todrive <ToDriveAttributes>*] [formatjson [quotechar <Character>]]
[adminaccess|asadmin]
[csv|csvformat] [todrive <ToDriveAttributes>*] [formatjson [quotechar <Character>]]
```
If `role` is not specified, `student` will be used.
You can only invite a co-teacher to be an owner of a course.
By default, classroom invitations are issued by the owner of the course, the `adminaccess` option causes the invitations to be issued by the admin named in `oauth2.txt`.
By default, when an invitation is created, GAM outputs details of the invitation as indented keywords and values.
* `csv|csvformat [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]` - Output the details in CSV format.
### Example
Suppose you have a CSV file CourseStudent.csv with two columns: Course,Student.
@@ -66,11 +71,13 @@ This command will invite all students to their courses in parallel
```
gam redirect stdout ./Invites.out multiprocess redirect stderr stdout multiprocess csv CourseStudent.csv gam user ~Student create classroominvitation role student course ~Course
```
## Accept classroom invitations
Accept classroom invitations for users. You can only invite a co-teacher to be an owner of a course.
## Accept classroom invitations by user
Accept classroom invitations for users.
```
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
```
`<UserTypeEntity>` must specify users in your domain.
By default, all invitations for the specified users will be accepted.
Select specific invitations to accept:
@@ -81,11 +88,13 @@ Select courses and accept invitations for those courses.
By default, invitations for all roles will be accepted; you can limit the acceptances to invitations of a specific role.
## Delete classroom invitations
## Delete classroom invitations by user
Delete classroom invitations for users.
```
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
```
`<UserTypeEntity>` must specify users in your domain.
By default, all invitations for the specified users will be deleted.
Select specific invitations to delete:
@@ -104,8 +113,23 @@ gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttributes>*] [role all|owner|student|teacher]
[formatjson [quotechar <Character>]]
```
`<UserTypeEntity>` must specify users in your domain.
By default, invitations for all roles will be displayed; you can limit the display to invitations of a specific role.
## Delete classroom invitations by course
Delete classroom invitations for courses. This command must be used to delete non-domain member invitations.
```
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
```
Select courses and delete invitations for those courses.
* `courses <CourseEntity>` - Specify courses
Select specific invitations to delete:
* `ids <ClassroomInvitationIDEntity>` - Specify invitation IDs
Select invitations to delete by role. By default, invitations for all roles will be deleted; you can limit the deletions to invitations of a specific role.
## Display classroom invitations by course
```
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])

View File

@@ -262,6 +262,8 @@ Data fields identified in a `csvkmd` argument.
<FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
<DriveLabelNameEntity> ::=
<DriveLabelNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<DriveLabelPermissionNameEntity> ::=
<DriveLabelPermissionNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<EmailAddressEntity> ::=
<EmailAddressList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
<FilterIDEntity> ::=

View File

@@ -133,7 +133,7 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
## Display Domain Profiles
### Display as an indented list of keys and values.
```
gam info people|domainprofiles <PeopleResourceNameEntity>
gam info domainprofiles|people|peopleprofiles <PeopleResourceNameEntity>
[allfields|(fields <PeopleFieldNameList>)]
[formatjson]
```
@@ -143,7 +143,7 @@ By default, Gam displays the fields `names,emailaddresses`.
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam show people|domainprofiles
gam show domainprofiles|people|peopleprofiles
[query <String>]
[mergesources <PeopleMergeSourceName>]
[allfields|(fields <PeopleFieldNameList>)]
@@ -163,7 +163,7 @@ By default, Gam displays the information as an indented list of keys and values.
### Display as a CSV file.
```
gam print people|domainprofiles [todrive <ToDriveAttribute>*]
gam print domainprofiles|people|peopleprofiles [todrive <ToDriveAttribute>*]
[query <String>]
[mergesources <PeopleMergeSourceName>]
[allfields|(fields <PeopleFieldNameList>)]

View File

@@ -48,10 +48,7 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
## Display File Ownership for Old files
If the above commands fail, you can try to loop through all accounts, however this might take a long time if you are on a large Google Workspace Account.
```
gam config auto_batch_min 1 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select id <DriveFileID> fields id,name,owners.emailaddress norecursion showownedby any
```
Starting with version 6.07.26, this can be made more efficient by terminating processing after the owner is identified.
```
gam config auto_batch_min 1 multiprocessexit rc=0 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select id <DriveFileID> fields id,name,owners.emailaddress norecursion showownedby any
gam config auto_batch_min 1 multiprocessexit rc=0 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select name <DriveFileName> fields id,name,owners.emailaddress norecursion showownedby any
```

View File

@@ -1,4 +1,3 @@
# Update GAMADV-XTD3 to latest version
Automatic update to the latest version on Linux/Mac OS/Google Cloud Shell/Raspberry Pi/ChromeOS:
- Do not create project or authorizations, default path `$HOME/bin`
@@ -11,6 +10,475 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
### 6.72.08
Added option `countsonly` to `gam <UserTypeEntity> print|show notes` that displays
the number of notes a user owns and the number of notes of user can edit.
### 6.72.07
Updated commands that send emails to not downshift `'First Last<firstlast@domain.com>'` to `'first last<firstlast@domain.com>'`.
### 6.72.06
Updated the following commands to properly handle emailaddress lists containing addresses of the form: `'First Last<firstlast@domain.com>'`.
```
gam <UserTypeEntity> sendemail recipient|to <RecipientEntity> [cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
gam create|update user ... notify <EmailAddressList>
```
### 6.72.05
Cleaned up code for all commands that display Chat objects.
### 6.72.04
Added commands to display Chat events.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Chat#display-chat-events
### 6.72.03
Fixed bug in `gam <UserTypeEntity> create chatspace` that caused a trap.
### 6.72.02
Updated `gam delete admin <RoleAssignmentId>` to handle the following error that
occurs when `<RoleAssignmentId>` references a user that has been deleted.
```
ERROR: 404: resourceNotFound - Does not exist
```
### 6.72.01
Improved commands to display drive file comments.
### 6.72.00
Added commands to display drive file comments.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Comments
### 6.71.18
Updated `<CrOSFieldName>` to include `cpuinfo` and `backlightinfo`.
### 6.71.17
Added `depth` column to output of `gam <UserTypeEntity> print diskusage <DriveFileEntity>` that can
be used to filter the depth of the folders displayed. Depth `-1` is the top level folder, depth `0`
are its immediate children, depth `2` are the children of depth `1` and so forth.
```
gam config csv_output_row_filter "depth:count<1" user organizer@domain.com print diskusage teamdriveid <TeamDriveID>
```
### 6.71.16
Updated `gam <UserTypeEntity> create|update sendas <EmailAddress> ... replyto <EmailAddress>`
to allow uppercase letters in `sendas <EmailAddress>` and `replyto <EmailAddress>`.
### 6.71.15
Updated `gam create project` to handle the following error:
```
ERROR: 403: permissionDenied - Authentication error: 7; Error Details: User not allowed to access GCP services.
```
This error occurs when the Google Workspace admin or GCP project manager email address used in the command
is in an OU where Google Cloud Platform is not enabled in Apps/Additional Google services.
### 6.71.14
Added a command to update a Gmail label's settings by specifying it's ID rather than it's name.
```
gam <UserTypeEntity> update labelid <LabelID> [name <String>]
[messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
[backgroundcolor <LabelColorHex>] [textcolor <LabelColorHex>]
```
### 6.71.13
Updated `<UserMultiAttribute>.location.buildingid <String>` to allow non-validated building IDs
by specifying `nv:` at the beginning of `<String>`; e.g., `nv:Building X' sets the building ID to `Building X`.
### 6.71.12
Added option `showmimetype category <MimeTypeNameList>` to `gam <UserTypeEntity> print|show filecounts|filelist|filetree`
```
<MimeTypeName> ::= application|audio|font|image|message|model|multipart|text|video
<MimeTypeNameList> ::= "<MimeTypeName>(,<MimeTypeName>)*"
gam user user@domain.com print filelist fields id,name,mimetype showmimetype prefixes audio,video
```
### 6.71.11
Added option `addcsvdata <FieldName> <String>` to `gam print cros` that adds
additional columns of data to the CSV file output. Typically, you would read CSV file of device IDs/serial numbers
to generate a CSV file of results and copy data from the input CSV to the outout CSV.
### 6.71.10
Reverted change made in 6.71.09 to `gam <UserTypeEntity> print filelist` when `showmimetype` and `filepath|fullpath`
were both specified. The change improved the performance when `showmimetype` selected a small number of files;
the information for just those files was downloaded and then additional API calls were made to construct the file paths.
However, if a large number of files were selected, the additional APIs calls decreased performance.
Added option `mimetypeinquery` can be used when you expect the query to return a small number of files
relative to the total number of files.
### 6.71.09
Improved the performance of `gam <UserTypeEntity> print filelist` when `showmimetype` and `filepath|fullpath`
are both specified.
### 6.71.08
Added option `oneitemperrow` to 'gam print admins|adminroles` to have each of a
roles privileges displayed on a separate row with all of the other admin/role fields.
This produces a CSV file that can be used in subsequent commands without further script processing.
### 6.71.07
Added command to upload changes to Google Docs.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Manage#upload-changes-to-google-documents
### 6.71.06
Added additional error handling to Gmail Client Side Encryption commands.
Added license product Education Endpoint Management
* ProductID - 101049
Added license SKU Endpoint Education Upgrade
* ProductID - 101049
* SKUID - 1010490001 | eeu
### 6.71.05
Fixed a bug introduced in 6.71.00 that caused a trap in `gam <UserTypeEntity> print filelist`.
Added option `tdfrom <EmailAddress>` to `<ToDriveAttribute>` that causes GAM to use `<EmailAddress>` as the from address
in all emails sent. By default, the from address is the Google Workspace Admin in `gam oauth info`.
### 6.71.04
Updated `gam <UserTypeEntity> create|update cseidentity` to accept either of the following key pair options:
* `primarykeypairid <KeyPairID>` - The configuration of a CSE identity that uses the same key pair for signing and encryption.
* `signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>` - The configuration of a CSE identity that uses different key pairs for signing and encryption.
Updated CSV output row sorting to avoid a trap that occurred when a row was missing one of the sort fields.
### 6.71.03
Added option `tdalert <EmailAddress>` to `<ToDriveAttribute>`. When a todrive file is created or updated,
GAM will send notification emails to all `tdalert <EmailAddress>` users if `tdnotify` is true.
`<EmailAddress>` must be valid within your Google Workspace.
### 6.71.02
Added additional error handling to Gmail Client Side Encryption commands.
### 6.71.01
Fixed bug in `gam audit monitor create` that caused a trap.
### 6.71.00
Added `csv_output_sort_headers` string list variable to `gam.cfg` that causes GAM to sort CSV output
rows by the column headers specified in the variable. The column headers are case insensitive and
if column header does not appear in the CSV output, it is ignored.
Added `sortheaders <StringList>` to `redirect csv <FileName>` that has the same effect as above.
The sort keys specified in `redirect csv ... sortheaders <StringList>` take precedence over the values from `gam.cfg`.
Added option `tdsubject <String>` to `<ToDriveAttribute>` that causes GAM to use `<String>` as the subject
in all emails sent. In `<String>`, `#file#` will, be replaced by the file title and `#sheet#` will be replaced
by the sheet/tab title. By default, the subject is the file title.
### 6.70.09
Added additional error handling to Gmail Client Side Encryption commands.
Added options `showpem` and `showkaclsdata` to all Gmail CSE commands that process/display
CSE key pairs. By default, the `pem` and `kaclsdata` fields will not be displayed unless
the corresponding `show` option is specified.
### 6.70.08
Fixed bug in `gam <UserTypeEntity> create cseidentity <KeyPairID>` that caused an error.
### 6.70.07
Updated user instructions in `gam oauth create` and `gam <UserTypeEntity> update serviceaccount`
and changed `s` from selecting all scopes to selecting default scopes.
### 6.70.06
Updated `gam info users <UserTypeEntity>` to not include group tree infornation unless option `grouptree` is specified.
### 6.70.05
Added commands to create|delete|display Drive Label permissions.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Labels
### 6.70.04
Added option `showvalidcolumn` to `gam print users` that can be used to identify whether
users are defined in the domain. Typically, you would read CSV file of email addresses
to verify as domain members.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#verify-domain-membership
Added option `addcsvdata <FieldName> <String>` to `gam print users` that adds
additional columns of data to the CSV file output. Typically, you would read CSV file of email addresses
to generate a CSV file of results and copy data from the input CSV to the outout CSV.
### 6.70.03
Renamed license product DuetAI to Gemini
* ProductID - 101047
Renamed license SKU DuetAI for Google Workspace to Gemini Enterprise
* ProductID - 101047
* SKUID - 1010470001 | geminient | duetai
Added support for license SKU Gemini Business
* ProductID - 101047
* SKUID - 1010470003 | geminibiz
### 6.70.02
In 6.69.00, GAM starting using course owner access when using `copyfrom` in `gam create|update course`
regardless of the value of `gam.cfg/use_course_owner_access`. This prevents copying from courses
with a deleted user. GAM now uses the value of `gam.cfg/use_course_owner_access` when `copyfrom` is used.o
### 6.70.01
Added `gmail_cse_incert_dir` and `gmail_cse_inkey_dir` path variables to `gam.cfg` that provide
default values for the `incertdir <FilePath>` and `inkeydir <FilePath>` options in `gam <UserTypeEntity> create csekeypair`.
### 6.70.00
Added support for Gmail Client Side Encryption.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-CSE
This is an initial, minimally tested release; proceed with care and report all issues.
### 6.69.00
Added `use_course_owner_access` Boolean variable to `gam.cfg` that controls how GAM gets
classroom member information and removes students/teachers. Client/admin access does not provide
complete information about non-domain students/teachers.
* `False` - Use client/admin access; this is the default. Use if you don't have non-domain members in your courses.
* `True` - Use service account access as the classroom owner. An extra API call is required per course to authenticate the owner; this will affect performance
Added the following command which must be used to delete classroom invitations for non-domain students/teachers.
```
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
```
You can obtain the classroom invitation IDs with these commands:
```
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
[role all|owner|student|teacher] [formatjson]
gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
[role all|owner|student|teacher] [formatjson [quotechar <Character>]]
```
### 6.68.08
Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
ACLs with multiple permission details on separate rows for each basic permission/permission detail combination.
This case occurs when a member of a Shared Drive has access to a file and also has explicitly granted access to the same file.
Added `pmtype member|file` to `<PermissionMatch>` that allows determining whether an ACL on a Shared Drive file was
derived from membership or explicitly granted.
### 6.68.07
Updated `gam info user ... locations formatjson` to include the `buildingName` field in the
`locations` entries. If `gam.cfg` contains `quick_info_user = true` or the `quick` option
is included on the command line, add the option `buildingnames` to the command line.
### 6.68.06
Fixed bug in `gam <UserTypeEntity> copy drivefile <DriveFileID> ... mergewithparent` that incorrectly named
the copied file with the name of the parent folder.
Updated `gam <UserTypeEntity> copy|move drivefile` to avoid copying/moving the same file twice.
### 6.68.05
Updated `gam print groups ... ciallfields|(cifields <CIGroupFieldNameList>)` to account for an
API shortcoming that failed to get all of the Cloud Identity fields.
### 6.68.04
Added option `skiprows <Integer>` to `gam csv|loop` that causes GAM to skip processing the first `<Integer>` filtered rows.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Bulk-Processing#csv-files
### 6.68.03
Fixed bug in `gam <UserTypeEntity> create drivefileacl` that caused a trap.
### 6.68.02
Upgraded to Python 3.12.2 where possible.
Added options `restricted|(audience <String>)` to `gam <UserTypeEntity> create|update chatspace` that
sets the access options for the chat space. These options are in Developer Preview and will not be generally available.
### 6.68.01
Fixed `<PermissionMatch>` bug for real.
### 6.68.00
Fixed `<PermissionMatch>` bug introduced in 6.67.35 that caused a command error like the following or would
not properly match `type|nottype <DriveFileACLType>` and `role|notrole <DriveFileACLRole>`.
```
ERROR: permission attribute allowfilediscovery/withlink not allowed with type {'a', 'y', 'e', 'o', 'n'}
```
My sincere apologies.
### 6.67.39
Added option `wait <Integer> <Integer>` to `gam create datatransfer` that causes GAM to wait
for the transfer to complete. The first `<Integer>` must be in the range 5-60 and is the number
of seconds between checks to see if the transfer has completed. The second `<Integer>` is the maximum
number of checks to perform. By default, GAM does not wait for the transfer to complete.
### 6.67.38
Added option `tdnotify [<Boolean>]` to `<ToDriveAttribute>` that causes GAM to send notification
emails to all `tdshare <EmailAddress>` users when the file is uploaded/updated.
### 6.67.37
Fixed bug in `gam <UserTypeEntity> show messages ... showattachments` to avoid a trap when `text/plain` attachments
in character sets other than `UTF-8` are displayed.
### 6.67.36
Updated `gam batch <BatchContent>` and `gam tbatch <BatchContent>` commands to accept lines with the following form:
```
sleep <Integer>
```
Batch processing will suspend for `<Integer>` seconds before the next command line is processed.
### 6.67.35
Added the following options to `<PermissionMatch>` that allow more powerful matching.
```
nottype <DriveFileACLType>
typelist <DriveFileACLTypeList>
nottypelist <DriveFileACLTypeList>
rolelist <DriveFileACLRoleList>
notrolelist <DriveFileACLRoleList>
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Permission-Matches#define-a-match
### 6.67.34
Added option `movetoorgunitdelay <Integer>` to `gam <UserTypeEntity> create shareddrive <Name> ... ou|org|orgunit <OrgUnitItem>`.
GAM creates the Shared Drive, verifies that it has been created and then tries to move it to `<OrgUnitItem>`. Google seems to
require a delay or the following error is generated.
```
ERROR: 409: 409 - The operation was aborted.
```
`movetoorgunitdelay` defaults to 20 seconds which seems to work; `<Integer>` can range from 0 to 60.
### 6.67.33
Upgraded to OpenSSL 3.2.1 where possible.
Fixed bug in `gam <UserTypeEntity> print shareddrives` where `role` was improperly displayed as `fileOrganizer`
rather than `writer`.
Added option `guiroles [<Boolean>]` to `gam <UserTypeEntity> info|print|show shareddrive` that maps
the Drive API role names to the Google Drive GUI role names.
```
API: GUI
commenter: Commenter
fileOrganizer: Content manager
organizer: Manager
reader: Viewer
writer: Contributor
```
### 6.67.32
Updated `<ToDriveAttribute>` to allow multiple `tdshare <EmailAddress> commenter|reader|writer` options.
Fixed bug in `gam <UserTypeEntity> print shareddrives` where `role` was improperly displayed as `unknown`
rather than `reader` when `Allow viewers and commenters to download, print, and copy files` was unchecked for the Shared Drive.
### 6.67.31
Updated `gam <UserTypeEntity> claim|transfer ownership <DriveFileEntity>` to properly
handle the case where `<DriveFileEntity>` referencess a Drive shortcut.
### 6.67.30
Fixed bug where the `fullpath` option in various commands was not converting the generic shared drive name `Drive` to the drive's actual name.
### 6.67.29
Added optional argument `owneraccess` to `gam courses <CourseEntity> remove teachers|students [owneracccess] <UserTypeEntity` and
`gam course <CourseID> remove teacher|student [owneraccess] <EmailAddress>` in order to test a possible API change.
Updated code to avoid a trap when `gam config auto_batch_min 1 csv file.csv gam ...` was entered.
The `config auto_batch_min 1` is not appropriate in this context and will be ignored.
### 6.67.28
Improved handling of `Bad Request` error in `gam <UserTypeEntity> collect orphans`.
### 6.67.27
Updated `gam <UserTypeEntity> collect orphans` to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```
### 6.67.26
Fixed bug in `gam print vaultexports ... formatjson` that caused a trap.
### 6.67.25
Added option `owneraccess` to `gam info courses <CourseEntity>` and `gam info course <CourseID>` in order
to test a possible API change.
### 6.67.24
Fixed bug that caused HTML password notification email messages to be displayed in raw form.
### 6.67.23
Use local copy of `googleapiclient` to remove static discovery documents to improve performance.
### 6.67.22
Added `permissionidlist <PermissionIDList>` to `<PermissionMatch>` that allows matching any permission ID in a list.
Added option `exportlinkeddrivefiles <Boolean>` to `gam create vaultexport` that is used with `corpus mail`.
### 6.67.21
Updated `gam remove aliases <EmailAddress> user|group <EmailAddressEntity>` to give a more informative
error message when the target/alias combination does not exist.
```
Old: User: testsimple@rdschool.org, User Alias: tsalias@rdschool.org, Remove Failed: Invalid Input: resource_id
New: User: testsimple@rdschool.org, User Alias: tsalias@rdschool.org, Remove Failed: Does not exist
```
### 6.67.20
Added option `onelicenseperrow|onelicenceperrow` to `gam print users ... licenses` that causes GAM to print

View File

@@ -15,7 +15,7 @@
<DataTransferService> ::=
calendar|
currents|
datastudio|"google data studio"|
datastudio|lookerstudio|"google data studio"|
drive|gdrive|googledrive|"drive and docs"
<DataTransferServiceList> ::= "<DataTransferService>(,<DataTransferService>)*"
@@ -37,6 +37,7 @@ gam create|add datatransfer|transfer <OldOwnerID> <DataTransferServiceList> <New
[private|shared|all] [privacy_level private|shared|private,shared]
[releaseresources [<Boolean>]]
(<ParameterKey> <ParameterValue>)*
[wait <Integer> <Integer>]
```
For`datastudio` and `drive`, there are options to control the privacy level of the files to be transferred.
* `private` or `privacy_level private` - Transfer files that are not shared with anyone
@@ -54,6 +55,10 @@ As of 2020-06-10, background transfers only transfer future non-private events w
The option `<ParameterKey> <ParameterValue>` is for future expansion.
By default, GAM does not wait for the transfer to complete. The option `wait <Integer> <Integer>` causes GAM to wait
for the transfer to complete. The first `<Integer>` must be in the range 5-60 and is the number
of seconds between checks to see if the transfer has completed. The second `<Integer>` is the maximum number of checks to perform.
## Display transfers
```
gam info datatransfer|transfer <TransferID>

View File

@@ -25,7 +25,7 @@
* https://cloud.google.com/identity/docs/reference/rest/v1/groups
## Name guidelines
* https://support.google.com/a/answer/9193374?hl=en
* https://support.google.com/a/answer/9193374
## Query documentation
* https://developers.google.com/admin-sdk/directory/v1/guides/search-groups

View File

@@ -264,9 +264,6 @@ writes the credentials into the file oauth2.txt.
```
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
@@ -274,7 +271,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[ ] 7) Chrome Version History API
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
@@ -284,7 +281,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[*] 17) Cloud Channel API (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
@@ -314,15 +311,22 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[*] 47) Reseller API
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com
@@ -709,9 +713,6 @@ writes the credentials into the file oauth2.txt.
```
C:\GAMADV-XTD3>gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
@@ -719,7 +720,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[ ] 7) Chrome Version History API
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
@@ -729,7 +730,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[*] 17) Cloud Channel API (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
@@ -759,15 +760,22 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[*] 47) Reseller API
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com

View File

@@ -99,9 +99,6 @@ writes the credentials into the file oauth2.txt.
```
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
@@ -109,7 +106,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[ ] 7) Chrome Version History API
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
@@ -119,7 +116,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[*] 17) Cloud Channel API (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
@@ -149,15 +146,22 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[*] 47) Reseller API
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com
@@ -382,9 +386,6 @@ writes the credentials into the file oauth2.txt.
```
C:\GAMADV-XTD3>gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
@@ -392,7 +393,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[ ] 7) Chrome Version History API
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
@@ -402,7 +403,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[*] 17) Cloud Channel API (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
@@ -432,15 +433,22 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[*] 47) Reseller API
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com

View File

@@ -334,18 +334,15 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAMADV-XTD3 6.67.20 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.72.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.1 64-bit final
Python 3.12.2 64-bit final
MacOS Sonoma 14.2.1 x86_64
Path: /Users/admin/bin/gamadv-xtd3
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain.com
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
@@ -353,7 +350,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[ ] 7) Chrome Version History API
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
@@ -363,7 +360,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[*] 17) Cloud Channel API (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
@@ -393,15 +390,22 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[*] 47) Reseller API
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com
@@ -1002,18 +1006,15 @@ writes the credentials into the file oauth2.txt.
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
C:\GAMADV-XTD3>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAMADV-XTD3 6.67.20 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.72.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.1 64-bit final
Python 3.12.2 64-bit final
Windows-10-10.0.17134 AMD64
Path: C:\GAMADV-XTD3
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain.com
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
C:\GAMADV-XTD3>gam oauth create
Select the authorized scopes by entering a number.
Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 0) Calendar API (supports readonly)
[*] 1) Chrome Browser Cloud Management API (supports readonly)
[*] 2) Chrome Management API - AppDetails read only
@@ -1021,7 +1022,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 4) Chrome Management API - read only
[*] 5) Chrome Policy API (supports readonly)
[*] 6) Chrome Printer Management API (supports readonly)
[ ] 7) Chrome Version History API
[*] 7) Chrome Version History API
[*] 8) Classroom API - Course Announcements (supports readonly)
[*] 9) Classroom API - Course Topics (supports readonly)
[*] 10) Classroom API - Course Work/Materials (supports readonly)
@@ -1031,7 +1032,7 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[*] 14) Classroom API - Profile Photos
[*] 15) Classroom API - Rosters (supports readonly)
[*] 16) Classroom API - Student Guardians (supports readonly)
[*] 17) Cloud Channel API (supports readonly)
[ ] 17) Cloud Channel API (supports readonly)
[*] 18) Cloud Identity - Inbound SSO Settings (supports readonly)
[*] 19) Cloud Identity Groups API (supports readonly)
[*] 20) Cloud Identity OrgUnits API (supports readonly)
@@ -1061,15 +1062,22 @@ Append an 'r' to grant read-only access or an 'a' to grant action-only access.
[ ] 44) Pub / Sub API
[*] 45) Reports API - Audit Reports
[*] 46) Reports API - Usage Reports
[*] 47) Reseller API
[ ] 47) Reseller API
[*] 48) Site Verification API
[ ] 49) Sites API
[*] 50) Vault API (supports readonly)
s) Select all scopes
u) Unselect all scopes
e) Exit without changes
c) Continue to authorization
Select an unselected scope [ ] by entering a number; yields [*]
For scopes that support readonly, enter a number and an 'r' to grant read-only access; yields [R]
For scopes that support action, enter a number and an 'a' to grant action-only access; yields [A]
Clear read-only access [R] or action-only access [A] from a scope by entering a number; yields [*]
Unselect a selected scope [*] by entering a number; yields [ ]
Select all default scopes by entering an 's'; yields [*] for default scopes, [ ] for others
Unselect all scopes by entering a 'u'; yields [ ] for all scopes
Exit without changes/authorization by entering an 'e'
Continue to authorization by entering a 'c'
Note, if all scopes are selected, Google will probably generate an authorization error
Please enter 0-50[a|r] or s|u|e|c: c
Enter your Google Workspace admin email address? admin@domain.com

View File

@@ -24,7 +24,8 @@
| Cloud Identity Free | 101001 |
| Cloud Identity Premium | 101005 |
| Cloud Search | 101035 |
| Duet AI | 101047 |
| Education Endpoint Management | 101049 |
| Gemini | 101047 |
| Google Chrome Device Management | Google-Chrome-Device-Management |
| Google Drive Storage | Google-Drive-storage |
| Google Meet Global Dialing | 101036 |
@@ -46,11 +47,13 @@
| Cloud Identity Free | 1010010001 | cloudidentity |
| Cloud Identity Premium | 1010050001 | cloudidentitypremium |
| Cloud Search | 1010350001 | cloudsearch |
| Duet AI | 1010470001 | duetai |
| Endpoint Education Upgrade | 1010490001 | eeu |
| G Suite Basic | Google-Apps-For-Business | gsuitebasic |
| G Suite Business | Google-Apps-Unlimited | gsuitebusiness |
| G Suite Legacy | Google-Apps | standard |
| G Suite Lite | Google-Apps-Lite | gsuitelite |
| Gemini Business | 1010470003 | geminibiz
| Gemini Enterprise | 1010470001 | geminient | duetai |
| Google Apps Message Security | Google-Apps-For-Postini | postini |
| Google Chrome Device Management | Google-Chrome-Device-Management | cdm |
| Google Drive Storage 16TB | Google-Drive-storage-16TB | 16tb |
@@ -115,6 +118,7 @@
101040 |
101043 |
101047 |
101049 |
Google-Apps |
Google-Chrome-Device-Management |
Google-Drive-storage |
@@ -132,52 +136,58 @@
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
appsheetcore | 1010380001 |
appsheetstandard | appsheetenterprisestandard | 1010380002 |
appsheetplus | appsheetenterpriseplus | 1010380003 |
assuredcontrols | 1010390001 |
bce | beyondcorp | beyondcorpenterprise | 1010400001 |
appsheetcore | 1010380001 | AppSheet Core |
appsheetstandard | appsheetenterprisestandard | 1010380002 | AppSheet Enterprise Standard |
appsheetplus | appsheetenterpriseplus | 1010380003 | AppSheet Enterprise Plus |
assuredcontrols | 1010390001 | Assured Controls |
bce | beyondcorp | beyondcorpenterprise | 1010400001 | Beyond Corp Enterprise |
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
cloudidentity | identity | 1010010001 |
cloudidentitypremium | identitypremium | 1010050001 |
cloudsearch | 1010350001 |
duetai | 1010470001 |
cloudidentity | identity | 1010010001 | Cloud Identity |
cloudidentitypremium | identitypremium | 1010050001 | Cloud Identity Premium |
cloudsearch | 1010350001 | Cloud Search |
eeu | 1010490001 | SKU Endpoint Education Upgrade |
geminibiz | 1010470003 | Gemini Business |
geminient| duetai | 1010470001 | Gemini Enterprise |
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 | Google Workspace Business - Archived User |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 | Google Workspace Enterprise Plus - Archived User |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 | Google Workspace for Education Plus - Legacy |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 | Google Workspace for Education Plus - Legacy (Student) |
gsuitegov | gafg | gsuitegovernment | Google-Apps-For-Government |
gsuitelite | gal | gsl | lite | Google-Apps-Lite |
gwep | workspaceeducationplus | 1010310008 |
gwepstaff | workspaceeducationplusstaff | 1010310009 |
gwepstudent | workspaceeducationplusstudent | 1010310010 |
gwes | workspaceeducationstandard | 1010310005 |
gwesstaff | workspaceeducationstandardstaff | 1010310006 |
gwesstudent | workspaceeducationstandardstudent | 1010310007 |
gwetlu | workspaceeducationupgrade | 1010370001 |
gwlabs | workspacelabs | 1010470002
meetdialing | googlemeetglobaldialing | 1010360001 |
gwep | workspaceeducationplus | 1010310008 | Google Workspace for Education Plus |
gwepstaff | workspaceeducationplusstaff | 1010310009 | Google Workspace for Education Plus (Staff) |
gwepstudent | workspaceeducationplusstudent | 1010310010 | Google Workspace for Education Plus (Extra Student)|
gwes | workspaceeducationstandard | 1010310005 | Google Workspace for Education Standard |
gwesstaff | workspaceeducationstandardstaff | 1010310006 | Google Workspace for Education Standard (Staff) |
gwesstudent | workspaceeducationstandardstudent | 1010310007 | Google Workspace for Education Standard (Extra Student)
gwetlu | workspaceeducationupgrade | 1010370001 | Google Workspace for Education: Teaching and Learning Upgrade |
gwlabs | workspacelabs | 1010470002 | Google Workspace Labs |
meetdialing | googlemeetglobaldialing | 1010360001 | Google Meet Global Dialing |
postini | gams | gsuitegams | gsuitepostini | gsuitemessagesecurity | Google-Apps-For-Postini |
standard | free | Google-Apps |
vault | googlevault | Google-Vault |
vfe | googlevaultformeremployee | Google-Vault-Former-Employee |
voicepremier | gvpremier | googlevoicepremier | 1010330002 |
voicestandard | gvstandard | googlevoicestandard | 1010330004 |
voicestarter | gvstarter | googlevoicestarter | 1010330003 |
wsas | plusstorage | 1010430001 |
wsbizplus | workspacebusinessplus | 1010020025 |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 |
wsbizstan | workspacebusinessstandard | 1010020028 |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 |
wsentess | workspaceenterpriseessentials | 1010060003 |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 |
wsentstan | workspaceenterprisestandard | 1010020026 |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 |
wsentstarter | workspaceenterprisestarter | 1010020029 | wes |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030
voicepremier | gvpremier | googlevoicepremier | 1010330002 | Google Voice Premier
voicestandard | gvstandard | googlevoicestandard | 1010330004 | Google Voice Standard |
voicestarter | gvstarter | googlevoicestarter | 1010330003 | Google Voice Starter |
wsas | plusstorage | 1010430001 | Google Workspace Additional Storage |
wsbizplus | workspacebusinessplus | 1010020025 | Google Workspace Business Plus |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 | Google Workspace Business Plus - Archived User |
wsbizstan | workspacebusinessstandard | 1010020028 | Google Workspace Business Standard }
wsbizstanarchived | workspacebusinessstandardarchived | 1010340006 | Google Workspace Business Standard - Archived User |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 | Google Workspace Business Starter |
wsbizstarterarchived | workspacebusinessstarterarchived | 1010340005 | Google Workspace Business Starter - Archived User |
wsentess | workspaceenterpriseessentials | 1010060003 | Google Workspace Enterprise Essentials |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 | Google Workspace Enterprise Plus |
wsentstan | workspaceenterprisestandard | 1010020026 | Google Workspace Enterprise Standard |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 | Google Workspace Enterprise Standard - Archived User |
wsentstarter | workspaceenterprisestarter | wes | 1010020029 | Workspace Enterprise Starter |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard
<SKUIDList> ::= "<SKUID>(,<SKUID>)*"
```
## Notes

View File

@@ -34,6 +34,7 @@
<DeviceUserList> ::= "<DeviceUserID>(,<DeviceUserID>)*"
<DomainNameList> ::= "<DomainName>(,<DomainName>)*"
<DriveFileACLRoleList> ::= "<DriveFileACLRole>(,<DriveFileACLRole>)*"
<DriveFileACLTypeList> ::= "<DriveFileACLType>(,<DriveFileACLType>)*"
<DriveFileList> ::= "<DriveFileItem>(,<DriveFileItem>)*"
<DriveFilePermissionList> ::= "<DriveFilePermission>(,<DriveFilePermission>)*"
<DriveFilePermissionIDList> ::= "<DriveFilePermissionID>(,<DriveFilePermissionID>)*"
@@ -42,6 +43,7 @@
<DriveFolderNameList> ::= "<DriveFolderName>(,<DriveFolderName>)*"
<DriveLabelIDList> ::= "<DriveLabelID>(,<DriveLabelID>)*"
<DriveLabelNameList> ::= "<DriveLabelName>(,<DriveLabelName>)*"
<DriveLabelPermissionNameList> ::= "<DriveLabelPermissionName>(,<DriveLabelPermissionName>)*"
<DriveLabelFieldIDList> ::= "<DriveLabelFieldID>(,<DriveLabelFieldID>)*"
<DriveLabelSelectionIDList> ::= "<DriveLabelSelectionID>(,<DriveLabelSelectionID>)*"
<EmailAddressList> ::= "<EmailAddress>(,<EmailAddress>)*"
@@ -67,6 +69,7 @@
<MatterStateList> ::= "<MatterState>(,<MatterState>)*"
<MessageIDList> ::= "<MessageID>(,<MessageID>)*"
<MimeTypeList> ::= "<MimeType>(,<MimeType>)*"
<MimeTypeNameList> ::= "<MimeTypeName>(,<MimeTypeName>)*"
<NamespaceList> ::= "<Namespace>(,<Namespace>)*"
<NotesNameList> ::= "<NotesName>(,<NotesName>)*"
<OrgUnitList> ::= "<OrgUnitItem>(,<OrgUnitItem>)*"

View File

@@ -56,6 +56,7 @@ The only `<VariableNames>` recognized in this `<Section>` are:
* `csv_output_row_drop_filter`
* `csv_output_row_drop_filter_mode`
* `csv_output_row_limit`
* `csv_output_sort_headers`
### Select input filter section
Select an input filter section from gam.cfg and process a GAM command using values from that section.
@@ -113,7 +114,7 @@ You can redirect stdout and stderr to null and stderr can be redirected to stdou
<Redirect> ::=
redirect csv <FileName> [multiprocess] [append] [noheader] [charset <Charset>]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[timestampcolumn <String>]
[sortheaders <StringList>] [timestampcolumn <String>]
[todrive <ToDriveAttribute>*] |
redirect stdout <FileName> [multiprocess] [append] |
redirect stdout null [multiprocess] |
@@ -151,6 +152,9 @@ The `quotechar <Character>` subargument sets the character used to quote fields
that contaim special charactere; the default value is the value of `csv_output_quote_char` in `gam.cfg`
which defaults to double quote.
The `sortheaders <StringList>` argument causes GAM to sort CSV output rows by the column headers specified in `<StringList>`.
The column headers are case insensitive and if column header does not appear in the CSV output, it is ignored.
The `timestampcolumn <String>` adds a column named `<String>` to the CSV file; the value is the
timestamp of when the GAM command started.

View File

@@ -13,7 +13,7 @@
- [Synchronize ChromeOS devices with an organizational unit](#synchronize-chromeos-devices-with-an-organizational-unit)
- [Display organizational units](#display-organizational-units)
- [Print organizational units](#print-organizational-units)
- [Display orgamizational unit counts](#display-organizational-unit-counts)
- [Display organizational unit counts](#display-organizational-unit-counts)
- [Display indented organizational unit tree](#display-indented-organizational-unit-tree)
- [Special case handling for large number of organizational units](#special-case-handling-for-large-number-of-organizational-units)
@@ -192,6 +192,7 @@ By default, all users of the org units are displayed:
* `nousers` - Don't display users of the org units
* `notsuspended` - Display non-suspended users of the org units
* `suspended` - Display suspended users of the org units
* `children|child` - Display users in any child org unit
## Print organizational units
This command displays information in CSV format.

View File

@@ -6,6 +6,7 @@ Thank you.
* Gabriel Clifton - https://docs.google.com/document/d/1p32QOBTr89GaG7RfCafSbFuhlUQ9r3qBM_666E0xvQM/edit
* Steve Larsen - https://docs.google.com/spreadsheets/d/1MzzA-u-cmoQcJnQOovCnZcEKMjvOyFhfkdFdf10X_GI/edit
* Iain Macleod - https://docs.google.com/document/d/1QxWAPdhROcx70OXLpSD9Trh3vs-nJKSMiaMZCTwOOTg/edit?pli=1#heading=h.2a2azzpy36k0
* Kevin Melillo - https://github.com/KevinMelilloIEEE/gam-script
* James Seymour - https://sites.google.com/jis.edu.bn/gam-commands/home
* Amado Tejada - https://github.com/amadotejada/GAMpass
@@ -13,3 +14,4 @@ Thank you.
* Goldy Arora - https://www.goldyarora.com/license-notifier/
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Tutorials https://www.youtube.com/watch?v=g9LDeyXQNLI&list=PL_dLiK09pJVhKJxZHNk9CHK0q5hkZ856w
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Course on Udemy https://taming.tech/GAMCourse
* Paul Ogier (Taming.Tech) - https://taming.tech/taming-gam-a-practical-guide-to-gam-and-gamadv-xtd3/

View File

@@ -18,7 +18,10 @@
contributor|editor|writer|
manager|organizer|owner|
reader|viewer
<DriveFileACLRoleList> ::= "<DriveFileACLRole>(,<DriveFileACLRole>)*"
<DriveFileACLType> ::= anyone|domain|group|user
<DriveFileACLTypeList> ::= "<DriveFileACLType>(,<DriveFileACLType>)*"
<EmailAddress> ::= <String>@<DomainName>
<EmailAddressList> ::= "<EmailAddress>(,<EmailAddress>)*"
@@ -31,13 +34,15 @@
<PermissionMatch> ::=
pm|permissionmatch [not]
[type <DriveFileACLType>] [role|notrole <DriveFileACLRole>]
[type|nottype <DriveFileACLType>] [role|notrole <DriveFileACLRole>]
[typelist|nottypelist <DriveFileACLTypeList>] [rolelist|notrolelist <DriveFileACLRoleList>]
[allowfilediscovery|withlink <Boolean>]
[emailaddress <RegularExpression>] [emailaddressList <EmailAddressList>]
[permissionidlist <PermissionIDList>
[name|displayname <String>]
[domain|notdomain <RegularExpression>] [domainlist|notdomainlist <DomainNameList>]
[expirationstart <Time>] [expirationend <Time>]
[deleted <Boolean>] [inherited <Boolean>]
[deleted <Boolean>] [inherited <Boolean>] [pmtype member|file]
em|endmatch
<PermissionMatchMode> ::=
pmm|permissionmatchmode or|and
@@ -71,12 +76,18 @@ In the `print/show drivefileacls` and `create/delete permissions` commands you c
## Define a Match
* `pm|permissionmatch` - Start of permission match definition.
* `not` - Negate the match.
* `type <DriveFileACLType>` - The type of the grantee.
* `role <DriveFileACLRole>` - The role granted by this permission.
* `notrole <DriveFileACLRole>` - The role granted by this permission.
* `type <DriveFileACLType>` - The type of the grantee must match.
* `nottype <DriveFileACLType>` - The type of the grantee must not match.
* `typelist <DriveFileACLTypeList>` - The type of the grantee must match any value in the list.
* `nottypelist <DriveFileACLTypeList>` - The type of the grantee must not match any value in the list.
* `role <DriveFileACLRole>` - The role granted by this permission must match.
* `notrole <DriveFileACLRole>` - The role granted by this permission must not match.
* `rolelist <DriveFileACLRoleList>` - The role granted by this permission must match any value in the list..
* `notrolelist <DriveFileACLRoleList>` - The role granted by this permission must not match any value in the list..
* `allowfilediscovery|withlink <Boolean>` - Whether a link is required or whether the file can be discovered through search.
* `emailaddress <RegularExpression>` - For types user and group, the required email address.
* `emailaddresslist <EmailAddressList>` - For types user and group, a list of required email addresses; any one of which must match.
* `permissionidlist <PermissionIDListList>` - A list of required permission IDs; any one of which must match.
* `name|displayname <RegularExpression>` - For types domain, user and group, the displayable name.
* `domain <RegularExpression>` - For type domain, the required domain name. For types user and group, the required domain name in the email address.
* `notdomain <RegularExpression>` - For type domain, any domain name that doesn't match. For types user and group, any domain name that doesn't match in the email address.
@@ -86,6 +97,7 @@ In the `print/show drivefileacls` and `create/delete permissions` commands you c
* `expirationend <Time>` - For types user and group, will the permission expire before or on <Time>.
* `deleted <Boolean>` - For types user and groups, has the user or group been deleted.
* `inherited <Boolean>` - For Shared Drive files/folders, is the permission inherited
* `pmtype member|file` - For Shared Drive files/folders, is the permission derived from membership or explicitly granted.
* `em|endmatch` - End of permission match definition
## File Selection Examples

View File

@@ -1,6 +1,7 @@
# Reseller
- [API documentation](#api-documentation)
- [Notes](#notes)
- [Manage Multiple Domains](#manage-multiple-domains)
- [Definitions](#definitions)
- [Manage Resold Customers](#manage-resold-customers)
- [Display Resold Customers](#display-resold-customers)
@@ -25,6 +26,11 @@ Prior to version 6.50.00, this is how the `seats <NumberOfSeats> <MaximumNumberO
Now, you can still use the above option which has been corrected or you can specify `seats <Number>` which will be properly passed in the correct form to the API based on plan name.
## Manage Multiple Domains
Thanks to Duncan Isaksen-Loxton for a script to help manage multiple domains.
* See: https://gist.github.com/65/b5e9cee9b5812b487b8ae3e8256e262b
## Definitions
```
<CustomerID> ::= <String>
@@ -53,46 +59,58 @@ Now, you can still use the above option which has been corrected or you can spec
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
assuredcontrols | 1010390001 |
bce | beyondcorp | beyondcorpenterprise | 1010400001 |
appsheetcore | 1010380001 | AppSheet Core |
appsheetstandard | appsheetenterprisestandard | 1010380002 | AppSheet Enterprise Standard |
appsheetplus | appsheetenterpriseplus | 1010380003 | AppSheet Enterprise Plus |
assuredcontrols | 1010390001 | Assured Controls |
bce | beyondcorp | beyondcorpenterprise | 1010400001 | Beyond Corp Enterprise |
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
cloudidentity | identity | 1010010001 |
cloudidentitypremium | identitypremium | 1010050001 |
cloudsearch | 1010350001 |
cloudidentity | identity | 1010010001 | Cloud Identity |
cloudidentitypremium | identitypremium | 1010050001 | Cloud Identity Premium |
cloudsearch | 1010350001 | Cloud Search |
eeu | 1010490001 | SKU Endpoint Education Upgrade |
geminibiz | 1010470003 | Gemini Business |
geminient| duetai | 1010470001 | Gemini Enterprise |
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 | Google Workspace Business - Archived User |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 | Google Workspace Enterprise Plus - Archived User |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 | Google Workspace for Education Plus - Legacy |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 | Google Workspace for Education Plus - Legacy (Student) |
gsuitegov | gafg | gsuitegovernment | Google-Apps-For-Government |
gsuitelite | gal | gsl | lite | Google-Apps-Lite |
gwep | workspaceeducationplus | 1010310008 |
gwepstaff | workspaceeducationplusstaff | 1010310009 |
gwepstudent | workspaceeducationplusstudent | 1010310010 |
gwes | workspaceeducationstandard | 1010310005 |
gwesstaff | workspaceeducationstandardstaff | 1010310006 |
gwesstudent | workspaceeducationstandardstudent | 1010310007 |
gwetlu | workspaceeducationupgrade | 1010370001 |
meetdialing | googlemeetglobaldialing | 1010360001 |
gwep | workspaceeducationplus | 1010310008 | Google Workspace for Education Plus |
gwepstaff | workspaceeducationplusstaff | 1010310009 | Google Workspace for Education Plus (Staff) |
gwepstudent | workspaceeducationplusstudent | 1010310010 | Google Workspace for Education Plus (Extra Student)|
gwes | workspaceeducationstandard | 1010310005 | Google Workspace for Education Standard |
gwesstaff | workspaceeducationstandardstaff | 1010310006 | Google Workspace for Education Standard (Staff) |
gwesstudent | workspaceeducationstandardstudent | 1010310007 | Google Workspace for Education Standard (Extra Student)
gwetlu | workspaceeducationupgrade | 1010370001 | Google Workspace for Education: Teaching and Learning Upgrade |
gwlabs | workspacelabs | 1010470002 | Google Workspace Labs |
meetdialing | googlemeetglobaldialing | 1010360001 | Google Meet Global Dialing |
postini | gams | gsuitegams | gsuitepostini | gsuitemessagesecurity | Google-Apps-For-Postini |
standard | free | Google-Apps |
vault | googlevault | Google-Vault |
vfe | googlevaultformeremployee | Google-Vault-Former-Employee |
voicepremier | gvpremier | googlevoicepremier | 1010330002 |
voicestandard | gvstandard | googlevoicestandard | 1010330004 |
voicestarter | gvstarter | googlevoicestarter | 1010330003 |
wsbizplus | workspacebusinessplus | 1010020025 |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 |
wsbizstan | workspacebusinessstandard | 1010020028 |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 |
wsentess | workspaceenterpriseessentials | 1010060003 |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 |
wsentstan | workspaceenterprisestandard | 1010020026 |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 |
wsentstarter | workspaceenterprisestarter | 1010020029 | wes |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030
voicepremier | gvpremier | googlevoicepremier | 1010330002 | Google Voice Premier
voicestandard | gvstandard | googlevoicestandard | 1010330004 | Google Voice Standard |
voicestarter | gvstarter | googlevoicestarter | 1010330003 | Google Voice Starter |
wsas | plusstorage | 1010430001 | Google Workspace Additional Storage |
wsbizplus | workspacebusinessplus | 1010020025 | Google Workspace Business Plus |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 | Google Workspace Business Plus - Archived User |
wsbizstan | workspacebusinessstandard | 1010020028 | Google Workspace Business Standard }
wsbizstanarchived | workspacebusinessstandardarchived | 1010340006 | Google Workspace Business Standard - Archived User |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 | Google Workspace Business Starter |
wsbizstarterarchived | workspacebusinessstarterarchived | 1010340005 | Google Workspace Business Starter - Archived User |
wsentess | workspaceenterpriseessentials | 1010060003 | Google Workspace Enterprise Essentials |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 | Google Workspace Enterprise Plus |
wsentstan | workspaceenterprisestandard | 1010020026 | Google Workspace Enterprise Standard |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 | Google Workspace Enterprise Standard - Archived User |
wsentstarter | workspaceenterprisestarter | wes | 1010020029 | Workspace Enterprise Starter |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard
```
## Manage Resold Customers
```

View File

@@ -241,7 +241,7 @@ Your HTML message will contain lines like this:
<img src="cid:image2"/>
```
Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg image2`
Your command line will have: `embedimage file1.jpg image1 embedimage file2.jpg image2`
## Send an email from a user sendas
You want to send an email from a user's sendas address.
@@ -312,7 +312,7 @@ Your HTML message will contain lines like this:
<img src="cid:image2"/>
```
Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg image2`
Your command line will have: `embedimage file1.jpg image1 embedimage file2.jpg image2`
### Examples
Send an email to a user's personal address notifying them of their new Google Workspace account;
@@ -376,7 +376,7 @@ Your HTML message will contain lines like this:
<img src="cid:image2"/>
```
Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg image2`
Your command line will have: `embedimage file1.jpg image1 embedimage file2.jpg image2`
## Send an email to users
```
@@ -418,7 +418,7 @@ Your HTML message will contain lines like this:
<img src="cid:image2"/>
```
Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg image2`
Your command line will have: `embedimage file1.jpg image1 embedimage file2.jpg image2`
## Example
Send a message to a user, save the Message-ID so that a later reminder message can be sent

View File

@@ -68,6 +68,10 @@
```
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
<OrgUnitID> ::= id:<String>
<OrgUnitPath> ::= /|(/<String>)+
<OrgUnitItem> ::= <OrgUnitID>|<OrgUnitPath>
<DriveFileACLRole> ::=
manager|organizer|owner|
contentmanager|fileorganizer|

View File

@@ -174,29 +174,33 @@ direct the uploaded file to a particular user and location and add a timestamp t
```
<ToDriveAttribute> ::=
(tdaddsheet [<Boolean>])|
(tdalert <EmailAddress>)*|
(tdbackupsheet (id:<Number>)|<String>)|
(tdcellnumberformat text|number)|
(tdcellwrap clip|overflow|wrap)|
(tdclearfilter [<Boolean>])|
(tdcopysheet (id:<Number>)|<String>)|
(tddescription <String>)|
(tdfileid <DriveFileID>)|
(tdfrom <EmailAddress>)|
(tdlocalcopy [<Boolean>])|
(tdlocale <Locale>)|
(tdnobrowser [<Boolean>])|
(tdnoemail [<Boolean>])|
(tdnoescapechar [<Boolean>])|
(tdnotify [<Boolean>])|
(tdparent (id:<DriveFolderID>)|<DriveFolderName>)|
(tdretaintitle [<Boolean>])|
(tdshare <EmailAddress> commenter|reader|writer)|
(tdshare <EmailAddress> commenter|reader|writer)*|
(tdsheet (id:<Number>)|<String>)|
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>])
(tdsheettitle <String>)|
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number])|
(tdtimestamp [<Boolean>] [tdtimeformat <String>])|
([tddaysoffset <Number>] [tdhoursoffset <Number])|
(tdsubject <String>)|
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
(tdtimestamp [<Boolean>] [tdtimeformat <String>]
([tddaysoffset <Number>] [tdhoursoffset <Number>])|
(tdtimezone <TimeZone>)|
(tdtitle <String>)|
(tdcellwrap clip|overflow|wrap)|
(tdcellnumberformat text|plain)|
(tdupdatesheet [<Boolean>])|
(tduploadnodata [<Boolean>])|
(tduser <EmailAddress>)
@@ -213,7 +217,7 @@ It is uploaded to the root folder of the admin user named in `oauth2.txt`.
## Create new file
If `tdfileid <DriveFileID>` is not specified, a new file is created.
* `tdparent` - An existing/writable parent folder for the uploaded file; if not specified, the `todrive_parent` value from gam.cfg is used; that value defaults to the root folder.
* `tdshare <EmailAddress> commenter|reader|writer` - Share the new file with `<EmailAddress>` with the specified role. `<EmailAddress>` must be valid within your Google Workspace.
* `tdshare <EmailAddress> commenter|reader|writer` - Share the new file with `<EmailAddress>` with the specified role. `<EmailAddress>` must be valid within your Google Workspace. You can specify multiple shares.
## File name, file description and sheet name
* `tdtitle` - The title for the uploaded file, if not specified, the Gam default title is used.
@@ -226,6 +230,7 @@ If `tdfileid <DriveFileID>` is not specified, a new file is created.
* `tdtimeformat` - Format of the timestamp added to the title of the uploaded file; if not specified, the `todrive_timeformat` value from gam.cfg is used, that value defaults to '' which selects an ISO format timestamp.
* See: https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
* `tddaysoffset` and `tdhoursoffset` - Values that subtract time from the timestamp, they default to 0. A possible use for these values is as documentation to reflect the end of the time period that the uploaded report covers.
* `tdsubject <String>` - Use `<String>` as the subject in all emails sent. In `<String>`, `#file#` will, be replaced by the file title and `#sheet#` will be replaced by the sheet/tab title. By default, the subject is the file title.
## Spreadsheet settings
* `tdlocale <Locale>` - The Spreadsheet settings Locale value.
@@ -234,8 +239,10 @@ If `tdfileid <DriveFileID>` is not specified, a new file is created.
* `tdcellnumberformat text|number` - The Spreadsheet number format.
## Open browser and send email
* `tdnobrowser` - If False, a browser is opened to view the file uploaded to Google Drive; if not specified, the `todrive_nobrowser` value from gam.cfg is used.
* `tdnoemail` - If False, an email is sent to `tduser` informing them of name and URL of the uploaded file; if not specified, the `todrive_noemail` value from gam.cfg is used.
* `tdnobrowser` - If False, a browser is opened to view the file uploaded to Google Drive; if not specified, the `todrive_nobrowser` value from gam.cfg is used. If True, no browser is opened.
* `tdnoemail` - If False, an email is sent to `tduser` informing them of name and URL of the uploaded file; if not specified, the `todrive_noemail` value from gam.cfg is used. If True, no email is sent to `tduser`.
* `tdnotify` - If True, an email is sent to all `tdshare <EmailAddress>` and `tdalert <EmailAddress>` users informing them of name and URL of the uploaded/updated file. If False, no emails are sent.
* `tdfrom <EmailAddress>` - Emails will be sent with `<EmailAddress>` as the from address. By default, the from address is the Google Workspace Admin in `gam oauth info`.
## Escape character
* `tdnoescapechar <Boolean>` - Should `\` be ignored as an escape character; if not specified, the value of `todrive_no_escape_char` from `gam.cfg` will be used

View File

@@ -592,6 +592,13 @@ To empty the calendar trash a temporary calendar is created, the deleted events
gam <UserTypeEntity> empty calendartrash <UserCalendarEntity>
```
## Move calendar events to another calendar
Generally you won't move all events from one calendar to another; typically, you'll move events created by the event creator
using `matchfield creatoremail <RegularExpression>` in conjunction with other `<EventSelectProperty>` and `<EventMatchProperty>` options.
```
gam <UserTypeEntity> move events <UserCalendarEntity> [<EventEntity>] destination|to <CalendarItem> [<EventNotificationAttribute>]
```
## Display calendar events
```
gam <UserTypeEntity> info events <UserCalendarEntity> [<EventEntity>] [maxinstances <Number>]
@@ -713,12 +720,14 @@ The attendee changes are displayed but not processed unless `doit` is specified.
## Manage focus time events
You can create and delete focus time events; they can not be updated.
To update a working location event, delete the working location event and recreate it.
To update a focus time event, delete the focus time event and recreate it.
```
gam <UserTypeEntity> create focustime
[chatstatus available|donotdisturb]|
[declinemode none|all|new] [declinemessage <String>]|
(timerange <Time> <Time>)+
[summary <String>]
(timerange <Time> <Time>
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)*
gam <UserTypeEntity> delete focustime
(timerange <Time> <Time>)+
@@ -762,17 +771,20 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
## Manage out of office events
You can create and delete out of office events; they can not be updated.
To update a working location event, delete the working location event and recreate it.
To update an out of office event, delete the out of office event and recreate it.
```
gam <UserTypeEntity> create outofoffice
[declinemode none|all|new] [declinemessage <String>]|
(timerange <Time> <Time>)+
[declinemode none|all|new]
[declinemessage <String>]
[summary <String>]
(timerange <Time> <Time>
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)*
gam <UserTypeEntity> delete outofoffice
(timerange <Time> <Time>)+
```
out of office events span a time range:
Out of office events span a time range:
* `timerange <Time> <Time>` - A time range, may span multiple days
## Display out of office events

View File

@@ -9,11 +9,15 @@
- [Display Chat Members](#display-chat-members)
- [Manage Chat Messages](#manage-chat-messages)
- [Display Chat Messages](#display-chat-messages)
- [Display Chat Events](#display-chat-events)
- [Bulk Operations](#bulk-operations)
## API documentation
* https://developers.google.com/chat/concepts
* https://developers.google.com/chat/reference/rest
* https://developers.google.com/workspace/chat/overview
* https://developers.google.com/workspace/chat/api/reference/rest
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.members/list
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/list
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.spaceEvents/list
* https://support.google.com/chat/answer/7655820
## Introduction
@@ -63,6 +67,7 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
(gdoc <UserGoogleDoc>)|
(gcsdoc <StorageBucketObjectName>))
<ChatEvent> ::= spaces/<String>/spaceEvents/<String>
<ChatMember> ::= spaces/<String>/members/<String>
<ChatMemberList> ::= "<ChatMember>(,<ChatMember>)*"
<ChatMessage> ::= spaces/<String>/messages/<String>
@@ -82,6 +87,7 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
```
gam <UserTypeEntity> create chatspace
[type <ChatSpaceType>]
[restricted|(audience <String>)]
[externalusersallowed <Boolean>]
[members <UserTypeEntity>]
[displayname <String>]
@@ -91,21 +97,21 @@ gam <UserTypeEntity> create chatspace
[formatjson|returnidonly]
```
For `type space`, the following apply:
* `member <UserTypeEntity>` - Optional, can not specify more that 20 users
* `members <UserTypeEntity>` - Optional, can not specify more that 20 users
* `displayname <String>` - Required
* `description <String>` - Optional
* `guidelines <String>` - Optional
* `history <Boolean>` - Optional
For `type groupchat`, the following apply:
* `member <UserTypeEntity>` - Required, must specify between 2 and 20 users
* `members <UserTypeEntity>` - Required, must specify between 2 and 20 users
* `displayname <String>` - Ignored
* `description <String>` - Optional
* `guidelines <String>` - Optional
* `history <Boolean>` - Optional
For `type directmessage`, the following apply:
* `member <UserTypeEntity>` - Required, must specify 1 user
* `members <UserTypeEntity>` - Required, must specify 1 user
* `displayname <String>` - Ignored
* `description <String>` - Ignored
* `guidelines <String>` - Ignored
@@ -117,20 +123,26 @@ By default, Gam displays the information about the created chatspace as an inden
Use the `<ChatContent>` option to send an initial message to the created chatspace.
The `restricted|audience` options are in Developer Preview and will not be generally available.
By default, details about the chatmessage are displayed.
* `returnidonly` - Display the chatmessage name only
### Update a chat space
```
gam <UserTypeEntity> update chatspace <ChatSpace>
[type space]
[displayname <String>]
[description <String>] [guidelines <String>]
[history <Boolean>]
[restricted|(audience <String>)]|
([displayname <String>]
[type space]
[description <String>] [guidelines|rules <String>]
[history <Boolean>])
[formatjson]
```
A groupchat space can be upgraded to a space by specifying `type space` and `displayname <String>`.
The `restricted|audience` options can not be combined with options `displayname,type,description,guidelines,history`.
They are in Developer Preview and will not be generally available.
By default, Gam displays the information about the created chatspace as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
@@ -371,7 +383,6 @@ Display a specific Chat message.
```
gam <UserTypeEntity> info chatmessage name <ChatMessage>
[filter <String>]
[formatjson]
```
By default, Gam displays the information as an indented list of keys and values.
@@ -440,6 +451,69 @@ filter 'createTime > \"2012-04-21T11:30:00+00:00\" AND createTime < \"2013-01-01
filter 'thread.name = spaces/AAAAAAAAAAA/threads/123'
```
## Display Chat Events
Display a specific Chat event.
```
gam <UserTypeEntity> info chatevent name <ChatEvent>
[formatjson]
```
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
### Example
```
gam user user@domain.com info chatevent name spaces/AAAAsUhqjkg/spaceEvents/MTcxMTY4ODM2NDE3OTQzOV81X3VwZGF0ZWQ
```
### Display information about all chat events in a chat space
```
gam <UserTypeEntity> show chatevents <ChatSpace>
filter <String>
[formatjson]
```
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam <UserTypeEntity> print chatevents [todrive <ToDriveAttribute>*] <ChatSpace>
filter <String>
[formatjson [quotechar <Character>]]
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
Use `filter <String>` to filter events by when they occurred and by the type of event.
To filter events by the date they happened, specify the start_time and end_time with a timestamp in RFC-3339 format and double quotation marks.
You must specify at least one event type (event_types) using the has : operator. To filter by multiple event types, use the OR operator.
For a list of supported event types, see: https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.spaceEvents#SpaceEvent.FIELDS.event_type
For example, the following queries are valid on Linux/MacOS:
```
filter 'start_time="2024-03-15T11:30:00-04:00" AND event_types:"google.workspace.chat.message.v1.created"'
filter 'start_time="2024-03-15T11:30:00+00:00" AND end_time="2024-03-3100:00:00+00:00"event_types:"google.workspace.chat.message.v1.created"'
```
For example, the following queries are valid on Windows Command Prompt:
```
filter "start_time=\"2024-03-15T11:30:00-04:00\" AND event_types:\"google.workspace.chat.message.v1.created\""
filter "start_time=\"2024-03-15T11:30:00+00:00\" AND end_time=\"2024-03-3100:00:00+00:00\" AND event_types:\"google.workspace.chat.message.v1.created\""
```
For example, the following queries are valid on Windows PowerShell:
```
filter 'start_time=\"2024-03-15T11:30:00-04:00\" AND event_types:\"google.workspace.chat.message.v1.created\"'
filter 'start_time=\"2024-03-15T11:30:00+00:00\" AND end_time=\"2024-03-3100:00:00+00:00\" AND event_types:\"google.workspace.chat.message.v1.created\"'
```
## Bulk Operations
### Display information about all chat spaces for a collection of users
```

View File

@@ -0,0 +1,157 @@
# Users - Drive - Comments
- [API documentation](#api-documentation)
- [Query documentation](Users-Drive-Query)
- [Definitions](#definitions)
- [Display file comments](#display-file-comments)
## API documentation
* https://developers.google.com/drive/api/v3/reference/comments
## Definitions
* [`<DriveFileEntity>`](Drive-File-Selection)
* [`<UserTypeEntity>`](Collections-of-Users)
```
<DomainName> ::= <String>(.<String>)+
<EmailAddress> ::= <String>@<DomainName>
<UniqueID> ::= id:<String>
<UserItem> ::= <EmailAddress>|<UniqueID>|<String>
<CommentsAuthorSubfieldName> ::=
author.displayname|
author.emailaddress|
author.me|
author.permissionid|
author.photolink
<CommentsRepliesSubfieldName> ::=
reply.action|
reply.author|
reply.author.<CommentsAuthorSubfieldName>|
reply.content|
reply.createddate|createdtime|
reply.deleted|
reply.htmlcontent|
reply.id|
reply.modifieddate|modifiedtime
<CommentsFieldName> ::=
action|
author|
content|
<CommentsAuthorSubfieldName>|
<CommentsRepliesSubfieldName>|
createddate|createdtime|
deleted|
htmlcontent|
id|
modifieddate|modifiedtime|
quotedfilecontent|
reply|replies|
resolved
<CommentsFieldNameList> ::= "<CommentsFieldName>(,<CommentsFieldName>)*"
```
## Display file comments
### Display as an indented list of keys and values.
```
gam <UserTypeEntity> show filecomments <DriveFileEntity>
[showdeleted] [start <Date>|<Time>]
[fields <CommentsFieldNameList>] [showphotolinks]
[countsonly]
[formatjson]
```
By default, all non-deleted comments for a file are displayed; use these options to modify that behavior.
* `showdeleted` - Display deleted comments
* `start <Date>|<Time>` - Display comments modified on or after `<Date>|<Time>`
By default, all comment and reply fields except author photolinks are displayed; use these options to modify that behavior.
* `fields <CommentsFieldNameList>` - Select fields to display
* `showphotolinks` - Display author photolinks
* `countsonly` - Display just the number of comments and replies; no fields
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
### Display as a CSV file.
Each comment/reply pair is output on a separate CSV file row.
```
gam <UserTypeEntity> print filecomments <DriveFileEntity> [todrive <ToDriveAttribute>*]
[showdeleted] [start <Date>|<Time>] [countsonly]
[fields <CommentsFieldNameList>] [showphotolinks]
(addcsvdata <FieldName> <String>)*
[formatjson [quotechar <Character>]]
```
By default, all non-deleted comments for a file are displayed; use these options to modify that behavior.
Files with no comments will not be displayed.
* `showdeleted` - Display deleted comments
* `start <Date>|<Time>` - Display comments modified on or after `<Date>|<Time>`
By default, all comment and reply fields except author photolinks are displayed; use these options to modify that behavior.
* `fields <CommentsFieldNameList>` - Select fields to display
* `showphotolinks` - Display author photolinks
* `countsonly` - Display just the number of comments and replies; no fields. Files with no comments will display zero counts.
Add additional columns of data from the command line to the output:
* `addcsvdata <FieldName> <String>`
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
### Example
```
# Get files that may have comments
$ gam redirect csv ./CheckForComments.csv user testsimple@domain.com print filelist showmimetype gdoc,gpresentation,gsheet fields id,name,mimetype
Getting all Drive Files/Folders that match query ('me' in owners and (mimeType = 'application/vnd.google-apps.presentation' or mimeType = 'application/vnd.google-apps.spreadsheet' or mimeType = 'application/vnd.google-apps.document')) for testsimple@domain.com
Got 131 Drive Files/Folders that matched query ('me' in owners and (mimeType = 'application/vnd.google-apps.presentation' or mimeType = 'application/vnd.google-apps.spreadsheet' or mimeType = 'application/vnd.google-apps.document')) for testsimple@domain.com...
# Display file comments
$ gam redirect csv ./FilesWithComments.csv multiprocess csv CheckForComments.csv gam user "~Owner" print filecomments "~id" addcsvdata fileName "~name" addcsvdata mimeType "~mimeType" fields author.displayName,author.me,content,createdTime,deleted,modifiedTime,resolved,reply.author.displayName,reply.author.me,reply.content,reply.createdTime,reply.deleted,reply.modifiedTime
2024-03-24T08:04:46.235-07:00,0/131,Using 10 processes...
2024-03-24T08:04:58.122-07:00,0,Processing item 100/131
2024-03-24T08:05:01.345-07:00,0,Processing item 131/131
2024-03-24T08:07:11.731-07:00,0/131,Processing complete
$ more FilesWithCommnts.csv
User,fileId,fileName,mimeType,commentId,replyId,author.displayName,author.me,content,createdTime,deleted,modifiedTime,resolved,reply.author.displayName,reply.author.me,reply.content,reply.createdTime,reply.deleted,reply.modifiedTime
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwm0,,Test-Simple,True,XXX Comment,2024-03-14T11:34:39-07:00,False,2024-03-14T11:34:39-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwkw,,Test-Simple,True,Grack Comment,2024-03-14T11:26:30-07:00,False,2024-03-14T11:26:30-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwkY,,Test-Simple,True,Again commnt,2024-03-14T11:24:13-07:00,False,2024-03-14T11:24:13-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwkQ,,Test-Simple,True,More Comment,2024-03-14T11:23:48-07:00,False,2024-03-14T11:23:48-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwkA,,Test-Simple,True,Comment 8,2024-03-14T11:23:14-07:00,False,2024-03-14T11:34:01-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwj4,,Test-Simple,True,Comment 7,2024-03-14T11:23:05-07:00,False,2024-03-14T11:23:05-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwj0,,Test-Simple,True,Comment 6,2024-03-14T11:22:55-07:00,False,2024-03-14T11:22:55-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwjs,,Test-Simple,True,Comment 5,2024-03-14T11:22:38-07:00,False,2024-03-14T11:22:38-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedwjo,,Test-Simple,True,Comment 4,2024-03-14T11:22:19-07:00,False,2024-03-14T11:22:19-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedtKQ,,Test-Simple,True,End Comment,2024-03-14T10:32:16-07:00,False,2024-03-14T10:32:16-07:00,False,,,,,,
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedtKI,AAABJFedwik,Test-Simple,True,My first comment,2024-03-14T10:32:03-07:00,False,2024-03-14T11:15:05-07:00,False,Test-Simple,True,My first reply,2024-03-14T11:14:13-07:00,False,2024-03-14T11:14:13-07:00
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,AAABJFedtKI,AAABJFedwiw,Test-Simple,True,My first comment,2024-03-14T10:32:03-07:00,False,2024-03-14T11:15:05-07:00,False,Test-Simple,True,Yet another reply,2024-03-14T11:15:05-07:00,False,2024-03-14T11:15:05-07:00
testsimple@domain.com,yyy,TS Sheet,application/vnd.google-apps.spreadsheet,AAABJM6zbc0,,Test-Simple,True,Sheet Comment,2024-03-14T20:43:18-07:00,False,2024-03-14T20:43:18-07:00,False,,,,,,
testsimple@domain.com,zzz,TS Pres,application/vnd.google-apps.presentation,AAABJLy5DpA,,Test-Simple,True,Presentation Comment,2024-03-14T20:42:48-07:00,False,2024-03-14T20:42:48-07:00,False,,,,,,
$ gam redirect csv ./FilesWithComments.csv multiprocess csv CheckForComments.csv gam user "~Owner" print filecomments "~id" addcsvdata fileName "~name" addcsvdata mimeType "~mimeType" fields author.displayName,author.me,content,createdTime,deleted,modifiedTime,resolved,reply.author.displayName,reply.author.me,reply.content,reply.createdTime,reply.deleted,,reply.modifiedTime
2024-03-24T08:04:46.235-07:00,0/131,Using 10 processes...
2024-03-24T08:04:58.122-07:00,0,Processing item 100/131
2024-03-24T08:05:01.345-07:00,0,Processing item 131/131
2024-03-24T08:07:11.731-07:00,0/131,Processing complete
# Display file comment counts
$ gam redirect csv ./FileCommentCounts.csv multiprocess csv CheckForComments.csv gam user "~Owner" print filecomments "~id" addcsvdata fileName "~name" addcsvdata mimeType "~mimeType" countsonly
2024-03-24T07:51:16.881-07:00,0/131,Using 10 processes...
2024-03-24T07:51:28.909-07:00,0,Processing item 100/131
2024-03-24T07:51:32.241-07:00,0,Processing item 131/131
2024-03-24T07:51:37.404-07:00,0/131,Processing complete
$ more FileCommentCounts.csv
User,fileId,fileName,mimeType,comments,replies
...
testsimple@domain.com,yyy,TS Sheet,application/vnd.google-apps.spreadsheet,1,0
testsimple@domain.com,aaa,ViewTest,application/vnd.google-apps.document,0,0
testsimple@domain.com,xxx,TS Doc,application/vnd.google-apps.document,11,2
testsimple@domain.com,zzz,TS Pres,application/vnd.google-apps.presentation,1,0
...
```

View File

@@ -71,6 +71,7 @@
g3pshortcut|
gsite
<MimeTypeName> ::= application|audio|font|image|message|model|multipart|text|video
<MimeTypeNameList> ::= "<MimeTypeName>(,<MimeTypeName>)*"
<MimeType> ::= <MimeTypeShortcut>|(<MimeTypeName>/<String>)
<MimeTypeList> ::= "<MimeType>(,<MimeType>)*"
```
@@ -267,9 +268,10 @@
<DriveOwnersSubfieldName>|
parents|
<DriveParentsSubfieldName>|
permissionids|
permissiondetails|
permissions|
<DrivePermissionsSubfieldName>|
permissionids|
properties|
quotabytesused|quotaused|
resourcekey|
@@ -572,7 +574,7 @@ The `querytime<String> <Time>` value replaces the string `#querytime<String>#` i
The characters following `querytime` can be any combination of lowercase letters and numbers. This is most useful in scripts
where you can specify a relative date without having to change the script.
For example, query for files last modified me than 5 years ago:
For example, query for files last modified more than 5 years ago:
```
querytime5years -5y query "modifiedTime<'#querytime5years#'"
```
@@ -610,9 +612,11 @@ By default, all types of files and folders are selected. You can specify a list
This option updates the current query.
```
showmimetype [not] <MimeTypeList>
showmimetype category <MimeTypeNameList>
```
* `showmimetype <MimeTypeList>` - Select files and folders with the specified MIME types
* `showmimetype not <MimeTypeList>` - Select files and folders with MIME types other than those specified
* `showmimetype category <MimeTypeNameList>` - Select files and folders with the specified MIME type categories
## File selection by file size
These options would typically be used with `showmimetype` to select files of a particular type. This
@@ -648,7 +652,7 @@ gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
[corpora <CorporaAttribute>]
[select <SharedDriveEntity>]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -661,7 +665,7 @@ gam <UserTypeEntity> show filecounts
[corpora <CorporaAttribute>]
[select <SharedDriveEntity>]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -893,7 +897,7 @@ gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
[select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
[depth <Number>]]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -905,7 +909,7 @@ gam <UserTypeEntity> show filetree
[select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
[depth <Number>]]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -998,14 +1002,14 @@ gam <UserTypeEntity> print|show filelist [todrive <ToDriveAttribute>*]
[select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
[(norecursion [<Boolean>])|(depth <Number>)] [showparent]]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>] [mimetypeinquery [<Boolean>]]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] [pmfilter] [oneitemperrow]
[excludetrashed]
[maxfiles <Integer>] [nodataheaders <String>]
[countsonly [summary none|only|plus] [summaryuser <String>]
[showsource] [showsize] [showmimetypesize]] [countsrowfilter]
[showsource] [showsize] [showmimetypesize]] [countsrowfilter]
[filepath|fullpath [pathdelimiter <Character>] [addpathstojson] [showdepth]] [buildtree]
[allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)]
[showdrivename] [showshareddrivepermissions]
@@ -1538,6 +1542,10 @@ For each folder in `<DriveFileEntity>`, the following items are displayed:
* `totalFileCount` - The number of files directly in the folder and all of its subfolders
* `totalFileSize` - The sum of the sizes of the files directly in the folder and all of its subfolders
* `totalFolderCount` - The number of folders directly in the folder and all of its subfolders
* `depth` - The depth of the folder
* `-1` - The top level folder
* `0` - Immediate children of the top level folder
* `1` - Immediate children of level 0 folders
* `path` - The path of the folder
There is a final row detailing files and folders in the trash; it is omitted if `excludetrashed` or `show summary` are specified.
@@ -1554,8 +1562,13 @@ There is a final row detailing files and folders in the trash; it is omitted if
* `totalFileCount` - The number of files in the trash
* `totalFileSize` - The sum of the sizes of the files in the trash
* `totalFolderCount` - The number of folders in the trash
* `depth` - Always -1
* `path` - Trash
GAM version `6.71.17` added the `depth` column that can be used to filter the depth of the folders displayed.
Depth `-1` is the top level folder, depth `0` are its immediate children, depth `2` are the children of depth `1` and so forth.
For example to limit the display to the top folder and its immediate children, use `config csv_output_row_filter depth:count<1`.
By default, files owned by the user are counted. These options update the current query with the desired ownership.
* `showownedby me` - Count files owned by the user; this is the default
* `showownedby any` or `anyowner` - Count files accessible by the user
@@ -1585,24 +1598,37 @@ Use the `show` option to control the display of data:
$ gam redirect csv ./MyDriveUsage.csv user testsimple@domain.com print diskusage mydrive
User: testsimple@domain.com, Print 1 Drive Disk Usage
$ more MyDriveUsage.csv
User,Owner,id,name,ownedByMe,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,path
testsimple@domain.com,testsimple@domain.com,012YenC8f12ALUk9PVA,My Drive,,False,False,100,138212,24,167,189598,79,My Drive
testsimple@domain.com,testsimple@domain.com,456YenC8f12ALfndaQ1NHc0RtUG92Y1BIUUl4bjVBRmNkWG5oakNqVVFDcXJWOHNmdFlwZmc,Classroom,True,False,False,0,0,15,9,6840,17,My Drive/Classroom
User,Owner,id,name,ownedByMe,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,depth,path
testsimple@domain.com,testsimple@domain.com,012YenC8f12ALUk9PVA,My Drive,,False,False,100,138212,24,167,189598,79,-1,My Drive
testsimple@domain.com,testsimple@domain.com,456YenC8f12ALfndaQ1NHc0RtUG92Y1BIUUl4bjVBRmNkWG5oakNqVVFDcXJWOHNmdFlwZmc,Classroom,True,False,False,0,0,15,9,6840,17,0,My Drive/Classroom
testsimple@domain.com,testsimple@domain.com,0B3YenC8f12ALfmRuX3I4WFlqaTRnMGhXNkVvWV9UUG1zRDQwY1BwVkJhUGx5WHVIcjJKZUU,TestUpdate,True,False,False,2,3420,0,2,3420,0,1,My Drive/Classroom/TestUpdate
testsimple@domain.com,testsimple@domain.com,1MT5xJ897oYa0Q2OuzBDfLHvig6k_b0EKaovVA2imGYcnrmqZu5hjlJkEPMH-rHKj4qDyy9_j,TS Course,True,False,False,0,0,0,0,0,0,1,My Drive/Classroom/TS Course
testsimple@domain.com,testsimple@domain.com,1gsbqsbhhwBx9hCF0sqtE213tpUn6Ebj2klLFhHb4xkzBKIdEFkvvwCVtZpYWPgOA796fIPEN,TS Course 2,True,False,False,0,0,0,0,0,0,1,My Drive/Classroom/TS Course 2
...
testsimple@domain.com,testsimple@domain.com,1bHS_Tp77W3KSGRNSs_jP1RhAJhIGRCaI,XferFolder,True,False,False,1,1024,0,1,1024,0,My Drive/XferFolder
testsimple@domain.com,testsimple@domain.com,Trash,Trash,,True,True,0,0,1,3,3072,9,Trash
testsimple@domain.com,testsimple@domain.com,1bHS_Tp77W3KSGRNSs_jP1RhAJhIGRCaI,XferFolder,True,False,False,1,1024,0,1,1024,0,0,My Drive/XferFolder
testsimple@domain.com,testsimple@domain.com,Trash,Trash,,True,True,0,0,1,3,3072,9,-1,Trash
$ gam config csv_output_row_filter "depth:count<1" redirect csv ./MyDriveUsage.csv user testsimple@domain.com print diskusage mydrive
User: testsimple@domain.com, Print 1 Drive Disk Usage
$ more MyDriveUsage.csv
User,Owner,id,name,ownedByMe,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,depth,path
testsimple@domain.com,testsimple@domain.com,012YenC8f12ALUk9PVA,My Drive,,False,False,100,138212,24,167,189598,79,-1,My Drive
testsimple@domain.com,testsimple@domain.com,456YenC8f12ALfndaQ1NHc0RtUG92Y1BIUUl4bjVBRmNkWG5oakNqVVFDcXJWOHNmdFlwZmc,Classroom,True,False,False,0,0,15,9,6840,17,0,My Drive/Classroom
...
testsimple@domain.com,testsimple@domain.com,1bHS_Tp77W3KSGRNSs_jP1RhAJhIGRCaI,XferFolder,True,False,False,1,1024,0,1,1024,0,0,My Drive/XferFolder
testsimple@domain.com,testsimple@domain.com,Trash,Trash,,True,True,0,0,1,3,3072,9,-1,Trash
$ gam redirect csv ./MyDriveUsage.csv user testsimple@domain.com print diskusage mydrive show summaryandtrash
User: testsimple@domain.com, Print 1 Drive Disk Usage
$ more MyDriveUsage.csv
User,Owner,id,name,ownedByMe,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,path
testsimple@domain.com,testsimple@domain.com,012YenC8f12ALUk9PVA,My Drive,,False,False,100,138212,24,167,189598,79,My Drive
testsimple@domain.com,testsimple@domain.com,Trash,Trash,,True,True,0,0,1,3,3072,9,Trash
User,Owner,id,name,ownedByMe,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,depth,path
testsimple@domain.com,testsimple@domain.com,012YenC8f12ALUk9PVA,My Drive,,False,False,100,138212,24,167,189598,79,-1,My Drive
testsimple@domain.com,testsimple@domain.com,Trash,Trash,,True,True,0,0,1,3,3072,9,-1,Trash
$ gam redirect csv ./MyDriveUsage.csv user testsimple@domain.com print diskusage shareddriveid 0AL5LiIe4dqxZUk9PVA show summaryandtrash
User: testsimple@domain.com, Print 1 Drive Disk Usage
$ more MyDriveUsage.csv
User,id,name,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,path
testsimple@domain.com,0125LiIe4dqxZUk9PVA,TS Shared Drive 1,False,False,16,6144,7,42,73799,25,SharedDrives/TS Shared Drive 1
testsimple@domain.com,Trash,Trash,True,True,1,1024,0,1,1024,0,Trash
User,id,name,trashed,explicitlyTrashed,directFileCount,directFileSize,directFolderCount,totalFileCount,totalFileSize,totalFolderCount,depth,path
testsimple@domain.com,0125LiIe4dqxZUk9PVA,TS Shared Drive 1,False,False,16,6144,7,42,73799,25,-1,SharedDrives/TS Shared Drive 1
testsimple@domain.com,Trash,Trash,True,True,1,1024,0,1,1024,0,-1,Trash
```

View File

@@ -19,6 +19,7 @@
- [Shortcuts](Users-Drive-Shortcuts)
- [Drive Labels](Users-Drive-Labels)
- [Download Google Documents as JSON](#download-google-documents-as-json)
- [Upload changes to Google Documents](#upload-changes-to-google-documents)
## API documentation
* https://developers.google.com/drive/api/v3/reference/files
@@ -642,8 +643,6 @@ gam <UserTypeEntity> delete|del drivefile <DriveFileEntity> purge
```
## Download Google Documents as JSON
This command was added in version 5.31.04, you'll have to do `gam update project` and
`gam <UserTypeEntity> check|update serviceaccount` to enable it.
```
gam <UserTypeEntity> get document <DriveFileEntity>
[viewmode default|suggestions_inline|preview_suggestions_accepted|preview_without_suggestions]
@@ -666,3 +665,31 @@ By default, when getting a document, an existing local file will not be overwrit
* `overwrite` - 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
## Upload changes to Google Documents
```
<DocumentJSONUpdateRequest> ::=
'{"requests": [{object (Request)}], "writeControl": {object (WriteControl) }`
See: https://developers.google.com/docs/api/reference/rest/v1/documents/request
gam <UserTypeEntity> update document <DriveFileEntity>
((json [charset <Charset>] <DocumentJSONUpdateRequest>) |
(json file <FileName> [charset <Charset>]))
[formatjson]
```
The JSON data can be read from a command line argument or a file. On the command line, the
JSON data is enclosed in single quotes; these should not be present when the JSON data is read from a file.
The output is formatted for human readability. Use the following option to produce JSON output for program parsing.
* `formatjson` - Display output in JSON format.
### Examples
Replace Foo with Goo in a document.
```
File Update.json contains:
{ "requests": [{"replaceAllText": {"replaceText": "Goo", "containsText": {"text": "Foo", "matchCase": "True"}}}]}
gam user testuser@domain.com update document <DriveFileItem> json file Update.json
```

View File

@@ -6,12 +6,15 @@
- [Introduction](#introduction)
- [Display Drive Labels](#display-drive-labels)
- [Process File Drive Labels](#process-file-drive-labels)
- [Manage Drive Label Permissions](#manage-drive-label-permissions)
- [Display Drive Label Permissions](#display-drive-label-permissions)
## API documentation
* https://support.google.com/a/answer/9292382
* https://developers.google.com/drive/labels/guides/overview
* https://developers.google.com/drive/labels/guides/authorize
* https://developers.google.com/drive/labels/reference/rest/v2beta/labels
* https://developers.google.com/drive/labels/reference/rest/v2beta/labels.permissions
* https://developers.google.com/drive/api/guides/about-labels
* https://developers.google.com/drive/api/v3/reference/files
@@ -19,13 +22,15 @@
To use these commands you must add the 'Drive Labels API' to your project and update your service account authorization.
```
gam update project
gam user user@domain.com check serviceaccount
gam user user@domain.com update serviceaccount
```
Supported editions for this feature: Business Standard and Business Plus; Enterprise; Education Standard and Education Plus; G Suite Business; Essentials.
## Definitions
* [`<DriveFileEntity>`](Drive-File-Selection)
* [`<UserTypeEntity>`](Collections-of-Users)
* [`<DriveLabelNameEntity>`, `<DriveLabelPermissionNameEntity'](Collections-of-Items)
* [`<UserTypeEntity>`](Collections-of-Items)
```
<DriveLabelID> ::= <String>
@@ -35,7 +40,11 @@ Supported editions for this feature: Business Standard and Business Plus; Enterp
<DriveLabelNameList> ::= "<DriveLabelName>(,<DriveLabelName)*"
<DriveLabelNameEntity> ::=
<DriveLabelNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-Items
<DriveLabelPermissionName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]/permissions/(audiences|groups|people)/<String>
<DriveLabelPermissionNameList> ::= "<DriveLabelPermissionName>(,<DriveLabelPermissionName>)*"
<DriveLabelPermissionNameEntity> ::=
<DriveLabelPermissionNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<DriveLabelFieldID> ::= <String>
<DriveLabelSelectionID> ::= <String>
@@ -86,9 +95,9 @@ A domain administrator with the Drive and Docs administrator privilege can searc
owned by their organization, regardless of the admin's membership in any given Shared Drive.
Three forms of the commands are available:
* `gam action ...` - The administrator named in oauth2.txt is used, domain administrator access implied and labels of type `SHARED` and `ADMIN`can be written
* `gam <UserTypeEntity> action ... adminaccess` - The user named in `<UserTypeEntty>` is used, adminaccess indicates that labels of type `SHARED` and `ADMIN`can be written
* `gam <UserTypeEntity> action ...` - The user named in `<UserTypeEntty>` is used, access is limited, onlylabels of type `SHARED` can be written
* `gam action ...` - The administrator named in oauth2.txt is used, domain administrator access implied and labels of type `SHARED` and `ADMIN`can be processed
* `gam <UserTypeEntity> action ... adminaccess` - The user named in `<UserTypeEntty>` is used, adminaccess indicates that labels of type `SHARED` and `ADMIN`can be processed
* `gam <UserTypeEntity> action ...` - The user named in `<UserTypeEntty>` is used, access is limited, onlylabels of type `SHARED` can be processed
## Display Drive Labels
@@ -156,3 +165,51 @@ gam <UserTypeEntity> process filedrivelabels <DriveFileEntity>
By default, details of the process labels are displayed, use `nodetails` to suppress this display.
## Manage Drive Label Permissions
Create a permission for a Drive Label by specifying the label name and the principal.
```
gam [<UserTypeEntity>] create drivelabelpermission <DriveLabelNameEntity>
(user <UserItem>) | (group <GroupItem) | (audience <String>)
role applier|editor|organizer|reader
[nodetails|formatjson] [adminaccess|asadmin]
```
By default, when a permission is created, GAM outputs details of the permission as indented keywords and values.
* `nodetails` - Suppress the details output.
* `formatjson` - Output the details in JSON format.
Delete a Drive Label permission by specifying the label name and the principal.
```
gam [<UserTypeEntity>] delete drivelabelpermission <DriveLabelNameEntity>
(user <UserItem>) | (group <GroupItem) | (audience <String>)
[adminaccess|asadmin]
```
Delete a Drive Label permission by specifying the label permission name.
```
gam [<UserTypeEntity>] remove drivelabelpermission <DriveLabelPermissionNameEntity>
[adminaccess|asadmin]
```
## Display Drive Label Permissions
Display permissions for a collection of Drive Label permission names.
```
gam [<UserTypeEntity>] show drivelabelpermissions <DriveLabelNameEntity>
[formatjson] [adminaccess|asadmin]
```
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam [<UserTypeEntity>] print drivelabelpermissions <DriveLabelNameEntity> [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]] [adminaccess|asadmin]
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.

View File

@@ -8,6 +8,7 @@
- [Display file permissions/sharing](#display-file-permissionssharing)
- [Delete all ACLs except owner from a file](#delete-all-acls-except-owner-from-a-file)
- [Change shares to User1 to shares to User2](#change-shares-to-user1-to-shares-to-user2)
- [Map All ACLs from an old domain to a new domain](#map-all-acls-from-an-old-domain-to-a-new-domain)
## API documentation
* https://developers.google.com/drive/api/v3/reference/permissions
@@ -316,4 +317,26 @@ gam redirect csv ./FilesSharedWithU1Settings.csv multiprocess csv FilesSharedWit
gam redirect stdout ./DeleteU1Sharing.txt multiprocess redirect stderr stdout csv FilesSharedWithU1Settings.csv gam user "~Owner" delete drivefileacl "~id" "~permissions.0.emailAddress"
# For each of these files, add the share to User2 with the same role that User1 had
gam redirect stdout ./AddUser2Sharing.txt multiprocess redirect stderr stdout csv FilesSharedWithU1Settings.csv gam user "~Owner" create drivefileacl "~id" user user2@domain.com role "~permissions.0.role"
```
```
## Map All ACLs from an old domain to a new domain
* Get ACLs
```
gam redirect csv ./allUsersFiles.csv multiprocess all users print filelist fields name,id,basicpermissions oneitemperrow pmfilter pm domain olddomain.com em
```
* Delete ACLs with olddomain.com
```
gam redirect stdout ./DeleteOldDomainACLs.txt multiprocess redirect stderr stdout csv ./allUsersFiles.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
```
* Add user/group ACLs replacing olddomain.com with newdomain.com
```
gam config csv_input_row_filter "permission.type:regex:user|group" redirect stdout ./AddNewDomainACLsUserGroupShares.txt multiprocess redirect stderr stdout csv ./allUsersFiles.csv gam user "~Owner" create drivefileacl "~id" "~permission.type" "~permission.emailAddress" role "~permission.role" mappermissionsdomain olddomain.com newdomain.com
```
* Add domain ACLs replacing olddomain.com with newdomain.com
```
gam config csv_input_row_filter "permission.type:regex:domain" redirect stdout ./AddNewDomainACLsDomainShares.txt multiprocess redirect stderr stdout csv ./allUsersFiles.csv gam user "~Owner" create drivefileacl "~id" "~permission.type" "~permission.domain" role "~permission.role" allowfilediscovery "~permission.allowFileDiscovery" mappermissionsdomain olddomain.com newdomain.com
```

217
docs/Users-Gmail-CSE.md Normal file
View File

@@ -0,0 +1,217 @@
# Users - Gmail - Client Side Encryption
- [API documentation](#api-documentation)
- [Notes](#notes)
- [Definitions](#definitions)
- [Create Gmail CSE Identity](#create-gmail-cse-identity)
- [Update Gmail CSE Identity](#update-gmail-cse-identity)
- [Delete Gmail CSE Identity](#delete-gmail-cse-identity)
- [Display Gmail CSE Identities](#display-gmail-cse-identities)
- [Create Gmail CSE Key Pair](#create-gmail-cse-key-pair)
- [Action Gmail CSE Key Pairs](#action-gmail-cse-key-pairs)
- [Display Gmail CSE Key Pairs](#display-gmail-cse-key-pairs)
## API documentation
* https://developers.google.com/gmail/api/reference/rest/v1/users.settings.cse.identities
* https://developers.google.com/gmail/api/reference/rest/v1/users.settings.cse.keypairs
## Notes
This is an initial, minimally tested release; proceed with care and report all issues.
Setting up Client Side Encryption is not for the faint of heart; here is a start.
* https://support.google.com/a/answer/10741897?hl=en&ref_topic=10742486&sjid=10342493441460488213-NA
Do I personally understand what's going on here? No, I just added the API calls to GAM.
Two sets of files are required for Gmail CSE, these two variables in `gam.cfg` control where GAM looks for these files.
You must edit `gam.cfg` to set the paths you currently use.
```
gmail_cse_incert_dir
Directory for the S/MIME certificate files used by Gmail Client Side Encryption.
Default: Blank
gmail_cse_inkey_dir
Directory for the Key Access Control List (KACL) wrapped private key data files used by Gmail Client Side Encryption.
Default: Blank
```
## Definitions
* [`<UserTypeEntity>`](Collections-of-Users)
```
<DomainName> ::= <String>(.<String>)+
<EmailAddress> ::= <String>@<DomainName>
<FilePath> ::= <String>
<Password> ::= <String>
<KeyPairID> ::= <String>
```
## Create Gmail CSE Identity
Creates and configures a client-side encryption identity that's authorized to send mail from the user account.
Google publishes the S/MIME certificate to a shared domain-wide directory so that people within a Google Workspace organization can encrypt and send mail to the identity.
```
gam <UserTypeEntity> create cseidentity
(primarykeypairid <KeyPairID>) | (signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>)
[kpemail <EmailAddress>]
[formatjson]
```
One of the following is required:
* `primarykeypairid <KeyPairID>` - The configuration of a CSE identity that uses the same key pair for signing and encryption.
* `signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>` - The configuration of a CSE identity that uses different key pairs for signing and encryption.
If `kpemail <EmailAddress>` is not specified, the user's primary email address is used for the identity.
By default, Gam displays the identity as an indented list of keys and values; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
## Update Gmail CSE Identity
Associates a different key pair with an existing client-side encryption identity. The updated key pair must validate against Google's S/MIME certificate profiles.
```
gam <UserTypeEntity> update cseidentity
(primarykeypairid <KeyPairID>) | (signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>)
[kpemail <EmailAddress>]
[formatjson]
```
One of the following is required:
* `primarykeypairid <KeyPairID>` - The configuration of a CSE identity that uses the same key pair for signing and encryption.
* `signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>` - The configuration of a CSE identity that uses different key pairs for signing and encryption.
bIf `kpemail <EmailAddress>` is not specified, the key pair for the user's primary email address is identity updated.
By default, Gam displays the identity as an indented list of keys and values; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
## Delete Gmail CSE Identity
Deletes a client-side encryption identity. The authenticated user can no longer use the identity to send encrypted messages.
You cannot restore the identity after you delete it. Instead, use the `create cseidentity` to create another identity with the same configuration.
```
gam <UserTypeEntity> delete cseidentity [kpemail <EmailAddress>]
```
If `kpemail <EmailAddress>` is not specified, the identity for the user's primary email address is deleted.
## Display Gmail CSE Identities
### Display a client-side encryption identity configuration.
```
gam <UserTypeEntity> info cseidentity [kpemail <EmailAddress>]
[formatjson]
```
If `kpemail <EmailAddress>` is not specified, the user's primary email address is used for the identity.
### Display all of the client-side encrypted identities for an authenticated user.
```
gam <UserTypeEntity> show cseidentities
[formatjson]
```
By default, Gam displays the identity as an indented list of keys and values; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
```
gam <UserTypeEntity> print cseidentities [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]]
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
## Create Gmail CSE Key Pair
Create a CSE Key Pair for the primary address of a user.
```
gam <UserTypeEntity> create csekeypair
[incertdir <FilePath>] [inkeydir <FilePath>]
[addidentity [<Boolean>]] [kpemail <EmailAddress>]
[showpem] [showkaclsdata] [formatjson|returnidonly]
```
* The S/MIME certificate files for the users are in the `incertdir <FilePath>` folder/directory.
* If this option is not specified, the directory is taken from `gam.cfg/gmail_cse_incert_dir`.
* The files must be named `user@domain.com.p7pem`.
* The certificate contains the public key and its certificate chain. The chain must be in PKCS#7 format and use PEM encoding and ASCII armor.
* The Key Access Control List (KACL) wrapped private key data files are in the `inkeydir <FilePath>` folder/directory.
* If this option is not specified, the directory is taken from `gam.cfg/gmail_cse_inkey_dir`.
* The files must be named `user@domain.com.wrap`.
* The files are in JSON format with two keys:
* `kacls_url` - The URI of the key access control list service that manages the private key.
* `wrapped_private_key` - Opaque data generated and used by the key access control list service.
By default, the `pem` and `kaclsdata` fields will not be displayed unless the corresponding `showpem` and `showkaclsdata` option is specified.
By default, Gam displays the new key pair as an indented list of keys and values; the following options cause the output to be displayed in alternate forms.
* `formatjson` - Display the fields in JSON format.
* `returnidonly` - Display just the new `<KeyPairID>`.
If 'addidentity` or `addidentity true` is specified, a client-side encryption identity is created with the new key pair.
If `kpemail <EmailAddress>` is not specified, the user's primary email address is used for the identity.
By default, Gam displays the identity as an indented list of keys and values; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
* `returnidonly` - Display just the new `<KeyPairID>-<EmailAddress>`.
## Action Gmail CSE Key Pairs
### Display pem and kaclsdata fields
By default, the `pem` and `kaclsdata` fields will not be displayed unless the corresponding `showpem` and `showkaclsdata` option is specified.
### Disable
Turns off a client-side encryption key pair. The authenticated user can no longer use the key pair to decrypt incoming CSE message texts or sign outgoing CSE mail.
```
gam <UserTypeEntity> disable csekeypair <KeyPairID>
[showpem] [showkaclsdata] [formatjson]
```
By default, Gam displays the disabled key pair as an indented list of keys and values; the following option causes the output to be displayed in alternate forms.
* `formatjson` - Display the fields in JSON format.
### Enable
Turn on a client-side encryption key pair that was turned off. The key pair becomes active again for any associated client-side encryption identities.
```
gam <UserTypeEntity> ensable csekeypair <KeyPairID>
[showpem] [showkaclsdata] [formatjson]
```
By default, Gam displays the enabled key pair as an indented list of keys and values; the following option causes the output to be displayed in alternate forms.
* `formatjson` - Display the fields in JSON format.
### Obliterate
Delete a client-side encryption key pair permanently and immediately. You can only permanently delete key pairs that have been turned off for more than 30 days.
To turn off a key pair, use `disable csekeypair`.
```
gam <UserTypeEntity> obliterate csekeypair <KeyPairID>
```
Gmail can't restore or decrypt any messages that were encrypted by an obliterated key. Authenticated users and Google Workspace administrators lose access to reading the encrypted messages.
## Display Gmail CSE Key Pairs
### Display pem and kaclsdata fields
By default, the `pem` and `kaclsdata` fields will not be displayed unless the corresponding `showpem` and `showkaclsdata` option is specified.
### Display an existing client-side encryption key pair.
```
gam <UserTypeEntity> info csekeypair <KeyPairID>
[showpem] [showkaclsdata] [formatjson]
```
By default, Gam displays the key pairs as an indented list of keys and values; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
### Display all client-side encryption key pairs for an authenticated user.
```
gam <UserTypeEntity> show csekeypairs
[showpem] [showkaclsdata] [formatjson]
```
By default, Gam displays the key pairs as an indented list of keys and values; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
```
gam <UserTypeEntity> print csekeypairs [todrive <ToDriveAttribute>*]
[showpem] [showkaclsdata] [formatjson [quotechar <Character>]]
```
By default, Gam displays the key pairs as columns of fields; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.

View File

@@ -10,7 +10,8 @@
## API documentation
* https://developers.google.com/gmail/api/v1/reference/users/settings/delegates
* https://support.google.com/a/answer/7223765?hl=en
* https://support.google.com/a/answer/7223765
* https://support.google.com/a/answer/11946994
## Definitions
* [`<UserTypeEntity>`](Collections-of-Users)

View File

@@ -88,11 +88,17 @@ all parent labels are created as necessary.
Example: `gam user user@domain.com add label "Top/Middle/Bottom" buildpath`
## Update a label's settings
The two commands are equivalent; in the first you specify a `<LabelName>`, in the second you specify a `<LabelId>`.
```
gam <UserTypeEntity> update labelsettings <LabelName> [name <String>]
[messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
[backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
[textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"]
gam <UserTypeEntity> update labelid <LabelID> [name <String>]
[messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
[backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
[textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"]
```
`<LabelColorHex>` values should be enclosed in " to keep the command shell on MacOS and Linux from mis-interpreting them.

View File

@@ -1,4 +1,5 @@
# Users - Gmail - Messages/Threads
- [Notes](#notes)
- [API documentation](#api-documentation)
- [Query documentation](#query-documentation)
- [Definitions](#definitions)
@@ -25,6 +26,13 @@
- [Display messages sent by delegates for delegator](#display-messages-sent-by-delegates-for-delegator)
- [User attribute `replace <Tag> <UserReplacement>` processing](Tag-Replace)
## Notes
Restrict email messages to authorized addresses or domains only
* https://support.google.com/a/answer/2640542
Block emails between specific user groups
* https://support.google.com/a/answer/9175444
## API documentation
* https://developers.google.com/gmail/api/v1/reference/users/messages
* https://developers.google.com/gmail/api/v1/reference/users/threads
@@ -347,10 +355,10 @@ See below for message selection.
Export messages in EML format.
```
gam <UserTypeEntity> export message|messages
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <MessageIDEntity>)
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [max_to_export <Number>])|(ids <MessageIDEntity>)
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
gam <UserTypeEntity> export thread|threads
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [max_to_export <Number>])|(ids <ThreadIDEntity>)
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
```

View File

@@ -131,13 +131,17 @@ Display all notes
```
gam <UserTypeEntity> show notes
[fields <NotesFieldList>] [filter <String>]
[role owner|writwer]
[role owner|writer]
[countsonly]
[compact|formatjson]
```
By default, GAM displays all non-trashed notes:
* `filter trashed` - Display notes in the trash
* `role owner|writer` - Display notes where the user has the specified role
When option `countsonly` is specified, the number of notes a user owns and the number of notes of user can edit
if displayed.
By default, Gam displays the information as an indented list of keys and values; the note text is displayed as individual lines.
* `compact` - Display the note text with escaped carriage returns as \r and newlines as \n
* `formatjson` - Display the note in JSON format
@@ -145,7 +149,8 @@ By default, Gam displays the information as an indented list of keys and values;
```
gam <UserTypeEntity> print notes [todrive <ToDriveAttribute>*]
[fields <NotesFieldList>] [filter <String>]
[role owner|writwer]
[role owner|writer]
[countsonly]
[formatjson [quotechar <Character>]]
```
@@ -153,6 +158,9 @@ By default, GAM displays all non-trashed notes:
* `filter trashed` - Display notes in the trash
* `role owner|writer` - Display notes where the user has the specified role
When option `countsonly` is specified, the number of notes a user owns and the number of notes of user can edit
if displayed.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.

View File

@@ -69,6 +69,10 @@
```
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
<OrgUnitID> ::= id:<String>
<OrgUnitPath> ::= /|(/<String>)+
<OrgUnitItem> ::= <OrgUnitID>|<OrgUnitPath>
<DriveFileACLRole> ::=
manager|organizer|owner|
contentmanager|fileorganizer|
@@ -277,16 +281,19 @@ gam <UserTypeEntity> unhide teamdrive <SharedDriveEntity>
```
gam <UserTypeEntity> show teamdriveinfo <SharedDriveEntity>
gam <UserTypeEntity> info teamdrive <SharedDriveEntity>
[fields <SharedDriveFieldNameList>] [formatjson]
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>] [formatjson]
gam <UserTypeEntity> show teamdriveinfo <SharedDriveEntity>
[fields <SharedDriveFieldNameList>] [formatjson]
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>] [formatjson]
gam <UserTypeEntity> show teamdrives
[matchname <RegularExpression>] (role|roles <SharedDriveACLRoleList>)*
[fields <SharedDriveFieldNameList>] [formatjson]
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>] [formatjson]
```
By default, Gam displays all Teams Drives accessible by the user.
* `matchname <RegularExpression>` - Display Shared Drives with names that match a pattern.
* `(role|roles <SharedDriveACLRoleList>)* - Display Shared Drives where the user has one of the specified roles.
* `(role|roles <SharedDriveACLRoleList>)*` - Display Shared Drives where the user has one of the specified roles.
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
@@ -301,10 +308,20 @@ By default, Gam displays all Teams Drives accessible by the user.
The Google Drive API does not list roles for Shared Drives so GAM generates a role from the capabilities:
* `commenter - canComment: True, canEdit: False`
* `fileOrganizer - canAddChildren: True, canManageMembers: False`
* `reader - canComment: False, canEdit: False`
* `writer - canEdit: True, canTrashChildren: False`
* `fileOrganizer - canTrashChildren: True, canManageMembers: False`
* `organizer - canManageMembers: True`
* `reader - canCopy': True, canComment: False`
* `writer - canEdit: True, canManageMembers: False`
By default, the Drive API role names are displayed, use `guiroles` to display the Google Drive GUI role names.
```
API: GUI
commenter: Commenter
fileOrganizer: Content manager
organizer: Manager
reader: Viewer
writer: Contributor
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.

View File

@@ -39,13 +39,14 @@
- [Print domain counts for users specified by `<UserTypeEntity>`](#print-domain-counts-for-users-specified-by-usertypeentity)
- [Print user list](#print-user-list)
- [Display user counts](#display-user-counts)
- [Verify domain membership]($verify-domain-membership)
## API documentation
* https://developers.google.com/admin-sdk/directory/reference/rest/v1/users
* https://developers.google.com/admin-sdk/directory/reference/rest/v1/schemas
## Name guidelines
* https://support.google.com/a/answer/9193374?hl=en
* https://support.google.com/a/answer/9193374
## Query documentation
* https://developers.google.com/admin-sdk/directory/v1/guides/search-users
@@ -337,6 +338,10 @@ relation manager manageremail@domain.com
externalid organization "Employee ID"
```
`<UserMultiAttribute>.location.buildingid <String>` allows non-validated building IDs
by specifying `nv:` at the beginning of `<String>`; e.g., `nv:Building X' sets the building ID to `Building X`.
## Passwords
To set a user's password, you specify a `<Password>` string and a hash method that specifies how to interpret the string
* `password random|uniquerandom` - A 25 character plain text string of ASCII uppercase/lowecase letters, digits and punctuation
@@ -981,14 +986,16 @@ gam print users [todrive <ToDriveAttribute>*]
[limittoou <OrgUnitItem>] [deleted_only|only_deleted])
[orderby <UserOrderByFieldName> [ascending|descending]]
[groups|groupsincolumns]
[license|licenses|licence|licences]
[license|licenses|licence|licences|licensebyuser|licensesbyuser|licencebyuser|licencesbyuser]
[onelicenseperrow|onelicenceperrow]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
[userview] [allfields|basic|full|(<UserFieldName>*|fields <UserFieldNameList>)]
[delimiter <Character>] [sortheaders [<Boolean>]] [scalarsfirst [<Boolean>]]
[formatjson [quotechar <Character>]] [quoteplusphonenumbers]
[issuspended <Boolean>] [aliasmatchpattern <RegularExpression>]
[showvalidcolumn] (addcsvdata <FieldName> <String>)*
```
By default, users in all domains in the account are selected; these options allow selection of subsets of users:
@@ -1008,11 +1015,13 @@ gam print users [todrive <ToDriveAttribute>*] select <UserTypeEntity>
[onelicenseperrow|onelicenceperrow]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username][schemas|custom all|<SchemaNameList>]
[userview] [allfields|basic|full|(<UserFieldName>*|fields <UserFieldNameList>)]
[emailpart|emailparts|username]
[userview] [basic|full|allfields|(<UserFieldName>*|fields <UserFieldNameList>)]
[delimiter <Character>] [sortheaders [<Boolean>]] [scalarsfirst [<Boolean>]]
[formatjson [quotechar <Character>]] [quoteplusphonenumbers]
[issuspended <Boolean>] [aliasmatchpattern <RegularExpression>]
[showvalidcolumn] (addcsvdata <FieldName> <String>)*
gam <UserTypeEntity> print users [todrive <ToDriveAttribute>*]
[orderby <UserOrderByFieldName> [ascending|descending]]
[groups|groupsincolumns]
@@ -1021,10 +1030,11 @@ gam <UserTypeEntity> print users [todrive <ToDriveAttribute>*]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
[userview] [allfields|basic|full|(<UserFieldName>*|fields <UserFieldNameList>)]
[userview] [basic|full|allfields|(<UserFieldName>*|fields <UserFieldNameList>)]
[delimiter <Character>] [sortheaders [<Boolean>]] [scalarsfirst [<Boolean>]]
[formatjson [quotechar <Character>]] [quoteplusphonenumbers]
[issuspended <Boolean>] [aliasmatchpattern <RegularExpression>]
[showvalidcolumn] (addcsvdata <FieldName> <String>)*
```
By default, Gam gets no group membership information for each user. The `groups` and `groupsincolumns`
@@ -1079,6 +1089,17 @@ In the output, primaryEmail is the always the first column; these options contro
* `<UserFieldName>*|fields <UserFieldNameList>` - The columns appear in the order that the fields are specified.
* `scalarsfirst [true]` - When columns are sorted by name, scalar fields appear before repeating fields.
By default, if `<UserTypeEntity>` includes an email address the is not a user member of the domain,
an error message is generated.
```
User: testuserxxx@domain.com, Does not exist
```
Using option `showvalidcolumn`, a new column `Found` indicates domain membership; no errors are generated
Add additional columns of data from the command line to the output
* `addcsvdata <FieldName> <String>`
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format:
* `formatjson` - Display the fields in JSON format.
@@ -1249,3 +1270,34 @@ count=$(gam print users query "orgUnitPath='/Students/Middle School'" showitemco
Windows PowerShell
count = & gam print users query "orgUnitPath='/Students/Middle School'" showitemcountonly
```
## Verify domain membership
You have a CSV file of email addresses and want to verify of the addresses are valid users in your domain.
```
# Users.csv
$ more Users.csv
primaryEmail,name
testuser1@domain.com,Test User 1
testuserxxx@domain.com,Test User XXX
testuser2@domain.com,Test User 2
# Without showvalidcolumn, non-domain users generate an error
$ gam redirect csv - multiprocess csv Users.csv gam user "~primaryEmail" print users fields primaryemail,id addcsvdata name "~name"
2024-02-23T11:29:00.407-08:00,0/3,Using 3 processes...
2024-02-23T11:29:00.410-08:00,0,Processing item 3/3
User: testuserxxx@domain.com, Does not exist
2024-02-23T11:29:06.511-08:00,0/3,Processing complete
primaryEmail,id,name
testuser1@domain.com,118080758787650801331,Test User 1
testuser2@domain.com,107344800159717682514,Test User 2
# Using showvalidcolumn, a new column `Valid` indicates domain membership; no errors are generated
$ gam redirect csv - multiprocess csv Users.csv gam user "~primaryEmail" print users fields primaryemail,id addcsvdata name "~name" showvalidcolumn
2024-02-23T11:29:22.287-08:00,0/3,Using 3 processes...
2024-02-23T11:29:22.292-08:00,0,Processing item 3/3
2024-02-23T11:29:23.366-08:00,0/3,Processing complete
primaryEmail,id,Valid,name
testuser1@domain.com,118080758787650801331,True,Test User 1
testuserxxx@domain.com,,False,Test User XXX
testuser2@domain.com,107344800159717682514,True,Test User 2
```

View File

@@ -219,7 +219,7 @@ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calenda
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[includerooms <Boolean>]
[excludedrafts <Boolean>] [format mbox|pst]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
[covereddata calllogs|textmessages|voicemails]
[region any|europe|us] [showdetails|returnidonly]
```
@@ -305,6 +305,10 @@ For `corpus mail`, you can specify whether to use the new export system:
* `usenewexport false` - Do not use the new export system
* `usenewexport true` - Use the new export system
For `corpus mail`, you can specify whether to enable exporting linked Drive files:
* `exportlinkeddrivefiles false` - Do not export linked Drive files
* `exportlinkeddrivefiles true` - Export linked Drive files
See: https://support.google.com/vault/answer/4388708#new_gmail_export&zippy=%2Cfebruary-new-gmail-export-system-available
For `corpus mail`, `corpus groups`, `corpus hangouts_chat`and `corpus voice`, you can specify the format of the exported data:

View File

@@ -1,44 +1,43 @@
\
# Version and Help
Print the current version of Gam with details
```
gam version
GAMADV-XTD3 6.67.20 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.72.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.1 64-bit final
Python 3.12.2 64-bit final
MacOS Sonoma 14.2.1 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain.com
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2023-06-02T21:10:00-07:00
```
Print the current version of Gam with details and time offset information
```
gam version timeoffset
GAMADV-XTD3 6.67.20 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.72.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.1 64-bit final
Python 3.12.2 64-bit final
MacOS Sonoma 14.2.1 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, 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
```
Print the current version of Gam with extended details and SSL information
```
gam version extended
GAMADV-XTD3 6.67.20 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.72.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.1 64-bit final
Python 3.12.2 64-bit final
MacOS Sonoma 14.2.1 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain.com
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2023-06-02T21:10:00-07:00
Your system time differs from admin.googleapis.com by less than 1 second
OpenSSL 3.1.1 30 May 2023
cryptography 41.0.1
filelock 3.12.1
filelock 3.12.2
google-api-python-client 2.88.0
google-auth-httplib2 0.1.0
google-auth-oauthlib 1.0.0
@@ -65,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Version Check:
Current: 5.35.08
Latest: 6.67.20
Latest: 6.72.08
echo $?
1
```
@@ -73,7 +72,7 @@ echo $?
Print the current version number without details
```
gam version simple
6.67.20
6.72.08
```
In Linux/MacOS you can do:
```
@@ -83,12 +82,12 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 6.67.20 - https://github.com/taers232c/GAMADV-XTD3
GAM 6.72.08 - https://github.com/taers232c/GAMADV-XTD3
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.1 64-bit final
Python 3.12.2 64-bit final
MacOS Sonoma 14.2.1 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain.com
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
Time: 2023-06-02T21:10:00-07:00
Help: Syntax in file /Users/Admin/bin/gamadv-xtd3/GamCommands.txt
Help: Documentation is at https://github.com/taers232c/GAMADV-XTD3/wiki

View File

@@ -129,6 +129,7 @@ Service Account Access
* [Users - Drive - File Selection](Drive-File-Selection)
* [Users - Drive - Activity/Settings](Users-Drive-Activity-Settings)
* [Users - Drive - Cleanup](Users-Drive-Cleanup)
* [Users - Drive - Comments](Users-Drive-Comments)
* [Users - Drive - Copy/Move](Users-Drive-Copy-Move)
* [Users - Drive - Files-Display](Users-Drive-Files-Display)
* [Users - Drive - Files-Manage](Users-Drive-Files-Manage)
@@ -141,6 +142,7 @@ Service Account Access
* [Users - Drive - Shortcuts](Users-Drive-Shortcuts)
* [Users - Drive - Transfer](Users-Drive-Transfer)
* [Users - Forms](Users-Forms)
* [Users - Gmail - Client Side Encryption](Users-Gmail-CSE)
* [Users - Gmail - Delegates](Users-Gmail-Delegates)
* [Users - Gmail - Filters](Users-Gmail-Filters)
* [Users - Gmail - Forwarding](Users-Gmail-Forwarding)

View File

@@ -150,7 +150,7 @@ csv_input_column_delimiter
Default: ','
csv_input_no_escape_char
When reading a CSV file, should `\` be ignored as an escape character.
Set this to False if the input file data was written using `\` as an escape character.
Set this to False if the input file data was written using `\` as an escape character.
Default: True
csv_input_quote_char
A one-character string used to quote fields containing special characters,
@@ -213,14 +213,14 @@ csv_output_header_force
for inclusion in the CSV file written by a gam print command
Default: ''
csv_output_line_terminator
p Allowed values: cr, lf, crlf
Allowed values: cr, lf, crlf
Designates character(s) used to terminate the lines of a CSV file.
For Linux and Mac OS, this would typically be lf.
For Windows, this would typically be crlf.
Default: lf
csv_output_no_escape_char
When writing a CSV file, should `\` be ignored as an escape character.
Set this to True if the output file data is to be read by a non-Python program.
Set this to True if the output file data is to be read by a non-Python program.
Default: False
csv_output_quote_char
A one-character string used to quote fields containing special characters,
@@ -255,6 +255,10 @@ csv_output_row_filter_mode
csv_output_row_limit
A limit on the number of rows to write to a CSV file; a value of 0 sets no limit.
Default: 0
csv_output_sort_headers
A list of column headers that causes GAM to sort CSV output rows by those headers.
The column headers are case insensitive and if column header does not appear in the CSV output, it is ignored.
Default: Blank
csv_output_subfield_delimiter
Character used to delimit fields and subfields in headers when writing CSV files;
this must be a single character
@@ -322,6 +326,12 @@ extra_args
Path to extra_args.txt
Default: Blank
Data file: extra_args.txt
gmail_cse_incert_dir
Directory for the S/MIME certificate files used by Gmail Client Side Encryption.
Default: Blank
gmail_cse_inkey_dir
Directory for the Key Access Control List (KACL) wrapped private key data files used by Gmail Client Side Encryption.
Default: Blank
inter_batch_wait
When processing items in batches, how many seconds should GAM wait between batches
Default: 0
@@ -420,23 +430,23 @@ print_agu_domains
gam print groups
gam print|show group-members
gam print users
This allows predefining the list of domains so they don't have to be specified in each command.
This allows predefining the list of domains so they don't have to be specified in each command.
Default: Blank
print_cros_ous
A comma separated list of org unit that are used in these commands:
gam print cros
gam print crosactivity
This allows predefining the list of org units so they don't have to be specified in each command.
This allows predefining the list of org units so they don't have to be specified in each command.
Default: Blank
print_cros_ous_and_children
A comma separated list of org unit names that are used in these commands:
gam print cros
gam print crosactivity
This allows predefining the list of org units so they don't have to be specified in each command.
This allows predefining the list of org units so they don't have to be specified in each command.
Default: Blank
process_wait_limit
When processing batch/CSV files, how long (in seconds) GAM should wait for all batch|csv processes to complete
after all have been started. If the limit is reached, GAM terminates any remaining processes.
When processing batch/CSV files, how long (in seconds) GAM should wait for all batch|csv processes to complete
after all have been started. If the limit is reached, GAM terminates any remaining processes.
Default: 0: no limit
Range: 0 - Unlimited
quick_cros_move
@@ -461,7 +471,7 @@ section
Default section of gam.cfg.
Default: DEFAULT
show_api_calls_retry_data
Enable/disable display of Google API calls retry data and end of processing
Enable/disable display of Google API calls retry data at end of processing
Default: False
show_commands
Enable/disable display of commands to stderr when executing `gam batch|tbatch|csv|loop`.
@@ -573,6 +583,13 @@ update_cros_ou_with_id
Set to true if you are getting the following error:
`400: invalidInput - Invalid Input: Inconsistent Orgunit id and path in request`
Default: False
use_classroom_owner_access
How is classroom member information obtained and how are classroom members deleted.
Client access does not provide complete information about non-domain students/teachers.
When False, GAM uses client access to get classroom member information and to delete members
When True, GAM uses service account access as the classroom owner.
An extra API call is required per course to authenticate the owner
Default: False
use_projectid_as_name
When False, new projects have a default project name of "GAM Project"
and a default app name of "GAM".

View File

@@ -22,43 +22,6 @@ If an item contains spaces, it should be surrounded by ".
<FalseValues>= false|off|no|disabled|0
<TrueValues> ::= true|on|yes|enabled|1
<Charset> ::= ascii|latin1|mbcs|utf-8|utf-8-sig|utf-16|<String>
<CalendarColorIndex> ::= <Number in range 1-24>
<CalendarColorName> ::=
amethyst|avocado|banana|basil|birch|blueberry|
cherryblossom|citron|cobalt|cocoa|eucalyptus|flamingo|
grape|graphite|lavender|mango|peacock|pistachio|
pumpkin|radicchio|sage|tangerine|tomato|wisteria|
<ColorHex> ::= "#<Hex><Hex><Hex><Hex><Hex><Hex>"
<ColorNameGoogle> ::=
asparagus|bluevelvet|bubblegum|cardinal|chocolateicecream|denim|desertsand|
earthworm|macaroni|marsorange|mountaingray|mountaingrey|mouse|oldbrickred|
pool|purpledino|purplerain|rainysky|seafoam|slimegreen|spearmint|
toyeggplant|vernfern|wildstrawberries|yellowcab
<ColorNameWeb> ::=
aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|
blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|
cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|
darkgrey|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|
darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|
darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|
firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|
gray|grey|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|
lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|
lightgoldenrodyellow|lightgray|lightgrey|lightgreen|lightpink|lightsalmon|
lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|
lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|
mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|
mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|
navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|
palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|
peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|
sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|
slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|
wheat|white|whitesmoke|yellow|yellowgreen
<ColorName> ::= <ColorNameGoogle>|<ColorNameWeb>
<ColorValue> ::= <ColorName>|<ColorHex>
<DayOfWeek> ::= mon|tue|wed|thu|fri|sat|sun
<BCP47LanguageCode> ::=
ar-sa| # Arabic Saudi Arabia
cs-cz| # Czech Czech Republic
@@ -97,6 +60,43 @@ If an item contains spaces, it should be surrounded by ".
zh-cn| # Chinese China
zh-hk| # Chinese Hong Kong
zh-tw # Chinese Taiwan
<Charset> ::= ascii|latin1|mbcs|utf-8|utf-8-sig|utf-16|<String>
<CalendarColorIndex> ::= <Number in range 1-24>
<CalendarColorName> ::=
amethyst|avocado|banana|basil|birch|blueberry|
cherryblossom|citron|cobalt|cocoa|eucalyptus|flamingo|
grape|graphite|lavender|mango|peacock|pistachio|
pumpkin|radicchio|sage|tangerine|tomato|wisteria|
<ColorHex> ::= "#<Hex><Hex><Hex><Hex><Hex><Hex>"
<ColorNameGoogle> ::=
asparagus|bluevelvet|bubblegum|cardinal|chocolateicecream|denim|desertsand|
earthworm|macaroni|marsorange|mountaingray|mountaingrey|mouse|oldbrickred|
pool|purpledino|purplerain|rainysky|seafoam|slimegreen|spearmint|
toyeggplant|vernfern|wildstrawberries|yellowcab
<ColorNameWeb> ::=
aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|
blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|
cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|
darkgrey|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|
darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|
darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|
firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|
gray|grey|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|
lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|
lightgoldenrodyellow|lightgray|lightgrey|lightgreen|lightpink|lightsalmon|
lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|
lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|
mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|
mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|
navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|
palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|
peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|
sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|
slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|
wheat|white|whitesmoke|yellow|yellowgreen
<ColorName> ::= <ColorNameGoogle>|<ColorNameWeb>
<ColorValue> ::= <ColorName>|<ColorHex>
<DayOfWeek> ::= mon|tue|wed|thu|fri|sat|sun
<EventColorIndex> ::= <Number in range 1-11>
<EventColorName> ::=
banana|basil|blueberry|flamingo|graphite|grape|
@@ -243,6 +243,7 @@ If an item contains spaces, it should be surrounded by ".
101040 |
101043 |
101047 |
101049 |
Google-Apps |
Google-Chrome-Device-Management |
Google-Drive-storage |
@@ -258,56 +259,58 @@ If an item contains spaces, it should be surrounded by ".
4tb | drive4tb | googledrivestorage4tb | Google-Drive-storage-4TB |
8tb | drive8tb | googledrivestorage8tb | Google-Drive-storage-8TB |
16tb | drive16tb | googledrivestorage16tb | Google-Drive-storage-16TB |
appsheetcore | 1010380001 |
appsheetstandard | appsheetenterprisestandard | 1010380002 |
appsheetplus | appsheetenterpriseplus | 1010380003 |
assuredcontrols | 1010390001 |
bce | beyondcorp | beyondcorpenterprise | 1010400001 |
appsheetcore | 1010380001 | AppSheet Core |
appsheetstandard | appsheetenterprisestandard | 1010380002 | AppSheet Enterprise Standard |
appsheetplus | appsheetenterpriseplus | 1010380003 | AppSheet Enterprise Plus |
assuredcontrols | 1010390001 | Assured Controls |
bce | beyondcorp | beyondcorpenterprise | 1010400001 | Beyond Corp Enterprise |
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
cloudidentity | identity | 1010010001 |
cloudidentitypremium | identitypremium | 1010050001 |
cloudsearch | 1010350001 |
duetai | 1010470001 |
cloudidentity | identity | 1010010001 | Cloud Identity |
cloudidentitypremium | identitypremium | 1010050001 | Cloud Identity Premium |
cloudsearch | 1010350001 | Cloud Search |
eeu | 1010490001 | SKU Endpoint Education Upgrade |
geminibiz | 1010470003 | Gemini Business |
geminient| duetai | 1010470001 | Gemini Enterprise |
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 |
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 | Google Workspace Business - Archived User |
gsuiteenterprisearchived | gseau | enterprisearchived | 1010340001 | Google Workspace Enterprise Plus - Archived User |
gsuiteenterpriseeducation | gsefe | e4e | 1010310002 | Google Workspace for Education Plus - Legacy |
gsuiteenterpriseeducationstudent | gsefes | e4es | 1010310003 | Google Workspace for Education Plus - Legacy (Student) |
gsuitegov | gafg | gsuitegovernment | Google-Apps-For-Government |
gsuitelite | gal | gsl | lite | Google-Apps-Lite |
gwep | workspaceeducationplus | 1010310008 |
gwepstaff | workspaceeducationplusstaff | 1010310009 |
gwepstudent | workspaceeducationplusstudent | 1010310010 |
gwes | workspaceeducationstandard | 1010310005 |
gwesstaff | workspaceeducationstandardstaff | 1010310006 |
gwesstudent | workspaceeducationstandardstudent | 1010310007 |
gwetlu | workspaceeducationupgrade | 1010370001 |
gwlabs | workspacelabs | 1010470002
meetdialing | googlemeetglobaldialing | 1010360001 |
gwep | workspaceeducationplus | 1010310008 | Google Workspace for Education Plus |
gwepstaff | workspaceeducationplusstaff | 1010310009 | Google Workspace for Education Plus (Staff) |
gwepstudent | workspaceeducationplusstudent | 1010310010 | Google Workspace for Education Plus (Extra Student)|
gwes | workspaceeducationstandard | 1010310005 | Google Workspace for Education Standard |
gwesstaff | workspaceeducationstandardstaff | 1010310006 | Google Workspace for Education Standard (Staff) |
gwesstudent | workspaceeducationstandardstudent | 1010310007 | Google Workspace for Education Standard (Extra Student)
gwetlu | workspaceeducationupgrade | 1010370001 | Google Workspace for Education: Teaching and Learning Upgrade |
gwlabs | workspacelabs | 1010470002 | Google Workspace Labs |
meetdialing | googlemeetglobaldialing | 1010360001 | Google Meet Global Dialing |
postini | gams | gsuitegams | gsuitepostini | gsuitemessagesecurity | Google-Apps-For-Postini |
standard | free | Google-Apps |
vault | googlevault | Google-Vault |
vfe | googlevaultformeremployee | Google-Vault-Former-Employee |
voicepremier | gvpremier | googlevoicepremier | 1010330002 |
voicestandard | gvstandard | googlevoicestandard | 1010330004 |
voicestarter | gvstarter | googlevoicestarter | 1010330003 |
wsas | plusstorage | 1010430001 |
wsbizplus | workspacebusinessplus | 1010020025 |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 |
wsbizstan | workspacebusinessstandard | 1010020028 |
wsbizstanarchived | workspacebusinessstandardarchived | 1010340006 |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 |
wsbizstarterarchived | workspacebusinessstarterarchived | 1010340005 |
wsentess | workspaceenterpriseessentials | 1010060003 |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 |
wsentstan | workspaceenterprisestandard | 1010020026 |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 |
wsentstarter | workspaceenterprisestarter | 1010020029 | wes |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 |
wsessplus | workspaceessentialsplus | 1010060005 |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 |
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031
voicepremier | gvpremier | googlevoicepremier | 1010330002 | Google Voice Premier
voicestandard | gvstandard | googlevoicestandard | 1010330004 | Google Voice Standard |
voicestarter | gvstarter | googlevoicestarter | 1010330003 | Google Voice Starter |
wsas | plusstorage | 1010430001 | Google Workspace Additional Storage |
wsbizplus | workspacebusinessplus | 1010020025 | Google Workspace Business Plus |
wsbizplusarchived | workspacebusinessplusarchived | 1010340003 | Google Workspace Business Plus - Archived User |
wsbizstan | workspacebusinessstandard | 1010020028 | Google Workspace Business Standard }
wsbizstanarchived | workspacebusinessstandardarchived | 1010340006 | Google Workspace Business Standard - Archived User |
wsbizstarter | workspacebusinessstarter | wsbizstart | 1010020027 | Google Workspace Business Starter |
wsbizstarterarchived | workspacebusinessstarterarchived | 1010340005 | Google Workspace Business Starter - Archived User |
wsentess | workspaceenterpriseessentials | 1010060003 | Google Workspace Enterprise Essentials |
wsentplus | workspaceenterpriseplus | gae | gse | enterprise | gsuiteenterprise | 1010020020 | Google Workspace Enterprise Plus |
wsentstan | workspaceenterprisestandard | 1010020026 | Google Workspace Enterprise Standard |
wsentstanarchived | workspaceenterprisestandardarchived | 1010340004 | Google Workspace Enterprise Standard - Archived User |
wsentstarter | workspaceenterprisestarter | wes | 1010020029 | Workspace Enterprise Starter |
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard
## Items built from primitives
@@ -441,6 +444,7 @@ If an item contains spaces, it should be surrounded by ".
<DriveLabelFieldID> ::= <String>
<DriveLabelSelectionID> ::= <String>
<DriveLabelName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]
<DriveLabelPermissionName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]/permissions/(audiences|groups|people)/<String>
<EmailAddress> ::= <String>@<DomainName>
<EmailItem> ::= <EmailAddress>|<UniqueID>|<String>
<EmailReplacement> ::= <String>
@@ -583,6 +587,7 @@ If an item contains spaces, it should be surrounded by ".
<StorageObjectName> ::= <String>
<StorageBucketObjectName> ::=
https://storage.cloud.google.com/<StorageBucketName>/<StorageObjectName>|
https://storage.googleapis.com/<StorageBucketName>/<StorageObjectName>|
gs://<StorageBucketName>/<StorageObjectName>|
<StorageBucketName>/<StorageObjectName>
<Tag> ::= <String>
@@ -597,6 +602,7 @@ If an item contains spaces, it should be surrounded by ".
<Title> ::= <String>
<ToDriveAttribute> ::=
(tdaddsheet [<Boolean>])|
(tdalert <EmailAddress>)*|
(tdbackupsheet (id:<Number>)|<String>)|
(tdcellnumberformat text|number)|
(tdcellwrap clip|overflow|wrap)|
@@ -604,20 +610,23 @@ If an item contains spaces, it should be surrounded by ".
(tdcopysheet (id:<Number>)|<String>)|
(tddescription <String>)|
(tdfileid <DriveFileID>)|
(tdfrom <EmailAddress>)|
(tdlocalcopy [<Boolean>])|
(tdlocale <Locale>)|
(tdnobrowser [<Boolean>])|
(tdnoemail [<Boolean>])|
(tdnoescapechar [<Boolean>])|
(tdnotify [<Boolean>])|
(tdparent (id:<DriveFolderID>)|<DriveFolderName>)|
(tdretaintitle [<Boolean>])|
(tdshare <EmailAddress> commenter|reader|writer)|
(tdshare <EmailAddress> commenter|reader|writer)*|
(tdsheet (id:<Number>)|<String>)|
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>])
(tdsheettitle <String>)|
(tdsubject <String>)|
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
(tdtimestamp [<Boolean>] [tdtimeformat <String>]
[tddaysoffset <Number>] [tdhoursoffset <Number>])|
([tddaysoffset <Number>] [tdhoursoffset <Number>])|
(tdtimezone <TimeZone>)|
(tdtitle <String>)|
(tdupdatesheet [<Boolean>])|
@@ -641,6 +650,7 @@ If an item contains spaces, it should be surrounded by ".
<AssetTagList> ::= "<AssetTag>(,<AssetTag>)*"
<CalendarACLScopeList> ::= "<CalendarACLScope>(,<CalendarACLScope>)*"
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
<ChatSpaceList> ::= "<ChatSpace>(,<ChatSpace>)*"
<CIGroupAliasList> ::= "<CIGroupAlias>(,<CIGroupAlias>)*"
<CIGroupTypeList> ::= "<CIGroupType>(,<CIGroupType>)*"
<ClassroomInvitationIDList> ::= "<ClassroomInvitationID>(,<ClassroomInvitationID>)*"
@@ -664,6 +674,7 @@ If an item contains spaces, it should be surrounded by ".
<DeviceUserList> ::= "<DeviceUserID>(,<DeviceUserID>)*"
<DomainNameList> ::= "<DomainName>(,<DomainName>)*"
<DriveFileACLRoleList> ::= "<DriveFileACLRole>(,<DriveFileACLRole>)*"
<DriveFileACLTypeList> ::= "<DriveFileACLType>(,<DriveFileACLType>)*"
<DriveFileList> ::= "<DriveFileItem>(,<DriveFileItem>)*"
<DriveFilePermissionList> ::= "<DriveFilePermission>(,<DriveFilePermission>)*"
<DriveFilePermissionIDList> ::= "<DriveFilePermissionID>(,<DriveFilePermissionID>)*"
@@ -672,6 +683,7 @@ If an item contains spaces, it should be surrounded by ".
<DriveFolderNameList> ::= "<DriveFolderName>(,<DriveFolderName>)*"
<DriveLabelIDList> ::= "<DriveLabelID>(,<DriveLabelID>)*"
<DriveLabelNameList> ::= "<DriveLabelName>(,<DriveLabelName>)*"
<DriveLabelPermissionNameList> ::= "<DriveLabelPermissionName>(,<DriveLabelPermissionName>)*"
<DriveLabelFieldIDList> ::= "<DriveLabelFieldID>(,<DriveLabelFieldID>)*"
<DriveLabelSelectionIDList> ::= "<DriveLabelSelectionID>(,<DriveLabelSelectionID>)*"
<EmailAddressList> ::= "<EmailAddress>(,<EmailAddress>)*"
@@ -697,6 +709,7 @@ If an item contains spaces, it should be surrounded by ".
<MatterStateList> ::= "<MatterState>(,<MatterState>)*"
<MessageIDList> ::= "<MessageID>(,<MessageID>)*"
<MimeTypeList> ::= "<MimeType>(,<MimeType>)*"
<MimeTypeNameList> ::= "<MimeTypeName>(,<MimeTypeName>)*"
<NamespaceList> ::= "<Namespace>(,<Namespace>)*"
<NotesNameList> ::= "<NotesName>(,<NotesName>)*"
<OrgUnitList> ::= "<OrgUnitItem>(,<OrgUnitItem>)*"
@@ -1094,6 +1107,8 @@ Specify a collection of items by directly specifying them; the item type is dete
<FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
<DriveLabelNameEntity> ::=
<DriveLabelNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<DriveLabelPermissionNameEntity> ::=
<DriveLabelPermissionNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<EmailAddressEntity> ::=
<EmailAddressList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
<FilterIDEntity> ::=
@@ -1239,7 +1254,7 @@ For redirect csv, the optional arguments must appear in the order shown.
<Redirect> ::=
redirect csv <FileName> [multiprocess] [append] [noheader] [charset <Charset>]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[timestampcolumn <String>]
[sortheaders <StringList>] [timestampcolumn <String>]
[todrive <ToDriveAttribute>*] |
redirect stdout <FileName> [multiprocess] [append] |
redirect stdout null [multiprocess] |
@@ -1287,13 +1302,13 @@ gam tbatch <BatchContent> [showcmds [<Boolean>]]
gam csv <CSVLoopContent> [warnifnodata]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [fields <FieldNameList>]
(matchfield|skipfield <FieldName> <RegularExpression>)* [showcmds [<Boolean>]]
[maxrows <Integer>]
[skiprows <Integer>] [maxrows <Integer>]
gam <GAMArgumentList>
gam loop <CSVLoopContent> [warnifnodata]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [fields <FieldNameList>]
(matchfield|skipfield <FieldName> <RegularExpression>)* [showcmds [<Boolean>]]
[maxrows <Integer>]
[skiprows <Integer>] [maxrows <Integer>]
gam <GAMArgumentList>
You can make substitutions in <GAMArgumentList> with values from the CSV file.
@@ -1424,7 +1439,8 @@ gam create adminrole <String> privileges all|all_ou|<PrivilegesList> [descriptio
gam update adminrole <RoleItem> [name <String>] [privileges all|all_ou|<PrivilegesList>] [description <String>]
gam delete adminrole <RoleItem>
gam info adminrole <RoleItem> [privileges]
gam print adminroles|roles [todrive <ToDriveAttribute>*] [privileges]
gam print adminroles|roles [todrive <ToDriveAttribute>*]
[privileges] [oneitemperrow]
gam show adminroles|roles [privileges]
gam create|add admin <EmailAddress>|<UniqueID> <RoleItem> customer|(org_unit <OrgUnitItem>)
@@ -1432,7 +1448,8 @@ gam create|add admin <EmailAddress>|<UniqueID> <RoleItem> customer|(org_unit <Or
gam delete admin <RoleAssignmentId>
gam print admins [todrive <ToDriveAttribute>*]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition]
[privileges] [oneitemperrow]
gam show admins
[user|group <EmailAddress>|<UniqueID>] [role <RoleItem>] [condition] [privileges]
@@ -1826,7 +1843,7 @@ gam calendar <CalendarEntity> deleteevent (id|eventid <EventID>)+ [doit] [<Event
[csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]
gam calendar <CalendarEntity> moveevent (id|eventid <EventID>)+ destination <CalendarItem> [<EventNotificationAttribute>]
gam calendar <CalendarEntity> wipe
gam calendar <CalendarEntity> printevents <EventSelectProperty>* <EventDisplayProperty>* [fields <EventFieldNameList>]
gam calendar <CalendarEntity> printevents <EventSelectProperty>* <EventDisplayProperty>*
[fields <EventFieldNameList>] [showdayofweek]
[countsonly]
[formatjson [quotechar <Character>]] [todrive <ToDriveAttribute>*]
@@ -2026,6 +2043,9 @@ gam delete chatmessage name <ChatMessage>
gam info chatmessage name <ChatMessage>
[formatjson]
gam info chatevent name <ChatEvent>
[formatjson]
# Chrome Installed Apps Counts
gam show chromeapps
@@ -2207,7 +2227,9 @@ gam <CrOSTypeEntity> update <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatc
annotatedlocation|location|
annotateduser|user|
autoupdateexpiration|
backlightinfo|
bootmode|
cpuinfo|
cpustatusreports|
deprovisionreason|
devicefiles|
@@ -2293,6 +2315,7 @@ gam print cros [todrive <ToDriveAttribute>*]
[start <Date>] [end <Date>] [listlimit <Number>]
[reverselists <CrOSListFieldNameList>]
[timerangeorder ascending|descending] [showdvrsfp]
(addcsvdata <FieldName> <String>)*
[sortheaders]
[formatjson [quotechar <Character>]]
[showitemcountonly]
@@ -2317,6 +2340,7 @@ gam <CrOSTypeEntity> print cros [todrive <ToDriveAttribute>*]
[start <Date>] [end <Date>] [listlimit <Number>]
[reverselists <CrOSListFieldNameList>]
[timerangeorder ascending|descending] [showdvrsfp]
(addcsvdata <FieldName> <String>)*
[sortheaders]
[formatjson [quotechar <Character>]]
[showitemcountonly]
@@ -2875,7 +2899,7 @@ gam course <CourseID> delete topic <CourseTopicID>
gam course <CourseID> create|add teachers [makefirstteacherowner] <UserItem>
gam course <CourseID> create|add students <UserItem>
gam course <CourseID> delete|remove teachers|students <UserItem>
gam course <CourseID> delete|remove teachers|students [owneraccess] <UserItem>
gam course <CourseID> clear teachers|students
gam course <CourseID> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
gam course <CourseID> sync students [addonly|removeonly] <UserTypeEntity>
@@ -2888,15 +2912,17 @@ gam courses <CourseEntity> delete topic <CourseTopicIDEntity>
gam courses <CourseEntity> create|add teachers [makefirstteacherowner] <UserTypeEntity>
gam courses <CourseEntity> create|add students <UserTypeEntity>
gam courses <CourseEntity> delete|remove teachers|students <UserTypeEntity>
gam courses <CourseEntity> delete|remove teachers|students [owneraccess] <UserTypeEntity>
gam courses <CourseEntity> clear teachers|students
gam courses <CourseEntity> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
gam courses <CourseEntity> sync students [addonly|removeonly] <UserTypeEntity>
gam info course <CourseID> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
gam info course <CourseID> [owneraccess]
[owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
[formatjson]
gam info courses <CourseEntity> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
gam info courses <CourseEntity> [owneraccess]
[owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
[formatjson]
gam print courses [todrive <ToDriveAttribute>*]
@@ -3040,8 +3066,8 @@ gam print course-works [todrive <ToDriveAttribute>*]
# Classroom - Invitations
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
[adminaccess|asadmin] [csv|csvformat] [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]]
[adminaccess|asadmin]
[csv|csvformat] [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
@@ -3049,6 +3075,7 @@ gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttribute>*] [role all|owner|student|teacher]
[formatjson [quotechar <Character>]]
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
[role all|owner|student|teacher]
[formatjson]
@@ -3141,7 +3168,7 @@ gam print|show transferapps
gam create|add datatransfer|transfer <OldOwnerID> <DataTransferServiceList> <NewOwnerID>
[private|shared|all] [release_resources]
(<ParameterKey> <ParameterValue>)*
[wait <Integer> <Integer>]
gam info datatransfer|transfer <TransferID>
gam print datatransfers|transfers [todrive <ToDriveAttribute>*]
[olduser|oldowner <UserItem>] [newuser|newowner <UserItem>]
@@ -3362,16 +3389,16 @@ gam show peoplecontacts
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson]
gam info people <PeopleResourceNameEntity>
gam info people|peopleprofile <PeopleResourceNameEntity>
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson]
gam print people [todrive <ToDriveAttribute>*]
gam print people|peopleprofile [todrive <ToDriveAttribute>*]
[query <String>]
[mergesources <PeopleMergeSourceName>]
[coountsonly]
[allfields|(fields <PeopleFieldNameList>)] [showmetadata]
[formatjson [quotechar <Character>]]
gam show people
gam show people|peopleprofile
[query <String>]
[mergesources <PeopleMergeSourceName>]
[coountsonly]
@@ -3391,6 +3418,21 @@ gam [<UserTypeEntity>] show drivelabels
[basic|full] [languagecode <LanguageCode>]
[publishedonly [<Boolean>]] [minimumrole applier|editor|organizer|reader]
[formatjson] [adminaccess|asadmin]
`
gam [<UserTypeEntity>] create drivelabelpermission <DriveLabelNameEntity>
(user <UserItem>) | (group <GroupItem) | (audience <String>)
role applier|editor|organizer|reader
[formatjson] [adminaccess|asadmin]
gam [<UserTypeEntity>] delete drivelabelpermission <DriveLabelNameEntity>
(user <UserItem>) | (group <GroupItem) | (audience <String>)
[adminaccess|asadmin]
gam [<UserTypeEntity>] remove drivelabelpermission <DriveLabelPermissionNameEntity>
[adminaccess|asadmin]
gam [<UserTypeEntity>] print drivelabelpermissions <DriveLabelNameEntity> [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]] [adminaccess|asadmin]
gam [<UserTypeEntity>] show drivelabelpermissions <DriveLabelNameEntity>
[formatjson] [adminaccess|asadmin]
# Email Audit Monitor
@@ -4533,6 +4575,7 @@ gam create shareddrive <Name>
(<SharedDriveRestrictionsSubfieldName> <Boolean>)*
[hide|hidden <Boolean>] [ou|org|orgunit <OrgUnitItem>]
[errorretries <Integer>] [updateinitialdelay <Integer>] [updateretrydelay <Integer>]
[movetoorgunitdelay <Integer>]
[(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*) | returnidonly]
gam update shareddrive <SharedDriveEntity> [name <Name>]
[(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
@@ -4542,9 +4585,11 @@ gam delete shareddrive <SharedDriveEntity>
[adminaccess|asadmin] [allowitemdeletion]
gam hide shareddrive <SharedDriveEntity>
gam unhide shareddrive <SharedDriveEntity>
gam info shareddrive <SharedDriveEntity> [fields <SharedDriveFieldNameList>]
gam info shareddrive <SharedDriveEntity>
[fields <SharedDriveFieldNameList>]
[formatjson]
gam show shareddriveinfo <SharedDriveEntity> [fields <SharedDriveFieldNameList>]
gam show shareddriveinfo <SharedDriveEntity>
[fields <SharedDriveFieldNameList>]
[formatjson]
gam print shareddrives [todrive <ToDriveAttribute>*]
[teamdriveadminquery|query <QueryTeamDrive>]
@@ -4571,16 +4616,19 @@ gam <UserTypeEntity> create shareddrive <Name> adminaccess
(<SharedDriveRestrictionsSubfieldName> <Boolean>)*
[hide|hidden <Boolean>] [ou|org|orgunit <OrgUnitItem>]
[errorretries <Integer>] [updateinitialdelay <Integer>] [updateretrydelay <Integer>]
[movetoorgunitdelay <Integer>]
[(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*) | returnidonly]
gam update shareddrive <SharedDriveEntity> asadmin [name <Name>]
gam <UserTypeEntity> update shareddrive <SharedDriveEntity> adminaccess [name <Name>]
[(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
(<SharedDriveRestrictionsFieldName> <Boolean>)*
[hide|hidden <Boolean>] [ou|org|orgunit <OrgUnitItem>]
gam <UserTypeEntity> delete shareddrive <SharedDriveEntity>
adminaccess [allowitemdeletion]
gam <UserTypeEntity> info shareddrive <SharedDriveEntity> adminaccess [fields <SharedDriveFieldNameList>]
gam <UserTypeEntity> info shareddrive <SharedDriveEntity>
adminaccess [fields <SharedDriveFieldNameList>]
[formatjson]
gam <UserTypeEntity> show shareddriveinfo <SharedDriveEntity> adminaccess [fields <SharedDriveFieldNameList>]
gam <UserTypeEntity> show shareddriveinfo <SharedDriveEntity>
adminaccess [fields <SharedDriveFieldNameList>]
[formatjson]
gam <UserTypeEntity> print shareddrives [todrive <ToDriveAttribute>*]
adminaccess [teamdriveadminquery|query <QueryTeamDrive>]
@@ -4595,6 +4643,57 @@ gam <UserTypeEntity> show shareddrives
[fields <SharedDriveFieldNameList>]
[formatjson]
In these commands, you specify a user, administrator access is not used.
gam <UserTypeEntity> create shareddrive <Name>
[(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
(<SharedDriveRestrictionsSubfieldName> <Boolean>)*
[hide|hidden <Boolean>] [ou|org|orgunit <OrgUnitItem>]
[errorretries <Integer>] [updateinitialdelay <Integer>] [updateretrydelay <Integer>]
[movetoorgunitdelay <Integer>]
[(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*) | returnidonly]
gam <UserTypeEntity> update shareddrive <SharedDriveEntity> [name <Name>]
[(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
(<SharedDriveRestrictionsFieldName> <Boolean>)*
[hide|hidden <Boolean>] [ou|org|orgunit <OrgUnitItem>]
gam <UserTypeEntity> delete shareddrive <SharedDriveEntity>
[allowitemdeletion]
gam <UserTypeEntity> info shareddrive <SharedDriveEntity>
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>]] [formatjson]
gam <UserTypeEntity> show shareddriveinfo <SharedDriveEntity>
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>]] [formatjson]
gam <UserTypeEntity> print shareddrives [todrive <ToDriveAttribute>*]
[teamdriveadminquery|query <QueryTeamDrive>]
[matchname <RegularExpression>] [orgunit|org|ou <OrgUnitPath>]
(role|roles <SharedDriveACLRoleList>)*
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>]] [formatjson [quotechar <Character>]]
gam <UserTypeEntity> show shareddrives
[teamdriveadminquery|query <QueryTeamDrive>]
[matchname <RegularExpression>] [orgunit|org|ou <OrgUnitPath>]
(role|roles <SharedDriveACLRoleList>)*
[fields <SharedDriveFieldNameList>]
[guiroles [<Boolean>]] [formatjson]
<PermissionMatch> ::=
pm|permissionmatch [not]
[type|nottype <DriveFileACLType>] [role|notrole <DriveFileACLRole>]
[typelist|nottypelist <DriveFileACLTypeList>] [rolelist|notrolelist <DriveFileACLRoleList>]
[allowfilediscovery|withlink <Boolean>]
[emailaddress <RegularExpression>] [emailaddressList <EmailAddressList>]
[permissionidlist <PermissionIDList>
[name|displayname <String>]
[domain|notdomain <RegularExpression>] [domainlist|notdomainlist <DomainNameList>]
[expirationstart <Time>] [expirationend <Time>]
[deleted <Boolean>] [inherited <Boolean>] [permtype member|file]
em|endmatch
<PermissionMatchMode> ::=
pmm|permissionmatchmode or|and
<PermissionMatchAction> ::=
pma|permissionmatchaction process|skip
These commands are used to manage the ACLs on the Team Drives themselves, not the files/folders on the Team Drives.
<DrivePermissionsFieldName> ::=
@@ -4939,7 +5038,7 @@ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calenda
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[includerooms <Boolean>]
[excludedrafts <Boolean>] [format mbox|pst]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
[covereddata calllogs|textmessages|voicemails]
[region any|europe|us] [showdetails|returnidonly]
gam delete vaultexport|export <ExportItem> matter <MatterItem>
@@ -5352,10 +5451,11 @@ gam print users [todrive <ToDriveAttribute>*]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
[userview] [basic|full|allfields | <UserFieldName>* | fields <UserFieldNameList>]
[userview] [basic|full|allfields|(<UserFieldName>*|fields <UserFieldNameList>)]
[delimiter <Character>] [sortheaders [<Boolean>]] [scalarsfirst [<Boolean>]]
[formatjson [quotechar <Character>]] [quoteplusphonenumbers]
[issuspended <Boolean>] [aliasmatchpattern <RegularExpression>]
[showvalidcolumn] (addcsvdata <FieldName> <String>)*
[showitemcountonly]
Print fields for specified users.
@@ -5368,10 +5468,11 @@ gam print users [todrive <ToDriveAttribute>*] select <UserTypeEntity>
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
[userview] [basic|full|allfields | <UserFieldName>* | fields <UserFieldNameList>]
[userview] [basic|full|allfields|(<UserFieldName>*|fields <UserFieldNameList>)]
[delimiter <Character>] [sortheaders [<Boolean>]] [scalarsfirst [<Boolean>]]
[formatjson [quotechar <Character>]] [quoteplusphonenumbers]
[issuspended <Boolean>] [aliasmatchpattern <RegularExpression>]
[showvalidcolumn] (addcsvdata <FieldName> <String>)*
[showitemcountonly]
gam <UserTypeEntity> print users [todrive <ToDriveAttribute>*]
@@ -5382,10 +5483,11 @@ gam <UserTypeEntity> print users [todrive <ToDriveAttribute>*]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
[userview] [basic|full|allfields | <UserFieldName>* | fields <UserFieldNameList>]
[userview] [basic|full|allfields|(<UserFieldName>*|fields <UserFieldNameList>)]
[delimiter <Character>] [sortheaders [<Boolean>]] [scalarsfirst [<Boolean>]]
[formatjson [quotechar <Character>]] [quoteplusphonenumbers]
[issuspended <Boolean>] [aliasmatchpattern <RegularExpression>]
[showvalidcolumn] (addcsvdata <FieldName> <String>)*
[showitemcountonly]
The first column will always be primaryEmail; the remaining field names will be sorted if allfields, basic, full or sortheaders is specified;
@@ -5770,13 +5872,14 @@ gam <UserTypeEntity> create focustime
[declinemessage <String>]
[summary <String>]
(timerange <Time> <Time> [recurrence <String>])+
[timezone <String>]
gam <UserTypeEntity> create outofoffice
[declinemode none|all|new]
[declinemessage <String>]
[summary <String>]
(timerange <Time> <Time> [recurrence <String>])+
[timezone <String>]
gam <UserTypeEntity> create workinglocation
(home|
(custom <String>)|
@@ -5836,6 +5939,7 @@ gam <UserTypeEntity> print focustime|outofoffice|workinglocation
gam <UserTypeEntity> create chatspace
[type <ChatSpaceType>]
[restricted|(audience <String>)]
[externalusersrallowed <Boolean>]
[members <UserTypeEntity>]
[displayname <String>]
@@ -5844,10 +5948,11 @@ gam <UserTypeEntity> create chatspace
[<ChatContent>]
[formatjson|returnidonly]
gam <UserTypeEntity> update chatspace <ChatSpace>
[type space]
[displayname <String>]
[description <String>] [guidelines <String>]
[history <Boolean>]
[restricted|(audience <String>)]|
([displayname <String>]
[type space]
[description <String>] [guidelines|rules <String>]
[history <Boolean>])
[formatjson]
gam <UserTypeEntity> delete chatspace <ChatSpace>
@@ -5899,6 +6004,15 @@ gam <UserTypeEntity> print chatmessages [todrive <ToDriveAttribute>*] <ChatSpace
[showdeleted [<Boolean>]] [filter <String>]
[formatjson [quotechar <Character>]]
gam <UserTypeEntity> info chatevent name <ChatEvent>
[formatjson]
gam <UserTypeEntity> show chatevents <ChatSpace>
filter <String>
[formatjson]
gam <UserTypeEntity> print chatevents [todrive <ToDriveAttribute>*] <ChatSpace>
filter <String>
[formatjson [quotechar <Character>]]
# Users - Drive
<DriveFileOrderByFieldName> ::=
@@ -6099,6 +6213,11 @@ gam <UserTypeEntity> get document <DriveFileEntity>
[targetfolder <FilePath>] [targetname <FileName>]
[donotfollowshortcuts [<Boolean>]] [overwrite [<Boolean>]]
gam <UserTypeEntity> update docuument <DriveFileEntity>
((json [charset <Charset>] <SpreadsheetJSONUpdateRequest>) |
(json file <FileName> [charset <Charset>]))
[formatjson]
gam <UserTypeEntity> get drivefile <DriveFileEntity> [revision <DriveFileRevisionID>]
[(format <FileFormatList>)|(gsheet|csvsheet <SheetEntity>)] [exportsheetaspdf <String>]
[targetfolder <FilePath>] [targetname <FileName>|-]
@@ -6247,6 +6366,52 @@ gam print ownership <DriveFileID>|(drivefilename <DriveFileName>) [todrive <ToDr
(addcsvdata <FieldName> <String>)*
[formatjson [quotechar <Character>]]
<CommentsAuthorSubfieldName> ::=
author.displayname|
author.emailaddress|
author.me|
author.permissionid|
author.photolink
<CommentsRepliesSubfieldName> ::=
reply.action|
reply.author|
reply.author.<CommentsAuthorSubfieldName>|
reply.content|
reply.createddate|createdtime|
reply.deleted|
reply.htmlcontent|
reply.id|
reply.modifieddate|modifiedtime
<CommentsFieldName> ::=
action|
author|
content|
<CommentsAuthorSubfieldName>|
<CommentsRepliesSubfieldName>|
createddate|createdtime|
deleted|
htmlcontent|
id|
modifieddate|modifiedtime|
quotedfilecontent|
reply|replies|
resolved
<CommentsFieldNameList> ::= "<CommentsFieldName>(,<CommentsFieldName>)*"
gam <UserTypeEntity> show filecomments <DriveFileEntity>
[showdeleted] [start <Date>|<Time>]
[fields <CommentsFieldNameList>] [showphotolinks]
[countsonly]
[formatjson]
gam <UserTypeEntity> print filecomments <DriveFileEntity> [todrive <ToDriveAttribute>*]
[showdeleted] [start <Date>|<Time>]
[fields <CommentsFieldNameList>] [showphotolinks]
[countsonly]
(addcsvdata <FieldName> <String>)*
[formatjson [quotechar <Character>]]
<RevisionsFieldName> ::=
filesize|
id|
@@ -6506,9 +6671,10 @@ gam <UserTypeEntity> collect orphans
<DriveOwnersSubfieldName>|
parents|
<DriveParentsSubfieldName>|
permissionids|
permissiondetails|
permissions|
<DrivePermissionsSubfieldName>|
permissionids|
properties|
quotabytesused|quotaused|
resourcekey|
@@ -6545,19 +6711,6 @@ gam <UserTypeEntity> collect orphans
writerscanshare
<DriveFieldNameList> ::= "<DriveFieldName>(,<DriveFieldName>)*"
<PermissionMatch> ::=
permissionmatch|pm [not]
[type anyone|user|group|domain] [role|notrole <DriveFileACLRole>] [allowfilediscovery|withlink <Boolean>]
[emailaddress <RegularExpression>] [name|displayname <String>]
[domain|notdomain <RegularExpression>] [domainlist|notdomainlist <DomainNameList>]
[expirationstart <Time>] [expirationend <Time>]
[deleted <Boolean>] [inherited <Boolean>]
endmatch|em
<PermissionMatchMode> ::=
permissionmatchmode|pmm or|and
<PermissionMatchAction> ::=
permissionmatchaction|pma process|skip
gam <UserTypeEntity> show fileinfo <DriveFileEntity>
[returnidonly]
[filepath|fullpath] [pathdelimiter <Character>]
@@ -6584,7 +6737,7 @@ gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
[corpora <CorporaAttribute>]
[select <SharedDriveEntity>]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -6597,7 +6750,7 @@ gam <UserTypeEntity> show filecounts
[corpora <CorporaAttribute>]
[select <SharedDriveEntity>]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [`<showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -6629,7 +6782,7 @@ gam <UserTypeEntity> print filetree [todrive <ToDriveAttribute>*]
[select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
[depth <Number>]]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -6641,7 +6794,7 @@ gam <UserTypeEntity> show filetree
[select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
[depth <Number>]]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
@@ -6661,7 +6814,7 @@ gam <UserTypeEntity> print filelist [todrive <ToDriveAttribute>*]
[select <DriveFileEntity> [selectsubquery <QueryDriveFile>]
[(norecursion [<Boolean>])|(depth <Number>)] [showparent]]
[anyowner|(showownedby any|me|others)]
[showmimetype [not] <MimeTypeList>]
[showmimetype [not] <MimeTypeList>] [showmimetype category <MimeTypeNameList>] [mimetypeinquery [<Boolean>]]
[sizefield quotabytesused|size] [minimumfilesize <Integer>] [maximumfilesize <Integer>]
[filenamematchpattern <RegularExpression>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] [pmfilter] [oneitemperrow]
@@ -6847,6 +7000,10 @@ gam <UserTypeEntity> create labellist <LabelNameEntity>
[backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
[textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"]
[buildpath [<Boolean>]]
gam <UserTypeEntity> update labelid <LabelID> [name <String>]
[messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
[backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
[textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"]
gam <UserTypeEntity> update labelsettings <LabelName> [name <String>]
[messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
[backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
@@ -7074,6 +7231,15 @@ gam <UserTypeEntity> show signature|sig [compact|format|html]
gam <UserTypeEntity> print signature [compact]
[primary|default] [verifyonly] [todrive <ToDriveAttribute>*]
gam <UserTypeEntity> vacation <Boolean> subject <String>
[<VacationMessageContent> (replace <Tag> <UserReplacement>)*]
[html [<Boolean>]] [contactsonly [<Boolean>]] [domainonly [<Boolean>]]
[start|startdate <Date>|Started] [end|enddate <Date>|NotSpecified]
gam <UserTypeEntity> show vacation [compact|format|html] [enabledonly]
gam <UserTypeEntity> print vacation [compact] [enabledonly] [todrive <ToDriveAttribute>*]
# Users - Gmail - S/MIME
gam <UserTypeEntity> create|add smime file <FileName> [password <Password>]
[sendas|sendasemail <EmailAddress>] [default]
gam <UserTypeEntity> update smime default
@@ -7085,12 +7251,41 @@ gam <UserTypeEntity> show smimes
gam <UserTypeEntity> print smimes [todrive <ToDriveAttribute>*]
[primary|default|(sendas|sendasemail <EmailAddress>)]
gam <UserTypeEntity> vacation <Boolean> subject <String>
[<VacationMessageContent> (replace <Tag> <UserReplacement>)*]
[html [<Boolean>]] [contactsonly [<Boolean>]] [domainonly [<Boolean>]]
[start|startdate <Date>|Started] [end|enddate <Date>|NotSpecified]
gam <UserTypeEntity> show vacation [compact|format|html] [enabledonly]
gam <UserTypeEntity> print vacation [compact] [enabledonly] [todrive <ToDriveAttribute>*]
# Users - Gmail Client Side Encryption
gam <UserTypeEntity> create cseidentity
(primarykeypairid <KeyPairID>) | (signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>)
[kpemail <EmailAddress>]
[formatjson]
gam <UserTypeEntity> update cseidentity
(primarykeypairid <KeyPairID>) | (signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>)
[kpemail <EmailAddress>]
[formatjson]
gam <UserTypeEntity> delete cseidentity [kpemail <EmailAddress>]
gam <UserTypeEntity> info cseidentity [kpemail <EmailAddress>]
[formatjson]
gam <UserTypeEntity> show cseidentities
[formatjson]
gam <UserTypeEntity> print cseidentities [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]]
gam <UserTypeEntity> create csekeypair
[incertdir <FilePath>] [inkeydir <FilePath>]
[addidentity [<Boolean>]] [kpemail <EmailAddress>]
[showpem] [showkaclsdata] [formatjson|returnidonly]
gam <UserTypeEntity> disable csekeypair <KeyPairID>
[showpem] [showkaclsdata] [formatjson]
gam <UserTypeEntity> enable csekeypair <KeyPairID>
[showpem] [showkaclsdata] [formatjson]
gam <UserTypeEntity> obliterate csekeypair <KeyPairID>
gam <UserTypeEntity> info csekeypair <KeyPairID>
[showpem] [showkaclsdata] [formatjson]
gam <UserTypeEntity> show csekeypairs
[showpem] [showkaclsdata] [formatjson]
gam <UserTypeEntity> print csekeypairs [todrive <ToDriveAttribute>*]
[showpem] [showkaclsdata] [formatjson [quotechar <Character>]]
# Users - Gmail - Settings
@@ -7196,10 +7391,12 @@ gam <UserTypeEntity> info note <NotesNameEntity>
gam <UserTypeEntity> show notes
[fields <NotesFieldList>] [filter <String>]
[role owner|writer]
[countsonly]
[compact|formatjson]
gam <UserTypeEntity> print notes [todrive <ToDriveAttribute>*]
[fields <NotesFieldList>] [filter <String>]
[role owner|writer]
[countsonly]
[formatjson [quotechar <Character>]]
gam <UserTypeEntity> get noteattachments <NotesNameEntity>

View File

@@ -2,6 +2,478 @@
Merged GAM-Team version
6.72.08
Added option `countsonly` to `gam <UserTypeEntity> print|show notes` that displays
the number of notes a user owns and the number of notes of user can edit.
6.72.07
Updated commands that send emails to not downshift `'First Last<firstlast@domain.com>'` to `'first last<firstlast@domain.com>'`.
6.72.06
Updated the following commands to properly handle emailaddress lists containing addresses of the form: `'First Last<firstlast@domain.com>'`.
```
gam <UserTypeEntity> sendemail recipient|to <RecipientEntity> [cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
gam create|update user ... notify <EmailAddressList>
```
6.72.05
Cleaned up code for all commands that display Chat objects.
6.72.04
Added commands to display Chat events.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Chat#display-chat-events
6.72.03
Fixed bug in `gam <UserTypeEntity> create chatspace` that caused a trap.
6.72.02
Updated `gam delete admin <RoleAssignmentId>` to handle the following error that
occurs when `<RoleAssignmentId>` references a user that has been deleted.
```
ERROR: 404: resourceNotFound - Does not exist
```
6.72.01
Improved commands to display drive file comments.
6.72.00
Added commands to display drive file comments.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Comments
6.71.18
Updated `<CrOSFieldName>` to include `cpuinfo` and `backlightinfo`.
6.71.17
Added `depth` column to output of `gam <UserTypeEntity> print diskusage <DriveFileEntity>` that can
be used to filter the depth of the folders displayed. Depth `-1` is the top level folder, depth `0`
are its immediate children, depth `2` are the children of depth `1` and so forth.
```
gam config csv_output_row_filter "depth:count<1" user organizer@domain.com print diskusage teamdriveid <TeamDriveID>
```
6.71.16
Updated `gam <UserTypeEntity> create|update sendas <EmailAddress> ... replyto <EmailAddress>`
to allow uppercase letters in `sendas <EmailAddress>` and `replyto <EmailAddress>`.
6.71.15
Updated `gam create project` to handle the following error:
```
ERROR: 403: permissionDenied - Authentication error: 7; Error Details: User not allowed to access GCP services.
```
This error occurs when the Google Workspace admin or GCP project manager email address used in the command
is in an OU where Google Cloud Platform is not enabled in Apps/Additional Google services.
6.71.14
Added a command to update a Gmail label's settings by specifying it's ID rather than it's name.
```
gam <UserTypeEntity> update labelid <LabelID> [name <String>]
[messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
[backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
[textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"]
```
6.71.13
Updated `<UserMultiAttribute>.location.buildingid <String>` to allow non-validated building IDs
by specifying `nv:` at the beginning of `<String>`; e.g., `nv:Building X' sets the building ID to `Building X`.
6.71.12
Added option `showmimetype category <MimeTypeNameList>` to `gam <UserTypeEntity> print|show filecounts|filelist|filetree`
```
<MimeTypeName> ::= application|audio|font|image|message|model|multipart|text|video
<MimeTypeNameList> ::= "<MimeTypeName>(,<MimeTypeName>)*"
gam user user@domain.com print filelist fields id,name,mimetype showmimetype prefixes audio,video
```
Fix bug in `gam <UserTypeEntity> info|show sheet <DriveFileEntity>` that caused a trap.
6.71.11
Added option `addcsvdata <FieldName> <String>` to `gam print cros` that adds
additional columns of data to the CSV file output. Typically, you would read CSV file of device IDs/serial numbers
to generate a CSV file of results and copy data from the input CSV to the outout CSV.
6.71.10
Reverted change made in 6.71.09 to `gam <UserTypeEntity> print filelist` when `showmimetype` and `filepath|fullpath`
were both specified. The change improved the performance when `showmimetype` selected a small number of files;
the information for just those files was downloaded and then additional API calls were made to construct the file paths.
However, if a large number of files were selected, the additional APIs calls decreased performance.
Added option `mimetypeinquery` can be used when you expect the query to return a small number of files
relative to the total number of files.
6.71.09
Improved the performance of `gam <UserTypeEntity> print filelist` when `showmimetype` and `filepath|fullpath`
are both specified.
6.71.08
Added option `oneitemperrow` to 'gam print admins|adminroles` to have each of a
roles privileges displayed on a separate row with all of the other admin/role fields.
This produces a CSV file that can be used in subsequent commands without further script processing.
6.71.07
Added command to upload changes to Google Docs.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Manage#upload-changes-to-google-documents
6.71.06
Added additional error handling to Gmail Client Side Encryption commands.
Added license product Education Endpoint Management
* ProductID - 101049
Added license SKU Endpoint Education Upgrade
* ProductID - 101049
* SKUID - 1010490001 | eeu
6.71.05
Fixed a bug introduced in 6.71.00 that caused a trap in `gam <UserTypeEntity> print filelist`.
Added option `tdfrom <EmailAddress>` to `<ToDriveAttribute>` that causes GAM to use `<EmailAddress>` as the from address
in all emails sent. By default, the from address is the Google Workspace Admin in `gam oauth info`.o
6.71.04
Updated `gam <UserTypeEntity> create|update cseidentity` to accept either of the following key pair options:
* `primarykeypairid <KeyPairID>` - The configuration of a CSE identity that uses the same key pair for signing and encryption.
* `signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>` - The configuration of a CSE identity that uses different key pairs for signing and encryption.
Updated CSV output row sorting to avoid a trap that occurred when a row was missing one of the sort fields.
6.71.03
Added option `tdalert <EmailAddress>` to `<ToDriveAttribute>`. When a todrive file is created or updated,
GAM will send notification emails to all `tdalert <EmailAddress>` users if `tdnotify` is true.
`<EmailAddress>` must be valid within your Google Workspace.
6.71.02
Added additional error handling to Gmail Client Side Encryption commands.
6.71.01
Fixed bug in `gam audit monitor create` that caused a trap.
6.71.00
Added `csv_output_sort_headers` string list variable to `gam.cfg` that causes GAM to sort CSV output
rows by the column headers specified in the variable. The column headers are case insensitive and
if column header does not appear in the CSV output, it is ignored.
Added `sortheaders <StringList>` to `redirect csv <FileName>` that has the same effect as above.
The sort keys specified in `redirect csv ... sortheaders <StringList>` take precedence over the values from `gam.cfg`.
Added option `tdsubject <String>` to `<ToDriveAttribute>` that causes GAM to use `<String>` as the subject
in all emails sent. In `<String>`, `#file#` will, be replaced by the file title and `#sheet#` will be replaced
by the sheet/tab title. By default, the subject is the file title.
6.70.09
Added additional error handling to Gmail Client Side Encryption commands.
Added options `showpem` and `showkaclsdata` to all Gmail CSE commands that process/display
CSE key pairs. By default, the `pem` and `kaclsdata` fields will not be displayed unless
the corresponding `show` option is specified.
6.70.08
Fixed bug in `gam <UserTypeEntity> create cseidentity <KeyPairID>` that caused an error.
6.70.07
Updated user instructions in `gam oauth create` and `gam <UserTypeEntity> update serviceaccount`
and changed `s` from selecting all scopes to selecting default scopes.
6.70.06
Updated `gam info users <UserTypeEntity>` to not include group tree infornation unless option `grouptree` is specified.
6.70.05
Added commands to create|delete|display Drive Label permissions.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Labels
6.70.04
Added option `showvalidcolumn` to `gam print users` that can be used to identify whether
users are defined in the domain. Typically, you would read CSV file of email addresses
to verify as domain members.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#verify-domain-membership
Added option `addcsvdata <FieldName> <String>` to `gam print users` that adds
additional columns of data to the CSV file output. Typically, you would read CSV file of email addresses
to generate a CSV file of results and copy data from the input CSV to the outout CSV.
6.70.03
Renamed license product DuetAI to Gemini
* ProductID - 101047
Renamed license SKU DuetAI for Google Workspace to Gemini Enterprise
* ProductID - 101047
* SKUID - 1010470001 | geminient | duetai
Added support for license SKU Gemini Business
* ProductID - 101047
* SKUID - 1010470003 | geminibiz
6.70.02
In 6.69.00, GAM starting using course owner access when using `copyfrom` in `gam create|update course`
regardless of the value of `gam.cfg/use_course_owner_access`. This prevents copying from courses
with a deleted user. GAM now uses the value of `gam.cfg/use_course_owner_access` when `copyfrom` is used.
6.70.01
Added `gmail_cse_incert_dir` and `gmail_cse_inkey_dir` path variables to `gam.cfg` that provide
default values for the `incertdir <FilePath>` and `inkeydir <FilePath>` options in `gam <UserTypeEntity> create csekeypair`.
6.70.00
Added support for Gmail Client Side Encryption.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-CSE
This is an initial, minimally tested release; proceed with care and report all issues.
6.69.00
Added `use_course_owner_access` Boolean variable to `gam.cfg` that controls how GAM gets
classroom member information and removes students/teachers. Client/admin access does not provide
complete information about non-domain students/teachers.
* `False` - Use client/admin access; this is the default. Use if you don't have non-domain members in your courses.
* `True` - Use service account access as the classroom owner. An extra API call is required per course to authenticate the owner; this will affect performance
Added the following command which must be used to delete classroom invitations for non-domain students/teachers.
```
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
```
You can obtain the classroom invitation IDs with these commands:
```
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
[role all|owner|student|teacher] [formatjson]
gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
[role all|owner|student|teacher] [formatjson [quotechar <Character>]]
```
6.68.08
Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
ACLs with multiple permission details on separate rows for each basic permission/permission detail combination.
This case occurs when a member of a Shared Drive has access to a file and also has explicitly granted access to the same file.
Added `permtype member|file` to `<PermissionMatch>` that allows determining whether an ACL on a Shared Drive file was
derived from membership or explicitly granted.
6.68.07
Updated `gam info user ... locations formatjson` to include the `buildingName` field in the
`locations` entries. If `gam.cfg` contains `quick_info_user = true` or the `quick` option
is included on the command line, add the option `buildingnames` to the command line.
6.68.06
Fixed bug in `gam <UserTypeEntity> copy drivefile <DriveFileID> ... mergewithparent` that incorrectly named
the copied file with the name of the parent folder.
Updated `gam <UserTypeEntity> copy|move drivefile` to avoid copying/moving the same file twice.
6.68.05
Updated `gam print groups ... ciallfields|(cifields <CIGroupFieldNameList>)` to account for an
API shortcoming that failed to get all of the Cloud Identity fields.
6.68.04
Added option `skiprows <Integer>` to `gam csv|loop` that causes GAM to skip processing the first `<Integer>` filtered rows.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Bulk-Processing#csv-files
6.68.03
Fixed bug in `gam <UserTypeEntity> create drivefileacl` that caused a trap.
6.68.02
Upgraded to Python 3.12.2 where possible.
Added options `restricted|(audience <String>)` to `gam <UserTypeEntity> create|update chatspace` that
sets the access options for the chat space. These options are in Developer Preview and will not be generally available.
6.68.01
Fixed `<PermissionMatch>` bug for real.
6.68.00
Fixed `<PermissionMatch>` bug introduced in 6.67.35 that caused a command error like the following or would
not properly match `type|nottype <DriveFileACLType>` and `role|notrole <DriveFileACLRole>`.
```
ERROR: permission attribute allowfilediscovery/withlink not allowed with type {'a', 'y', 'e', 'o', 'n'}
```
My sincere apologies.
6.67.39
Added option `wait <Integer> <Integer>` to `gam create datatransfer` that causes GAM to wait
for the transfer to complete. The first `<Integer>` must be in the range 5-60 and is the number
of seconds between checks to see if the transfer has completed. The second `<Integer>` is the maximum
number of checks to perform. By default, GAM does not wait for the transfer to complete.
6.67.38
Added option `tdnotify [<Boolean>]` to `<ToDriveAttribute>` that causes GAM to send notification
emails to all `tdshare <EmailAddress>` users when the file is uploaded/updated.
6.67.37
Fixed bug in `gam <UserTypeEntity> show messages ... showattachments` to avoid a trap when `text/plain` attachments
in character sets other than `UTF-8` are displayed.
6.67.36
Updated `gam batch <BatchContent>` and `gam tbatch <BatchContent>` commands to accept lines with the following form:
```
sleep <Integer>
```
Batch processing will suspend for `<Integer>` seconds before the next command line is processed.
6.67.35
Added the following options to `<PermissionMatch>` that allow more powerful matching.
```
nottype <DriveFileACLType>
typelist <DriveFileACLTypeList>
nottypelist <DriveFileACLTypeList>
rolelist <DriveFileACLRoleList>
notrolelist <DriveFileACLRoleList>
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Permission-Matches#define-a-match
6.67.34
Added option `movetoorgunitdelay <Integer>` to `gam <UserTypeEntity> create shareddrive <Name> ... ou|org|orgunit <OrgUnitItem>`.
GAM creates the Shared Drive, verifies that it has been created and then tries to move it to `<OrgUnitItem>`. Google seems to
require a delay or the following error is generated.
```
ERROR: 409: 409 - The operation was aborted.
```
`movetoorgunitdelay` defaults to 20 seconds which seems to work; `<Integer>` can range from 0 to 60.
6.67.33
Upgraded to OpenSSL 3.2.1 where possible.
Fixed bug in `gam <UserTypeEntity> print shareddrives` where `role` was improperly displayed as `fileOrganizer`
rather than `writer`.
Added option `guiroles [<Boolean>]` to `gam <UserTypeEntity> info|print|show shareddrive` that maps
the Drive API role names to the Google Drive GUI role names.
```
API: GUI
commenter: Commenter
fileOrganizer: Content manager
organizer: Manager
reader: Viewer
writer: Contributor
```
6.67.32
Updated `<ToDriveAttribute>` to allow multiple `tdshare <EmailAddress> commenter|reader|writer` options.
Fixed bug in `gam <UserTypeEntity> print shareddrives` where `role` was improperly displayed as `unknown`
rather than `reader` when `Allow viewers and commenters to download, print, and copy files` was unchecked for the Shared Drive.
6.67.31
Updated `gam <UserTypeEntity> claim|transfer ownership <DriveFileEntity>` to properly
handle the case where `<DriveFileEntity>` referencess a Drive shortcut.
6.67.30
Fixed bug where the `fullpath` option in various commands was not converting the generic shared drive name `Drive` to the drive's actual name.
6.67.29
Added optional argument `owneraccess` to `gam courses <CourseEntity> remove teachers|students [owneracccess] <UserTypeEntity` and
`gam course <CourseID> remove teacher|student [owneraccess] <EmailAddress>` in order to test a possible API change.
Updated code to avoid a trap when `gam config auto_batch_min 1 csv file.csv gam ...` was entered.
The `config auto_batch_min 1` is not appropriate in this context and will be ignored.
6.67.28
Improved handling of `Bad Request` error in `gam <UserTypeEntity> collect orphans`.
6.67.27
Updated `gam <UserTypeEntity> collect orphans` to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```
6.67.26
Fixed bug in `gam print vaultexports ... formatjson` that caused a trap.
6.67.25
Added option `owneraccess` to `gam info courses <CourseEntity>` and `gam info course <CourseID>` in order
to test a possible API change.
6.67.24
Fixed bug that caused HTML password notification email messages to be displayed in raw form.
6.67.23
Use local copy of `googleapiclient` to remove static discovery documents to improve performance.
6.67.22
Added `permissionidlist <PermissionIDList>` to `<PermissionMatch>` that allows matching any permission ID in a list.
Added option `exportlinkeddrivefiles <Boolean>` to `gam create vaultexport` that is used with `corpus mail`.
6.67.21
Updated `gam remove aliases <EmailAddress> user|group <EmailAddressEntity>` to give a more informative
error message when the target/alias combination does not exist.
```
Old: User: testsimple@domain.com, User Alias: tsalias@domain.com, Remove Failed: Invalid Input: resource_id
New: User: testsimple@domain.com, User Alias: tsalias@domain.com, Remove Failed: Does not exist
```
6.67.20
Added option `onelicenseperrow|onelicenceperrow` to `gam print users ... licenses` that causes GAM to print

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -77,6 +77,7 @@ class GamAction():
MOVE_MERGE = 'movm'
NOACTION = 'noac'
NOACTION_PREVIEW = 'noap'
OBLITERATE = 'obli'
PERFORM = 'perf'
PRE_PROVISIONED_DISABLE ='ppdi'
PRE_PROVISIONED_REENABLE ='ppre'
@@ -193,6 +194,7 @@ class GamAction():
MOVE_MERGE: ['Moved(Merge)', 'Move(Merge)'],
NOACTION: ['No Action', 'No Action'],
NOACTION_PREVIEW: ['No Action (Preview)', 'No Action (Preview)'],
OBLITERATE: ['Obliterated', 'Obliterate'],
PERFORM: ['Action Performed', 'Perform Action'],
PRE_PROVISIONED_DISABLE: ['PreProvisioned Disabled', 'PreProvisioned Disable'],
PRE_PROVISIONED_REENABLE: ['PreProvisioned Reenabled', 'PreProvisioned Reenable'],

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -27,6 +27,7 @@ ANALYTICS_ADMIN = 'analyticsadmin'
CALENDAR = 'calendar'
CBCM = 'cbcm'
CHAT = 'chat'
CHAT_EVENTS = 'chatevents'
CHAT_MEMBERSHIPS = 'chatmemberships'
CHAT_MESSAGES = 'chatmessages'
CHAT_SPACES = 'chatspaces'
@@ -190,6 +191,7 @@ _INFO = {
CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True},
CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
CHAT_MESSAGES: {'name': 'Chat API - Messages', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
CHAT_SPACES: {'name': 'Chat API - Spaces', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
@@ -539,6 +541,10 @@ _SVCACCT_SCOPES = [
'api': CLASSROOM,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/classroom.profile.emails'},
{'name': 'Classroom API - Profile Photos',
'api': CLASSROOM,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/classroom.profile.photos'},
{'name': 'Classroom API - Rosters',
'api': CLASSROOM,
'subscopes': READONLY,
@@ -638,6 +644,7 @@ _SVCACCT_SCOPES = [
{'name': 'Youtube API - read only',
'api': YOUTUBE,
'subscopes': [],
'offByDefault': True,
'scope': 'https://www.googleapis.com/auth/youtube.readonly'},
]
@@ -653,10 +660,12 @@ _SVCACCT_SPECIAL_SCOPES = [
{'name': 'Gmail API - Full Access - read only',
'api': GMAIL,
'subscopes': [],
'offByDefault': True,
'scope': 'https://www.googleapis.com/auth/gmail.readonly'},
{'name': 'Gmail API - Send Messages - including todrive',
'api': GMAIL,
'subscopes': [],
'offByDefault': True,
'scope': GMAIL_SEND_SCOPE},
{'name': 'Sheets API - todrive',
'api': SHEETSTD,

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -131,6 +131,8 @@ CSV_OUTPUT_ROW_DROP_FILTER = 'csv_output_row_drop_filter'
CSV_OUTPUT_ROW_DROP_FILTER_MODE = 'csv_output_row_drop_filter_mode'
# Limit number of output rows
CSV_OUTPUT_ROW_LIMIT = 'csv_output_row_limit'
# Output sort headers
CSV_OUTPUT_SORT_HEADERS = 'csv_output_sort_headers'
# Column header subfield name delimiter in CSV output file
CSV_OUTPUT_SUBFIELD_DELIMITER = 'csv_output_subfield_delimiter'
# Add timestamp column to CSV output file
@@ -161,6 +163,10 @@ ENABLE_GCLOUD_REAUTH = 'enable_gcloud_reauth'
EVENT_MAX_RESULTS = 'event_max_results'
# Path to extra_args.txt
EXTRA_ARGS = 'extra_args'
# Gmail CSE certificates directory
GMAIL_CSE_INCERT_DIR = 'gmail_cse_incert_dir'
# Gmail CSE KACL wrapped key files
GMAIL_CSE_INKEY_DIR = 'gmail_cse_inkey_dir'
# When processing items in batches, how many seconds should GAM wait between batches
INTER_BATCH_WAIT = 'inter_batch_wait'
# When retrieving lists of licenses from API, how many should be retrieved in each chunk
@@ -284,6 +290,8 @@ TODRIVE_UPLOAD_NODATA = 'todrive_upload_nodata'
TODRIVE_USER = 'todrive_user'
# Update CrOS org unit with orgUnitId
UPDATE_CROS_OU_WITH_ID = 'update_cros_ou_with_id'
# Use course owner for course access
USE_COURSE_OWNER_ACCESS = 'use_course_owner_access'
# Use Project ID as Project Name and App Name
USE_PROJECTID_AS_NAME = 'use_projectid_as_name'
# When retrieving lists of Users from API, how many should be retrieved in each chunk
@@ -344,6 +352,7 @@ Defaults = {
CSV_OUTPUT_ROW_DROP_FILTER: '',
CSV_OUTPUT_ROW_DROP_FILTER_MODE: 'anymatch',
CSV_OUTPUT_ROW_LIMIT: '0',
CSV_OUTPUT_SORT_HEADERS: '',
CSV_OUTPUT_SUBFIELD_DELIMITER: '.',
CSV_OUTPUT_TIMESTAMP_COLUMN: '',
CSV_OUTPUT_USERS_AUDIT: FALSE,
@@ -359,6 +368,8 @@ Defaults = {
ENABLE_GCLOUD_REAUTH: FALSE,
EVENT_MAX_RESULTS: '250',
EXTRA_ARGS: '',
GMAIL_CSE_INCERT_DIR: '',
GMAIL_CSE_INKEY_DIR: '',
INTER_BATCH_WAIT: '0',
LICENSE_MAX_RESULTS: '100',
LICENSE_SKUS: '',
@@ -420,6 +431,7 @@ Defaults = {
TODRIVE_UPLOAD_NODATA: TRUE,
TODRIVE_USER: '',
UPDATE_CROS_OU_WITH_ID: FALSE,
USE_COURSE_OWNER_ACCESS: FALSE,
USE_PROJECTID_AS_NAME: FALSE,
USER_MAX_RESULTS: '500',
USER_SERVICE_ACCOUNT_ACCESS_ONLY: FALSE,
@@ -445,6 +457,7 @@ TYPE_LOCALE = 'locl'
TYPE_PASSWORD = 'pass'
TYPE_ROWFILTER = 'rowf'
TYPE_STRING = 'stri'
TYPE_STRINGLIST = 'strl'
TYPE_TIMEZONE = 'tmzn'
VAR_TYPE = 'type'
@@ -499,6 +512,7 @@ VAR_INFO = {
CSV_OUTPUT_ROW_DROP_FILTER: {VAR_TYPE: TYPE_ROWFILTER},
CSV_OUTPUT_ROW_DROP_FILTER_MODE: {VAR_TYPE: TYPE_CHOICE, VAR_CHOICES: {'allmatch': True, 'anymatch': False}},
CSV_OUTPUT_ROW_LIMIT: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (0, None)},
CSV_OUTPUT_SORT_HEADERS: {VAR_TYPE: TYPE_STRINGLIST},
CSV_OUTPUT_SUBFIELD_DELIMITER: {VAR_TYPE: TYPE_CHARACTER},
CSV_OUTPUT_TIMESTAMP_COLUMN: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
CSV_OUTPUT_USERS_AUDIT: {VAR_TYPE: TYPE_BOOLEAN},
@@ -514,6 +528,8 @@ VAR_INFO = {
ENABLE_GCLOUD_REAUTH: {VAR_TYPE: TYPE_BOOLEAN},
EVENT_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 2500)},
EXTRA_ARGS: {VAR_TYPE: TYPE_FILE, VAR_SIGFILE: FN_EXTRA_ARGS_TXT, VAR_SFFT: ('', FN_EXTRA_ARGS_TXT), VAR_ACCESS: os.R_OK},
GMAIL_CSE_INCERT_DIR: {VAR_TYPE: TYPE_DIRECTORY},
GMAIL_CSE_INKEY_DIR: {VAR_TYPE: TYPE_DIRECTORY},
INTER_BATCH_WAIT: {VAR_TYPE: TYPE_FLOAT, VAR_LIMITS: (0.0, 60.0)},
LICENSE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (10, 1000)},
LICENSE_SKUS: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
@@ -575,6 +591,7 @@ VAR_INFO = {
TODRIVE_UPLOAD_NODATA: {VAR_TYPE: TYPE_BOOLEAN},
TODRIVE_USER: {VAR_TYPE: TYPE_STRING, VAR_LIMITS: (0, None)},
UPDATE_CROS_OU_WITH_ID: {VAR_TYPE: TYPE_BOOLEAN},
USE_COURSE_OWNER_ACCESS: {VAR_TYPE: TYPE_BOOLEAN},
USE_PROJECTID_AS_NAME: {VAR_TYPE: TYPE_BOOLEAN},
USER_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 500)},
USER_SERVICE_ACCOUNT_ACCESS_ONLY: {VAR_TYPE: TYPE_BOOLEAN},

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -379,6 +379,7 @@ class GamCLArgs():
PRINT_CMD = 'print'
SET_CMD = 'set'
CLEAR_CMD = 'clear'
SLEEP_CMD = 'sleep'
# Command line batch/csv/loop/tbatch keywords
BATCH_CMD = 'batch'
CSV_CMD = 'csv'
@@ -462,6 +463,8 @@ class GamCLArgs():
ARG_CHANNELSKU = 'channelsku'
ARG_CHANNELSKUS = 'channelskus'
ARG_CHAT = 'chat'
ARG_CHATEVENT = 'chatevent'
ARG_CHATEVENTS = 'chatevents'
ARG_CHATMEMBER = 'chatmember'
ARG_CHATMEMBERS = 'chatmembers'
ARG_CHATMESSAGE = 'chatmessage'
@@ -519,6 +522,10 @@ class GamCLArgs():
ARG_CROSES = 'croses'
ARG_CROSACTIVITY = 'crosactivity'
ARG_CROSTELEMETRY = 'crostelemetry'
ARG_CSEIDENTITY = 'cseidentity'
ARG_CSEIDENTITIES = 'cseidentities'
ARG_CSEKEYPAIR = 'csekeypair'
ARG_CSEKEYPAIRS = 'csekeypairs'
ARG_CURRENTPROJECTID = 'currentprojectid'
ARG_CUSTOMER = 'customer'
ARG_DATASTUDIOASSET = 'datastudioasset'
@@ -562,6 +569,8 @@ class GamCLArgs():
ARG_DRIVEFOLDERPATH = 'drivefolderpath'
ARG_DRIVELABEL = 'drivelabel'
ARG_DRIVELABELS = 'drivelabels'
ARG_DRIVELABELPERMISSION = 'drivelabelpermission'
ARG_DRIVELABELPERMISSIONS = 'drivelabelpermissions'
ARG_DRIVESETTINGS = 'drivesettings'
ARG_DRIVETRASH = 'drivetrash'
ARG_EMPTYDRIVEFOLDERS = 'emptydrivefolders'
@@ -571,6 +580,8 @@ class GamCLArgs():
ARG_EXPORTS = 'exports'
ARG_FEATURE = 'feature'
ARG_FEATURES = 'features'
ARG_FILECOMMENT = 'filecomment'
ARG_FILECOMMENTS = 'filecomments'
ARG_FILECOUNT = 'filecount'
ARG_FILECOUNTS = 'filecounts'
ARG_FILEDRIVELABEL = 'filedrivelabel'
@@ -809,6 +820,8 @@ class GamCLArgs():
OB_CHANNEL_CUSTOMER_ID = 'ChannelCustomerID'
OB_CHARACTER = 'Character'
OB_CHAR_SET = 'CharacterSet'
OG_CHAT_ATTACHMENT = 'ChatAttachment'
OB_CHAT_EVENT = 'ChatEvent'
OB_CHAT_MEMBER = 'ChatMember'
OB_CHAT_MESSAGE = 'ChatMessage'
OB_CHAT_MESSAGE_ID = 'ChatMessageID'
@@ -845,6 +858,7 @@ class GamCLArgs():
OB_COURSE_WORK_STATE_LIST = "CourseWorkStateList"
OB_CROS_DEVICE_ENTITY = 'CrOSDeviceEntity'
OB_CROS_ENTITY = 'CrOSEntity'
OB_CSE_KEYPAIR_ID = 'CSEKeyPairID'
OB_CUSTOMER_ID = 'CustomerID'
OB_CUSTOMER_AUTH_TOKEN = 'CustomerAuthToken'
OB_DEVICE_FILE_ENTITY = 'DeviceFileEntity'
@@ -871,6 +885,7 @@ class GamCLArgs():
OB_DRIVE_FOLDER_PATH = 'DriveFolderPath'
OB_DRIVE_LABEL_ID = 'DriveLabelID'
OB_DRIVE_LABEL_NAME = 'DriveLabelName'
OB_DRIVE_LABEL_PERMISSION_NAME = 'DriveLabelPermissionName'
OB_DRIVE_LABEL_FIELD_ID = 'DriveLabelFieldID'
OB_DRIVE_LABEL_SELECTION_ID_LIST = 'DriveLabelSelectionIDList'
OB_EMAIL_ADDRESS = 'EmailAddress'
@@ -930,6 +945,9 @@ class GamCLArgs():
OB_ORGUNIT_PATH = 'OrgUnitPath'
OB_PARAMETER_VALUE = 'ParameterValue'
OB_PASSWORD = 'Password'
OB_PERMISSION_ID_LIST = 'PermissionIDList'
OB_PERMISSION_ROLE_LIST = 'PermissionRoleList'
OB_PERMISSION_TYPE_LIST = 'PermissionTypeList'
OB_PHOTO_FILENAME_PATTERN = 'FilenameNamePattern'
OB_PRINTER_ID = 'PrinterID'
OB_PRIVILEGE_LIST = 'PrivilegeList'

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -84,6 +84,7 @@ class GamEntity():
CHANNEL_PRODUCT = 'chpr'
CHANNEL_SKU = 'chsk'
CHAT_BOT = 'chbo'
CHAT_EVENT = 'chev'
CHAT_MANAGER_USER = 'chgu'
CHAT_MEMBER = 'chme'
CHAT_MEMBER_GROUP = 'chmg'
@@ -150,12 +151,14 @@ class GamEntity():
CRITERIA = 'crit'
CROS_DEVICE = 'cros'
CROS_SERIAL_NUMBER = 'crsn'
CSE_IDENTITY = 'csei'
CSE_KEYPAIR = 'csek'
CUSTOMER_DOMAIN = 'cudo'
CUSTOMER_ID = 'cuid'
DATE = 'date'
DEFAULT_LANGUAGE = 'dfla'
DELEGATE = 'dele'
DELETED_USER = 'del'
DELETED_USER = 'delu'
DELIVERY = 'deli'
DEVICE = 'devi'
DEVICE_FILE = 'devf'
@@ -163,7 +166,7 @@ class GamEntity():
DEVICE_USER = 'devu'
DEVICE_USER_CLIENT_STATE = 'ducs'
DISCOVERY_JSON_FILE = 'disc'
DOCUMENT = 'doc '
DOCUMENT = 'docu'
DOMAIN = 'doma'
DOMAIN_ALIAS = 'doal'
DOMAIN_CONTACT = 'doco'
@@ -171,6 +174,7 @@ class GamEntity():
DOMAIN_PROFILE = 'dopr'
DRIVE_DISK_USAGE = 'drdu'
DRIVE_FILE = 'dfil'
DRIVE_FILE_COMMENT = 'filc'
DRIVE_FILE_ID = 'fili'
DRIVE_FILE_NAME = 'filn'
DRIVE_FILE_RENAMED = 'firn'
@@ -189,6 +193,8 @@ class GamEntity():
DRIVE_LABEL_FIELD_ID = 'dlfi'
DRIVE_LABEL_ID = 'dlid'
DRIVE_LABEL_NAME = 'dlna'
DRIVE_LABEL_PERMISSION = 'dlpe'
DRIVE_LABEL_PERMISSION_NAME = 'dlpn'
DRIVE_ORPHAN_FILE_OR_FOLDER = 'orph'
DRIVE_PARENT_FOLDER = 'fipf'
DRIVE_PARENT_FOLDER_ID = 'fipi'
@@ -286,6 +292,7 @@ class GamEntity():
PERSONAL_DEVICE = 'pedv'
PHOTO = 'phot'
POP_ENABLED = 'popa'
PRESENTATION = 'pres'
PRINTER = 'prin'
PRINTER_ID = 'prid'
PRINTER_MODEL = 'prmd'
@@ -417,6 +424,7 @@ class GamEntity():
CHANNEL_PRODUCT: ['Channel Products', 'Channel Product'],
CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'],
CHAT_BOT: ['Chat BOTs', 'Chat BOT'],
CHAT_EVENT: ['Chat Events', 'Chat Event'],
CHAT_MANAGER_USER: ['Chat User Managers', 'Chat User Manager'],
CHAT_MESSAGE: ['Chat Messages', 'Chat Message'],
CHAT_MESSAGE_ID: ['Chat Message IDs', 'Chat Message ID'],
@@ -483,6 +491,8 @@ class GamEntity():
CRITERIA: ['Criteria', 'Criteria'],
CROS_DEVICE: ['CrOS Devices', 'CrOS Device'],
CROS_SERIAL_NUMBER: ['CrOS Serial Numbers', 'CrOS Serial Numbers'],
CSE_IDENTITY: ['CSE Identities', 'CSE Identity'],
CSE_KEYPAIR: ['CSE KeyPairs', 'CSE KeyPair'],
CUSTOMER_DOMAIN: ['Customer Domains', 'Customer Domain'],
CUSTOMER_ID: ['Customer IDs', 'Customer ID'],
DATE: ['Dates', 'Date'],
@@ -504,6 +514,7 @@ class GamEntity():
DOMAIN_PROFILE: ['Domain Profiles', 'Domain Profile'],
DRIVE_DISK_USAGE: ['Drive Disk Usages', 'Drive Disk Usage'],
DRIVE_FILE: ['Drive Files', 'Drive File'],
DRIVE_FILE_COMMENT: ['Drive File Comments', 'Drive File Comment'],
DRIVE_FILE_ID: ['Drive File IDs', 'Drive File ID'],
DRIVE_FILE_NAME: ['Drive File Names', 'Drive File Name'],
DRIVE_FILE_REVISION: ['Drive File Revisions', 'Drive File Revision'],
@@ -522,6 +533,8 @@ class GamEntity():
DRIVE_LABEL_FIELD_ID: ['Drive Label Field IDs', 'Drive Label Field ID'],
DRIVE_LABEL_ID: ['Drive Label IDs', 'Drive Label ID'],
DRIVE_LABEL_NAME: ['Drive Label Names', 'Drive Label Name'],
DRIVE_LABEL_PERMISSION: ['Drive Label Permissions', 'Drive Label Permission'],
DRIVE_LABEL_PERMISSION_NAME: ['Drive Label Permission Names', 'Drive Label Permission Name'],
DRIVE_ORPHAN_FILE_OR_FOLDER: ['Drive Orphan Files/Folders', 'Drive Orphan File/Folder'],
DRIVE_PARENT_FOLDER: ['Drive Parent Folders', 'Drive Parent Folder'],
DRIVE_PARENT_FOLDER_ID: ['Drive Parent Folder IDs', 'Drive Parent Folder ID'],
@@ -619,6 +632,7 @@ class GamEntity():
PERSONAL_DEVICE: ['Personal Devices', 'Personal Device'],
PHOTO: ['Photos', 'Photo'],
POP_ENABLED: ['POP Enabled', 'POP Enabled'],
PRESENTATION: ['Presentations', 'Presentation'],
PRINTER: ['Printers', 'Printer'],
PRINTER_ID: ['Printer IDs', 'Printer ID'],
PRINTER_MODEL: ['Printer Models', 'Printer Model'],

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -24,6 +24,7 @@ ABORTED = 'aborted'
ABUSIVE_CONTENT_RESTRICTION = 'abusiveContentRestriction'
ACCESS_NOT_CONFIGURED = 'accessNotConfigured'
ALREADY_EXISTS = 'alreadyExists'
APPLY_LABEL_FORBIDDEN = 'applyLabelForbidden'
AUTH_ERROR = 'authError'
BACKEND_ERROR = 'backendError'
BAD_GATEWAY = 'badGateway'
@@ -66,6 +67,7 @@ DOMAIN_CANNOT_USE_APIS = 'domainCannotUseApis'
DOMAIN_NOT_FOUND = 'domainNotFound'
DOMAIN_NOT_VERIFIED_SECONDARY = 'domainNotVerifiedSecondary'
DOMAIN_POLICY = 'domainPolicy'
DOWNLOAD_QUOTA_EXCEEDED = 'downloadQuotaExceeded'
DUPLICATE = 'duplicate'
EVENT_DURATION_EXCEEDS_LIMIT = 'eventDurationExceedsLimit'
FAILED_PRECONDITION = 'failedPrecondition'
@@ -115,11 +117,13 @@ LIMIT_EXCEEDED = 'limitExceeded'
LOGIN_REQUIRED = 'loginRequired'
MALFORMED_WORKING_LOCATION_EVENT = 'malformedWorkingLocationEvent'
MEMBER_NOT_FOUND = 'memberNotFound'
MYDRIVE_HIERARCHY_DEPTH_LIMIT_EXCEEDED = 'myDriveHierarchyDepthLimitExceeded'
NO_LIST_TEAMDRIVES_ADMINISTRATOR_PRIVILEGE = 'noListTeamDrivesAdministratorPrivilege'
NO_MANAGE_TEAMDRIVE_ADMINISTRATOR_PRIVILEGE = 'noManageTeamDriveAdministratorPrivilege'
NOT_A_CALENDAR_USER = 'notACalendarUser'
NOT_FOUND = 'notFound'
NOT_IMPLEMENTED = 'notImplemented'
NUM_CHILDREN_IN_NON_ROOT_LIMIT_EXCEEDED = 'numChildrenInNonRootLimitExceeded'
OPERATION_NOT_SUPPORTED = 'operationNotSupported'
ORGANIZER_ON_NON_TEAMDRIVE_NOT_SUPPORTED = 'organizerOnNonTeamDriveNotSupported'
ORGANIZER_ON_NON_TEAMDRIVE_ITEM_NOT_SUPPORTED = 'organizerOnNonTeamDriveItemNotSupported'
@@ -181,8 +185,8 @@ SERVICE_NOT_AVAILABLE_RETRY_REASONS = [SERVICE_NOT_AVAILABLE]
ACTIVITY_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST]
ALERT_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR]
CALENDAR_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, NOT_A_CALENDAR_USER]
CIGROUP_CREATE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, ALREADY_EXISTS, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, INVALID, INVALID_ARGUMENT, PERMISSION_DENIED]
CIGROUP_GET_THROW_REASONS = [SERVICE_NOT_AVAILABLE, NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, SYSTEM_ERROR, PERMISSION_DENIED]
CIGROUP_CREATE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, ALREADY_EXISTS, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, INVALID, INVALID_ARGUMENT, PERMISSION_DENIED, FAILED_PRECONDITION]
CIGROUP_GET_THROW_REASONS = [SERVICE_NOT_AVAILABLE, NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, SYSTEM_ERROR, PERMISSION_DENIED]
CIGROUP_LIST_THROW_REASONS = [SERVICE_NOT_AVAILABLE, RESOURCE_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, INVALID_ARGUMENT, SYSTEM_ERROR, PERMISSION_DENIED]
CIGROUP_LIST_USERKEY_THROW_REASONS = CIGROUP_LIST_THROW_REASONS+[INVALID_ARGUMENT]
CIGROUP_UPDATE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS,
@@ -203,7 +207,7 @@ DRIVE_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, FORBIDDEN
DRIVE_COPY_THROW_REASONS = DRIVE_ACCESS_THROW_REASONS+[CANNOT_COPY_FILE, BAD_REQUEST, RESPONSE_PREPARATION_FAILURE, TEAMDRIVES_SHARING_RESTRICTION_NOT_ALLOWED,
FIELD_NOT_WRITABLE, RATE_LIMIT_EXCEEDED, USER_RATE_LIMIT_EXCEEDED,
STORAGE_QUOTA_EXCEEDED, TEAMDRIVE_FILE_LIMIT_EXCEEDED, TEAMDRIVE_HIERARCHY_TOO_DEEP]
DRIVE_GET_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND]
DRIVE_GET_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, DOWNLOAD_QUOTA_EXCEEDED]
DRIVE3_CREATE_ACL_THROW_REASONS = [BAD_REQUEST, INVALID, INVALID_SHARING_REQUEST, OWNERSHIP_CHANGE_ACROSS_DOMAIN_NOT_PERMITTED, CANNOT_SET_EXPIRATION,
NOT_FOUND, TEAMDRIVE_DOMAIN_USERS_ONLY_RESTRICTION, TEAMDRIVE_TEAM_MEMBERS_ONLY_RESTRICTION,
TARGET_USER_ROLE_LIMITED_BY_LICENSE_RESTRICTION, INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, SHARING_RATE_LIMIT_EXCEEDED,
@@ -241,16 +245,19 @@ DRIVE3_DELETE_ACL_THROW_REASONS = [BAD_REQUEST, CANNOT_REMOVE_OWNER,
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, SHARING_RATE_LIMIT_EXCEEDED,
NOT_FOUND, PERMISSION_NOT_FOUND]
DRIVE3_MODIFY_LABEL_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, NOT_FOUND, FORBIDDEN, INTERNAL_ERROR,
FILE_NEVER_WRITABLE, APPLY_LABEL_FORBIDDEN,
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, INSUFFICIENT_FILE_PERMISSIONS,
UNKNOWN_ERROR, INVALID_INPUT, BAD_REQUEST,
LABEL_MULTIPLE_VALUES_FOR_SINGULAR_FIELD, LABEL_MUTATION_FORBIDDEN,
LABEL_MUTATION_ILLEGAL_SELECTION, LABEL_MUTATION_UNKNOWN_FIELD]
DOCS_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[NOT_FOUND, PERMISSION_DENIED, FORBIDDEN, INTERNAL_ERROR, INSUFFICIENT_FILE_PERMISSIONS,
BAD_REQUEST, INVALID, INVALID_ARGUMENT, FAILED_PRECONDITION]
GMAIL_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST]
GMAIL_LIST_THROW_REASONS = [FAILED_PRECONDITION, PERMISSION_DENIED, INVALID, INVALID_ARGUMENT]
GMAIL_SMIME_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, INVALID_ARGUMENT, FORBIDDEN, NOT_FOUND, PERMISSION_DENIED]
GROUP_GET_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, SYSTEM_ERROR]
GROUP_GET_RETRY_REASONS = [INVALID, SYSTEM_ERROR, SERVICE_NOT_AVAILABLE]
GROUP_CREATE_THROW_REASONS = [DUPLICATE, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, INVALID, INVALID_INPUT]
GROUP_GET_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, INVALID, SYSTEM_ERROR]
GROUP_UPDATE_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, INVALID, INVALID_INPUT]
GROUP_SETTINGS_THROW_REASONS = [NOT_FOUND, GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, SYSTEM_ERROR, PERMISSION_DENIED,
INVALID, INVALID_PARAMETER, INVALID_ATTRIBUTE_VALUE, INVALID_INPUT, SERVICE_LIMIT, SERVICE_NOT_AVAILABLE, AUTH_ERROR, REQUIRED]
@@ -274,6 +281,7 @@ YOUTUBE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, UNSUPPORTED_SUPERVIS
REASON_MESSAGE_MAP = {
ABORTED: [
('Label name exists or conflicts', DUPLICATE),
('The operation was aborted', ABORTED),
],
CONDITION_NOT_MET: [
('Cyclic memberships not allowed', CYCLIC_MEMBERSHIPS_NOT_ALLOWED),
@@ -346,6 +354,8 @@ class accessNotConfigured(Exception):
pass
class alreadyExists(Exception):
pass
class applyLabelForbidden(Exception):
pass
class authError(Exception):
pass
class backendError(Exception):
@@ -426,6 +436,8 @@ class domainNotVerifiedSecondary(Exception):
pass
class domainPolicy(Exception):
pass
class downloadQuotaExceeded(Exception):
pass
class duplicate(Exception):
pass
class eventDurationExceedsLimit(Exception):
@@ -646,6 +658,7 @@ REASON_EXCEPTION_MAP = {
ABUSIVE_CONTENT_RESTRICTION: abusiveContentRestriction,
ACCESS_NOT_CONFIGURED: accessNotConfigured,
ALREADY_EXISTS: alreadyExists,
APPLY_LABEL_FORBIDDEN: applyLabelForbidden,
AUTH_ERROR: authError,
BACKEND_ERROR: backendError,
BAD_REQUEST: badRequest,
@@ -686,6 +699,7 @@ REASON_EXCEPTION_MAP = {
DOMAIN_NOT_FOUND: domainNotFound,
DOMAIN_NOT_VERIFIED_SECONDARY: domainNotVerifiedSecondary,
DOMAIN_POLICY: domainPolicy,
DOWNLOAD_QUOTA_EXCEEDED: downloadQuotaExceeded,
DUPLICATE: duplicate,
EVENT_DURATION_EXCEEDS_LIMIT: eventDurationExceedsLimit,
FAILED_PRECONDITION: failedPrecondition,

View File

@@ -81,6 +81,8 @@ CSV_OUTPUT_ROW_FILTER_MODE = 'corm'
CSV_OUTPUT_ROW_LIMIT = 'corl'
# Add timestamp column to CSV output file
CSV_OUTPUT_TIMESTAMP_COLUMN = 'csv_output_timestamp_column'
# Output sort headers
CSV_OUTPUT_SORT_HEADERS = 'cosh'
# CSV todrive options
CSV_TODRIVE = 'todr'
# Current API services
@@ -236,6 +238,7 @@ Globals = {
CSV_OUTPUT_ROW_FILTER: [],
CSV_OUTPUT_ROW_FILTER_MODE: True,
CSV_OUTPUT_ROW_LIMIT: 0,
CSV_OUTPUT_SORT_HEADERS: [],
CSV_OUTPUT_TIMESTAMP_COLUMN: None,
CSV_TODRIVE: {},
CURRENT_API_SERVICES: {},

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
# Copyright (C) 2024 Ross Scroggs All Rights Reserved.
#
# All Rights Reserved.
#
@@ -150,6 +150,7 @@ API_CALLS_RETRY_DATA = 'API calls retry data\n'
API_CHECK_CLIENT_AUTHORIZATION = 'Please make sure the Client ID: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam oauth create\n'
API_CHECK_SVCACCT_AUTHORIZATION = 'Please make sure the Service Account Client name: {0} is authorized for the appropriate API or scopes:\n{1}\n\nRun: gam user {2} check serviceaccount\n'
API_ERROR_SETTINGS = 'API error, some settings not set'
ARE_BOTH_REQUIRED = 'Arguments {0} and {1} are both required'
ARE_MUTUALLY_EXCLUSIVE = 'Arguments {0} and {1} are mutually exclusive'
AS = 'as'
ATTENDEES_ADD = 'Add Attendees'
@@ -191,6 +192,7 @@ CSV_DATA_ALREADY_SAVED = 'CSV data already saved'
CSV_FILE_HEADERS = 'The CSV file ({0}) has the following headers:\n'
CSV_SAMPLE_COMMANDS = 'Here are the first {0} commands {1} will run\n'
DATA_FIELD_MISMATCH = 'datafield {0} does not match saved datafield {1}'
DATA_TRANSFER_COMPLETED = 'Data Transfer completed: {0}\n'
DATA_UPLOADED_TO_DRIVE_FILE = 'Data uploaded to Drive File'
DEFAULT_SMIME = 'Default S/MIME'
DELETED = 'Deleted'
@@ -231,6 +233,7 @@ FAILED_PRECONDITION = 'Failed precondition'
FAILED_TO_PARSE_AS_JSON = 'Failed to parse as JSON'
FAILED_TO_PARSE_AS_LIST = 'Failed to parse as list'
FIELD_NOT_FOUND_IN_SCHEMA = 'Field {0} not found in schema {1}'
FILE_NOT_FOUND = 'File {0} not found'
FINISHED = 'Finished'
FILTER_CAN_ONLY_CONTAIN_ONE_CATEGORY_LABEL = 'Filter can only contain one CATEGORY label'
FILTER_CAN_ONLY_CONTAIN_ONE_USER_LABEL = 'Filter can only contain one USER label'
@@ -299,6 +302,8 @@ IS_NOT_UNIQUE = 'Is not unique, {0}: {1}'
IS_REQD_TO_CHG_PWD_NO_DELEGATION = 'Is required to change password at next login. You must change password or clear changepassword flag for delegation.'
IS_SUSPENDED_NO_BACKUPCODES = 'User is suspended. You must unsuspend to process backupcodes'
IS_SUSPENDED_NO_DELEGATION = 'Is suspended. You must unsuspend for delegation.'
JSON_ERROR = 'JSON error "{0}" in file {1}'
JSON_KEY_NOT_FOUND = 'JSON key "{0}" not found in file {1}'
KIOSK_MODE_REQUIRED = ' This command ({0}) requires that the ChromeOS device be in Kiosk mode.'
LESS_THAN_1_SECOND = 'less than 1 second'
LIST_CHROMEOS_INVALID_INPUT_PAGE_TOKEN_RETRY = 'List ChromeOSdevices Invalid Input: pageToken retry'
@@ -479,6 +484,7 @@ USE_DOIT_ARGUMENT_TO_PERFORM_ACTION = 'Use the "doit" argument to perform action
USING_N_PROCESSES = '{0},0/{1},Using {2} {3}...\n'
VALUES_ARE_NOT_CONSISTENT = 'Values are not consistent'
VERSION_UPDATE_AVAILABLE = 'Version update available'
WAITING_FOR_DATA_TRANSFER_TO_COMPLETE_SLEEPING = 'Waiting for Data Transfer to complete. Sleeping {0} seconds\n'
WAITING_FOR_SERVICE_ACCOUNT_CREATION_TO_COMPLETE_SLEEPING = 'Waiting for Service Account creation to complete. Sleeping {0} seconds\n'
WAITING_FOR_SHARED_DRIVE_CREATION_TO_COMPLETE_SLEEPING = 'Waiting for Shared Drive creation to complete. Sleeping {0} seconds\n'
WHAT_IS_YOUR_PROJECT_ID = '\nWhat is your project ID? '

View File

@@ -34,7 +34,8 @@ _PRODUCTS = {
'101039': 'Assured Controls',
'101040': 'Beyond Corp Enterprise',
'101043': 'Google Workspace Additional Storage',
'101047': 'Duet AI',
'101047': 'Gemini',
'101049': 'Education Endpoint Management',
'Google-Apps': 'Google Workspace',
'Google-Chrome-Device-Management': 'Google Chrome Device Management',
'Google-Drive-storage': 'Google Drive Storage',
@@ -61,12 +62,12 @@ _SKUS = {
'product': '101031', 'aliases': ['gwepstaff', 'workspaceeducationplusstaff'], 'displayName': 'Google Workspace for Education Plus (Staff)'},
'1010310010': {
'product': '101031', 'aliases': ['gwepstudent', 'workspaceeducationplusstudent'], 'displayName': 'Google Workspace for Education Plus (Extra Student)'},
'1010330002': {
'product': '101033', 'aliases': ['gvpremier', 'voicepremier', 'googlevoicepremier'], 'displayName': 'Google Voice Premier'},
'1010330003': {
'product': '101033', 'aliases': ['gvstarter', 'voicestarter', 'googlevoicestarter'], 'displayName': 'Google Voice Starter'},
'1010330004': {
'product': '101033', 'aliases': ['gvstandard', 'voicestandard', 'googlevoicestandard'], 'displayName': 'Google Voice Standard'},
'1010330002': {
'product': '101033', 'aliases': ['gvpremier', 'voicepremier', 'googlevoicepremier'], 'displayName': 'Google Voice Premier'},
'1010350001': {
'product': '101035', 'aliases': ['cloudsearch'], 'displayName': 'Cloud Search'},
'1010360001': {
@@ -86,9 +87,13 @@ _SKUS = {
'1010430001': {
'product': '101043', 'aliases': ['gwas', 'plusstorage'], 'displayName': 'Google Workspace Additional Storage'},
'1010470001': {
'product': '101047', 'aliases': ['duetai'], 'displayName': 'Duet AI for Enterprise'},
'product': '101047', 'aliases': ['geminient', 'duetai'], 'displayName': 'Gemini Enterprise'},
'1010470002': {
'product': '101047', 'aliases': ['gwlabs', 'workspacelabs'], 'displayName': 'Google Workspace Labs'},
'1010470003': {
'product': '101047', 'aliases': ['geminibiz'], 'displayName': 'Gemini Business'},
'1010490001': {
'product': '101049', 'aliases': ['eeu'], 'displayName': 'Endpoint Education Upgrade'},
'Google-Apps': {
'product': 'Google-Apps', 'aliases': ['standard', 'free'], 'displayName': 'G Suite Legacy'},
'Google-Apps-For-Business': {

View File

@@ -0,0 +1,27 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set default logging handler to avoid "No handler found" warnings.
import logging
try: # Python 2.7+
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
logging.getLogger(__name__).addHandler(NullHandler())

View File

@@ -0,0 +1,167 @@
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helpers for authentication using oauth2client or google-auth."""
import httplib2
try:
import google.auth
import google.auth.credentials
HAS_GOOGLE_AUTH = True
except ImportError: # pragma: NO COVER
HAS_GOOGLE_AUTH = False
try:
import google_auth_httplib2
except ImportError: # pragma: NO COVER
google_auth_httplib2 = None
try:
import oauth2client
import oauth2client.client
HAS_OAUTH2CLIENT = True
except ImportError: # pragma: NO COVER
HAS_OAUTH2CLIENT = False
def credentials_from_file(filename, scopes=None, quota_project_id=None):
"""Returns credentials loaded from a file."""
if HAS_GOOGLE_AUTH:
credentials, _ = google.auth.load_credentials_from_file(
filename, scopes=scopes, quota_project_id=quota_project_id
)
return credentials
else:
raise EnvironmentError(
"client_options.credentials_file is only supported in google-auth."
)
def default_credentials(scopes=None, quota_project_id=None):
"""Returns Application Default Credentials."""
if HAS_GOOGLE_AUTH:
credentials, _ = google.auth.default(
scopes=scopes, quota_project_id=quota_project_id
)
return credentials
elif HAS_OAUTH2CLIENT:
if scopes is not None or quota_project_id is not None:
raise EnvironmentError(
"client_options.scopes and client_options.quota_project_id are not supported in oauth2client."
"Please install google-auth."
)
return oauth2client.client.GoogleCredentials.get_application_default()
else:
raise EnvironmentError(
"No authentication library is available. Please install either "
"google-auth or oauth2client."
)
def with_scopes(credentials, scopes):
"""Scopes the credentials if necessary.
Args:
credentials (Union[
google.auth.credentials.Credentials,
oauth2client.client.Credentials]): The credentials to scope.
scopes (Sequence[str]): The list of scopes.
Returns:
Union[google.auth.credentials.Credentials,
oauth2client.client.Credentials]: The scoped credentials.
"""
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
return google.auth.credentials.with_scopes_if_required(credentials, scopes)
else:
try:
if credentials.create_scoped_required():
return credentials.create_scoped(scopes)
else:
return credentials
except AttributeError:
return credentials
def authorized_http(credentials):
"""Returns an http client that is authorized with the given credentials.
Args:
credentials (Union[
google.auth.credentials.Credentials,
oauth2client.client.Credentials]): The credentials to use.
Returns:
Union[httplib2.Http, google_auth_httplib2.AuthorizedHttp]: An
authorized http client.
"""
from googleapiclient.http import build_http
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
if google_auth_httplib2 is None:
raise ValueError(
"Credentials from google.auth specified, but "
"google-api-python-client is unable to use these credentials "
"unless google-auth-httplib2 is installed. Please install "
"google-auth-httplib2."
)
return google_auth_httplib2.AuthorizedHttp(credentials, http=build_http())
else:
return credentials.authorize(build_http())
def refresh_credentials(credentials):
# Refresh must use a new http instance, as the one associated with the
# credentials could be a AuthorizedHttp or an oauth2client-decorated
# Http instance which would cause a weird recursive loop of refreshing
# and likely tear a hole in spacetime.
refresh_http = httplib2.Http()
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
request = google_auth_httplib2.Request(refresh_http)
return credentials.refresh(request)
else:
return credentials.refresh(refresh_http)
def apply_credentials(credentials, headers):
# oauth2client and google-auth have the same interface for this.
if not is_valid(credentials):
refresh_credentials(credentials)
return credentials.apply(headers)
def is_valid(credentials):
if HAS_GOOGLE_AUTH and isinstance(credentials, google.auth.credentials.Credentials):
return credentials.valid
else:
return (
credentials.access_token is not None
and not credentials.access_token_expired
)
def get_credentials_from_http(http):
if http is None:
return None
elif hasattr(http.request, "credentials"):
return http.request.credentials
elif hasattr(http, "credentials") and not isinstance(
http.credentials, httplib2.Credentials
):
return http.credentials
else:
return None

View File

@@ -0,0 +1,207 @@
# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helper functions for commonly used utilities."""
import functools
import inspect
import logging
import urllib
logger = logging.getLogger(__name__)
POSITIONAL_WARNING = "WARNING"
POSITIONAL_EXCEPTION = "EXCEPTION"
POSITIONAL_IGNORE = "IGNORE"
POSITIONAL_SET = frozenset(
[POSITIONAL_WARNING, POSITIONAL_EXCEPTION, POSITIONAL_IGNORE]
)
positional_parameters_enforcement = POSITIONAL_WARNING
_SYM_LINK_MESSAGE = "File: {0}: Is a symbolic link."
_IS_DIR_MESSAGE = "{0}: Is a directory"
_MISSING_FILE_MESSAGE = "Cannot access {0}: No such file or directory"
def positional(max_positional_args):
"""A decorator to declare that only the first N arguments may be positional.
This decorator makes it easy to support Python 3 style keyword-only
parameters. For example, in Python 3 it is possible to write::
def fn(pos1, *, kwonly1=None, kwonly2=None):
...
All named parameters after ``*`` must be a keyword::
fn(10, 'kw1', 'kw2') # Raises exception.
fn(10, kwonly1='kw1') # Ok.
Example
^^^^^^^
To define a function like above, do::
@positional(1)
def fn(pos1, kwonly1=None, kwonly2=None):
...
If no default value is provided to a keyword argument, it becomes a
required keyword argument::
@positional(0)
def fn(required_kw):
...
This must be called with the keyword parameter::
fn() # Raises exception.
fn(10) # Raises exception.
fn(required_kw=10) # Ok.
When defining instance or class methods always remember to account for
``self`` and ``cls``::
class MyClass(object):
@positional(2)
def my_method(self, pos1, kwonly1=None):
...
@classmethod
@positional(2)
def my_method(cls, pos1, kwonly1=None):
...
The positional decorator behavior is controlled by
``_helpers.positional_parameters_enforcement``, which may be set to
``POSITIONAL_EXCEPTION``, ``POSITIONAL_WARNING`` or
``POSITIONAL_IGNORE`` to raise an exception, log a warning, or do
nothing, respectively, if a declaration is violated.
Args:
max_positional_arguments: Maximum number of positional arguments. All
parameters after this index must be
keyword only.
Returns:
A decorator that prevents using arguments after max_positional_args
from being used as positional parameters.
Raises:
TypeError: if a keyword-only argument is provided as a positional
parameter, but only if
_helpers.positional_parameters_enforcement is set to
POSITIONAL_EXCEPTION.
"""
def positional_decorator(wrapped):
@functools.wraps(wrapped)
def positional_wrapper(*args, **kwargs):
if len(args) > max_positional_args:
plural_s = ""
if max_positional_args != 1:
plural_s = "s"
message = (
"{function}() takes at most {args_max} positional "
"argument{plural} ({args_given} given)".format(
function=wrapped.__name__,
args_max=max_positional_args,
args_given=len(args),
plural=plural_s,
)
)
if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
raise TypeError(message)
elif positional_parameters_enforcement == POSITIONAL_WARNING:
logger.warning(message)
return wrapped(*args, **kwargs)
return positional_wrapper
if isinstance(max_positional_args, int):
return positional_decorator
else:
args, _, _, defaults, _, _, _ = inspect.getfullargspec(max_positional_args)
return positional(len(args) - len(defaults))(max_positional_args)
def parse_unique_urlencoded(content):
"""Parses unique key-value parameters from urlencoded content.
Args:
content: string, URL-encoded key-value pairs.
Returns:
dict, The key-value pairs from ``content``.
Raises:
ValueError: if one of the keys is repeated.
"""
urlencoded_params = urllib.parse.parse_qs(content)
params = {}
for key, value in urlencoded_params.items():
if len(value) != 1:
msg = "URL-encoded content contains a repeated value:" "%s -> %s" % (
key,
", ".join(value),
)
raise ValueError(msg)
params[key] = value[0]
return params
def update_query_params(uri, params):
"""Updates a URI with new query parameters.
If a given key from ``params`` is repeated in the ``uri``, then
the URI will be considered invalid and an error will occur.
If the URI is valid, then each value from ``params`` will
replace the corresponding value in the query parameters (if
it exists).
Args:
uri: string, A valid URI, with potential existing query parameters.
params: dict, A dictionary of query parameters.
Returns:
The same URI but with the new query parameters added.
"""
parts = urllib.parse.urlparse(uri)
query_params = parse_unique_urlencoded(parts.query)
query_params.update(params)
new_query = urllib.parse.urlencode(query_params)
new_parts = parts._replace(query=new_query)
return urllib.parse.urlunparse(new_parts)
def _add_query_parameter(url, name, value):
"""Adds a query parameter to a url.
Replaces the current value if it already exists in the URL.
Args:
url: string, url to add the query parameter to.
name: string, query parameter name.
value: string, query parameter value.
Returns:
Updated query parameter. Does not update the url if value is None.
"""
if value is None:
return url
else:
return update_query_params(url, {name: value})

View File

@@ -0,0 +1,315 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Channel notifications support.
Classes and functions to support channel subscriptions and notifications
on those channels.
Notes:
- This code is based on experimental APIs and is subject to change.
- Notification does not do deduplication of notification ids, that's up to
the receiver.
- Storing the Channel between calls is up to the caller.
Example setting up a channel:
# Create a new channel that gets notifications via webhook.
channel = new_webhook_channel("https://example.com/my_web_hook")
# Store the channel, keyed by 'channel.id'. Store it before calling the
# watch method because notifications may start arriving before the watch
# method returns.
...
resp = service.objects().watchAll(
bucket="some_bucket_id", body=channel.body()).execute()
channel.update(resp)
# Store the channel, keyed by 'channel.id'. Store it after being updated
# since the resource_id value will now be correct, and that's needed to
# stop a subscription.
...
An example Webhook implementation using webapp2. Note that webapp2 puts
headers in a case insensitive dictionary, as headers aren't guaranteed to
always be upper case.
id = self.request.headers[X_GOOG_CHANNEL_ID]
# Retrieve the channel by id.
channel = ...
# Parse notification from the headers, including validating the id.
n = notification_from_headers(channel, self.request.headers)
# Do app specific stuff with the notification here.
if n.resource_state == 'sync':
# Code to handle sync state.
elif n.resource_state == 'exists':
# Code to handle the exists state.
elif n.resource_state == 'not_exists':
# Code to handle the not exists state.
Example of unsubscribing.
service.channels().stop(channel.body()).execute()
"""
from __future__ import absolute_import
import datetime
import uuid
from googleapiclient import _helpers as util
from googleapiclient import errors
# The unix time epoch starts at midnight 1970.
EPOCH = datetime.datetime(1970, 1, 1)
# Map the names of the parameters in the JSON channel description to
# the parameter names we use in the Channel class.
CHANNEL_PARAMS = {
"address": "address",
"id": "id",
"expiration": "expiration",
"params": "params",
"resourceId": "resource_id",
"resourceUri": "resource_uri",
"type": "type",
"token": "token",
}
X_GOOG_CHANNEL_ID = "X-GOOG-CHANNEL-ID"
X_GOOG_MESSAGE_NUMBER = "X-GOOG-MESSAGE-NUMBER"
X_GOOG_RESOURCE_STATE = "X-GOOG-RESOURCE-STATE"
X_GOOG_RESOURCE_URI = "X-GOOG-RESOURCE-URI"
X_GOOG_RESOURCE_ID = "X-GOOG-RESOURCE-ID"
def _upper_header_keys(headers):
new_headers = {}
for k, v in headers.items():
new_headers[k.upper()] = v
return new_headers
class Notification(object):
"""A Notification from a Channel.
Notifications are not usually constructed directly, but are returned
from functions like notification_from_headers().
Attributes:
message_number: int, The unique id number of this notification.
state: str, The state of the resource being monitored.
uri: str, The address of the resource being monitored.
resource_id: str, The unique identifier of the version of the resource at
this event.
"""
@util.positional(5)
def __init__(self, message_number, state, resource_uri, resource_id):
"""Notification constructor.
Args:
message_number: int, The unique id number of this notification.
state: str, The state of the resource being monitored. Can be one
of "exists", "not_exists", or "sync".
resource_uri: str, The address of the resource being monitored.
resource_id: str, The identifier of the watched resource.
"""
self.message_number = message_number
self.state = state
self.resource_uri = resource_uri
self.resource_id = resource_id
class Channel(object):
"""A Channel for notifications.
Usually not constructed directly, instead it is returned from helper
functions like new_webhook_channel().
Attributes:
type: str, The type of delivery mechanism used by this channel. For
example, 'web_hook'.
id: str, A UUID for the channel.
token: str, An arbitrary string associated with the channel that
is delivered to the target address with each event delivered
over this channel.
address: str, The address of the receiving entity where events are
delivered. Specific to the channel type.
expiration: int, The time, in milliseconds from the epoch, when this
channel will expire.
params: dict, A dictionary of string to string, with additional parameters
controlling delivery channel behavior.
resource_id: str, An opaque id that identifies the resource that is
being watched. Stable across different API versions.
resource_uri: str, The canonicalized ID of the watched resource.
"""
@util.positional(5)
def __init__(
self,
type,
id,
token,
address,
expiration=None,
params=None,
resource_id="",
resource_uri="",
):
"""Create a new Channel.
In user code, this Channel constructor will not typically be called
manually since there are functions for creating channels for each specific
type with a more customized set of arguments to pass.
Args:
type: str, The type of delivery mechanism used by this channel. For
example, 'web_hook'.
id: str, A UUID for the channel.
token: str, An arbitrary string associated with the channel that
is delivered to the target address with each event delivered
over this channel.
address: str, The address of the receiving entity where events are
delivered. Specific to the channel type.
expiration: int, The time, in milliseconds from the epoch, when this
channel will expire.
params: dict, A dictionary of string to string, with additional parameters
controlling delivery channel behavior.
resource_id: str, An opaque id that identifies the resource that is
being watched. Stable across different API versions.
resource_uri: str, The canonicalized ID of the watched resource.
"""
self.type = type
self.id = id
self.token = token
self.address = address
self.expiration = expiration
self.params = params
self.resource_id = resource_id
self.resource_uri = resource_uri
def body(self):
"""Build a body from the Channel.
Constructs a dictionary that's appropriate for passing into watch()
methods as the value of body argument.
Returns:
A dictionary representation of the channel.
"""
result = {
"id": self.id,
"token": self.token,
"type": self.type,
"address": self.address,
}
if self.params:
result["params"] = self.params
if self.resource_id:
result["resourceId"] = self.resource_id
if self.resource_uri:
result["resourceUri"] = self.resource_uri
if self.expiration:
result["expiration"] = self.expiration
return result
def update(self, resp):
"""Update a channel with information from the response of watch().
When a request is sent to watch() a resource, the response returned
from the watch() request is a dictionary with updated channel information,
such as the resource_id, which is needed when stopping a subscription.
Args:
resp: dict, The response from a watch() method.
"""
for json_name, param_name in CHANNEL_PARAMS.items():
value = resp.get(json_name)
if value is not None:
setattr(self, param_name, value)
def notification_from_headers(channel, headers):
"""Parse a notification from the webhook request headers, validate
the notification, and return a Notification object.
Args:
channel: Channel, The channel that the notification is associated with.
headers: dict, A dictionary like object that contains the request headers
from the webhook HTTP request.
Returns:
A Notification object.
Raises:
errors.InvalidNotificationError if the notification is invalid.
ValueError if the X-GOOG-MESSAGE-NUMBER can't be converted to an int.
"""
headers = _upper_header_keys(headers)
channel_id = headers[X_GOOG_CHANNEL_ID]
if channel.id != channel_id:
raise errors.InvalidNotificationError(
"Channel id mismatch: %s != %s" % (channel.id, channel_id)
)
else:
message_number = int(headers[X_GOOG_MESSAGE_NUMBER])
state = headers[X_GOOG_RESOURCE_STATE]
resource_uri = headers[X_GOOG_RESOURCE_URI]
resource_id = headers[X_GOOG_RESOURCE_ID]
return Notification(message_number, state, resource_uri, resource_id)
@util.positional(2)
def new_webhook_channel(url, token=None, expiration=None, params=None):
"""Create a new webhook Channel.
Args:
url: str, URL to post notifications to.
token: str, An arbitrary string associated with the channel that
is delivered to the target address with each notification delivered
over this channel.
expiration: datetime.datetime, A time in the future when the channel
should expire. Can also be None if the subscription should use the
default expiration. Note that different services may have different
limits on how long a subscription lasts. Check the response from the
watch() method to see the value the service has set for an expiration
time.
params: dict, Extra parameters to pass on channel creation. Currently
not used for webhook channels.
"""
expiration_ms = 0
if expiration:
delta = expiration - EPOCH
expiration_ms = (
delta.microseconds / 1000 + (delta.seconds + delta.days * 24 * 3600) * 1000
)
if expiration_ms < 0:
expiration_ms = 0
return Channel(
"web_hook",
str(uuid.uuid4()),
token,
url,
expiration=expiration_ms,
params=params,
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Caching utility for the discovery document."""
from __future__ import absolute_import
import logging
import os
LOGGER = logging.getLogger(__name__)
DISCOVERY_DOC_MAX_AGE = 60 * 60 * 24 # 1 day
DISCOVERY_DOC_DIR = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "documents"
)
def autodetect():
"""Detects an appropriate cache module and returns it.
Returns:
googleapiclient.discovery_cache.base.Cache, a cache object which
is auto detected, or None if no cache object is available.
"""
if "GAE_ENV" in os.environ:
try:
from . import appengine_memcache
return appengine_memcache.cache
except Exception:
pass
try:
from . import file_cache
return file_cache.cache
except Exception:
LOGGER.info(
"file_cache is only supported with oauth2client<4.0.0", exc_info=False
)
return None
def get_static_doc(serviceName, version):
"""Retrieves the discovery document from the directory defined in
DISCOVERY_DOC_DIR corresponding to the serviceName and version provided.
Args:
serviceName: string, name of the service.
version: string, the version of the service.
Returns:
A string containing the contents of the JSON discovery document,
otherwise None if the JSON discovery document was not found.
"""
content = None
doc_name = "{}.{}.json".format(serviceName, version)
try:
with open(os.path.join(DISCOVERY_DOC_DIR, doc_name), "r") as f:
content = f.read()
except FileNotFoundError:
# File does not exist. Nothing to do here.
pass
return content

View File

@@ -0,0 +1,55 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""App Engine memcache based cache for the discovery document."""
import logging
# This is only an optional dependency because we only import this
# module when google.appengine.api.memcache is available.
from google.appengine.api import memcache
from . import base
from ..discovery_cache import DISCOVERY_DOC_MAX_AGE
LOGGER = logging.getLogger(__name__)
NAMESPACE = "google-api-client"
class Cache(base.Cache):
"""A cache with app engine memcache API."""
def __init__(self, max_age):
"""Constructor.
Args:
max_age: Cache expiration in seconds.
"""
self._max_age = max_age
def get(self, url):
try:
return memcache.get(url, namespace=NAMESPACE)
except Exception as e:
LOGGER.warning(e, exc_info=True)
def set(self, url, content):
try:
memcache.set(url, content, time=int(self._max_age), namespace=NAMESPACE)
except Exception as e:
LOGGER.warning(e, exc_info=True)
cache = Cache(max_age=DISCOVERY_DOC_MAX_AGE)

View File

@@ -0,0 +1,46 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""An abstract class for caching the discovery document."""
import abc
class Cache(object):
"""A base abstract cache class."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def get(self, url):
"""Gets the content from the memcache with a given key.
Args:
url: string, the key for the cache.
Returns:
object, the value in the cache for the given key, or None if the key is
not in the cache.
"""
raise NotImplementedError()
@abc.abstractmethod
def set(self, url, content):
"""Sets the given key and content in the cache.
Args:
url: string, the key for the cache.
content: string, the discovery document.
"""
raise NotImplementedError()

View File

@@ -0,0 +1,145 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""File based cache for the discovery document.
The cache is stored in a single file so that multiple processes can
share the same cache. It locks the file whenever accessing to the
file. When the cache content is corrupted, it will be initialized with
an empty cache.
"""
from __future__ import division
import datetime
import json
import logging
import os
import tempfile
try:
from oauth2client.contrib.locked_file import LockedFile
except ImportError:
# oauth2client < 2.0.0
try:
from oauth2client.locked_file import LockedFile
except ImportError:
# oauth2client > 4.0.0 or google-auth
raise ImportError(
"file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth"
)
from . import base
from ..discovery_cache import DISCOVERY_DOC_MAX_AGE
LOGGER = logging.getLogger(__name__)
FILENAME = "google-api-python-client-discovery-doc.cache"
EPOCH = datetime.datetime(1970, 1, 1)
def _to_timestamp(date):
try:
return (date - EPOCH).total_seconds()
except AttributeError:
# The following is the equivalent of total_seconds() in Python2.6.
# See also: https://docs.python.org/2/library/datetime.html
delta = date - EPOCH
return (
delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6
) / 10**6
def _read_or_initialize_cache(f):
f.file_handle().seek(0)
try:
cache = json.load(f.file_handle())
except Exception:
# This means it opens the file for the first time, or the cache is
# corrupted, so initializing the file with an empty dict.
cache = {}
f.file_handle().truncate(0)
f.file_handle().seek(0)
json.dump(cache, f.file_handle())
return cache
class Cache(base.Cache):
"""A file based cache for the discovery documents."""
def __init__(self, max_age):
"""Constructor.
Args:
max_age: Cache expiration in seconds.
"""
self._max_age = max_age
self._file = os.path.join(tempfile.gettempdir(), FILENAME)
f = LockedFile(self._file, "a+", "r")
try:
f.open_and_lock()
if f.is_locked():
_read_or_initialize_cache(f)
# If we can not obtain the lock, other process or thread must
# have initialized the file.
except Exception as e:
LOGGER.warning(e, exc_info=True)
finally:
f.unlock_and_close()
def get(self, url):
f = LockedFile(self._file, "r+", "r")
try:
f.open_and_lock()
if f.is_locked():
cache = _read_or_initialize_cache(f)
if url in cache:
content, t = cache.get(url, (None, 0))
if _to_timestamp(datetime.datetime.now()) < t + self._max_age:
return content
return None
else:
LOGGER.debug("Could not obtain a lock for the cache file.")
return None
except Exception as e:
LOGGER.warning(e, exc_info=True)
finally:
f.unlock_and_close()
def set(self, url, content):
f = LockedFile(self._file, "r+", "r")
try:
f.open_and_lock()
if f.is_locked():
cache = _read_or_initialize_cache(f)
cache[url] = (content, _to_timestamp(datetime.datetime.now()))
# Remove stale cache.
for k, (_, timestamp) in list(cache.items()):
if (
_to_timestamp(datetime.datetime.now())
>= timestamp + self._max_age
):
del cache[k]
f.file_handle().truncate(0)
f.file_handle().seek(0)
json.dump(cache, f.file_handle())
else:
LOGGER.debug("Could not obtain a lock for the cache file.")
except Exception as e:
LOGGER.warning(e, exc_info=True)
finally:
f.unlock_and_close()
cache = Cache(max_age=DISCOVERY_DOC_MAX_AGE)

View File

@@ -0,0 +1,197 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Errors for the library.
All exceptions defined by the library
should be defined in this file.
"""
from __future__ import absolute_import
__author__ = "jcgregorio@google.com (Joe Gregorio)"
import json
from googleapiclient import _helpers as util
class Error(Exception):
"""Base error for this module."""
pass
class HttpError(Error):
"""HTTP data was invalid or unexpected."""
@util.positional(3)
def __init__(self, resp, content, uri=None):
self.resp = resp
if not isinstance(content, bytes):
raise TypeError("HTTP content should be bytes")
self.content = content
self.uri = uri
self.error_details = ""
self.reason = self._get_reason()
@property
def status_code(self):
"""Return the HTTP status code from the response content."""
return self.resp.status
def _get_reason(self):
"""Calculate the reason for the error from the response content."""
reason = self.resp.reason
try:
try:
data = json.loads(self.content.decode("utf-8"))
except json.JSONDecodeError:
# In case it is not json
data = self.content.decode("utf-8")
if isinstance(data, dict):
reason = data["error"]["message"]
error_detail_keyword = next(
(
kw
for kw in ["detail", "details", "errors", "message"]
if kw in data["error"]
),
"",
)
if error_detail_keyword:
self.error_details = data["error"][error_detail_keyword]
elif isinstance(data, list) and len(data) > 0:
first_error = data[0]
reason = first_error["error"]["message"]
if "details" in first_error["error"]:
self.error_details = first_error["error"]["details"]
else:
self.error_details = data
except (ValueError, KeyError, TypeError):
pass
if reason is None:
reason = ""
return reason.strip()
def __repr__(self):
if self.error_details:
return '<HttpError %s when requesting %s returned "%s". Details: "%s">' % (
self.resp.status,
self.uri,
self.reason,
self.error_details,
)
elif self.uri:
return '<HttpError %s when requesting %s returned "%s">' % (
self.resp.status,
self.uri,
self.reason,
)
else:
return '<HttpError %s "%s">' % (self.resp.status, self.reason)
__str__ = __repr__
class InvalidJsonError(Error):
"""The JSON returned could not be parsed."""
pass
class UnknownFileType(Error):
"""File type unknown or unexpected."""
pass
class UnknownLinkType(Error):
"""Link type unknown or unexpected."""
pass
class UnknownApiNameOrVersion(Error):
"""No API with that name and version exists."""
pass
class UnacceptableMimeTypeError(Error):
"""That is an unacceptable mimetype for this operation."""
pass
class MediaUploadSizeError(Error):
"""Media is larger than the method can accept."""
pass
class ResumableUploadError(HttpError):
"""Error occurred during resumable upload."""
pass
class InvalidChunkSizeError(Error):
"""The given chunksize is not valid."""
pass
class InvalidNotificationError(Error):
"""The channel Notification is invalid."""
pass
class BatchError(HttpError):
"""Error occurred during batch operations."""
@util.positional(2)
def __init__(self, reason, resp=None, content=None):
self.resp = resp
self.content = content
self.reason = reason
def __repr__(self):
if getattr(self.resp, "status", None) is None:
return '<BatchError "%s">' % (self.reason)
else:
return '<BatchError %s "%s">' % (self.resp.status, self.reason)
__str__ = __repr__
class UnexpectedMethodError(Error):
"""Exception raised by RequestMockBuilder on unexpected calls."""
@util.positional(1)
def __init__(self, methodId=None):
"""Constructor for an UnexpectedMethodError."""
super(UnexpectedMethodError, self).__init__(
"Received unexpected call %s" % methodId
)
class UnexpectedBodyError(Error):
"""Exception raised by RequestMockBuilder on unexpected bodies."""
def __init__(self, expected, provided):
"""Constructor for an UnexpectedMethodError."""
super(UnexpectedBodyError, self).__init__(
"Expected: [%s] - Provided: [%s]" % (expected, provided)
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
# Copyright 2014 Joe Gregorio
#
# Licensed under the MIT License
"""MIME-Type Parser
This module provides basic functions for handling mime-types. It can handle
matching mime-types against a list of media-ranges. See section 14.1 of the
HTTP specification [RFC 2616] for a complete explanation.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
Contents:
- parse_mime_type(): Parses a mime-type into its component parts.
- parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q'
quality parameter.
- quality(): Determines the quality ('q') of a mime-type when
compared against a list of media-ranges.
- quality_parsed(): Just like quality() except the second parameter must be
pre-parsed.
- best_match(): Choose the mime-type with the highest quality ('q')
from a list of candidates.
"""
from __future__ import absolute_import
from functools import reduce
__version__ = "0.1.3"
__author__ = "Joe Gregorio"
__email__ = "joe@bitworking.org"
__license__ = "MIT License"
__credits__ = ""
def parse_mime_type(mime_type):
"""Parses a mime-type into its component parts.
Carves up a mime-type and returns a tuple of the (type, subtype, params)
where 'params' is a dictionary of all the parameters for the media range.
For example, the media range 'application/xhtml;q=0.5' would get parsed
into:
('application', 'xhtml', {'q', '0.5'})
"""
parts = mime_type.split(";")
params = dict(
[tuple([s.strip() for s in param.split("=", 1)]) for param in parts[1:]]
)
full_type = parts[0].strip()
# Java URLConnection class sends an Accept header that includes a
# single '*'. Turn it into a legal wildcard.
if full_type == "*":
full_type = "*/*"
(type, subtype) = full_type.split("/")
return (type.strip(), subtype.strip(), params)
def parse_media_range(range):
"""Parse a media-range into its component parts.
Carves up a media range and returns a tuple of the (type, subtype,
params) where 'params' is a dictionary of all the parameters for the media
range. For example, the media range 'application/*;q=0.5' would get parsed
into:
('application', '*', {'q', '0.5'})
In addition this function also guarantees that there is a value for 'q'
in the params dictionary, filling it in with a proper default if
necessary.
"""
(type, subtype, params) = parse_mime_type(range)
if (
"q" not in params
or not params["q"]
or not float(params["q"])
or float(params["q"]) > 1
or float(params["q"]) < 0
):
params["q"] = "1"
return (type, subtype, params)
def fitness_and_quality_parsed(mime_type, parsed_ranges):
"""Find the best match for a mime-type amongst parsed media-ranges.
Find the best match for a given mime-type against a list of media_ranges
that have already been parsed by parse_media_range(). Returns a tuple of
the fitness value and the value of the 'q' quality parameter of the best
match, or (-1, 0) if no match was found. Just as for quality_parsed(),
'parsed_ranges' must be a list of parsed media ranges.
"""
best_fitness = -1
best_fit_q = 0
(target_type, target_subtype, target_params) = parse_media_range(mime_type)
for (type, subtype, params) in parsed_ranges:
type_match = type == target_type or type == "*" or target_type == "*"
subtype_match = (
subtype == target_subtype or subtype == "*" or target_subtype == "*"
)
if type_match and subtype_match:
param_matches = reduce(
lambda x, y: x + y,
[
1
for (key, value) in target_params.items()
if key != "q" and key in params and value == params[key]
],
0,
)
fitness = (type == target_type) and 100 or 0
fitness += (subtype == target_subtype) and 10 or 0
fitness += param_matches
if fitness > best_fitness:
best_fitness = fitness
best_fit_q = params["q"]
return best_fitness, float(best_fit_q)
def quality_parsed(mime_type, parsed_ranges):
"""Find the best match for a mime-type amongst parsed media-ranges.
Find the best match for a given mime-type against a list of media_ranges
that have already been parsed by parse_media_range(). Returns the 'q'
quality parameter of the best match, 0 if no match was found. This function
bahaves the same as quality() except that 'parsed_ranges' must be a list of
parsed media ranges.
"""
return fitness_and_quality_parsed(mime_type, parsed_ranges)[1]
def quality(mime_type, ranges):
"""Return the quality ('q') of a mime-type against a list of media-ranges.
Returns the quality 'q' of a mime-type when compared against the
media-ranges in ranges. For example:
>>> quality('text/html','text/*;q=0.3, text/html;q=0.7,
text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
0.7
"""
parsed_ranges = [parse_media_range(r) for r in ranges.split(",")]
return quality_parsed(mime_type, parsed_ranges)
def best_match(supported, header):
"""Return mime-type with the highest quality ('q') from list of candidates.
Takes a list of supported mime-types and finds the best match for all the
media-ranges listed in header. The value of header must be a string that
conforms to the format of the HTTP Accept: header. The value of 'supported'
is a list of mime-types. The list of supported mime-types should be sorted
in order of increasing desirability, in case of a situation where there is
a tie.
>>> best_match(['application/xbel+xml', 'text/xml'],
'text/*;q=0.5,*/*; q=0.1')
'text/xml'
"""
split_header = _filter_blank(header.split(","))
parsed_header = [parse_media_range(r) for r in split_header]
weighted_matches = []
pos = 0
for mime_type in supported:
weighted_matches.append(
(fitness_and_quality_parsed(mime_type, parsed_header), pos, mime_type)
)
pos += 1
weighted_matches.sort()
return weighted_matches[-1][0][1] and weighted_matches[-1][2] or ""
def _filter_blank(i):
for s in i:
if s.strip():
yield s

View File

@@ -0,0 +1,409 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Model objects for requests and responses.
Each API may support one or more serializations, such
as JSON, Atom, etc. The model classes are responsible
for converting between the wire format and the Python
object representation.
"""
from __future__ import absolute_import
__author__ = "jcgregorio@google.com (Joe Gregorio)"
import json
import logging
import platform
import urllib
from googleapiclient import version as googleapiclient_version
from googleapiclient.errors import HttpError
_LIBRARY_VERSION = googleapiclient_version.__version__
_PY_VERSION = platform.python_version()
LOGGER = logging.getLogger(__name__)
dump_request_response = False
def _abstract():
raise NotImplementedError("You need to override this function")
class Model(object):
"""Model base class.
All Model classes should implement this interface.
The Model serializes and de-serializes between a wire
format such as JSON and a Python object representation.
"""
def request(self, headers, path_params, query_params, body_value):
"""Updates outgoing requests with a serialized body.
Args:
headers: dict, request headers
path_params: dict, parameters that appear in the request path
query_params: dict, parameters that appear in the query
body_value: object, the request body as a Python object, which must be
serializable.
Returns:
A tuple of (headers, path_params, query, body)
headers: dict, request headers
path_params: dict, parameters that appear in the request path
query: string, query part of the request URI
body: string, the body serialized in the desired wire format.
"""
_abstract()
def response(self, resp, content):
"""Convert the response wire format into a Python object.
Args:
resp: httplib2.Response, the HTTP response headers and status
content: string, the body of the HTTP response
Returns:
The body de-serialized as a Python object.
Raises:
googleapiclient.errors.HttpError if a non 2xx response is received.
"""
_abstract()
class BaseModel(Model):
"""Base model class.
Subclasses should provide implementations for the "serialize" and
"deserialize" methods, as well as values for the following class attributes.
Attributes:
accept: The value to use for the HTTP Accept header.
content_type: The value to use for the HTTP Content-type header.
no_content_response: The value to return when deserializing a 204 "No
Content" response.
alt_param: The value to supply as the "alt" query parameter for requests.
"""
accept = None
content_type = None
no_content_response = None
alt_param = None
def _log_request(self, headers, path_params, query, body):
"""Logs debugging information about the request if requested."""
if dump_request_response:
LOGGER.info("--request-start--")
LOGGER.info("-headers-start-")
for h, v in headers.items():
LOGGER.info("%s: %s", h, v)
LOGGER.info("-headers-end-")
LOGGER.info("-path-parameters-start-")
for h, v in path_params.items():
LOGGER.info("%s: %s", h, v)
LOGGER.info("-path-parameters-end-")
LOGGER.info("body: %s", body)
LOGGER.info("query: %s", query)
LOGGER.info("--request-end--")
def request(self, headers, path_params, query_params, body_value):
"""Updates outgoing requests with a serialized body.
Args:
headers: dict, request headers
path_params: dict, parameters that appear in the request path
query_params: dict, parameters that appear in the query
body_value: object, the request body as a Python object, which must be
serializable by json.
Returns:
A tuple of (headers, path_params, query, body)
headers: dict, request headers
path_params: dict, parameters that appear in the request path
query: string, query part of the request URI
body: string, the body serialized as JSON
"""
query = self._build_query(query_params)
headers["accept"] = self.accept
headers["accept-encoding"] = "gzip, deflate"
if "user-agent" in headers:
headers["user-agent"] += " "
else:
headers["user-agent"] = ""
headers["user-agent"] += "(gzip)"
if "x-goog-api-client" in headers:
headers["x-goog-api-client"] += " "
else:
headers["x-goog-api-client"] = ""
headers["x-goog-api-client"] += "gdcl/%s gl-python/%s" % (
_LIBRARY_VERSION,
_PY_VERSION,
)
if body_value is not None:
headers["content-type"] = self.content_type
body_value = self.serialize(body_value)
self._log_request(headers, path_params, query, body_value)
return (headers, path_params, query, body_value)
def _build_query(self, params):
"""Builds a query string.
Args:
params: dict, the query parameters
Returns:
The query parameters properly encoded into an HTTP URI query string.
"""
if self.alt_param is not None:
params.update({"alt": self.alt_param})
astuples = []
for key, value in params.items():
if type(value) == type([]):
for x in value:
x = x.encode("utf-8")
astuples.append((key, x))
else:
if isinstance(value, str) and callable(value.encode):
value = value.encode("utf-8")
astuples.append((key, value))
return "?" + urllib.parse.urlencode(astuples)
def _log_response(self, resp, content):
"""Logs debugging information about the response if requested."""
if dump_request_response:
LOGGER.info("--response-start--")
for h, v in resp.items():
LOGGER.info("%s: %s", h, v)
if content:
LOGGER.info(content)
LOGGER.info("--response-end--")
def response(self, resp, content):
"""Convert the response wire format into a Python object.
Args:
resp: httplib2.Response, the HTTP response headers and status
content: string, the body of the HTTP response
Returns:
The body de-serialized as a Python object.
Raises:
googleapiclient.errors.HttpError if a non 2xx response is received.
"""
self._log_response(resp, content)
# Error handling is TBD, for example, do we retry
# for some operation/error combinations?
if resp.status < 300:
if resp.status == 204:
# A 204: No Content response should be treated differently
# to all the other success states
return self.no_content_response
return self.deserialize(content)
else:
LOGGER.debug("Content from bad request was: %r" % content)
raise HttpError(resp, content)
def serialize(self, body_value):
"""Perform the actual Python object serialization.
Args:
body_value: object, the request body as a Python object.
Returns:
string, the body in serialized form.
"""
_abstract()
def deserialize(self, content):
"""Perform the actual deserialization from response string to Python
object.
Args:
content: string, the body of the HTTP response
Returns:
The body de-serialized as a Python object.
"""
_abstract()
class JsonModel(BaseModel):
"""Model class for JSON.
Serializes and de-serializes between JSON and the Python
object representation of HTTP request and response bodies.
"""
accept = "application/json"
content_type = "application/json"
alt_param = "json"
def __init__(self, data_wrapper=False):
"""Construct a JsonModel.
Args:
data_wrapper: boolean, wrap requests and responses in a data wrapper
"""
self._data_wrapper = data_wrapper
def serialize(self, body_value):
if (
isinstance(body_value, dict)
and "data" not in body_value
and self._data_wrapper
):
body_value = {"data": body_value}
return json.dumps(body_value)
def deserialize(self, content):
try:
content = content.decode("utf-8")
except AttributeError:
pass
try:
body = json.loads(content)
except json.decoder.JSONDecodeError:
body = content
else:
if self._data_wrapper and "data" in body:
body = body["data"]
return body
@property
def no_content_response(self):
return {}
class RawModel(JsonModel):
"""Model class for requests that don't return JSON.
Serializes and de-serializes between JSON and the Python
object representation of HTTP request, and returns the raw bytes
of the response body.
"""
accept = "*/*"
content_type = "application/json"
alt_param = None
def deserialize(self, content):
return content
@property
def no_content_response(self):
return ""
class MediaModel(JsonModel):
"""Model class for requests that return Media.
Serializes and de-serializes between JSON and the Python
object representation of HTTP request, and returns the raw bytes
of the response body.
"""
accept = "*/*"
content_type = "application/json"
alt_param = "media"
def deserialize(self, content):
return content
@property
def no_content_response(self):
return ""
class ProtocolBufferModel(BaseModel):
"""Model class for protocol buffers.
Serializes and de-serializes the binary protocol buffer sent in the HTTP
request and response bodies.
"""
accept = "application/x-protobuf"
content_type = "application/x-protobuf"
alt_param = "proto"
def __init__(self, protocol_buffer):
"""Constructs a ProtocolBufferModel.
The serialized protocol buffer returned in an HTTP response will be
de-serialized using the given protocol buffer class.
Args:
protocol_buffer: The protocol buffer class used to de-serialize a
response from the API.
"""
self._protocol_buffer = protocol_buffer
def serialize(self, body_value):
return body_value.SerializeToString()
def deserialize(self, content):
return self._protocol_buffer.FromString(content)
@property
def no_content_response(self):
return self._protocol_buffer()
def makepatch(original, modified):
"""Create a patch object.
Some methods support PATCH, an efficient way to send updates to a resource.
This method allows the easy construction of patch bodies by looking at the
differences between a resource before and after it was modified.
Args:
original: object, the original deserialized resource
modified: object, the modified deserialized resource
Returns:
An object that contains only the changes from original to modified, in a
form suitable to pass to a PATCH method.
Example usage:
item = service.activities().get(postid=postid, userid=userid).execute()
original = copy.deepcopy(item)
item['object']['content'] = 'This is updated.'
service.activities.patch(postid=postid, userid=userid,
body=makepatch(original, item)).execute()
"""
patch = {}
for key, original_value in original.items():
modified_value = modified.get(key, None)
if modified_value is None:
# Use None to signal that the element is deleted
patch[key] = None
elif original_value != modified_value:
if type(original_value) == type({}):
# Recursively descend objects
patch[key] = makepatch(original_value, modified_value)
else:
# In the case of simple types or arrays we just replace
patch[key] = modified_value
else:
# Don't add anything to patch if there's no change
pass
for key in modified:
if key not in original:
patch[key] = modified[key]
return patch

View File

@@ -0,0 +1,317 @@
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Schema processing for discovery based APIs
Schemas holds an APIs discovery schemas. It can return those schema as
deserialized JSON objects, or pretty print them as prototype objects that
conform to the schema.
For example, given the schema:
schema = \"\"\"{
"Foo": {
"type": "object",
"properties": {
"etag": {
"type": "string",
"description": "ETag of the collection."
},
"kind": {
"type": "string",
"description": "Type of the collection ('calendar#acl').",
"default": "calendar#acl"
},
"nextPageToken": {
"type": "string",
"description": "Token used to access the next
page of this result. Omitted if no further results are available."
}
}
}
}\"\"\"
s = Schemas(schema)
print s.prettyPrintByName('Foo')
Produces the following output:
{
"nextPageToken": "A String", # Token used to access the
# next page of this result. Omitted if no further results are available.
"kind": "A String", # Type of the collection ('calendar#acl').
"etag": "A String", # ETag of the collection.
},
The constructor takes a discovery document in which to look up named schema.
"""
from __future__ import absolute_import
# TODO(jcgregorio) support format, enum, minimum, maximum
__author__ = "jcgregorio@google.com (Joe Gregorio)"
from collections import OrderedDict
from googleapiclient import _helpers as util
class Schemas(object):
"""Schemas for an API."""
def __init__(self, discovery):
"""Constructor.
Args:
discovery: object, Deserialized discovery document from which we pull
out the named schema.
"""
self.schemas = discovery.get("schemas", {})
# Cache of pretty printed schemas.
self.pretty = {}
@util.positional(2)
def _prettyPrintByName(self, name, seen=None, dent=0):
"""Get pretty printed object prototype from the schema name.
Args:
name: string, Name of schema in the discovery document.
seen: list of string, Names of schema already seen. Used to handle
recursive definitions.
Returns:
string, A string that contains a prototype object with
comments that conforms to the given schema.
"""
if seen is None:
seen = []
if name in seen:
# Do not fall into an infinite loop over recursive definitions.
return "# Object with schema name: %s" % name
seen.append(name)
if name not in self.pretty:
self.pretty[name] = _SchemaToStruct(
self.schemas[name], seen, dent=dent
).to_str(self._prettyPrintByName)
seen.pop()
return self.pretty[name]
def prettyPrintByName(self, name):
"""Get pretty printed object prototype from the schema name.
Args:
name: string, Name of schema in the discovery document.
Returns:
string, A string that contains a prototype object with
comments that conforms to the given schema.
"""
# Return with trailing comma and newline removed.
return self._prettyPrintByName(name, seen=[], dent=0)[:-2]
@util.positional(2)
def _prettyPrintSchema(self, schema, seen=None, dent=0):
"""Get pretty printed object prototype of schema.
Args:
schema: object, Parsed JSON schema.
seen: list of string, Names of schema already seen. Used to handle
recursive definitions.
Returns:
string, A string that contains a prototype object with
comments that conforms to the given schema.
"""
if seen is None:
seen = []
return _SchemaToStruct(schema, seen, dent=dent).to_str(self._prettyPrintByName)
def prettyPrintSchema(self, schema):
"""Get pretty printed object prototype of schema.
Args:
schema: object, Parsed JSON schema.
Returns:
string, A string that contains a prototype object with
comments that conforms to the given schema.
"""
# Return with trailing comma and newline removed.
return self._prettyPrintSchema(schema, dent=0)[:-2]
def get(self, name, default=None):
"""Get deserialized JSON schema from the schema name.
Args:
name: string, Schema name.
default: object, return value if name not found.
"""
return self.schemas.get(name, default)
class _SchemaToStruct(object):
"""Convert schema to a prototype object."""
@util.positional(3)
def __init__(self, schema, seen, dent=0):
"""Constructor.
Args:
schema: object, Parsed JSON schema.
seen: list, List of names of schema already seen while parsing. Used to
handle recursive definitions.
dent: int, Initial indentation depth.
"""
# The result of this parsing kept as list of strings.
self.value = []
# The final value of the parsing.
self.string = None
# The parsed JSON schema.
self.schema = schema
# Indentation level.
self.dent = dent
# Method that when called returns a prototype object for the schema with
# the given name.
self.from_cache = None
# List of names of schema already seen while parsing.
self.seen = seen
def emit(self, text):
"""Add text as a line to the output.
Args:
text: string, Text to output.
"""
self.value.extend([" " * self.dent, text, "\n"])
def emitBegin(self, text):
"""Add text to the output, but with no line terminator.
Args:
text: string, Text to output.
"""
self.value.extend([" " * self.dent, text])
def emitEnd(self, text, comment):
"""Add text and comment to the output with line terminator.
Args:
text: string, Text to output.
comment: string, Python comment.
"""
if comment:
divider = "\n" + " " * (self.dent + 2) + "# "
lines = comment.splitlines()
lines = [x.rstrip() for x in lines]
comment = divider.join(lines)
self.value.extend([text, " # ", comment, "\n"])
else:
self.value.extend([text, "\n"])
def indent(self):
"""Increase indentation level."""
self.dent += 1
def undent(self):
"""Decrease indentation level."""
self.dent -= 1
def _to_str_impl(self, schema):
"""Prototype object based on the schema, in Python code with comments.
Args:
schema: object, Parsed JSON schema file.
Returns:
Prototype object based on the schema, in Python code with comments.
"""
stype = schema.get("type")
if stype == "object":
self.emitEnd("{", schema.get("description", ""))
self.indent()
if "properties" in schema:
properties = schema.get("properties", {})
sorted_properties = OrderedDict(sorted(properties.items()))
for pname, pschema in sorted_properties.items():
self.emitBegin('"%s": ' % pname)
self._to_str_impl(pschema)
elif "additionalProperties" in schema:
self.emitBegin('"a_key": ')
self._to_str_impl(schema["additionalProperties"])
self.undent()
self.emit("},")
elif "$ref" in schema:
schemaName = schema["$ref"]
description = schema.get("description", "")
s = self.from_cache(schemaName, seen=self.seen)
parts = s.splitlines()
self.emitEnd(parts[0], description)
for line in parts[1:]:
self.emit(line.rstrip())
elif stype == "boolean":
value = schema.get("default", "True or False")
self.emitEnd("%s," % str(value), schema.get("description", ""))
elif stype == "string":
value = schema.get("default", "A String")
self.emitEnd('"%s",' % str(value), schema.get("description", ""))
elif stype == "integer":
value = schema.get("default", "42")
self.emitEnd("%s," % str(value), schema.get("description", ""))
elif stype == "number":
value = schema.get("default", "3.14")
self.emitEnd("%s," % str(value), schema.get("description", ""))
elif stype == "null":
self.emitEnd("None,", schema.get("description", ""))
elif stype == "any":
self.emitEnd('"",', schema.get("description", ""))
elif stype == "array":
self.emitEnd("[", schema.get("description"))
self.indent()
self.emitBegin("")
self._to_str_impl(schema["items"])
self.undent()
self.emit("],")
else:
self.emit("Unknown type! %s" % stype)
self.emitEnd("", "")
self.string = "".join(self.value)
return self.string
def to_str(self, from_cache):
"""Prototype object based on the schema, in Python code with comments.
Args:
from_cache: callable(name, seen), Callable that retrieves an object
prototype for a schema with the given name. Seen is a list of schema
names already seen as we recursively descend the schema definition.
Returns:
Prototype object based on the schema, in Python code with comments.
The lines of the code will all be properly indented.
"""
self.from_cache = from_cache
return self._to_str_impl(self.schema)

View File

@@ -0,0 +1,15 @@
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
__version__ = "2.124.0"