mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-16 20:21:37 +00:00
Compare commits
94 Commits
20231212.1
...
20240301.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63b1ca7e30 | ||
|
|
a328ac8ea9 | ||
|
|
2188bfa704 | ||
|
|
0f5adbe211 | ||
|
|
d0251182de | ||
|
|
a04345fb10 | ||
|
|
80440255ab | ||
|
|
7b3cc6d819 | ||
|
|
76d3ead61b | ||
|
|
21ca008a47 | ||
|
|
96aa4f3bd2 | ||
|
|
883979f5f5 | ||
|
|
b03a43777d | ||
|
|
a0e4be4b50 | ||
|
|
115caf2486 | ||
|
|
d5255615fd | ||
|
|
d949ca2cad | ||
|
|
4b0533ff0e | ||
|
|
d1e87df2df | ||
|
|
dc8f6c3b5e | ||
|
|
70640c1ddb | ||
|
|
a72b81f99e | ||
|
|
89a7c86840 | ||
|
|
a086c1c2a8 | ||
|
|
be3c6f10c7 | ||
|
|
1c9f65f7ca | ||
|
|
b023ecf8ce | ||
|
|
0a0cb2a18b | ||
|
|
a02afe76fc | ||
|
|
0b24beca30 | ||
|
|
7dfa236bc1 | ||
|
|
b7400b9010 | ||
|
|
50c5986c3e | ||
|
|
fff892300b | ||
|
|
adbee45073 | ||
|
|
2d091c8ca0 | ||
|
|
933fc19379 | ||
|
|
2bb2684165 | ||
|
|
868e5e1ab6 | ||
|
|
d537067908 | ||
|
|
a9b8a14d8e | ||
|
|
f3d654fc76 | ||
|
|
62a01bbcfd | ||
|
|
e60e1e939b | ||
|
|
5305f1bda0 | ||
|
|
6126e6ac67 | ||
|
|
58e2f74700 | ||
|
|
dcaf892e95 | ||
|
|
e8b2dee02d | ||
|
|
267d63fcd6 | ||
|
|
566a0c0345 | ||
|
|
6ed3f8ebfc | ||
|
|
51c7a542e3 | ||
|
|
ee68669652 | ||
|
|
e7e653d395 | ||
|
|
e6a4eb7fd9 | ||
|
|
25cdf2e544 | ||
|
|
5e1702018c | ||
|
|
a404af0582 | ||
|
|
741b69ff2d | ||
|
|
da1f808c06 | ||
|
|
39a8bf9485 | ||
|
|
53d1ce5ddb | ||
|
|
432ef09129 | ||
|
|
647da9f980 | ||
|
|
cc50ae28cd | ||
|
|
64ed92692a | ||
|
|
2dd810ba69 | ||
|
|
5922d939e2 | ||
|
|
14eaa9f32f | ||
|
|
f935a6bdfc | ||
|
|
29ceda7f43 | ||
|
|
f950c863f4 | ||
|
|
90f9931dca | ||
|
|
4c357d5281 | ||
|
|
0abf2ceeca | ||
|
|
3088570449 | ||
|
|
800943c401 | ||
|
|
3bedb57443 | ||
|
|
668ded91e2 | ||
|
|
293e1c1d9a | ||
|
|
7596215bbe | ||
|
|
7c6bbaf107 | ||
|
|
5271368776 | ||
|
|
430a30e2d2 | ||
|
|
b0eae53f80 | ||
|
|
dd03bafaec | ||
|
|
ded3ea104b | ||
|
|
0d9c6a77b6 | ||
|
|
ae46ae8738 | ||
|
|
06a4c7a8c9 | ||
|
|
f89f730957 | ||
|
|
80fc40a9c7 | ||
|
|
2bb0088ade |
647
.github/workflows/build.yml
vendored
647
.github/workflows/build.yml
vendored
@@ -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
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -55,13 +55,18 @@ gam create alias bob[@yourdomain.com] user robert[@yourdomain.com]
|
||||
The existing alias is deleted and a new alias is created.
|
||||
```
|
||||
gam update alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
|
||||
[notargetverify]
|
||||
[notargetverify] [waitafterdelete <Integer>]
|
||||
```
|
||||
`<EmailAddressEntity>` are the aliases, `<EmailAddress>` is the target.
|
||||
|
||||
By default, GAM makes additional API calls to verify that the target email address exists before updating the alias;
|
||||
if you know that the target exists, you can suppress the verification with `notargetverify.
|
||||
|
||||
GAM updates an alias to point to a new target by deleting the alias and then recreates the alias pointing to the new target.
|
||||
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
|
||||
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
|
||||
use the option `waitafterdelete <Integer>` to increase the wait time to a maximum of 10 seconds.
|
||||
|
||||
## Delete an alias regardless of the target
|
||||
```
|
||||
gam delete alias|aliases [user|group|target] <EmailAddressEntity>
|
||||
@@ -80,7 +85,7 @@ gam <UserTypeEntity> delete aliases
|
||||
```
|
||||
|
||||
## Display aliases
|
||||
Display a specific alise.
|
||||
Display a specific alias.
|
||||
```
|
||||
gam info alias|aliases <EmailAddressEntity>
|
||||
```
|
||||
@@ -124,6 +129,9 @@ By default, the aliases in a list are separated by the `csv_output_field_delimit
|
||||
|
||||
Specifying both `onerowpertarget` and `suppressnoaliasrows` causes GAM to not display any targets that have no aliases.
|
||||
|
||||
Add additional columns of data from the command line to the output
|
||||
* `addcsvdata <FieldName> <String>`
|
||||
|
||||
When multiple domains are specified and a query/queries are specified, an API call is made for each domain/query combination.
|
||||
```
|
||||
$ gam print aliases domains school.org,students.school.org queries "'email:admin*','email:test*'"
|
||||
|
||||
@@ -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,15 @@ 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
|
||||
|
||||
## 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 +404,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 +497,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 +837,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 +896,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.
|
||||
|
||||
@@ -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|
|
||||
@@ -232,8 +232,11 @@
|
||||
101035 |
|
||||
101036 |
|
||||
101037 |
|
||||
101038 |
|
||||
101039 |
|
||||
101040 |
|
||||
101043 |
|
||||
101047 |
|
||||
Google-Apps |
|
||||
Google-Chrome-Device-Management |
|
||||
Google-Drive-storage |
|
||||
@@ -249,12 +252,17 @@
|
||||
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 |
|
||||
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
|
||||
cloudidentity | identity | 1010010001 |
|
||||
cloudidentitypremium | identitypremium | 1010050001 |
|
||||
cloudsearch | 1010350001 |
|
||||
geminibiz | 1010470003 |
|
||||
geminient| duetai | 1010470001 |
|
||||
gsuitebasic | gafb | gafw | basic | Google-Apps-For-Business |
|
||||
gsuitebusiness | gau | gsb | unlimited | Google-Apps-Unlimited |
|
||||
gsuitebusinessarchived | gsbau | businessarchived | 1010340002 |
|
||||
@@ -270,6 +278,7 @@
|
||||
gwesstaff | workspaceeducationstandardstaff | 1010310006 |
|
||||
gwesstudent | workspaceeducationstandardstudent | 1010310007 |
|
||||
gwetlu | workspaceeducationupgrade | 1010370001 |
|
||||
gwlabs | workspacelabs | 1010470002
|
||||
meetdialing | googlemeetglobaldialing | 1010360001 |
|
||||
postini | gams | gsuitegams | gsuitepostini | gsuitemessagesecurity | Google-Apps-For-Postini |
|
||||
standard | free | Google-Apps |
|
||||
@@ -278,16 +287,22 @@
|
||||
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 |
|
||||
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030
|
||||
wsessplus | workspaceessentialsplus | 1010060005 |
|
||||
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 |
|
||||
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031
|
||||
```
|
||||
## Items built from primitives
|
||||
```
|
||||
@@ -346,7 +361,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 +436,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>
|
||||
@@ -460,8 +476,7 @@
|
||||
(message|textmessage|htmlmessage <String>)|
|
||||
(file|textfile|htmlfile <FileName> [charset <Charset>])|
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
(emlfile <FileName>)
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)
|
||||
<MessageID> ::= <String>
|
||||
<Namespace> ::= <String>
|
||||
<NotesName> ::= notes/<String>
|
||||
@@ -535,7 +550,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>
|
||||
@@ -590,8 +605,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>)|
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ This Wiki page was built directly from Jay Lee's Wiki page; my sincere thanks fo
|
||||
|
||||
<ChatContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <CharSet>])|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
|
||||
@@ -162,7 +162,7 @@ gam create chatmessage space <ChatSpace>
|
||||
```
|
||||
Specify the text of the message: `<ChatContent>`
|
||||
* `text <String>` - The message is `<String>`
|
||||
* `textfile <FileName> [charset <CharSet>]` - The message is read from a local file
|
||||
* `textfile <FileName> [charset <Charset>]` - The message is read from a local file
|
||||
* `gdoc <UserGoogleDoc>` - The message is read from a Google Doc.
|
||||
* `gcsdoc <StorageBucketObjectName>` - The message is read from a Google Cloud Storage file.
|
||||
|
||||
@@ -207,7 +207,7 @@ gam update chatmessage name <ChatMessage>
|
||||
```
|
||||
Specify the source of the message:
|
||||
* `text <String>` - The message is `<String>`
|
||||
* `textfile <FileName> [charset <CharSet>]` - The message is read from a local file
|
||||
* `textfile <FileName> [charset <Charset>]` - The message is read from a local file
|
||||
* `gdoc <UserGoogleDoc>` - The message is read from a Google Doc.
|
||||
* `gcsdoc <StorageBucketObjectName>` - The message is read from a Google Cloud Storage file.
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ gam create chromepolicyimage <ChromePolicyImageSchemaName> <FileName>
|
||||
## Update Chrome policy
|
||||
You can update a policy for all devices/users within an OU or for a specific printer or application within an OU.
|
||||
```
|
||||
gam update chromepolicy (<SchemaName> (<Field> <Value>)+)+
|
||||
gam update chromepolicy [convertcrnl]
|
||||
(<SchemaName> ((<Field> <Value>)+ | <JSONData>))+
|
||||
ou|org|orgunit <OrgUnitItem> [(printerid <PrinterID>)|(appid <AppID>)]
|
||||
```
|
||||
@@ -190,6 +190,14 @@ When specifying a value for this field you can enter the value in one of two way
|
||||
* `DEFAULT_PRINT_COLOR_ENUM_MONOCHROME` - The full value
|
||||
* `MONOCHROME` - The text following `..._ENUM_`
|
||||
|
||||
### TYPE_STRING fields with carriage returns (\r) and line feeds (\n)
|
||||
Use the `convertcrnl` option to properly handle these characters
|
||||
in value strings entered on the command line in the `<Field> <Value>` form.
|
||||
```
|
||||
gam update chromepolicy convertcrnl chrome.devices.DisabledDeviceReturnInstructions
|
||||
deviceDisabledMessage "Please return device to:\nSchool\n123 Main Street\nAnytown US" ou /Path/to/OU
|
||||
```
|
||||
|
||||
### Examples
|
||||
Restrict student users from adding additional printers and set default printing to black and white.
|
||||
```
|
||||
@@ -322,12 +330,12 @@ Version `6.21.02` is required.
|
||||
Display direct policies, update all
|
||||
```
|
||||
gam redirect csv ChromePolicies.csv print chromepolicies ou "/Path/To/OU1" show direct formatjson quotechar "'"
|
||||
gam csv ChromePolicies.csv quotechar "'" gam update chromepolicy "~name" json "~JSON"
|
||||
gam csv ChromePolicies.csv quotechar "'" gam update chromepolicy "~name" json "~JSON" ou "/Path/To/OU2"
|
||||
```
|
||||
Display all policies, select direct on update
|
||||
```
|
||||
gam redirect csv ChromePolicies.csv print chromepolicies ou "/Path/To/OU1" formatjson quotechar "'"
|
||||
gam config csv_input_row_filter "direct:boolean:true" csv ChromePolicies.csv quotechar "'" gam update chromepolicy "~name" json "~JSON"
|
||||
gam config csv_input_row_filter "direct:boolean:true" csv ChromePolicies.csv quotechar "'" gam update chromepolicy "~name" json "~JSON" ou "/Path/To/OU2"
|
||||
```
|
||||
|
||||
## Create Chrome network
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
- [Print a header row and fields for selected CrOS devices](#print-a-header-row-and-fields-for-selected-cros-devices)
|
||||
- [Print a header row and fields for specified CrOS devices](#print-a-header-row-and-fields-for-specified-cros-devices)
|
||||
- [Display Examples](#display-examples)
|
||||
- [Display CrOS device count](#display-cros-device-count)
|
||||
- [Display CrOS device counts](#display-cros-device-counts)
|
||||
- [Print ChromeOS device activity](#print-chromeos-device-activity)
|
||||
- [Print a header row and activity for selected CrOS devices](#print-a-header-row-and-activity-for-selected-cros-devices)
|
||||
- [Print a header row and activity for specified CrOS devices](#print-a-header-row-and-activity-for-specified-cros-devices)
|
||||
@@ -160,8 +160,10 @@ The second form is backwards compatible with Standard GAM and selection with `<C
|
||||
```
|
||||
<CrOSAction> ::=
|
||||
deprovision_different_model_replace|
|
||||
deprovision_different_model_replacement|
|
||||
deprovision_retiring_device|
|
||||
deprovision_same_model_replace|
|
||||
deprovision_same_model_replacement|
|
||||
deprovision_upgrade_transfer|
|
||||
disable|
|
||||
reenable|
|
||||
@@ -403,13 +405,15 @@ gam update ou csvkmd cros.csv keyfield OU datafield deviceId add croscsvdata dev
|
||||
deprovision_same_model_replace|
|
||||
deprovision_upgrade_transfer|
|
||||
disable|
|
||||
reenable|
|
||||
pre_provisioned_disable|
|
||||
pre_provisioned_reenable
|
||||
reenable
|
||||
|
||||
gam <CrOSTypeEntity> update action <CrOSAction> [acknowledge_device_touch_requirement]
|
||||
[actionbatchsize <Integer>]
|
||||
gam update cros <CrOSEntity> action <CrOSAction> [acknowledge_device_touch_requirement]
|
||||
[actionbatchsize <Integer>]
|
||||
```
|
||||
As of GAM version `6.67.00`, the new API function `batchChangeStatus` replaces the old API function `action`; ChromeOS devices are now processed in batches.
|
||||
The batch size defaults to 10, the `actionbatchsize <Integer>` option can be used to set a batch size between 10 and 250.
|
||||
|
||||
As deprovisioning ChromeOS devices is not reversible, you must enter `acknowledge_device_touch_requirement`
|
||||
when `<CrOSAction>` is `deprovision_same_model_replace`, `deprovision_different_model_replace`,
|
||||
@@ -679,10 +683,34 @@ Print information about CrOS devices synced between 45 days ago and 30 days ago:
|
||||
gam print cros query "sync:#querytime1#..#querytime2#" querytime1 -45d querytime2 -30d
|
||||
```
|
||||
|
||||
## Display CrOS device count
|
||||
## Display CrOS device counts
|
||||
Display the number of CrOS devices in an entity.
|
||||
```
|
||||
gam <CrOSTypeEntity> show count
|
||||
gam <CrOSTypeEntity> print cros showitemcountonly
|
||||
gam print cros select <CrOSTypeEntity> showitemcountonly
|
||||
gam print cros
|
||||
[(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
[(limittoou|cros_ou <OrgUnitItem>)|(cros_ou_and_children <OrgUnitItem>)|
|
||||
(cros_ous <OrgUnitList>)|(cros_ous_and_children <OrgUnitList>)]]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print cros query "sync:..2020-01-01" showitemcountonly
|
||||
Getting all CrOS Devices that match query (sync:..2020-01-01) for /, may take some time on a large Organizational Unit...
|
||||
Got 77 CrOS Devices that matched query (sync:..2020-01-01) for /...
|
||||
Got 77 CrOS Devices that matched query (sync:..2020-01-01)
|
||||
77
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print cros query "sync:..2020-01-01" showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print cros query "sync:..2020-01-01" showitemcountonly
|
||||
```
|
||||
|
||||
## Print ChromeOS device activity
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
- [Manage course aliases](#manage-course-aliases)
|
||||
- [Manage course topics](#manage-course-topics)
|
||||
- [Display courses](#display-courses)
|
||||
- [Display course counts](#display-course-counts)
|
||||
- [Display course announcements](#display-course-announcements)
|
||||
- [Display course materials](#display-course-materials)
|
||||
- [Display course topics](#display-course-topics)
|
||||
@@ -432,6 +433,33 @@ When using the `formatjson` option, double quotes are used extensively in the da
|
||||
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.
|
||||
|
||||
## Display course counts
|
||||
Display the number of courses.
|
||||
```
|
||||
gam print courses
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
[owneremailmatchpattern <RegularExpression>]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print courses states active showitemcountonly
|
||||
Getting all Courses that match query (Course State: ACTIVE), may take some time on a large Google Workspace Account...
|
||||
Got 268 Courses...
|
||||
Got 272 Courses...
|
||||
Got 272 Courses...
|
||||
272
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print courses states active showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print courses states active showitemcountonly
|
||||
```
|
||||
|
||||
## Display course announcements
|
||||
```
|
||||
gam print course-announcements [todrive <ToDriveAttribute>*]
|
||||
|
||||
@@ -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>])
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- [Legacy manage membership](#legacy-manage-membership)
|
||||
- [Bulk membership changes](#bulk-membership-changes)
|
||||
- [Display course membership](#display-course-membership)
|
||||
- [Display course membership counts](#display-course-membership-counts)
|
||||
|
||||
## API documentation
|
||||
* https://developers.google.com/classroom/reference/rest/
|
||||
@@ -131,3 +132,35 @@ the quote character itself, the column delimiter (comma by default) and new-line
|
||||
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.
|
||||
|
||||
## Display course membership counts
|
||||
Display the number of course participants.
|
||||
```
|
||||
gam print course-participants
|
||||
(course|class <CourseID>)*|([teacher <UserItem>] [student <UserItem>]) [states <CourseStateList>]
|
||||
[show all|students|teachers]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print course-participants teacher asmith states active show students showitemcountonly
|
||||
Getting all Courses that match query (Teacher: asmith@domain.com, Course State: ACTIVE), may take some time on a large Google Workspace Account...
|
||||
Got 3 Courses...
|
||||
Getting Students for Course: 636981507234 (1/3)
|
||||
Got 30 Students...
|
||||
Got 43 Students...
|
||||
Getting Students for Course: 589346784341 (2/3)
|
||||
Got 22 Students...
|
||||
Getting Students for Course: 589345535881 (3/3)
|
||||
Got 23 Students...
|
||||
88
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print course-participants teacher asmith states active show students showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print course-participants teacher asmith states active show students showitemcountonly
|
||||
```
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
- [Synchronize devices](#synchronize-devices)
|
||||
- [Display devices](#display-devices)
|
||||
- [Print devices](#print-devices)
|
||||
- [Display device counts](#display-device-counts)
|
||||
- [Approve or block device users](#approve-or-block-device-users)
|
||||
- [Delete device users](#delete-device-users)
|
||||
- [Wipe device users](#wipe-device-users)
|
||||
- [Perform device user actions](#perform-device-user-actions)
|
||||
- [Display device users](#display-device-users)
|
||||
- [Display device user counts](#display-device-user-counts)
|
||||
- [Print device users](#print-device-users)
|
||||
- [Display device user client state](#display-device-user-client-state)
|
||||
- [Update device user client state](#update-device-user-client-state)
|
||||
@@ -225,6 +227,37 @@ When using the `formatjson` option, double quotes are used extensively in the da
|
||||
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.
|
||||
|
||||
## Display device counts
|
||||
Display the number of devices.
|
||||
```
|
||||
gam print devices
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
[all|company|personal|nocompanydevices|nopersonaldevices]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print devices queries "'model:Mac'" showitemcountonly
|
||||
Getting all Devices that match query (model:Mac), may take some time on a large Google Workspace Account...
|
||||
Got 100 Devices...
|
||||
Got 200 Devices...
|
||||
Got 300 Devices...
|
||||
...
|
||||
Got 900 Devices...
|
||||
Got 995 Devices...
|
||||
Got 995 Devices...
|
||||
995
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print devices queries "'model:Mac'" showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print devices queries "'model:Mac'" showitemcountonly
|
||||
```
|
||||
|
||||
## Approve or block device users
|
||||
Approve or block user profiles on a device.
|
||||
```
|
||||
@@ -285,6 +318,38 @@ When using the `formatjson` option, double quotes are used extensively in the da
|
||||
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.
|
||||
|
||||
## Display device user counts
|
||||
Display the number of device users.
|
||||
```
|
||||
gam print deviceusers [todrive <ToDriveAttribute>*]
|
||||
[select <DeviceID>]
|
||||
[(query <QueryDevice>)|(queries <QueryDeviceList>) (querytime<String> <Time>)*]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print deviceusers queries "'model:Mac'" showitemcountonly
|
||||
Getting all Device Users that match query (model:Mac), may take some time on a large Google Workspace Account...
|
||||
Got 20 Device Users...
|
||||
Got 40 Device Users...
|
||||
Got 60 Device Users...
|
||||
...
|
||||
Got 980 Device Users...
|
||||
Got 995 Device Users...
|
||||
Got 995 Device Users...
|
||||
995
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print deviceusers queries "'model:Mac'" showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print deviceusers queries "'model:Mac'" showitemcountonly
|
||||
```
|
||||
|
||||
|
||||
## Display device user client state
|
||||
```
|
||||
gam info deviceuserstate <DeviceUserEntity> [clientid <String>]
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
- [Manage groups](#manage-groups)
|
||||
- [Display information about individual groups](#display-information-about-individual-groups)
|
||||
- [Display information about multiple groups](#display-information-about-multiple-groups)
|
||||
- [Display group counts](#display-group-counts)
|
||||
|
||||
## API documentation
|
||||
* https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups
|
||||
@@ -376,3 +377,29 @@ gam print cigroups query "'cloudidentity.googleapis.com/groups.dynamic' in label
|
||||
```
|
||||
gam print cigroups query "'cloudidentity.googleapis.com/groups.security' in labels"
|
||||
```
|
||||
|
||||
## Display group counts
|
||||
Display the number of groups.
|
||||
```
|
||||
gam print cigroups
|
||||
[(cimember|showownedby <UserItem>)|(select <GroupEntity>)|(query <String>)]
|
||||
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
|
||||
[descriptionmatchpattern [not] <RegularExpression>]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print cigroups showitemcountonly
|
||||
Getting all Cloud Identity Groups, may take some time on a large Google Workspace Account...
|
||||
Got 242 Cloud Identity Groups: td.current@domain.com - postmaster@domain.com
|
||||
242
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print cigroups showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print cidgroups showitemcountonly
|
||||
```
|
||||
|
||||
@@ -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> ::=
|
||||
|
||||
@@ -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>)]
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<NoteContent> ::=
|
||||
((<String>)|
|
||||
(file <FileName> [charset <CharSet>])|
|
||||
(file <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -10,6 +10,589 @@ 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.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
|
||||
a seperate user information row for each license a user is assigned. This makes processing
|
||||
the licenses in a script possible and allows better sorting in a CSV File.
|
||||
|
||||
By default, all licenses for a user are displayed in a list on one row:
|
||||
```
|
||||
primaryEmail,LicensesCount,Licenses,LicensesDisplay
|
||||
user@domain.com,2,1010020020 1010330004,Google Workspace Enterprise Plus Google Voice Standard
|
||||
```
|
||||
With `onelicenseperrow|onelicenceperrow`, each license is on a separate row:
|
||||
```
|
||||
primaryEmail,License,LicenseDisplay
|
||||
user@domain.com,1010020020,Google Workspace Enterprise Plus
|
||||
user@domain.com 1010330004,Google Voice Standard
|
||||
```
|
||||
|
||||
### 6.67.19
|
||||
|
||||
Updated `gam create|update user ... notify` to encode the characters `<>&` in the password
|
||||
so that they display correctly when the notify message content is HTML.
|
||||
|
||||
### 6.67.18
|
||||
|
||||
Cleaned up `Getting/Got` messages for `gam print courses|course-participants`.
|
||||
|
||||
### 6.67.17
|
||||
|
||||
Added option `showitemcountonly` to various commands that causes GAM to display the
|
||||
item count on stdout; no CSV file is written.
|
||||
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups#display-group-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Courses#display-course-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Membership#display-course-membership-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices#display-cros-device-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-user-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups#display-group-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Mobile-Devices#display-mobile-device-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#display-organizational-unit-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Resources#display-resource-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#display-user-counts
|
||||
|
||||
### 6.67.16
|
||||
|
||||
By default, `gam print group-members membernames` displays `Unknown` for members whose names can not be determined.
|
||||
Added option `unknownname <String>` that let's you specify an alternative value.
|
||||
|
||||
Further improved performance of `gam print group-members membernames cachememberinfo`.
|
||||
|
||||
### 6.67.15
|
||||
|
||||
Update `gam print group-members membernames` to handle the following error:
|
||||
```
|
||||
ERROR: 400: failedPrecondition - Precondition check failed.
|
||||
```
|
||||
|
||||
Added option `cachememberinfo [Boolean]` to `gam print group-members` that causes GAM to cache member info
|
||||
so that only one API call is made to get information for each user/group. This consumes
|
||||
more memory but dramatically reduces the number of API calls.
|
||||
|
||||
### 6.67.14
|
||||
|
||||
Updated reseller commands to handle the following error:
|
||||
```
|
||||
ERROR: 400: invalid - Customer domain [domain.com] is linked to one or more email verified customers, please provide a customer id.
|
||||
```
|
||||
|
||||
### 6.67.13
|
||||
|
||||
Updated `gam create domain <DomainName>` to handle the following error:
|
||||
```
|
||||
ERROR: 409: conflict - Domain in request is in use by an email verified customer.
|
||||
```
|
||||
|
||||
### 6.67.12
|
||||
|
||||
Added option `addcsvdata <FieldName> <String>` to `gam print datatransfers` that adds
|
||||
additional columns of data to the CSV file output.
|
||||
|
||||
### 6.67.11
|
||||
|
||||
Updated various Gmail related commands to handle this error:
|
||||
```
|
||||
ERROR: 403: permissionDenied - Insufficient Permission
|
||||
```
|
||||
when the following service account scopes are selected:
|
||||
|
||||
```
|
||||
[ ] 23) Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read
|
||||
[ ] 24) Gmail API - Full Access (Labels, Messages)
|
||||
[ ] 25) Gmail API - Full Access (Labels, Messages) except delete message
|
||||
[*] 26) Gmail API - Full Access - read only
|
||||
[ ] 27) Gmail API - Send Messages - including todrive
|
||||
[ ] 28) Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
|
||||
```
|
||||
|
||||
### 6.67.10
|
||||
|
||||
Fixed bug that caused a trap when optional argument `charset <Charset>` was used with `emlfile <FileName>` in `gam <UserTypeEntity> draft|import|insert message`.
|
||||
|
||||
### 6.67.09
|
||||
|
||||
Added option `maxevents <Number>` to `gam report <ActivityApplictionName>` that limits
|
||||
the number of events displayed for each activity; the default is 0, no limit.
|
||||
Setting options `maxactivities 1 maxevents 1 maxresults 1` can be used to as efficiently as possible
|
||||
show the most recent activity/event; this can be useful when reporting drive activity for individual drive files.
|
||||
|
||||
### 6.67.08
|
||||
|
||||
Added optional argument `charset <Charset>` to `emlfile <FileName>` in `gam <UserTypeEntity> draft|import|insert message`;
|
||||
the default value is `ascii`.
|
||||
|
||||
### 6.67.07
|
||||
|
||||
Updated `gam <UserTypeEntity> delete message` to handle this error:
|
||||
```
|
||||
ERROR: 403: permissionDenied - Insufficient Permission
|
||||
```
|
||||
when the following service account scopes are selected:
|
||||
|
||||
```
|
||||
[ ] 24) Gmail API - Full Access (Labels, Messages)
|
||||
[*] 25) Gmail API - Full Access (Labels, Messages) except delete message
|
||||
```
|
||||
|
||||
### 6.67.06
|
||||
|
||||
Updated commands that create ACLs to handle the following error:
|
||||
```
|
||||
ERROR: 400: abusiveContentRestriction - Bad Request. User message: "You cannot share this item because it has been flagged as inappropriate."
|
||||
```
|
||||
|
||||
### 6.67.05
|
||||
|
||||
Updated the following commands:
|
||||
```
|
||||
gam <UserTypeEntity> create|delete|update delegate
|
||||
gam <UserTypeEntity> forward
|
||||
gam <UserTypeEntity> create|delete forwardingaddresses
|
||||
gam <UserTypeEntity> create|delete sendas
|
||||
```
|
||||
to handle this error:
|
||||
```
|
||||
ERROR: 403: permissionDenied - Insufficient Permission
|
||||
```
|
||||
when the following serice account scope is not enabled:
|
||||
```
|
||||
[ ] 28) Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
|
||||
```
|
||||
|
||||
### 6.67.04
|
||||
|
||||
Updated user attribute `replace <Tag> <UserReplacement>` to allow `field:photourl` which allows
|
||||
embedding a link to a user's photo in their signature. Formatting the signature HTML
|
||||
to properly display the photo is left to the GAM admin.
|
||||
|
||||
### 6.67.03
|
||||
|
||||
Fixed bug introduced in 6.67.02 in `gam <UserTypeEntity> claim ownership` that caused a trap.
|
||||
|
||||
### 6.67.02
|
||||
|
||||
Added option `skipids <DriveFileEntity>` to `gam <UserTypeEntity> transfer drive` that handles special cases
|
||||
where you want to prevent ownership from being transferred for selected files/folders.
|
||||
|
||||
Added option `skipids <DriveFileEntity>` to `gam <UserTypeEntity> copy drivefile` that handles special cases
|
||||
where you want to prevent selected files/folders from being copied.
|
||||
|
||||
Updated commands that create files/folders on Shared Drives to handle the following errors:
|
||||
```
|
||||
storageQuotaExceeded
|
||||
teamDriveFileLimitExceeded
|
||||
teamDriveHierarchyTooDeep
|
||||
```
|
||||
* See: https://support.google.com/a/users/answer/7338880#shared_drives_file_folder_limits
|
||||
|
||||
### 6.67.01
|
||||
|
||||
Fixed bug in `gam print vaultcounts` that caused a trap.
|
||||
|
||||
### 6.67.00
|
||||
|
||||
Updated `gam <CrOSTypeEntity> update action <CrOSAction>` to use the new API function `batchChangeStatus`
|
||||
that replaces the old API function `action`; ChromeOS devices are now processed in batches.
|
||||
The batch size defaults to 10, the `actionbatchsize <Integer>` option can be used to set a batch size between 10 and 250.
|
||||
|
||||
Updated `gam create vaultexport matter <MatterItem>` to support `corpus calendar`.
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault-Takeout#create-vault-exports
|
||||
|
||||
### 6.66.16
|
||||
|
||||
Added option `convertcrnl` to `gam update chromepolicy` to properly handle carriage returns (\r) and line feeds (\n)
|
||||
in value strings entered on the command line in the `<Field> <Value>` form.
|
||||
```
|
||||
gam update chromepolicy convertcrnl chrome.devices.DisabledDeviceReturnInstructions
|
||||
deviceDisabledMessage "Please return device to:\nSchool\n123 Main Street\nAnytown US" ou /Path/to/OU
|
||||
```
|
||||
|
||||
### 6.66.15
|
||||
|
||||
Added option `copysubfilesownedby any|me|others` to `gam <UserTypeEntity> copy drivefile` that allows
|
||||
specification of which source folder sub files to copy based on file ownership; the default is `any`.
|
||||
This only applies when files are being copied from a 'My Drive'.
|
||||
|
||||
### 6.66.14
|
||||
|
||||
Updated `gam <UserTypeEntity> modify messages` to recognize the following error:
|
||||
```
|
||||
ERROR: 400: invalid - Invalid label: SENT
|
||||
```
|
||||
|
||||
Updated `gam update alias <EmailAddressEntity> user|group|target <EmailAddress>`
|
||||
to avoid the following problem.
|
||||
```
|
||||
$ gam update alias testalias@domain.com user testuser
|
||||
User Alias: testalias@domain.com, Deleted
|
||||
User Alias: testalias@domain.com, User: testuser@domain.com, Update Failed: Duplicate, Email Address: testalias@domain.com
|
||||
```
|
||||
GAM updates an alias to point to a new target by deleting the alias and then recreating the alias pointing to the new target.
|
||||
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
|
||||
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
|
||||
the option `waitafterdelete <Integer>` can be used to increase the wait time to a maximum of 10 seconds.
|
||||
|
||||
### 6.66.13
|
||||
|
||||
Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`.
|
||||
|
||||
* Current
|
||||
* `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
|
||||
* `preservefiletimes` - No effect
|
||||
* Updated
|
||||
* `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
|
||||
* `preservefiletimes` - `modifiedTime` of `<DriveFileEntity>` retains its current value
|
||||
|
||||
### 6.66.12
|
||||
|
||||
Upgraded to Python 3.12.1 where possible.
|
||||
|
||||
Updated all drive commands to handle the following error:
|
||||
```
|
||||
ERROR: 401: Active session is invalid. Error code: 4 - authError
|
||||
```
|
||||
This is due to the Drive SDK API being disabled in the user's OU.
|
||||
* See: https://support.google.com/a/answer/6105699
|
||||
|
||||
### 6.66.11
|
||||
|
||||
Fixed/improved handling of shortcuts in `gam <UserTypeEntity> transfer drive`.
|
||||
|
||||
@@ -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>
|
||||
@@ -63,6 +68,7 @@ gam show datatransfers|transfers
|
||||
gam print datatransfers|transfers [todrive <ToDriveAttribute>*]
|
||||
[olduser|oldowner <UserItem>] [newuser|newowner <UserItem>]
|
||||
[status completed|failed|inprogress|<String>] [delimiter <Character>]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
```
|
||||
By default, all data transfer operations are printed, use these options to select specific transfers.
|
||||
* `olduser|oldowner <UserItem>`
|
||||
@@ -72,3 +78,5 @@ By default, all data transfer operations are printed, use these options to selec
|
||||
By default, the entries in lists of items are separated by the `csv_output_field_delimiter` from `gam.cfg`.
|
||||
* `delimiter <Character>` - Separate list items with `<Character>`
|
||||
|
||||
Add additional columns of data from the command line to the output
|
||||
* `addcsvdata <FieldName> <String>`
|
||||
|
||||
@@ -583,6 +583,7 @@ gam print group-members [todrive <ToDriveAttribute>*]
|
||||
[userfields <UserFieldNameList>]
|
||||
[(recursive [noduplicates])|includederivedmembership] [nogroupemail]
|
||||
[peoplelookup|(peoplelookupuser <EmailAddress>)]
|
||||
[unknownname <String>] [cachememberinfo [Boolean]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, the group membership of all groups in the account are displayed, these options allow selection of subsets of groups:
|
||||
@@ -646,11 +647,17 @@ these options specify which fields to display:
|
||||
* `delivery|deliverysettings` - Specify this field to get delivery information; an additional API call per member is required
|
||||
* `userfields <UserFieldNameList>` - For members that are users, display these user fields; an additional API call per member is required
|
||||
|
||||
The additional API calls can be reduced with the `cachememberinfo` option; a single API call is made for each user/group
|
||||
and the data is cached to eliminate to need to repeat the API call; this consumes more memory but dramatically reduces the number of API calls.
|
||||
|
||||
If member names are requested, names are not available for users not in the domain; you can request that GAM use the People API to retrieve
|
||||
names for these users. Names are not retrieved in all cases and success is dependent on what user is used to perform the retrievals.
|
||||
* `peoplelookup` - Use the administrator named in oauth2.txt to perform the retrievals
|
||||
* `peoplelookupuser <EmailAddress>` - Use `<EmailAddress>` to perform the retrievals
|
||||
|
||||
By default, when `membernames` is specified, GAM displays `Unknown` for members whose names can not be determined.
|
||||
Use `unknownname <String>` to specify an alternative value.
|
||||
|
||||
By default, the group email address is always shown, you can suppress it with the `nogroupemail` option.
|
||||
|
||||
By default, members that are groups are displayed as a single entry of type GROUP; this option recursively expands group members to display their user members.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
- [Display information about selected groups](#display-information-about-selected-groups)
|
||||
- [Display a group and its parents](#Display-a-group-and-its-parents)
|
||||
- [Examples](#Examples)
|
||||
- [Display group counts](#display-group-counts)
|
||||
|
||||
## API documentation
|
||||
* https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups
|
||||
@@ -563,3 +564,31 @@ Group,Name,ParentsCount,Parents,ParentsName
|
||||
testgroup2@domain.com,Test - Group 2,2,testgroup1@domain.com|testgroup@domain.com,Test Group1|Test Group Org
|
||||
testgroup2@domain.com,Test - Group 2,1,testgroup@domain.net,Test Group Net
|
||||
```
|
||||
## Display group counts
|
||||
Display the number of groups.
|
||||
```
|
||||
gam print groups
|
||||
[([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryGroupList>)]))|
|
||||
(select <GroupEntity>)]
|
||||
[emailmatchpattern [not] <RegularExpression>] [namematchpattern [not] <RegularExpression>]
|
||||
[descriptionmatchpattern [not] <RegularExpression>] (matchsetting [not] <GroupAttribute>)*
|
||||
[admincreatedmatch <Boolean>]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print groups showitemcountonly
|
||||
Getting all Groups, may take some time on a large Google Workspace Account...
|
||||
Got 200 Groups: 1aparents@domain.com - students-genderfood@domain.com
|
||||
Got 238 Groups: students-worldculture@domain.com - xcarestaff@domain.com
|
||||
238
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print groups showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print groups showitemcountonly
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.66.11 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.71.06 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.10.8 64-bit final
|
||||
MacOS High Sierra 10.13.6 x86_64
|
||||
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.66.11 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.71.06 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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>)*"
|
||||
@@ -97,6 +99,7 @@
|
||||
<TasklistIDTaskIDList> ::= "<TasklistIDTaskID>(,<TasklistIDTaskID>)*"
|
||||
<ThreadIDList> ::= "<ThreadID>(,<ThreadID>)*"
|
||||
<TimeList> ::= "<Time>(,<Time>)*"
|
||||
<URLList> ::= "<URL>(,<URL>)*"
|
||||
<UserList> ::= "<UserItem>(,<UserItem>)*"
|
||||
<YouTubeChannelIDList> ::= "<YouTubeChannelID>(,<YouTubeChannelID>)*"
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
- [Manage mobile devices](#manage-mobile-devices)
|
||||
- [Display mobile devices](#display-mobile-devices)
|
||||
- [Print mobile devices](#print-mobile-devices)
|
||||
- [Display mobile device counts](#display-mobile-device-counts)
|
||||
|
||||
## API documentation
|
||||
* https://developers.google.com/admin-sdk/directory/reference/rest/v1/mobiledevices
|
||||
@@ -150,3 +151,27 @@ When using the `formatjson` option, double quotes are used extensively in the da
|
||||
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.
|
||||
|
||||
## Display mobile device counts
|
||||
Display the number of mobile devices.
|
||||
```
|
||||
gam print mobile
|
||||
[(query <QueryMobile>)|(queries <QueryMobileList>) (querytime<String> <Time>)*]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print mobile showitemcountonly
|
||||
Getting all Mobile Devices, may take some time on a large Google Workspace Account...
|
||||
Got 100 Mobile Devices...
|
||||
Got 115 Mobile Devices
|
||||
115
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print mobile showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print mobile showitemcountonly
|
||||
```
|
||||
|
||||
@@ -13,6 +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 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)
|
||||
|
||||
@@ -237,6 +238,30 @@ Get file count summaries by OU; top level selector is ou, sub level selectors ar
|
||||
gam redirect csv ./TopLevelOUs.csv print ous showparent toplevelonly parentselector ou childselector ou_and_children fields orgunitpath
|
||||
gam redirect csv ./FileCounts.csv multiprocess csv ./TopLevelOUs.csv gam "~orgUnitSelector" "~orgUnitPath" print filecounts excludetrashed summary only summaryuser "~orgUnitPath"
|
||||
```
|
||||
## Display organizational unit counts
|
||||
Display the number of organizational units.
|
||||
```
|
||||
gam print orgs|ous
|
||||
[fromparent <OrgUnitItem>] [showparent [Boolean>]] [toplevelonly]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print orgs showitemcountonly
|
||||
Getting all Organizational Units, may take some time on a large Google Workspace Account...
|
||||
Got 98 Organizational Units
|
||||
98
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print orgs showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print orgs showitemcountonly
|
||||
```
|
||||
|
||||
## Display indented organizational unit tree
|
||||
```
|
||||
gam show orgtree [fromparent <OrgUnitItem>] [batchsuborgs [<Boolean>]]
|
||||
|
||||
@@ -13,3 +13,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/
|
||||
@@ -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
|
||||
|
||||
@@ -58,7 +58,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttributes>*]
|
||||
[filtertime.* <Time>] [filter|filters <String>]
|
||||
[event|events <EventNameList>] [ip <String>]
|
||||
[groupidfilter <String>]
|
||||
[maxactivities <Number>] [maxresults <Number>]
|
||||
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
[countsonly [summary] [eventrowfilter]]
|
||||
(addcsvdata <FieldName> <String>)* [shownoactivities]
|
||||
```
|
||||
@@ -100,9 +100,15 @@ Limit to those users that are a member of at least one of a list of groups.
|
||||
Limit the total number of activites.
|
||||
* `maxactivities <Number>`
|
||||
|
||||
Limit the number of events per activity; this only applies when `countsonly` is False.
|
||||
* `maxevents <Number>`
|
||||
|
||||
Limit the number of activities downloaded per API call; infrequently used.
|
||||
* `maxresults <Number>`
|
||||
|
||||
Setting options `maxactivities 1 maxevents 1 maxresults 1` can be used to as efficiently as possible
|
||||
show the most recent activity/event; this can be useful when reporting drive activity for individual drive files.
|
||||
|
||||
Add additional columns of data from the command line to the output.
|
||||
* `addcsvdata <FieldName> <String>`
|
||||
|
||||
@@ -333,6 +339,9 @@ Select the users for whom information is desired.
|
||||
* `showorgunit` - Add a column labelled `orgUnitPath` to the output; an additional API call is made to get the email addresses of the users in `<OrgUnitPath>`
|
||||
* `select <UserTypeEntity>` - A selected collection of users, e.g., `select group staff@domain.com`; there is one API call per user
|
||||
|
||||
By default, when `user all` is specified (or no user specification in supplied), GAM backs up looking for data with a (basically) random user. If the randaom
|
||||
doesn't have any data, the command reports that no data was found. Use `allverifyuser <UserItem>` to specify a specific user to use to search for data.
|
||||
|
||||
Specify the report date; the default is today's date.
|
||||
* `date <Date>` - A single date; there is one API call
|
||||
* `range <Date> <Date>` - A range of dates; there is an API call per date
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
- [Display features](#display-features)
|
||||
- [Manage resources](#manage-resources)
|
||||
- [Display resources](#display-resources)
|
||||
- [Display resource counts](#display-resource-counts)
|
||||
- [Manage resource calendar ACLs](#manage-resource-calendar-acls)
|
||||
- [Display resource calendar ACLs](#display-resource-calendar-acls)
|
||||
|
||||
@@ -245,6 +246,30 @@ Print all resources and their owners.
|
||||
gam config csv_output_row_filter "role:regex:owner" redirect csv Resource.csv print resources acls
|
||||
```
|
||||
|
||||
## Display resource counts
|
||||
Display the number of mobile devices.
|
||||
```
|
||||
gam print resources
|
||||
[query <String>]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print resources showitemcountonly
|
||||
Getting all Resource Calendars, may take some time on a large Google Workspace Account...
|
||||
Got 32 Resource Calendars: Back 50 - Video Cameras Class Set
|
||||
32
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print resources showitemcountonly)
|
||||
Windows PowerShell
|
||||
count = & gam print resources showitemcountonly
|
||||
```
|
||||
|
||||
## Manage resource calendar ACLs
|
||||
These commands operate on a single resource calendar.
|
||||
```
|
||||
|
||||
@@ -54,8 +54,7 @@ Added the option `mailbox <EmailAddress>` to `gam sendemail` to allow specifying
|
||||
(message|textmessage|htmlmessage <String>)|
|
||||
(file|textfile|htmlfile <FileName> [charset <Charset>])|
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
(emlfile <FileName>)
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)
|
||||
```
|
||||
```
|
||||
<Time> ::=
|
||||
@@ -211,7 +210,7 @@ gam sendemail [recipient|to] <RecipientEntity>
|
||||
[cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
|
||||
[subject <String>]
|
||||
[<MessageContent>] (replace <Tag> <String>)*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <CharSet>])*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[newuser <EmailAddress> firstname|givenname <String> lastname|familyname <string> password <Password>]
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
@@ -242,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.
|
||||
@@ -267,7 +266,7 @@ gam sendemail [recipient|to] <RecipientEntity> [from <EmailAddress>]
|
||||
[cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
|
||||
[subject <String>]
|
||||
[<MessageContent>] (replace <Tag> <String>)*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <CharSet>])*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[newuser <EmailAddress> firstname|givenname <String> lastname|familyname <string> password <Password>]
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
@@ -298,7 +297,7 @@ If `message` is not specified, the following value will be used:
|
||||
* `Hello #givenname# #familyname#,\n\nYou have a new account at #domain#\nAccount details:\n\nUsername\n#user#\n\nPassword\n#password#\n\n
|
||||
Start using your new account by signing in at\nhttps://www.google.com/accounts/AccountChooser?Email=#user#&continue=https://apps.google.com/user/hub\n`
|
||||
|
||||
If you want a language/organization specific message, use a template file: `message file <FileName> [charset <CharSet>]`
|
||||
If you want a language/organization specific message, use a template file: `message file <FileName> [charset <Charset>]`
|
||||
|
||||
The `<SMTPDateHeader> <Time>` argument requires `<Time>` values which will be converted to RFC2822 dates. If you have these headers with values that
|
||||
are not in `<Time>` format, use the argument `header <SMTPDateHeader> <String>`.
|
||||
@@ -313,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;
|
||||
@@ -346,7 +345,7 @@ gam <UserTypeEntity> sendemail recipient|to <RecipientEntity>
|
||||
[cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
|
||||
[subject <String>]
|
||||
[<MessageContent>] (replace <Tag> <String>)*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <CharSet>])*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[newuser <EmailAddress> firstname|givenname <String> lastname|familyname <string> password <Password>]
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
@@ -377,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
|
||||
```
|
||||
@@ -386,7 +385,7 @@ gam <UserTypeEntity> sendemail [from <EmailAddress>]
|
||||
[cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
|
||||
[subject <String>]
|
||||
[<MessageContent>] (replace <Tag> <String>)*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <CharSet>])*
|
||||
[html [<Boolean>]] (attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[newuser <EmailAddress> firstname|givenname <String> lastname|familyname <string> password <Password>]
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
@@ -419,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
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
* https://developers.google.com/drive/api/v3/reference/teamdrives/list
|
||||
* https://support.google.com/a/answer/7374057
|
||||
* https://workspaceupdates.googleblog.com/2022/05/shared-drives-in-organizational-units-open-beta.html
|
||||
* https://support.google.com/a/users/answer/7338880
|
||||
|
||||
## Query documentation
|
||||
* https://developers.google.com/drive/api/v3/search-shareddrives
|
||||
@@ -67,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|
|
||||
|
||||
@@ -130,8 +130,11 @@
|
||||
relation.<RelationSubfieldName>.<RelationSubfieldName>.<String>|
|
||||
sshkeys.<SSHkeysSubfieldName>.<SSHkeysSubfieldName>.<String>|
|
||||
website.<WebsiteSubfieldName>.<WebsiteSubfieldName>.<String>
|
||||
<UserReplacementField> ::=
|
||||
photourl
|
||||
<Tag> ::= <String>
|
||||
<UserReplacement> ::=
|
||||
(field:<UserReplacementField>)|
|
||||
(field:<UserReplacementFieldSubfield>)|
|
||||
(field:<UserReplacementFieldSubfieldMatchSubfield>)|
|
||||
(schema:<SchemaName>.<FieldName>)|
|
||||
@@ -145,7 +148,7 @@ This command allows simple text replacement in the message.
|
||||
```
|
||||
gam sendemail <EmailAddressEntity> [from <UserItem>] [replyto <EmailAddress>]
|
||||
[cc <EmailAddressEntity>] [bcc <EmailAddressEntity>] [singlemessage [<Boolean>]]
|
||||
[subject <String>] [message <String>|(file <FileName> [charset <CharSet>])]
|
||||
[subject <String>] [message <String>|(file <FileName> [charset <Charset>])]
|
||||
(replace <Tag> <String>)* [html [<Boolean>]] (attach <FileName>)*
|
||||
```
|
||||
* Every instance of `{Tag}` in the message will be replaced by `<String>`.
|
||||
@@ -162,30 +165,30 @@ These commands allow simple text replacement in the message/signature as well as
|
||||
```
|
||||
gam create user <EmailAddress> <UserAttribute>*
|
||||
[notify <EmailAddress>] [subject <String>]
|
||||
[message <String>|(file <FileName> [charset <CharSet>])] [html [<Boolean>]]
|
||||
[message <String>|(file <FileName> [charset <Charset>])] [html [<Boolean>]]
|
||||
(replace <Tag> <UserReplacement>)*
|
||||
gam update user <UserItem> <UserAttribute>
|
||||
[updateprimaryemail <RegularExpression> <EmailReplacement>]
|
||||
[updateoufromgroup <FileName> [charset <CharSet>]
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
[createifnotfound] [notify <EmailAddress>] [subject <String>]
|
||||
[message <String>|(file <FileName> [charset <CharSet>])] [html [<Boolean>]]
|
||||
[message <String>|(file <FileName> [charset <Charset>])] [html [<Boolean>]]
|
||||
(replace <Tag> <UserReplacement>)*
|
||||
|
||||
gam <UserTypeEntity> draft message (<SMTPDateHeader> <Time>)*
|
||||
(<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(addlabel <LabelName>)* [labels <LabelNameList>]
|
||||
(textmessage|message <String>)|(textfile|file <FileName> [charset <CharSet>])
|
||||
(htmlmessage <String>)|(htmlfile <FileName> [charset <CharSet>])
|
||||
(replace <Tag> <UserReplacement>)* (attach <FileName> [charset <CharSet>])*
|
||||
(textmessage|message <String>)|(textfile|file <FileName> [charset <Charset>])
|
||||
(htmlmessage <String>)|(htmlfile <FileName> [charset <Charset>])
|
||||
(replace <Tag> <UserReplacement>)* (attach <FileName> [charset <Charset>])*
|
||||
gam <UserTypeEntity> import message (<SMTPDateHeader> <Time>)*
|
||||
(<SMTPHeader> <String>)*
|
||||
(header <String> <String>)*
|
||||
(addlabel <LabelName>)*
|
||||
(textmessage <String>)|(textfile <FileName> [charset <CharSet>])
|
||||
(htmlmessage <String>)|(htmlfile <FileName> [charset <CharSet>])
|
||||
(textmessage <String>)|(textfile <FileName> [charset <Charset>])
|
||||
(htmlmessage <String>)|(htmlfile <FileName> [charset <Charset>])
|
||||
(replace <Tag> <UserReplacement>)* (attach <FileName>)*
|
||||
[deleted [<Boolean>]] [nevermarkspam [<Boolean>]]
|
||||
[processforcalendar [<Boolean>]]
|
||||
@@ -194,19 +197,19 @@ gam <UserTypeEntity> insert message
|
||||
(<SMTPHeader> <String>)*
|
||||
(header <String> <String>)*
|
||||
(addlabel <LabelName>)*
|
||||
(textmessage <String>)|(textfile <FileName> [charset <CharSet>])
|
||||
(htmlmessage <String>)|(htmlfile <FileName> [charset <CharSet>])
|
||||
(textmessage <String>)|(textfile <FileName> [charset <Charset>])
|
||||
(htmlmessage <String>)|(htmlfile <FileName> [charset <Charset>])
|
||||
(replace <Tag> <UserReplacement>)* (attach <FileName>)*
|
||||
[deleted [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> [create|add] sendas <EmailAddress> <String>
|
||||
[signature|sig <String>|(file <FileName> [charset <CharSet>])
|
||||
[signature|sig <String>|(file <FileName> [charset <Charset>])
|
||||
(replace <Tag> <UserReplacement>)*]
|
||||
[html [<Boolean>]] [replyto <EmailAddress>]
|
||||
[default] [treatasalias <Boolean>]
|
||||
|
||||
gam <UserTypeEntity> update sendas <EmailAddress>
|
||||
[name <String>] [signature|sig <String>|(file <FileName> [charset <CharSet>])
|
||||
[name <String>] [signature|sig <String>|(file <FileName> [charset <Charset>])
|
||||
(replace <Tag> <UserReplacement>)*]
|
||||
[html [<Boolean>]] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
|
||||
|
||||
@@ -216,7 +219,7 @@ gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]
|
||||
[default] [primary] [treatasalias <Boolean>]
|
||||
|
||||
gam <UserTypeEntity> vacation <TrueValues> subject <String>
|
||||
[message <String>|(file <FileName> [charset <CharSet>])]
|
||||
[message <String>|(file <FileName> [charset <Charset>])]
|
||||
(replace <Tag> <UserReplacement>)*
|
||||
[html [<Boolean>]] [contactsonly [<Boolean>]] [domainonly [<Boolean>]]
|
||||
[startdate <Date>|Started] [enddate <Date>|NotSpecified]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -59,7 +59,7 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
|
||||
<ChatContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <CharSet>])|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>))
|
||||
|
||||
@@ -82,7 +82,8 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
```
|
||||
gam <UserTypeEntity> create chatspace
|
||||
[type <ChatSpaceType>]
|
||||
[externalusersrallowed <Boolean>]
|
||||
[restricted|(audience <String>)]
|
||||
[externalusersallowed <Boolean>]
|
||||
[members <UserTypeEntity>]
|
||||
[displayname <String>]
|
||||
[description <String>] [guidelines <String>]
|
||||
@@ -117,20 +118,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.
|
||||
|
||||
@@ -301,7 +308,7 @@ gam <UserTypeEntity> create chatmessage <ChatSpace>
|
||||
```
|
||||
Specify the text of the message: `<ChatContent>`
|
||||
* `text <String>` - The message is `<String>`
|
||||
* `textfile <FileName> [charset <CharSet>]` - The message is read from a local file
|
||||
* `textfile <FileName> [charset <Charset>]` - The message is read from a local file
|
||||
* `gdoc <UserGoogleDoc>` - The message is read from a Google Doc.
|
||||
* `gcsdoc <StorageBucketObjectName>` - The message is read from a Google Cloud Storage file.
|
||||
|
||||
@@ -344,7 +351,7 @@ gam <UserTypeEntity> update chatmessage name <ChatMessage>
|
||||
```
|
||||
Specify the text of the message: `<ChatContent>`
|
||||
* `text <String>` - The message is `<String>`
|
||||
* `textfile <FileName> [charset <CharSet>]` - The message is read from a local file
|
||||
* `textfile <FileName> [charset <Charset>]` - The message is read from a local file
|
||||
* `gdoc <UserGoogleDoc>` - The message is read from a Google Doc.
|
||||
* `gcsdoc <StorageBucketObjectName>` - The message is read from a Google Cloud Storage file.
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ As of version `6.14.04`, There is now support for managing "Other Contacts".
|
||||
|
||||
<NoteContent> ::=
|
||||
((<String>)|
|
||||
(file <FileName> [charset <CharSet>])|
|
||||
(file <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>)
|
||||
```
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
## API documentation
|
||||
* https://developers.google.com/drive/api/v3/reference/files
|
||||
* https://support.google.com/a/answer/7374057
|
||||
* https://support.google.com/a/users/answer/7338880
|
||||
|
||||
## Definitions
|
||||
* [`<DriveFileEntity>`](Drive-File-Selection)
|
||||
@@ -66,11 +67,13 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
[summary [<Boolean>]] [showpermissionmessages [<Boolean>]]
|
||||
[<DriveFileParentAttribute>]
|
||||
[mergewithparent [<Boolean>]] [recursive [depth <Number>]]
|
||||
<DriveFileCopyAttribute>*
|
||||
[skipids <DriveFileEntity>]
|
||||
[copysubfiles [<Boolean>]] [filenamematchpattern <RegularExpression>]
|
||||
[filemimetype [not] <MimeTypeList>]
|
||||
[copysubfilesownedby any|me|others]
|
||||
[copysubfolders [<Boolean>]] [foldernamematchpattern <RegularExpression>]
|
||||
[copysubshortcuts [<Boolean>]] [shortcutnamematchpattern <RegularExpression>]
|
||||
<DriveFileCopyAttribute>*
|
||||
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
|
||||
[duplicatefolders merge|duplicatename|uniquename|skip]
|
||||
[copiedshortcutspointtocopiedfiles [<Boolean>]]
|
||||
@@ -124,6 +127,9 @@ The `depth <Number>` argument controls which files or folders within the top fol
|
||||
* `depth 0` - the files or folders in the top folder are copied, no descendants of folders are copied.
|
||||
* `depth N` - the files and folders within the top folder and those files and folders N levels below the top folder are copied.
|
||||
|
||||
### This option handles special cases where you want to prevent selected files/folders from being copied.
|
||||
* `skipids <DriveFileEntity>` - Do not copy files/folders with the specified IDs.
|
||||
|
||||
### By default, when recursively copying a top folder, all sub files, folders and shortcuts are copied, subject to the `depth` option.
|
||||
You can specify whether sub files, folders and shortcuts are copied. If sub folders are not copied, their contents are not copied.
|
||||
* `copysubfiles false` - Sub files are not copied
|
||||
@@ -148,6 +154,11 @@ You can specify `<RegularExpression>` patterns that limit the items copied based
|
||||
* `foldernamematchpattern <RegularExpression>` - Only folders whose name matches `<RegularExpression>` are copied
|
||||
* `shortcutnamematchpattern <RegularExpression>` - Only shortcuts whose name matches `<RegularExpression>` are copied
|
||||
|
||||
### By default, when copying sub files, all files, regardless of ownership, are copied.
|
||||
* `copysubfilesownedby any` - All files, regardless of ownership, are copied.
|
||||
* `copysubfilesownedby me` - Only files owned by `<UserTypeEntity>` are copied.
|
||||
* `copysubfilesownedby others` - Only files not owned by `<UserTypeEntity>` are copied.
|
||||
|
||||
### Specify a new name for the file/folder
|
||||
* `newfilename <DriveFileName>` - The copied file/folder will be named `<DriveFileName>`
|
||||
* If `stripnameprefix <String>` is specified, `<String>` will be stripped from the front of `<DriveFileName>`
|
||||
@@ -197,6 +208,7 @@ In previous versions, copying shortcuts caused an error because shortcuts can't
|
||||
|
||||
If a shortcut in the source structure points to a file/folder that is not in the source structure:
|
||||
* The shortcut is re-created to point to the original file/folder.
|
||||
|
||||
If a shortcut in the source structure points to a file/folder that is in the source structure:
|
||||
* `copiedshortcutspointtocopiedfiles` omitted or `copiedshortcutspointtocopiedfiles true` - The shortcut is re-created to point to the copied file/folder.
|
||||
* `copiedshortcutspointtocopiedfiles false` - The shortcut is re-created to point to the original file/folder.
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
## API documentation
|
||||
* https://developers.google.com/drive/api/v3/reference/files
|
||||
* https://support.google.com/a/answer/6105699
|
||||
|
||||
## Definitions
|
||||
* [`<DriveFileEntity>`](Drive-File-Selection)
|
||||
@@ -266,9 +267,10 @@
|
||||
<DriveOwnersSubfieldName>|
|
||||
parents|
|
||||
<DriveParentsSubfieldName>|
|
||||
permissionids|
|
||||
permissiondetails|
|
||||
permissions|
|
||||
<DrivePermissionsSubfieldName>|
|
||||
permissionids|
|
||||
properties|
|
||||
quotabytesused|quotaused|
|
||||
resourcekey|
|
||||
@@ -571,7 +573,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#'"
|
||||
```
|
||||
@@ -1004,7 +1006,7 @@ gam <UserTypeEntity> print|show filelist [todrive <ToDriveAttribute>*]
|
||||
[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]
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
* https://developers.google.com/drive/api/v3/ref-single-parent
|
||||
* https://developers.google.com/drive/api/v3/shared-drives-diffs
|
||||
* https://developers.google.com/drive/api/v3/shortcuts
|
||||
* https://support.google.com/a/answer/6105699
|
||||
* https://support.google.com/a/answer/7374057
|
||||
* https://support.google.com/a/users/answer/7338880
|
||||
* https://developers.google.com/docs/api/reference/rest
|
||||
|
||||
## Definitions
|
||||
@@ -462,7 +464,7 @@ gam <UserTypeEntity> update drivefile <DriveFileEntity> [copy] [returnidonly|ret
|
||||
[stripnameprefix <String>]
|
||||
<DriveFileUpdateAttribute>*
|
||||
[(gsheet|csvsheet <SheetEntity> [clearfilter])|(addsheet <String>)]
|
||||
[charset <CharSet>] [columndelimiter <Character>]
|
||||
[charset <Charset>] [columndelimiter <Character>]
|
||||
```
|
||||
By default, an existing file's attributes are updated.
|
||||
|
||||
@@ -492,7 +494,8 @@ From the Google Drive API documentation.
|
||||
By default, Google assigns the current time to the attribute `modifiedTime`; you can assign your own value
|
||||
with `modifiedtime <Time>`.
|
||||
|
||||
The option `preservefiletimes`, when used with `localfile <FileName>`, will set the `modifiedTime` attribute from the local file.
|
||||
* `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
|
||||
* `preservefiletimes` - `modifiedTime` of `<DriveFileEntity>` retains its current value
|
||||
|
||||
These are the naming rules when updating from a local file:
|
||||
* `update drivefile drivefilename "GoogleFile.csv" localfile "NewLocalFile.csv"` - Google Drive file "GoogleFile.csv" is renamed "NewLocalFile.csv"
|
||||
@@ -513,7 +516,7 @@ You can update a specific sheet within a Google spreadsheet or add a new sheet t
|
||||
* `gsheet|csvsheet id:<Number>` - Specify a sheet by ID in a Google Sheets file to be updated
|
||||
* `clearfilter` - When updating a sheet, this option causes GAM to clear the spreadsheet basic filter so hidden data will be overwritten
|
||||
* `addsheet <String>` - Specify a sheet name to be added to the Google Sheets file
|
||||
* `charset <CharSet>` - Specify the character set of the local file; if not specified, the value of `charset` from `gam.cfg` will be used
|
||||
* `charset <Charset>` - Specify the character set of the local file; if not specified, the value of `charset` from `gam.cfg` will be used
|
||||
* `columndelimiter <Character>` - Columns are separated by `<Character>`; if not specified, the value of `csv_input_column_delimiter` from `gam.cfg` will be used
|
||||
If you want the Google spreadsheet to retain its name, specify: `retainname localfile LocalFile.csv`.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -107,9 +107,9 @@ By default, files in the trash are not transferred.
|
||||
Specify order of file processing.
|
||||
* `(orderby <DriveOrderByFieldName> [ascending|descending])*`
|
||||
|
||||
These options handle special cases where you want to prevent ownership from being transferred for selected files.
|
||||
* `skipids <DriveFileEntity>` - Do not transfer ownership for files with the specified IDs.
|
||||
* `skipusers <UserTypeEntity>` - Do not transfer ownership for files owned by the specified users.
|
||||
These options handle special cases where you want to prevent ownership from being transferred for selected files/folders.
|
||||
* `skipids <DriveFileEntity>` - Do not transfer ownership for files/folders with the specified IDs.
|
||||
* `skipusers <UserTypeEntity>` - Do not transfer ownership for files/folders owned by the specified users.
|
||||
|
||||
By default, only files owned by users in the same domain as the claiming user have their ownership transferred.
|
||||
* `subdomains <DomainNameEntity>` - Transfer ownership for files in the selected sub-domains.
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- [Manage file permissions/sharing](#manage-file-permissionssharing)
|
||||
- [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
|
||||
* https://developers.google.com/drive/api/v3/ref-single-parent
|
||||
@@ -303,3 +306,37 @@ Inspect Permissions.csv, verify that you want to proceed.
|
||||
```
|
||||
gam config csv_input_row_drop_filter "permission.role:regex:(owner)|(organizer)" csv ./Permissions.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Change shares to User1 to shares to User2
|
||||
```
|
||||
# Get files shared to User1
|
||||
gam redirect csv ./FilesSharedWithU1.csv user user1@domain.com print filelist choose sharedwithme fields id,name,mimetype,owners.emailaddress
|
||||
# For each of these files, get the sharing settings for U1
|
||||
gam redirect csv ./FilesSharedWithU1Settings.csv multiprocess csv FilesSharedWithU1.csv gam user "~owners.0.emailAddress" print drivefileacls "~id" pm emailaddress "~Owner" em
|
||||
# For each of these files, delete the share to User1
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>]
|
||||
By default, all of the source users files will be transferred except those in the trash. If you want to transfer a subset of
|
||||
the source users files, use the `select <DriveFileEntity>` option.
|
||||
|
||||
This option handles special cases where you want to prevent selected files from being transferred.
|
||||
* `skipids <DriveFileEntity>` - Do not transfer files with the specified IDs.
|
||||
This option handles special cases where you want to prevent selected files/folders from being transferred.
|
||||
* `skipids <DriveFileEntity>` - Do not transfer files/folders with the specified IDs.
|
||||
|
||||
You can specify the access that the source user retains to the files that it owns.
|
||||
If no option is specified, the source user retains no access to the transferred files.
|
||||
|
||||
217
docs/Users-Gmail-CSE.md
Normal file
217
docs/Users-Gmail-CSE.md
Normal 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.
|
||||
@@ -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)
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
(file|textfile|htmlfile <FileName> [charset <Charset>])|
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
(emlfile <FileName>)
|
||||
(emlfile <FileName> [charset <Charset>]))
|
||||
```
|
||||
## Message queries with dates
|
||||
```
|
||||
@@ -204,21 +204,24 @@ You can also replace ` ` with `-` but it doesn't seem to be required.
|
||||
|
||||
* `query "label:Foo -Bar-"` - Select messages with label `Foo (Bar)`
|
||||
|
||||
You can have GAM do the substitutions for you with the `matchlabel <LabelName>` option.
|
||||
* `matchlabel "Foo (Bar)"` is converted to `query "label:Foo -Bar-"`
|
||||
|
||||
## Draft messages
|
||||
Add a draft message to a user's mailbox.
|
||||
```
|
||||
gam <UserTypeEntity> draft message
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(attach <FileName> [charset <CharSet>])*
|
||||
<MessageContent>
|
||||
(attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
```
|
||||
`<MessageContent>` is the message, there are five ways to specify it:
|
||||
* `message|textmessage|htmlmessage <String>` - Use `<String>` as the message
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the message from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the message from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the message from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the message from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
* `emlfile <FileName>` - Read the message from the EML message file `<FileName>`. SMTP headers specified in the command will replace those in the message file.
|
||||
* `emlfile <FileName> [charset <Charset>]` - Read the message from the EML message file `<FileName>`. SMTP headers specified in the command will replace those in the message file. The default `chatser` is `ascii`.
|
||||
|
||||
The `<SMTPDateHeader> <Time>` argument requires `<Time>` values which will be converted to RFC2822 dates. If you have these headers with values that
|
||||
are not in `<Time>` format, use the argument `header <SMTPDateHeader> <String>`.
|
||||
@@ -241,20 +244,20 @@ Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg
|
||||
Import a message into a user's mailbox, with standard email delivery scanning and classification similar to receiving via SMTP.
|
||||
```
|
||||
gam <UserTypeEntity> import message
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(addlabel <LabelName>)* [labels <LabelNameList>]
|
||||
(attach <FileName> [charset <CharSet>])*
|
||||
<MessageContent>
|
||||
(attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[deleted [<Boolean>]] [checkspam [<Boolean>]] [processforcalendar [<Boolean>]]
|
||||
```
|
||||
|
||||
`<MessageContent>` is the message, there are five ways to specify it:
|
||||
* `message|textmessage|htmlmessage <String>` - Use `<String>` as the message
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the message from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the message from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the message from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the message from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
* `emlfile <FileName>` - Read the message from the EML message file `<FileName>`. SMTP headers specified in the command will replace those in the message.
|
||||
* `emlfile <FileName> [charset <Charset>]` - Read the message from the EML message file `<FileName>`. SMTP headers specified in the command will replace those in the message. The default `chatser` is `ascii`.
|
||||
|
||||
When `emlfile` is not specified:
|
||||
* If `to` is not specified, it is set to the user email addresses in `<UserTypeEntity>`.
|
||||
@@ -289,20 +292,20 @@ Your command line will have: `embedimage file1.jpg image1` embedimage file2.jpg
|
||||
Insert a message into a user's mailbox similar to IMAP APPEND, bypassing most scanning and classification.
|
||||
```
|
||||
gam <UserTypeEntity> insert message
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(addlabel <LabelName>)* [labels <LabelNameList>]
|
||||
(attach <FileName> [charset <CharSet>])*
|
||||
<MessageContent>
|
||||
(attach <FileName> [charset <Charset>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[deleted [<Boolean>]]
|
||||
```
|
||||
|
||||
`<MessageContent>` is the message, there are five ways to specify it:
|
||||
* `message|textmessage|htmlmessage <String>` - Use `<String>` as the message
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the message from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the message from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the message from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the message from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
* `emlfile <FileName>` - Read the message from the EML message file `<FileName>`. SMTP headers specified in the command will replace those in the message file.
|
||||
* `emlfile <FileName> [charset <Charset>]` - Read the message from the EML message file `<FileName>`. SMTP headers specified in the command will replace those in the message file. The default `chatser` is `ascii`.
|
||||
|
||||
When `emlfile` is not specified:
|
||||
* If `to` is not specified, it is set to the user email addresses in `<UserTypeEntity>`.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
## API documentation
|
||||
* https://developers.google.com/gmail/api/reference/rest/v1/users.settings.sendAs
|
||||
* https://developers.google.com/gmail/api/v1/reference/users/settings
|
||||
* https://support.google.com/a/answer/1710338
|
||||
|
||||
## Definitions
|
||||
* [`<UserTypeEntity>`](Collections-of-Users)
|
||||
@@ -81,12 +82,14 @@ of the sendas address.
|
||||
|
||||
`<SendAsContent>` is the signature, there are four ways to specify it:
|
||||
* `sig|signature|htmlsig <String>` - Use `<String>` as the signature
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the signature from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the signature from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the signature from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the signature from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
|
||||
The `default` option sets `<EmailAddress>` as the default sendas address for the user.
|
||||
|
||||
For `treatasalias`, see: https://support.google.com/a/answer/1710338
|
||||
|
||||
You can allow users to send mail through an external SMTP server when configuring a sendas address hosted outside your email domains. You must enable
|
||||
this capability in Admin Console/Apps/Google Workspace/Gmail/Advanced settings/End User Access/Allow per-user outbound gateways.
|
||||
|
||||
@@ -139,12 +142,14 @@ gam <UserTypeEntity> signature|sig
|
||||
```
|
||||
`<SignatureContent>` is the signature, there are four ways to specify it:
|
||||
* `<String>` - Use `<String>` as the signature
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the signature from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the signature from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the signature from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the signature from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
|
||||
The `default` option sets `<EmailAddress>` as the default sendas address for the user.
|
||||
|
||||
For `treatasalias`, see: https://support.google.com/a/answer/1710338
|
||||
|
||||
When `<UserTypeEntity>` specifies an alias, the `primary` option causes the primary
|
||||
email address signature rather than the alias signature to be set.
|
||||
|
||||
@@ -211,7 +216,7 @@ gam <UserTypeEntity> vacation <Boolean> subject <String>
|
||||
```
|
||||
`<VacationMessageContent>` is the vacation message, there are four ways to specify it:
|
||||
* `message|textmessage|htmlmessage <String>` - Use `<String>` as the vacation message
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the vacation message from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the vacation message from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the vacation message from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the vacation message from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ gam user user@domain.com check serviceaccount
|
||||
|
||||
<NoteContent> ::=
|
||||
((text <String>)|
|
||||
(textfile <FileName> [charset <CharSet>])|
|
||||
(textfile <FileName> [charset <Charset>])|
|
||||
(gdoc <UserGoogleDoc>)|
|
||||
(gcsdoc <StorageBucketObjectName>)|
|
||||
<JSONData>)
|
||||
@@ -90,7 +90,7 @@ gam <UserTypeEntity> create note [title <String>]
|
||||
```
|
||||
`<NoteContent>` is the note text, there are four ways to specify it:
|
||||
* `message|textmessage|htmlmessage <String>` - Use `<String>` as the note text
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the note text from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the note text from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the note text from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the note text from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
- [Display Shared Drive access](#display-shared-drive-access)
|
||||
- [Display Shared Drive access for specific Shared Drives](#display-shared-drive-access-for-specific-shared-drives)
|
||||
- [Display Shared Drive access for selected Shared Drives](#display-shared-drive-access-for-selected-shared-drives)
|
||||
- [Change User1 Shared Drive access to User2](#change-user1-shared-drive-access-to-user2)
|
||||
- [Display empty folders on a Shared Drive](#display-empty-folders-on-a-shared-drive)
|
||||
- [Delete empty folders on a Shared Drive](#delete-empty-folders-on-a-shared-drive)
|
||||
- [Empty the trash on a Shared Drive](#empty-the-trash-on-a-shared-drive)
|
||||
@@ -25,6 +26,7 @@
|
||||
* https://developers.google.com/drive/v3/web/manage-teamdrives#managing_team_drives_for_domain_administrators
|
||||
* https://support.google.com/a/answer/7374057
|
||||
* https://workspaceupdates.googleblog.com/2022/05/shared-drives-in-organizational-units-open-beta.html
|
||||
* https://support.google.com/a/users/answer/7338880
|
||||
|
||||
## Query documentation
|
||||
* https://developers.google.com/drive/api/v3/search-shareddrives
|
||||
@@ -67,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|
|
||||
@@ -275,12 +281,15 @@ 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.
|
||||
@@ -299,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.
|
||||
@@ -428,6 +447,17 @@ This command must be issued by a user with Shared Drive permission role organize
|
||||
gam <UserTypeEntity> print emptydrivefolders [todrive <ToDriveAttribute>*]
|
||||
select <SharedDriveEntity>
|
||||
```
|
||||
|
||||
## Change User1 Shared Drive access to User2
|
||||
```
|
||||
# Get Shared Drives for User1
|
||||
gam redirect csv ./U1SharedDrives.csv user user1@domain.com print shareddriveacls pm emailaddress user1@domain.com em oneitemperrow
|
||||
# For each of those Shared Drives, delete User1 access
|
||||
gam redirect stdout ./DeleteU1SharedDriveAccess.txt multiprocess redirect stderr stdout gam delete drivefileacl "~id" "~permission.emailAddress"
|
||||
# For each of those Shared Drives, add User2 with the same role that User1 had
|
||||
gam redirect stdout ./AddU2SharedDriveAccess.txt multiprocess redirect stderr stdout gam create drivefileacl "~id" user user2@domain.com role "~permission.role"
|
||||
```
|
||||
|
||||
## Delete empty folders on a Shared Drive
|
||||
This command must be issued by a user with Shared Drive permission role organizer.
|
||||
```
|
||||
|
||||
117
docs/Users.md
117
docs/Users.md
@@ -38,7 +38,8 @@
|
||||
- [Print domain counts for users in a specific domain and/or selected by a query](#print-domain-counts-for-users-in-a-specific-domain-and-or-selected-by-a-query)
|
||||
- [Print domain counts for users specified by `<UserTypeEntity>`](#print-domain-counts-for-users-specified-by-usertypeentity)
|
||||
- [Print user list](#print-user-list)
|
||||
- [Display user count](#display-user-count)
|
||||
- [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
|
||||
@@ -385,7 +386,7 @@ If subject is not specified, the following value will be used:
|
||||
|
||||
`<NotifyMessageContent>` is the message, there are four ways to specify it:
|
||||
* `message|textmessage|htmlmessage <String>` - Use `<String>` as the message
|
||||
* `file|htmlfile <FileName> [charset <CharSet>]` - Read the message from `<FileName>`
|
||||
* `file|htmlfile <FileName> [charset <Charset>]` - Read the message from `<FileName>`
|
||||
* `gdoc|ghtml <UserGoogleDoc>` - Read the message from `<UserGoogleDoc>`
|
||||
* `gcsdoc|gcshtml <StorageBucketObjectName>` - Read the message from the Google Cloud Storage file `<StorageBucketObjectName>`
|
||||
|
||||
@@ -554,6 +555,14 @@ gam redirect stdout CreateUsers.log multiprocess redirect stderr stdout csv Crea
|
||||
gam create user "~useremail" firstname "~firstname" lastname "~lastname" ou "~ou" password "~password"
|
||||
notify "~~notifyemail~~,helpdesk@domain.com"
|
||||
```
|
||||
### Create users in bulk in OU with forced 2FA, notify each user and send a second email with backup codes. Log each step.
|
||||
OU needs to be already set with forced 2FA, else you can't create backup codes in step 2.
|
||||
These three commands should be run in sequence, as commands two and three are reliant on the previous command being run.
|
||||
```
|
||||
gam redirect stdout CreateUsers.log multiprocess redirect stderr stdout csv CreateUsers.csv gam create user "~useremail" firstname "~firstname" lastname "~lastname" ou "~ou" password random notify "~~notifyemail"
|
||||
gam redirect stdout UpdateUsers.log multiprocess redirect stderr stdout csv CreateUsers.csv gam user ~useremail update backupcodes
|
||||
gam redirect stdout SendBackupCodes.log multiprocess redirect stderr stdout csv CreateUsers.csv gam user ~useremail print backupcodes | gam csv - gam sendemail "~notifyemail" subject "Backup codes for 2FA login" message "~verificationCodes"
|
||||
```
|
||||
|
||||
## Specify a user's attributes with JSON data
|
||||
When creating a user, you may have a set of attributes that you'd like to assign to the user without having to specify
|
||||
@@ -597,7 +606,7 @@ If the mailbox is setup, a zero return code is returned; if the retries are exha
|
||||
gam update user <UserItem> [ignorenullpassword] <UserAttribute>*
|
||||
[verifynotinvitable|alwaysevict] [noactionifalias]
|
||||
[updateprimaryemail <RegularExpression> <EmailReplacement>]
|
||||
[updateoufromgroup <FileName> [charset <CharSet>]
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
@@ -618,7 +627,7 @@ gam update user <UserItem> [ignorenullpassword] <UserAttribute>*
|
||||
gam update users <UserTypeEntity> [ignorenullpassword] <UserAttribute>*
|
||||
[verifynotinvitable|alwaysevict] [noactionifalias]
|
||||
[updateprimaryemail <RegularExpression> <EmailReplacement>]
|
||||
[updateoufromgroup <FileName> [charset <CharSet>]
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
@@ -639,7 +648,7 @@ gam update users <UserTypeEntity> [ignorenullpassword] <UserAttribute>*
|
||||
gam <UserTypeEntity> update users [ignorenullpassword] <UserAttribute>*
|
||||
[verifynotinvitable|alwaysevict] [noactionifalias]
|
||||
[updateprimaryemail <RegularExpression> <EmailReplacement>]
|
||||
[updateoufromgroup <FileName> [charset <CharSet>]
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
|
||||
@@ -813,7 +822,7 @@ groupz@domain.com,/Path/To/OUz
|
||||
No update is performed if a user does not belong to any group in the CSV file or belongs to multiple groups in the CSV file.
|
||||
|
||||
```
|
||||
[updateoufromgroup <FileName> [charset <CharSet>]
|
||||
[updateoufromgroup <FileName> [charset <Charset>]
|
||||
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
|
||||
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
|
||||
```
|
||||
@@ -972,13 +981,17 @@ gam print users [todrive <ToDriveAttribute>*]
|
||||
([domain|domains <DomainNameEntity>] [(query <QueryUser>)|(queries <QueryUserList>)]
|
||||
[limittoou <OrgUnitItem>] [deleted_only|only_deleted])
|
||||
[orderby <UserOrderByFieldName> [ascending|descending]]
|
||||
[groups|groupsincolumns] [license|licenses|licence|licences]
|
||||
[groups|groupsincolumns]
|
||||
[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:
|
||||
@@ -995,24 +1008,29 @@ gam print users [todrive <ToDriveAttribute>*] select <UserTypeEntity>
|
||||
[orderby <UserOrderByFieldName> [ascending|descending]]
|
||||
[groups|groupsincolumns]
|
||||
[license|licenses|licence|licences|licensebyuser|licensesbyuser|licencebyuser|licencesbyuser]
|
||||
[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]
|
||||
[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>)]
|
||||
[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`
|
||||
@@ -1039,7 +1057,7 @@ By default, Gam displays fields that only an adminstrator can view.
|
||||
|
||||
By default, Gam displays only the primary email address for each user.
|
||||
* `allfields|basic` - Display all non custom schema fields for each user.
|
||||
* `full` - Display all non custom schema fields and all custom schema fields for each user.
|
||||
* `full` - Display all fields including all custom schema fields for each user.
|
||||
* `<UserFieldName>* [fields <UserFieldNameList>]` - Only display selected fields.
|
||||
* `schemas|custom all` - Get custom schema information for all schemas.
|
||||
* `schemas|custom <SchemaNameList>` - Get custom schema information for a selected list of schemas.
|
||||
@@ -1050,12 +1068,34 @@ to limit the display of aliases to those that match `<RegularExpression>`.
|
||||
By default, the entries in lists of groups and licenses are separated by the `csv_output_field_delimiter` from `gam.cfg`.
|
||||
* `delimiter <Character>` - Separate list items with `<Character>`
|
||||
|
||||
By default, all licenses for a user are displayed in a list on one row:
|
||||
```
|
||||
primaryEmail,LicensesCount,Licenses,LicensesDisplay
|
||||
user@domain.com,2,1010020020 1010330004,Google Workspace Enterprise Plus Google Voice Standard
|
||||
```
|
||||
With `onelicenseperrow|onelicenceperrow`, each license is on a separate row:
|
||||
```
|
||||
primaryEmail,License,LicenseDisplay
|
||||
user@domain.com,1010020020,Google Workspace Enterprise Plus
|
||||
user@domain.com 1010330004,Google Voice Standard
|
||||
```
|
||||
In the output, primaryEmail is the always the first column; these options control the sorting of the remaining columns.
|
||||
* `allfields|basic|full` - All other columns are sorted by name.
|
||||
* `sortheaders [true]` - All other columns are sorted by name.
|
||||
* `<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.
|
||||
|
||||
@@ -1198,9 +1238,62 @@ $ more UsersList.csv
|
||||
["testuser1@domain.org", "testuser2@domain.org", "testuser3@domain.org", "testuser4@domain.org"]
|
||||
```
|
||||
|
||||
## Display user count
|
||||
## Display user counts
|
||||
Display the number of users in an entity.
|
||||
```
|
||||
gam <UserTypeEntity> show count
|
||||
gam <UserTypeEntity> print users showitemcountonly
|
||||
gam print users select <UserTypeEntity> showitemcountonly
|
||||
gam print users
|
||||
([domain|domains <DomainNameEntity>] [(query <QueryUser>)|(queries <QueryUserList>)]
|
||||
[limittoou <OrgUnitItem>] [deleted_only|only_deleted])|[select <UserTypeEntity>]
|
||||
[issuspended <Boolean>]
|
||||
showitemcountonly
|
||||
```
|
||||
Example
|
||||
```
|
||||
$ gam print users query "orgUnitPath='/Students/Middle School'" showitemcountonly
|
||||
Getting all Users that match query (query="orgUnitPath='/Students/Middle School'"), may take some time on a large Google Workspace Account...
|
||||
Got 221 Users: aaron-first@domain.com - zoe-last@domain.com
|
||||
221
|
||||
```
|
||||
The `Getting` and `Got` messages are written to stderr, the count is writtem to stdout.
|
||||
|
||||
To retrieve the count with `showitemcountonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
count=$(gam print users query "orgUnitPath='/Students/Middle School'" showitemcountonly)
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
## Definitions
|
||||
```
|
||||
<AttendeeStatus> ::= accepted|declined|needsaction|tentative
|
||||
<EmailItem> ::= <EmailAddress>|<UniqueID>|<String>
|
||||
<EmailItemList> ::= "<EmailItem>(,<EmailItem>)*"
|
||||
<EmailAddressList> ::= "<EmailAddess>(,<EmailAddress>)*"
|
||||
@@ -52,6 +53,7 @@
|
||||
<MatterItem> ::= <UniqueID>|<String>
|
||||
<MatterState> ::= open|closed|deleted
|
||||
<MatterStateList> ::= "<MatterState>(,<MatterState>)*"
|
||||
<URLList> ::= "<URL>(,<URL>)*"
|
||||
|
||||
<QueryVaultCorpus> ::= <String>
|
||||
See: https://developers.google.com/vault/reference/rest/v1/matters.holds#CorpusQuery
|
||||
@@ -192,12 +194,9 @@ This command can be useful for discovering legacy former employee accounts which
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> corpus mail|groups
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
|
||||
[scope <all_data|held_data|unprocessed_data>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[excludedrafts <Boolean>]
|
||||
[includerooms <Boolean>]
|
||||
[includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>]
|
||||
[wait <Integer>]
|
||||
```
|
||||
Check the status of a previous count operation with the name from a previous command.
|
||||
@@ -210,16 +209,18 @@ gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
## Create Vault Exports
|
||||
Create a Google Vault export request.
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat|voice
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
|
||||
[scope <all_data|held_data|unprocessed_data>]
|
||||
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>)
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[excludedrafts <Boolean>] [format mbox|pst]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
|
||||
[includerooms <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
[includerooms <Boolean>]
|
||||
[excludedrafts <Boolean>] [format mbox|pst]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
<MatterItem> specifies the matter name or ID the export should be associated with.
|
||||
@@ -228,7 +229,8 @@ Specify the name of the export:
|
||||
* `name <String>` - The export will be named `<String>`
|
||||
* `default` - The export will be named `GAM <corpus> Export - <Time>`
|
||||
|
||||
Specify the corpus of data, this option is required::
|
||||
Specify the corpus of data, this option is required:
|
||||
* `calendar`
|
||||
* `drive`
|
||||
* `mail`
|
||||
* `groups`
|
||||
@@ -241,17 +243,43 @@ Specify the search method, this option is required:
|
||||
* `everyone` - Search for all accounts in the organization
|
||||
* `shareddrives|teamdrives <SharedDriveIDList>` - Search for all accounts in the Shared Drives specified in `<SharedDriveIDList>`
|
||||
* `rooms <RoomList>` - Search in the Room specified in the chat rooms specified in `<RoomList>`
|
||||
* `sitesurl <URLList>` - Search the published site URLs of new Google Sites
|
||||
|
||||
Specify the scope of data to include in the export:
|
||||
* `all_data` - All available data; this is the default
|
||||
* `held_data` - Data on Hold
|
||||
* `unprocessed_data` - Data not processed
|
||||
|
||||
You can specify search terms to limit the scope of data:
|
||||
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
|
||||
|
||||
Specify time limits on the scope of data:
|
||||
* `start|starttime <Date>|<Time>` - The start time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
* `end|endtime <Date>|<Time>` - The end time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
|
||||
* `timezone <TimeZone>` - The time zone name. It should be an IANA TZ name, such as "America/Los_Angeles"
|
||||
|
||||
For `corpus calendar`, you can specify advanced search options:
|
||||
* `locationquery <StringList>`
|
||||
* Matches only those events whose location contains all of the words in the given set.
|
||||
* If the string contains quoted phrases, this method only matches those events whose location contain the exact phrase.
|
||||
* Entries in the set are considered in "and".
|
||||
* Word splitting example: ["New Zealand"] vs ["New","Zealand"] "New Zealand": matched by both "New and better Zealand": only matched by the latter.
|
||||
* `peoplequery <StringList>`
|
||||
* Matches only those events whose attendees contain all of the words in the given set.
|
||||
* Entries in the set are considered in "and".
|
||||
* `minuswords <StringList>`
|
||||
* Matches only those events that do not contain any of the words in the given set in title, description, location, or attendees.
|
||||
* Entries in the set are considered in "or".
|
||||
* `responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*
|
||||
* Matches only events for which the custodian gave one of these responses. If the set is empty, there will be no filtering on responses.
|
||||
* `calendarversiondate <Date>|<Time>`
|
||||
* Search the current version of the Calendar event, but export the contents of the last version saved before 12:00 AM UTC on the specified date.
|
||||
* Enter the date in UTC.
|
||||
|
||||
For `corpus calendar`, you can specify the format of the exported data:
|
||||
* `format ics` - Export in ICS format, this is the default
|
||||
* `format pst` - Export in PST format
|
||||
|
||||
For `corpus drive`, you can specify advanced search options:
|
||||
* `driveversiondate <Date>|<Time>` - Search the versions of the Drive file as of the reference date. These timestamps are in GMT and rounded down to the given date.
|
||||
* `includeshareddrives False` - Do not include Shared Drives in the search, this is the default.
|
||||
@@ -265,9 +293,6 @@ For `corpus hangouts_chat` you can specify advanced search options:
|
||||
* `includerooms False` - Do not include rooms, this is the default
|
||||
* `includerooms True` - Include rooms
|
||||
|
||||
For `corpus mail`, you can specify search terms to limit the scope of data:
|
||||
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
|
||||
|
||||
For `corpus mail`, you can specify whether to exclude draft messages:
|
||||
* `excludedrafts False` - Do not exclude drafts, this is the default
|
||||
* `excludedrafts True` - Exclude drafts
|
||||
@@ -280,9 +305,13 @@ 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` and `corpus hangouts_chat`, you can specify the format of the exported data:
|
||||
For `corpus mail`, `corpus groups`, `corpus hangouts_chat`and `corpus voice`, you can specify the format of the exported data:
|
||||
* `format mbox` - Export in MBOX format, this is the default
|
||||
* `format pst` - Export in PST format
|
||||
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
\
|
||||
# Version and Help
|
||||
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAMADV-XTD3 6.66.11 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.71.06 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
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.66.11 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.71.06 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
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.66.11 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.71.06 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
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.0
|
||||
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.66.11
|
||||
Latest: 6.71.06
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -73,7 +72,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
6.66.11
|
||||
6.71.06
|
||||
```
|
||||
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.66.11 - https://github.com/taers232c/GAMADV-XTD3
|
||||
GAM 6.71.06 - https://github.com/taers232c/GAMADV-XTD3
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.0 64-bit final
|
||||
MacOS Monterey 12.7 x86_64
|
||||
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
|
||||
|
||||
@@ -141,6 +141,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)
|
||||
|
||||
@@ -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
|
||||
@@ -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".
|
||||
@@ -1043,7 +1060,7 @@ $gam csv NewGooUsers.csv gam select goo create user ~Email firstname ~FirstName
|
||||
```
|
||||
The gam loop command and the select and redirect arguments can be combined to perform powerful operations in a single command line.
|
||||
```
|
||||
gam loop (-|<FileName>) [charset <CharSet>] (matchfield|skipfield <FieldName> <RegularExpression>)* gam <GAM argument list>
|
||||
gam loop (-|<FileName>) [charset <Charset>] (matchfield|skipfield <FieldName> <RegularExpression>)* gam <GAM argument list>
|
||||
```
|
||||
Suppose you have the following CSV file, InfoDomains.csv:
|
||||
```
|
||||
|
||||
@@ -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>
|
||||
@@ -480,8 +484,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
(message|textmessage|htmlmessage <String>)|
|
||||
(file|textfile|htmlfile <FileName> [charset <Charset>])|
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
(emlfile <FileName>)
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)
|
||||
<MessageID> ::= <String>
|
||||
<Namespace> ::= <String>
|
||||
<NotesName> ::= notes/<String>
|
||||
@@ -584,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>
|
||||
@@ -598,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)|
|
||||
@@ -605,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>])|
|
||||
@@ -642,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>)*"
|
||||
@@ -665,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>)*"
|
||||
@@ -673,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>)*"
|
||||
@@ -728,6 +739,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
<TasklistIDTaskIDList> ::= "<TasklistIDTaskID>(,<TasklistIDTaskID>)*"
|
||||
<ThreadIDList> ::= "<ThreadID>(,<ThreadID>)*"
|
||||
<TimeList> ::= "<Time>(,<Time>)*"
|
||||
<URLList> ::= "<URL>(,<URL>)*"
|
||||
<UserList> ::= "<UserItem>(,<UserItem>)*"
|
||||
<YouTubeChannelIDList> ::= "<YouTubeChannelID>(,<YouTubeChannelID>)*"
|
||||
|
||||
@@ -1094,6 +1106,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 +1253,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 +1301,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.
|
||||
@@ -1457,7 +1471,7 @@ gam print alertfeedback [todrive <ToDriveAttribute>*] [alert <AlertID>] [filter
|
||||
gam create|add alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
|
||||
[verifynotinvitable]
|
||||
gam update alias|aliases <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
|
||||
[notargetverify]
|
||||
[notargetverify] [waitafterdelete <Integer>]
|
||||
gam delete alias|aliases [user|group|target] <EmailAddressEntity>
|
||||
gam remove aliases|nicknames <EmailAddress> user|group <EmailAddressEntity>
|
||||
gam <UserTypeEntity> delete alias|aliases
|
||||
@@ -2164,8 +2178,10 @@ gam print chromehistory releases [todrive <ToDriveAttribute>*]
|
||||
|
||||
<CrOSAction> ::=
|
||||
deprovision_different_model_replace|
|
||||
deprovision_different_model_replacement|
|
||||
deprovision_retiring_device|
|
||||
deprovision_same_model_replace|
|
||||
deprovision_same_model_replacement|
|
||||
deprovision_upgrade_transfer|
|
||||
disable|
|
||||
reenable|
|
||||
@@ -2173,7 +2189,9 @@ gam print chromehistory releases [todrive <ToDriveAttribute>*]
|
||||
pre_provisioned_reenable
|
||||
|
||||
gam update cros <CrOSEntity> action <CrOSAction> [acknowledge_device_touch_requirement]
|
||||
[actionbatchsize <Integer>]
|
||||
gam <CrOSTypeEntity> update action <CrOSAction> [acknowledge_device_touch_requirement]
|
||||
[actionbatchsize <Integer>]
|
||||
|
||||
<CrOSCommand>
|
||||
reboot|
|
||||
@@ -2291,6 +2309,7 @@ gam print cros [todrive <ToDriveAttribute>*]
|
||||
[timerangeorder ascending|descending] [showdvrsfp]
|
||||
[sortheaders]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
Print fields for specified CrOS devices.
|
||||
|
||||
@@ -2303,6 +2322,7 @@ gam print cros [todrive <ToDriveAttribute>*] select <CrOSTypeEntity>
|
||||
[timerangeorder ascending|descending] [showdvrsfp]
|
||||
[sortheaders]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
gam <CrOSTypeEntity> print cros [todrive <ToDriveAttribute>*]
|
||||
[orderby <CrOSOrderByFieldName> [ascending|descending]]
|
||||
@@ -2313,6 +2333,7 @@ gam <CrOSTypeEntity> print cros [todrive <ToDriveAttribute>*]
|
||||
[timerangeorder ascending|descending] [showdvrsfp]
|
||||
[sortheaders]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
The first column will always be deviceId; the remaining field names will be sorted if allfields, basic, full or sortheaders is specified;
|
||||
otherwise, the remaining field names will appear in the order specified.
|
||||
@@ -2475,7 +2496,7 @@ gam print crostelemetry [todrive <ToDriveAttribute>*]
|
||||
|
||||
gam create chromepolicyimage <ChromePolicyImageSchemaName> <FileName>
|
||||
|
||||
gam update chromepolicy
|
||||
gam update chromepolicy [convertcrnl]
|
||||
(<SchemaName> ((<Field> <Value>)+ | <JSONData>))+
|
||||
ou|org|orgunit <OrgUnitItem> [(printerid <PrinterID>)|(appid <AppID>)]
|
||||
gam delete chromepolicy
|
||||
@@ -2868,7 +2889,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>
|
||||
@@ -2881,15 +2902,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>*]
|
||||
@@ -2897,13 +2920,16 @@ gam print courses [todrive <ToDriveAttribute>*]
|
||||
[owneremail] [owneremailmatchpattern <RegularExpression>]
|
||||
[alias|aliases|aliasesincolumns [delimiter <Character>]]
|
||||
[show all|students|teachers] [countsonly]
|
||||
[timefilter creationtime|updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[timefilter creationtime|updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[showitemcountonly]
|
||||
|
||||
gam print course-participants [todrive <ToDriveAttribute>*]
|
||||
(course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
|
||||
[show all|students|teachers]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
<CourseAnnouncementFieldName> ::=
|
||||
alternatelink|
|
||||
@@ -3030,8 +3056,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]
|
||||
@@ -3039,6 +3065,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]
|
||||
@@ -3131,11 +3158,12 @@ 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>]
|
||||
[status completed|failed|inprogress] [delimiter <Character>]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
gam show datatransfers|transfers
|
||||
[olduser|oldowner <UserItem>] [newuser|newowner <UserItem>]
|
||||
[status completed|failed|inprogress] [delimiter <Character>]
|
||||
@@ -3351,16 +3379,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]
|
||||
@@ -3380,6 +3408,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
|
||||
|
||||
@@ -3611,6 +3654,7 @@ gam print groups [todrive <ToDriveAttribute>*]
|
||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||
[convertcrnl] [delimiter <Character>] [sortheaders]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
gam print grouptree <GroupEntity> [todrive <ToDriveAttribute>*]
|
||||
[showparentsaslist [<Boolean>]] [delimiter <Character>]
|
||||
@@ -3647,6 +3691,7 @@ gam print group-members [todrive <ToDriveAttribute>*]
|
||||
[userfields <UserFieldNameList>]
|
||||
[(recursive [noduplicates])|includederivedmembership] [nogroupemail]
|
||||
[peoplelookup|(peoplelookupuser <EmailAddress>)]
|
||||
[unknownname <String>] [cachememberinfo [Boolean]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam show group-members
|
||||
[([domain|domains <DomainNameEntity>] ([member|showownedby <EmailItem>]|[(query <QueryGroup>)|(queries <QueryGroupList>)]))|
|
||||
@@ -3730,6 +3775,7 @@ gam print cigroups [todrive <ToDriveAttribute>*]
|
||||
[memberemaildisplaypattern|memberemailskippattern <RegularExpression>]
|
||||
[convertcrnl] [delimiter <Character>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
<CIGroupMembersFieldName> ::=
|
||||
createtime
|
||||
@@ -3854,6 +3900,7 @@ gam print devices [todrive <ToDriveAttribute>*]
|
||||
[all|company|personal|nocompanydevices|nopersonaldevices]
|
||||
[nodeviceusers]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
<DeviceUserAction> ::=
|
||||
approve|
|
||||
@@ -3877,6 +3924,7 @@ gam print deviceusers [todrive <ToDriveAttribute>*]
|
||||
<DeviceUserFieldName>* [fields <DeviceUserFieldNameList>]
|
||||
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
gam info deviceuserstate <DeviceUserEntity> [clientid <String>]
|
||||
gam update deviceuserstate <DeviceUserEntity> [clientid <String>]
|
||||
@@ -4019,6 +4067,7 @@ gam print mobile [todrive <ToDriveAttribute>*]
|
||||
[basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
|
||||
[delimiter <Character>] [appslimit <Number>] [oneappperrow] [listlimit <Number>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
# Organizational Units
|
||||
|
||||
@@ -4061,6 +4110,7 @@ gam print orgs|ous [todrive <ToDriveAttribute>*]
|
||||
[allfields|<OrgUnitFieldName>*|(fields <OrgUnitFieldNameList>)] [convertcrnl] [batchsuborgs [<Boolean>]]
|
||||
[mincroscount <Number>] [maxcroscount <Number>]
|
||||
[minusercount <Number>] [maxusercount <Number>]
|
||||
[showitemcountonly]
|
||||
gam show orgtree [fromparent <OrgUnitItem>] [batchsuborgs [<Boolean>]]
|
||||
|
||||
# Printers
|
||||
@@ -4162,7 +4212,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
|
||||
[filtertime.* <Time>] [filter|filters <String>]
|
||||
[event|events <EventNameList>] [ip <String>]
|
||||
[groupidfilter <String>]
|
||||
[maxactivities <Number>] [maxresults <Number>]
|
||||
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
[countsonly [summary] [eventrowfilter]]
|
||||
(addcsvdata <FieldName> <String>)* [shownoactivities]
|
||||
|
||||
@@ -4354,6 +4404,7 @@ gam print resources [todrive <ToDriveAttribute>*] [allfields|<ResourceFieldName>
|
||||
[query <String>]
|
||||
[acls] [noselfowner] [calendar] [convertcrnl]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
<CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer|none
|
||||
<CalendarACLScope> ::= <EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|domain:<DomainName>|domain|default
|
||||
@@ -4407,6 +4458,12 @@ gam print schema|schemas [todrive <ToDriveAttribute>*]
|
||||
|
||||
# Send Email
|
||||
|
||||
<MessageContent> ::=
|
||||
(message|textmessage|htmlmessage <String>)|
|
||||
(file|textfile|htmlfile <FileName> [charset <Charset>])|
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
|
||||
gam sendemail [recipient|to] <RecipientEntity>
|
||||
[from <EmailAddress>] [mailbox <EmailAddress>] [replyto <EmailAddress>]
|
||||
[cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
|
||||
@@ -4508,6 +4565,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>])]
|
||||
@@ -4517,9 +4575,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>]
|
||||
@@ -4546,16 +4606,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>]
|
||||
@@ -4570,6 +4633,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> ::=
|
||||
@@ -4853,8 +4967,11 @@ gam <UserTypeEntity> show teamdriveacls
|
||||
relation.<RelationSubfieldName>.<RelationSubfieldName>.<String>|
|
||||
sshkeys.<SSHkeysSubfieldName>.<SSHkeysSubfieldName>.<String>|
|
||||
website.<WebsiteSubfieldName>.<WebsiteSubfieldName>.<String>
|
||||
<UserReplacementField> ::=
|
||||
photourl
|
||||
<Tag> ::= <String>
|
||||
<UserReplacement> ::=
|
||||
(field:<UserReplacementField>)|
|
||||
(field:<UserReplacementFieldSubfield>)|
|
||||
(field:<UserReplacementFieldSubfieldMatchSubfield>)|
|
||||
(schema:<SchemaName>.<FieldName>)|
|
||||
@@ -4894,25 +5011,25 @@ gam show vaultmatters|matters [matterstate <MatterStateList>]
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> corpus mail|groups
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
|
||||
[scope [all_data|held_data|unprocessed_data]]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[excludedrafts <Boolean>]
|
||||
[includerooms <Boolean>]
|
||||
[includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>]
|
||||
[wait <Integer>]
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> operation <String> [wait <Integer>]
|
||||
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat|voice
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
|
||||
[scope [all_data|held_data|unprocessed_data]]
|
||||
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>)
|
||||
[scope all_data|held_data|unprocessed_data]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
[includerooms <Boolean>]
|
||||
[excludedrafts <Boolean>] [format mbox|pst]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
|
||||
[includerooms <Boolean>] [covereddata calllogs|textmessages|voicemails]
|
||||
[includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
gam delete vaultexport|export <ExportItem> matter <MatterItem>
|
||||
gam delete vaultexport|export <MatterItem> <ExportItem>
|
||||
@@ -5320,13 +5437,16 @@ gam print users [todrive <ToDriveAttribute>*]
|
||||
[orderby <UserOrderByFieldName> [ascending|descending]]
|
||||
[groups|groupsincolumns]
|
||||
[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] [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.
|
||||
|
||||
@@ -5334,25 +5454,31 @@ gam print users [todrive <ToDriveAttribute>*] select <UserTypeEntity>
|
||||
[orderby <UserOrderByFieldName> [ascending|descending]]
|
||||
[groups|groupsincolumns]
|
||||
[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] [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>*]
|
||||
[orderby <UserOrderByFieldName> [ascending|descending]]
|
||||
[groups|groupsincolumns]
|
||||
[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] [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;
|
||||
otherwise, the remaining field names will appear in the order specified.
|
||||
@@ -5736,18 +5862,19 @@ 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>)|
|
||||
(office <String> [building|buildingid <String>] [floor|floorname <String>]
|
||||
[section|floorsection <String>] [desk|deskcode <String>]))
|
||||
[section|floorsection <String>] [desk|deskcode <String>]))
|
||||
((date yyyy-mm-dd)|
|
||||
(range yyyy-mm-dd yyyy-mm-dd)|
|
||||
(daily yyyy-mm-dd N)|
|
||||
@@ -5802,6 +5929,7 @@ gam <UserTypeEntity> print focustime|outofoffice|workinglocation
|
||||
|
||||
gam <UserTypeEntity> create chatspace
|
||||
[type <ChatSpaceType>]
|
||||
[restricted|(audience <String>)]
|
||||
[externalusersrallowed <Boolean>]
|
||||
[members <UserTypeEntity>]
|
||||
[displayname <String>]
|
||||
@@ -5810,10 +5938,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>
|
||||
|
||||
@@ -6006,10 +6135,13 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
[summary [<Boolean>]] [showpermissionmessages [<Boolean>]]
|
||||
[<DriveFileParentAttribute>]
|
||||
[mergewithparent [<Boolean>]] [recursive [depth <Number>]]
|
||||
[copysubfiles [<Boolean>]] [filenamematchpattern <RegularExpression>] [filemimetype [not] <MimeTypeList>]
|
||||
<DriveFileCopyAttribute>*
|
||||
[skipids <DriveFileEntity>]
|
||||
[copysubfiles [<Boolean>]] [filenamematchpattern <RegularExpression>]
|
||||
[filemimetype [not] <MimeTypeList>]
|
||||
[copysubfilesownedby any|me|others]
|
||||
[copysubfolders [<Boolean>]] [foldernamematchpattern <RegularExpression>]
|
||||
[copysubshortcuts [<Boolean>]] [shortcutnamematchpattern <RegularExpression>]
|
||||
<DriveFileCopyAttribute>*
|
||||
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
|
||||
[duplicatefolders merge|duplicatename|uniquename|skip]
|
||||
[copiedshortcutspointtocopiedfiles [<Boolean>]]
|
||||
@@ -6062,6 +6194,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>|-]
|
||||
@@ -6469,9 +6606,10 @@ gam <UserTypeEntity> collect orphans
|
||||
<DriveOwnersSubfieldName>|
|
||||
parents|
|
||||
<DriveParentsSubfieldName>|
|
||||
permissionids|
|
||||
permissiondetails|
|
||||
permissions|
|
||||
<DrivePermissionsSubfieldName>|
|
||||
permissionids|
|
||||
properties|
|
||||
quotabytesused|quotaused|
|
||||
resourcekey|
|
||||
@@ -6508,19 +6646,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>]
|
||||
@@ -6921,22 +7046,29 @@ gam <UserTypeEntity> print labels|label [todrive <ToDriveAttribute>*]
|
||||
x400-trace
|
||||
<SMTPHeaderList> ::= "<SMTPDateHeader>|<SMTPHeader>(,<SMTPDateHeader>|<SMTPHeader>)*"
|
||||
|
||||
<MessageContent> ::=
|
||||
(message|textmessage|htmlmessage <String>)|
|
||||
(file|textfile|htmlfile <FileName> [charset <Charset>])|
|
||||
(gdoc|ghtml <UserGoogleDoc>)|
|
||||
(gcsdoc|gcshtml <StorageBucketObjectName>)|
|
||||
(emlfile <FileName> [charset <Charset>])
|
||||
|
||||
gam <UserTypeEntity> draft message
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(attach <FileName> [charset <CharSet>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
gam <UserTypeEntity> import message
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(addlabel <LabelName>)* [labels <LabelNameList>]
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(attach <FileName> [charset <CharSet>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[deleted [<Boolean>]] [checkspam|nevermarkspam [<Boolean>]] [processforcalendar [<Boolean>]]
|
||||
gam <UserTypeEntity> insert message
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*
|
||||
(addlabel <LabelName>)* [labels <LabelNameList>]
|
||||
<MessageContent> (replace <Tag> <UserReplacement>)*
|
||||
(attach <FileName> [charset <CharSet>])*
|
||||
(embedimage <FileName> <String>)*
|
||||
[deleted [<Boolean>]]
|
||||
@@ -7030,6 +7162,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
|
||||
@@ -7041,12 +7182,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
|
||||
|
||||
|
||||
@@ -2,6 +2,592 @@
|
||||
|
||||
Merged GAM-Team version
|
||||
|
||||
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.
|
||||
|
||||
c6.69.00
|
||||
|
||||
Added `use_classroom_owner_access` Boolean variable to `gam.cfg` that controls how GAM gets
|
||||
classroom member information and removes students/teachers. Client access does not provide
|
||||
complete information about non-domain students/teachers.
|
||||
* `False` - Use client 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@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
|
||||
a seperate user information row for each license a user is assigned. This makes processing
|
||||
the licenses in a script possible and allows better sorting in a CSV File.
|
||||
|
||||
By default, all licenses for a user are displayed in a list on one row:
|
||||
```
|
||||
primaryEmail,LicensesCount,Licenses,LicensesDisplay
|
||||
user@domain.com,2,1010020020 1010330004,Google Workspace Enterprise Plus Google Voice Standard
|
||||
```
|
||||
With `onelicenseperrow|onelicenceperrow`, each license is on a separate row:
|
||||
```
|
||||
primaryEmail,License,LicenseDisplay
|
||||
user@domain.com,1010020020,Google Workspace Enterprise Plus
|
||||
user@domain.com 1010330004,Google Voice Standard
|
||||
```
|
||||
|
||||
6.67.19
|
||||
|
||||
Updated `gam create|update user ... notify` to encode the characters `<>&` in the password
|
||||
so that they display correctly when the notify message content is HTML.
|
||||
|
||||
6.67.18
|
||||
|
||||
Cleaned up `Getting/Got` messages for `gam print courses|course-participants`.
|
||||
|
||||
6.67.17
|
||||
|
||||
Added option `showitemcountonly` to various commands that causes GAM to display the
|
||||
item count on stdout; no CSV file is written.
|
||||
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups#display-group-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Courses#display-course-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Membership#display-course-membership-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices#display-cros-device-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-user-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups#display-group-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Mobile-Devices#display-mobile-device-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#display-organizational-unit-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Resources#display-resource-counts
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#display-user-counts
|
||||
|
||||
6.67.16
|
||||
|
||||
By default, `gam print group-members membernames` displays `Unknown` for members whose names can not be determined.
|
||||
Added option `unknownname <String>` that let's you specify an alternative value.
|
||||
|
||||
Further improved performance of `gam print group-members membernames cachememberinfo`.
|
||||
|
||||
6.67.15
|
||||
|
||||
Update `gam print group-members membernames` to handle the following error:
|
||||
```
|
||||
ERROR: 400: failedPrecondition - Precondition check failed.
|
||||
```
|
||||
|
||||
Added option `cachememberinfo [Boolean]` to `gam print group-members` that causes GAM to cache member info
|
||||
so that only one API call is made to get information for each user/group. This consumes
|
||||
more memory but dramatically reduces the number of API calls.
|
||||
|
||||
6.67.14
|
||||
|
||||
Updated reseller commands to handle the following error:
|
||||
```
|
||||
ERROR: 400: invalid - Customer domain [domain.com] is linked to one or more email verified customers, please provide a customer id.
|
||||
```
|
||||
|
||||
6.67.13
|
||||
|
||||
Updated `gam create domain <DomainName>` to handle the following error:
|
||||
```
|
||||
ERROR: 409: conflict - Domain in request is in use by an email verified customer.
|
||||
```
|
||||
|
||||
6.67.12
|
||||
|
||||
Added option `addcsvdata <FieldName> <String>` to `gam print datatransfers` that adds
|
||||
additional columns of data to the CSV file output.
|
||||
|
||||
6.67.11
|
||||
|
||||
Updated various Gmail related commands to handle this error:
|
||||
```
|
||||
ERROR: 403: permissionDenied - Insufficient Permission
|
||||
```
|
||||
when the following service account scopes are selected:
|
||||
|
||||
```
|
||||
[ ] 23) Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read
|
||||
[ ] 24) Gmail API - Full Access (Labels, Messages)
|
||||
[ ] 25) Gmail API - Full Access (Labels, Messages) except delete message
|
||||
[*] 26) Gmail API - Full Access - read only
|
||||
[ ] 27) Gmail API - Send Messages - including todrive
|
||||
[ ] 28) Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
|
||||
```
|
||||
|
||||
6.67.10
|
||||
|
||||
Fixed bug that caused a trap when optional argument `charset <Charset>` was used with `emlfile <FileName>` in `gam <UserTypeEntity> draft|import|insert message`.
|
||||
|
||||
6.67.09
|
||||
|
||||
Added option `maxevents <Number>` to `gam report <ActivityApplictionName>` that limits
|
||||
the number of events displayed for each activity; the default is 0, no limit.
|
||||
Setting options `maxactivities 1 maxevents 1 maxresults 1` can be used to as efficiently as possible
|
||||
show the most recent activity/event; this can be useful when reporting drive activity for individual drive files.
|
||||
|
||||
6.67.08
|
||||
|
||||
Added optional argument `charset <Charset>` to `emlfile <FileName>` in `gam <UserTypeEntity> draft|import|insert message`;
|
||||
the default value is `ascii`.
|
||||
|
||||
6.67.07
|
||||
|
||||
Updated `gam <UserTypeEntity> delete message` to handle this error:
|
||||
```
|
||||
ERROR: 403: permissionDenied - Insufficient Permission
|
||||
```
|
||||
when the following service account scopes are selected:
|
||||
|
||||
```
|
||||
[ ] 24) Gmail API - Full Access (Labels, Messages)
|
||||
[*] 25) Gmail API - Full Access (Labels, Messages) except delete message
|
||||
```
|
||||
|
||||
6.67.06
|
||||
|
||||
Updated commands that create ACLs to handle the following error:
|
||||
```
|
||||
ERROR: 400: abusiveContentRestriction - Bad Request. User message: "You cannot share this item because it has been flagged as inappropriate."
|
||||
```
|
||||
|
||||
6.67.05
|
||||
|
||||
Updated the following commands:
|
||||
```
|
||||
gam <UserTypeEntity> create|delete|update delegate
|
||||
gam <UserTypeEntity> forward
|
||||
gam <UserTypeEntity> create|delete forwardingaddresses
|
||||
gam <UserTypeEntity> create|delete sendas
|
||||
```
|
||||
to handle this error:
|
||||
```
|
||||
ERROR: 403: permissionDenied - Insufficient Permission
|
||||
```
|
||||
when the following serice account scope is not enabled:
|
||||
```
|
||||
[ ] 28) Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
|
||||
```
|
||||
|
||||
6.67.04
|
||||
|
||||
Updated user attribute `replace <Tag> <UserReplacement>` to allow `field:photourl` which allows
|
||||
embedding a link to a user's photo in their signature. Formatting the signature HTML
|
||||
to properly display the photo is left to the GAM admin.
|
||||
|
||||
6.67.03
|
||||
|
||||
Fixed bug introduced in 6.67.02 in `gam <UserTypeEntity> claim ownership` that caused a trap.
|
||||
|
||||
6.67.02
|
||||
|
||||
Added option `skipids <DriveFileEntity>` to `gam <UserTypeEntity> copy drivefile` that handles special cases
|
||||
where you want to prevent selected files/folders from being copied.
|
||||
|
||||
Updated commands that create files/folders on Shared Drives to handle the following errors:
|
||||
```
|
||||
storageQuotaExceeded
|
||||
teamDriveFileLimitExceeded
|
||||
teamDriveHierarchyTooDeep
|
||||
```
|
||||
* See: https://support.google.com/a/users/answer/7338880#shared_drives_file_folder_limits
|
||||
|
||||
6.67.01
|
||||
|
||||
Fixed bug in `gam print vaultcounts` that caused a trap.
|
||||
|
||||
6.67.00
|
||||
|
||||
Updated `gam <CrOSTypeEntity> update action <CrOSAction>` to use the new API function `batchChangeStatus`
|
||||
that replaces the old API function `action`; ChromeOS devices are now processed in batches.
|
||||
The batch size defaults to 10, the `actionbatchsize <Integer>` option can be used to set a batch size between 10 and 250.
|
||||
|
||||
Updated `gam create vaultexport matter <MatterItem>` to support `corpus calendar`.
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault-Takeout#create-vault-exports
|
||||
|
||||
6.66.16
|
||||
|
||||
Added option `convertcrnl` to `gam update chromepolicy` to properly handle carriage returns (\r) and line feeds (\n)
|
||||
in value strings entered on the command line in the `<Field> <Value>` form.
|
||||
```
|
||||
gam update chromepolicy convertcrnl chrome.devices.DisabledDeviceReturnInstructions
|
||||
deviceDisabledMessage "Please return device to:\nSchool\n123 Main Street\nAnytown US" ou /Path/to/OU
|
||||
```
|
||||
|
||||
6.66.15
|
||||
|
||||
Added option `copysubfilesownedby any|me|others` to `gam <UserTypeEntity> copy drivefile` that allows
|
||||
specification of which source folder sub files to copy based on file ownership; the default is `any`.
|
||||
This only applies when files are being copied from a 'My Drive'.
|
||||
|
||||
6.66.14
|
||||
|
||||
Updated `gam <UserTypeEntity> modify messages` to recognize the following error:
|
||||
```
|
||||
ERROR: 400: invalid - Invalid label: SENT
|
||||
```
|
||||
|
||||
Updated `gam update alias <EmailAddressEntity> user|group|target <EmailAddress>`
|
||||
to avoid the following problem.
|
||||
```
|
||||
$ gam update alias testalias@domain.com user testuser
|
||||
User Alias: testalias@domain.com, Deleted
|
||||
User Alias: testalias@domain.com, User: testuser@domain.com, Update Failed: Duplicate, Email Address: testalias@domain.com
|
||||
```
|
||||
GAM updates an alias to point to a new target by deleting the alias and then recreating the alias pointing to the new target.
|
||||
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
|
||||
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
|
||||
the option `waitafterdelete <Integer>` can be used to increase the wait time to a maximum of 10 seconds.
|
||||
|
||||
6.66.13
|
||||
|
||||
Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`.
|
||||
|
||||
* Current
|
||||
* `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
|
||||
* `preservefiletimes` - No effect
|
||||
* Updated
|
||||
* `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
|
||||
* `preservefiletimes` - `modifiedTime` of `<DriveFileEntity>` retains its current value
|
||||
|
||||
6.66.12
|
||||
|
||||
Upgraded to Python 3.12.1 where possible.
|
||||
|
||||
Updated all drive commands to handle the following error:
|
||||
```
|
||||
ERROR: 401: Active session is invalid. Error code: 4 - authError
|
||||
```
|
||||
This is due to the Drive SDK API being disabled in the user's OU.
|
||||
* See: https://support.google.com/a/answer/6105699
|
||||
|
||||
6.66.11
|
||||
|
||||
Fixed/improved handling of shortcuts in `gam <UserTypeEntity> transfer drive`.
|
||||
|
||||
3118
src/gam/__init__.py
3118
src/gam/__init__.py
File diff suppressed because it is too large
Load Diff
@@ -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'
|
||||
@@ -166,9 +167,7 @@ class GamAction():
|
||||
DELETE: ['Deleted', 'Delete'],
|
||||
DELETE_EMPTY: ['Deleted', 'Delete Empty'],
|
||||
DELETE_PREVIEW: ['Deleted (Preview)', 'Delete (Preview)'],
|
||||
DEPROVISION: ['Deprovisioned', 'Deprovision'],
|
||||
DELETE_SHORTCUT: ['Deleted Shortcut', 'Delete Shortcut'],
|
||||
DISABLE: ['Disabled', 'Disable'],
|
||||
DEPROVISION: ['Deprovisioned', 'Deprovision'],
|
||||
DISABLE: ['Disabled', 'Disable'],
|
||||
DOWNLOAD: ['Downloaded', 'Download'],
|
||||
@@ -195,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'],
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
@@ -539,6 +539,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,
|
||||
@@ -579,19 +583,19 @@ _SVCACCT_SCOPES = [
|
||||
'api': FORMS,
|
||||
'subscopes': [],
|
||||
'scope': DRIVE_SCOPE},
|
||||
{'name': 'Gmail API - Full Access',
|
||||
{'name': 'Gmail API - Full Access (Labels, Messages)',
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://mail.google.com/'},
|
||||
{'name': 'Gmail API - Full Access except immediate delete',
|
||||
{'name': 'Gmail API - Full Access (Labels, Messages) except delete message',
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.modify'},
|
||||
{'name': 'Gmail API - Basic Settings',
|
||||
{'name': 'Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read',
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.settings.basic'},
|
||||
{'name': 'Gmail API - Settings Sharing (Aliases, Delegates, Forwarding)',
|
||||
{'name': 'Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write',
|
||||
'api': GMAIL,
|
||||
'subscopes': [],
|
||||
'scope': 'https://www.googleapis.com/auth/gmail.settings.sharing'},
|
||||
@@ -638,6 +642,7 @@ _SVCACCT_SCOPES = [
|
||||
{'name': 'Youtube API - read only',
|
||||
'api': YOUTUBE,
|
||||
'subscopes': [],
|
||||
'offByDefault': True,
|
||||
'scope': 'https://www.googleapis.com/auth/youtube.readonly'},
|
||||
]
|
||||
|
||||
@@ -653,10 +658,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,
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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'
|
||||
@@ -519,6 +520,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 +567,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'
|
||||
@@ -845,6 +852,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 +879,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 +939,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'
|
||||
@@ -991,6 +1003,7 @@ class GamCLArgs():
|
||||
OB_TRANSFER_ID = 'TransferID'
|
||||
OB_URI = 'URI'
|
||||
OB_URL = 'URL'
|
||||
OB_URL_LIST = 'URLList'
|
||||
OB_USER_ENTITY = 'UserEntity'
|
||||
OB_USER_ITEM = 'UserItem'
|
||||
OB_USER_NAME = 'UserName'
|
||||
|
||||
@@ -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_MANAGER_USER = 'chgu'
|
||||
CHAT_MEMBER = 'chme'
|
||||
CHAT_MEMBER_GROUP = 'chmg'
|
||||
CHAT_MEMBER_USER = 'chmu'
|
||||
@@ -149,12 +150,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'
|
||||
@@ -162,7 +165,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'
|
||||
@@ -188,6 +191,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'
|
||||
@@ -416,6 +421,7 @@ class GamEntity():
|
||||
CHANNEL_PRODUCT: ['Channel Products', 'Channel Product'],
|
||||
CHANNEL_SKU: ['Channel SKUs', 'Channel SKU'],
|
||||
CHAT_BOT: ['Chat BOTs', 'Chat BOT'],
|
||||
CHAT_MANAGER_USER: ['Chat User Managers', 'Chat User Manager'],
|
||||
CHAT_MESSAGE: ['Chat Messages', 'Chat Message'],
|
||||
CHAT_MESSAGE_ID: ['Chat Message IDs', 'Chat Message ID'],
|
||||
CHAT_MEMBER: ['Chat Members', 'Chat Member'],
|
||||
@@ -481,6 +487,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'],
|
||||
@@ -520,6 +528,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'],
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
@@ -21,8 +21,10 @@
|
||||
"""
|
||||
# callGAPI throw reasons
|
||||
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'
|
||||
@@ -114,11 +116,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'
|
||||
@@ -155,6 +159,7 @@ TARGET_USER_ROLE_LIMITED_BY_LICENSE_RESTRICTION = 'targetUserRoleLimitedByLicens
|
||||
TEAMDRIVE_ALREADY_EXISTS = 'teamDriveAlreadyExists'
|
||||
TEAMDRIVE_DOMAIN_USERS_ONLY_RESTRICTION = 'teamDriveDomainUsersOnlyRestriction'
|
||||
TEAMDRIVE_TEAM_MEMBERS_ONLY_RESTRICTION = 'teamDriveTeamMembersOnlyRestriction'
|
||||
TEAMDRIVE_FILE_LIMIT_EXCEEDED = 'teamDriveFileLimitExceeded'
|
||||
TEAMDRIVE_HIERARCHY_TOO_DEEP = 'teamDriveHierarchyTooDeep'
|
||||
TEAMDRIVE_MEMBERSHIP_REQUIRED = 'teamDriveMembershipRequired'
|
||||
TEAMDRIVES_FOLDER_MOVE_IN_NOT_SUPPORTED = 'teamDrivesFolderMoveInNotSupported'
|
||||
@@ -179,8 +184,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,
|
||||
@@ -199,7 +204,8 @@ COURSE_ACCESS_THROW_REASONS = [NOT_FOUND, INSUFFICIENT_PERMISSIONS, PERMISSION_D
|
||||
DRIVE_USER_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR, DOMAIN_POLICY]
|
||||
DRIVE_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, FORBIDDEN, INTERNAL_ERROR, INSUFFICIENT_FILE_PERMISSIONS, UNKNOWN_ERROR, INVALID]
|
||||
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]
|
||||
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]
|
||||
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,
|
||||
@@ -213,7 +219,7 @@ DRIVE3_CREATE_ACL_THROW_REASONS = [BAD_REQUEST, INVALID, INVALID_SHARING_REQUEST
|
||||
FILE_ORGANIZER_NOT_YET_ENABLED_FOR_THIS_TEAMDRIVE,
|
||||
FILE_ORGANIZER_ON_FOLDERS_IN_SHARED_DRIVE_ONLY,
|
||||
FILE_ORGANIZER_ON_NON_TEAMDRIVE_NOT_SUPPORTED,
|
||||
TEAMDRIVES_FOLDER_SHARING_NOT_SUPPORTED, INVALID_LINK_VISIBILITY]
|
||||
TEAMDRIVES_FOLDER_SHARING_NOT_SUPPORTED, INVALID_LINK_VISIBILITY, ABUSIVE_CONTENT_RESTRICTION]
|
||||
DRIVE3_GET_ACL_REASONS = DRIVE_USER_THROW_REASONS+[FILE_NOT_FOUND, FORBIDDEN, INTERNAL_ERROR,
|
||||
INSUFFICIENT_ADMINISTRATOR_PRIVILEGES, INSUFFICIENT_FILE_PERMISSIONS,
|
||||
UNKNOWN_ERROR, INVALID]
|
||||
@@ -238,16 +244,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]
|
||||
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]
|
||||
@@ -260,6 +269,7 @@ MEMBERS_THROW_REASONS = [GROUP_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_AP
|
||||
MEMBERS_RETRY_REASONS = [SYSTEM_ERROR, SERVICE_NOT_AVAILABLE]
|
||||
ORGUNIT_GET_THROW_REASONS = [INVALID_ORGUNIT, ORGUNIT_NOT_FOUND, BACKEND_ERROR, BAD_REQUEST, INVALID_CUSTOMER_ID, LOGIN_REQUIRED]
|
||||
PEOPLE_ACCESS_THROW_REASONS = [SERVICE_NOT_AVAILABLE, FORBIDDEN, PERMISSION_DENIED]
|
||||
RESELLER_THROW_REASONS = [BAD_REQUEST, RESOURCE_NOT_FOUND, FORBIDDEN, INVALID]
|
||||
SHEETS_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[NOT_FOUND, PERMISSION_DENIED, FORBIDDEN, INTERNAL_ERROR, INSUFFICIENT_FILE_PERMISSIONS,
|
||||
BAD_REQUEST, INVALID, INVALID_ARGUMENT, FAILED_PRECONDITION]
|
||||
TASK_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
|
||||
@@ -270,6 +280,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),
|
||||
@@ -336,10 +347,14 @@ REASON_MESSAGE_MAP = {
|
||||
|
||||
class aborted(Exception):
|
||||
pass
|
||||
class abusiveContentRestriction(Exception):
|
||||
pass
|
||||
class accessNotConfigured(Exception):
|
||||
pass
|
||||
class alreadyExists(Exception):
|
||||
pass
|
||||
class applyLabelForbidden(Exception):
|
||||
pass
|
||||
class authError(Exception):
|
||||
pass
|
||||
class backendError(Exception):
|
||||
@@ -598,6 +613,8 @@ class teamDriveDomainUsersOnlyRestriction(Exception):
|
||||
pass
|
||||
class teamDriveTeamMembersOnlyRestriction(Exception):
|
||||
pass
|
||||
class teamDriveFileLimitExceeded(Exception):
|
||||
pass
|
||||
class teamDriveHierarchyTooDeep(Exception):
|
||||
pass
|
||||
class teamDriveMembershipRequired(Exception):
|
||||
@@ -635,8 +652,10 @@ class userRateLimitExceeded(Exception):
|
||||
|
||||
REASON_EXCEPTION_MAP = {
|
||||
ABORTED: aborted,
|
||||
ABUSIVE_CONTENT_RESTRICTION: abusiveContentRestriction,
|
||||
ACCESS_NOT_CONFIGURED: accessNotConfigured,
|
||||
ALREADY_EXISTS: alreadyExists,
|
||||
APPLY_LABEL_FORBIDDEN: applyLabelForbidden,
|
||||
AUTH_ERROR: authError,
|
||||
BACKEND_ERROR: backendError,
|
||||
BAD_REQUEST: badRequest,
|
||||
@@ -766,6 +785,7 @@ REASON_EXCEPTION_MAP = {
|
||||
TEAMDRIVE_ALREADY_EXISTS: teamDriveAlreadyExists,
|
||||
TEAMDRIVE_DOMAIN_USERS_ONLY_RESTRICTION: teamDriveDomainUsersOnlyRestriction,
|
||||
TEAMDRIVE_TEAM_MEMBERS_ONLY_RESTRICTION: teamDriveTeamMembersOnlyRestriction,
|
||||
TEAMDRIVE_FILE_LIMIT_EXCEEDED: teamDriveFileLimitExceeded,
|
||||
TEAMDRIVE_HIERARCHY_TOO_DEEP: teamDriveHierarchyTooDeep,
|
||||
TEAMDRIVE_MEMBERSHIP_REQUIRED: teamDriveMembershipRequired,
|
||||
TEAMDRIVES_FOLDER_MOVE_IN_NOT_SUPPORTED: teamDrivesFolderMoveInNotSupported,
|
||||
|
||||
@@ -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: {},
|
||||
|
||||
@@ -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'
|
||||
@@ -431,7 +436,7 @@ SELECTED = 'Selected'
|
||||
SERVICE_NOT_APPLICABLE = 'Service not applicable/Does not exist'
|
||||
SERVICE_NOT_APPLICABLE_THIS_ADDRESS = 'Service not applicable for this address: {0}'
|
||||
STARTING_THREAD = 'Starting thread'
|
||||
STATISTICS_COPY_FILE = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Copy Failed: {5}, Not copyable: {6}, Permissions Failed: {7}, Protected Ranges Failed: {8}'
|
||||
STATISTICS_COPY_FILE = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Copy Failed: {5}, Not copyable: {6}, In skipids: {7}, Permissions Failed: {8}, Protected Ranges Failed: {9}'
|
||||
STATISTICS_COPY_FOLDER = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Copy Failed: {6}, Not writable: {7}, Permissions Failed: {8}'
|
||||
STATISTICS_MOVE_FILE = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Move Failed: {5}, Not movable: {6}'
|
||||
STATISTICS_MOVE_FOLDER = 'Total: {0}, Moved: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Move Failed: {6}, Not writable: {7}'
|
||||
@@ -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? '
|
||||
|
||||
@@ -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': {
|
||||
|
||||
27
src/gam/googleapiclient/__init__.py
Normal file
27
src/gam/googleapiclient/__init__.py
Normal 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())
|
||||
167
src/gam/googleapiclient/_auth.py
Normal file
167
src/gam/googleapiclient/_auth.py
Normal 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
|
||||
207
src/gam/googleapiclient/_helpers.py
Normal file
207
src/gam/googleapiclient/_helpers.py
Normal 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})
|
||||
315
src/gam/googleapiclient/channel.py
Normal file
315
src/gam/googleapiclient/channel.py
Normal 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,
|
||||
)
|
||||
1582
src/gam/googleapiclient/discovery.py
Normal file
1582
src/gam/googleapiclient/discovery.py
Normal file
File diff suppressed because it is too large
Load Diff
78
src/gam/googleapiclient/discovery_cache/__init__.py
Normal file
78
src/gam/googleapiclient/discovery_cache/__init__.py
Normal 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
|
||||
@@ -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)
|
||||
46
src/gam/googleapiclient/discovery_cache/base.py
Normal file
46
src/gam/googleapiclient/discovery_cache/base.py
Normal 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()
|
||||
145
src/gam/googleapiclient/discovery_cache/file_cache.py
Normal file
145
src/gam/googleapiclient/discovery_cache/file_cache.py
Normal 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)
|
||||
197
src/gam/googleapiclient/errors.py
Normal file
197
src/gam/googleapiclient/errors.py
Normal 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)
|
||||
)
|
||||
1962
src/gam/googleapiclient/http.py
Normal file
1962
src/gam/googleapiclient/http.py
Normal file
File diff suppressed because it is too large
Load Diff
183
src/gam/googleapiclient/mimeparse.py
Normal file
183
src/gam/googleapiclient/mimeparse.py
Normal 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
|
||||
409
src/gam/googleapiclient/model.py
Normal file
409
src/gam/googleapiclient/model.py
Normal 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
|
||||
317
src/gam/googleapiclient/schema.py
Normal file
317
src/gam/googleapiclient/schema.py
Normal 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)
|
||||
15
src/gam/googleapiclient/version.py
Normal file
15
src/gam/googleapiclient/version.py
Normal 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.114.0"
|
||||
Reference in New Issue
Block a user