mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-16 20:21:37 +00:00
Compare commits
131 Commits
20240916.1
...
20241002.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79f83f34fd | ||
|
|
a34b6610d2 | ||
|
|
24f2efb833 | ||
|
|
d77d873a42 | ||
|
|
ccaa76026c | ||
|
|
ac540b75a7 | ||
|
|
be573c8ae4 | ||
|
|
6076111d83 | ||
|
|
7c1ee239c7 | ||
|
|
d3a02f9d25 | ||
|
|
b8501195ad | ||
|
|
49192cb604 | ||
|
|
5e8bbd4ce4 | ||
|
|
5a85572a9c | ||
|
|
d2d48f772b | ||
|
|
25e7196a37 | ||
|
|
8a4fabb4c9 | ||
|
|
7825a66768 | ||
|
|
2b6891c12d | ||
|
|
70fb68d81b | ||
|
|
6b15628d81 | ||
|
|
7c88793e8f | ||
|
|
896f7f5d37 | ||
|
|
46d05e37d0 | ||
|
|
9dc87a060d | ||
|
|
3e638dd35e | ||
|
|
e4ad4fb26c | ||
|
|
cc63aee62c | ||
|
|
31806438a9 | ||
|
|
74ac351aa4 | ||
|
|
7e157dab42 | ||
|
|
8b2586ead2 | ||
|
|
ebcfd18457 | ||
|
|
cbb496e491 | ||
|
|
1ff93b1051 | ||
|
|
2fdb6156e7 | ||
|
|
f7c13a3063 | ||
|
|
c0470c35a9 | ||
|
|
304a897290 | ||
|
|
af2499a0ea | ||
|
|
52ccd735ca | ||
|
|
ffcb1c4ddf | ||
|
|
0dd74e226c | ||
|
|
bd5149d3f8 | ||
|
|
7c6649b24f | ||
|
|
cfd9447f39 | ||
|
|
820698d9d4 | ||
|
|
7645edee6b | ||
|
|
7e6f7b8bab | ||
|
|
ee77ae8319 | ||
|
|
0f2eba580d | ||
|
|
1cdf160b35 | ||
|
|
7e68c108c1 | ||
|
|
8ecbe67054 | ||
|
|
a6016825ff | ||
|
|
15221a1a20 | ||
|
|
6718938c1a | ||
|
|
acd1a9ad91 | ||
|
|
cce2894dac | ||
|
|
877ea0cc19 | ||
|
|
cd4c1fc7ac | ||
|
|
09292fd28b | ||
|
|
ccef86d2a0 | ||
|
|
ba34ef4494 | ||
|
|
26eca09bb9 | ||
|
|
64d4cc00e4 | ||
|
|
33b4de86a9 | ||
|
|
f33da85518 | ||
|
|
93ecbf479e | ||
|
|
ca2d6541ce | ||
|
|
db7154dca9 | ||
|
|
72bba3d948 | ||
|
|
07bbf4d4ea | ||
|
|
7aafbbe58e | ||
|
|
c2058211fe | ||
|
|
08a6cbb270 | ||
|
|
c5da8963d4 | ||
|
|
89b854ea57 | ||
|
|
42fd8cd1e8 | ||
|
|
0e0f49c540 | ||
|
|
f0b1b62e79 | ||
|
|
7606a40a58 | ||
|
|
ac5098522b | ||
|
|
d84ff8d392 | ||
|
|
4a0687cfe9 | ||
|
|
19e386ed21 | ||
|
|
8165c72606 | ||
|
|
5267992e31 | ||
|
|
1949b3346c | ||
|
|
38375b1710 | ||
|
|
281e790260 | ||
|
|
2b8b2521d1 | ||
|
|
52601edb35 | ||
|
|
5475f281eb | ||
|
|
b1f8893783 | ||
|
|
640cb322d7 | ||
|
|
c4f15cbf3a | ||
|
|
bef392cf7a | ||
|
|
abb49ed336 | ||
|
|
fe5bc5569d | ||
|
|
18615f246d | ||
|
|
7958632046 | ||
|
|
3e8bff23c4 | ||
|
|
0221781a05 | ||
|
|
e6ced7fff6 | ||
|
|
484238ece2 | ||
|
|
ee32bb87f0 | ||
|
|
73803acb89 | ||
|
|
a40df40f9b | ||
|
|
a33b89788c | ||
|
|
54f815e503 | ||
|
|
e54d3d274a | ||
|
|
b7a20ceb4f | ||
|
|
bbc965d38f | ||
|
|
8935cf7041 | ||
|
|
4583f6d996 | ||
|
|
92282fb493 | ||
|
|
65ea328f2a | ||
|
|
2da4833a0d | ||
|
|
631ce68126 | ||
|
|
480aca680d | ||
|
|
6e3ab6700d | ||
|
|
61319fa08e | ||
|
|
673e9f88ad | ||
|
|
f2b8200a3b | ||
|
|
0383624c72 | ||
|
|
cb03b8d9d4 | ||
|
|
e7e821ca3d | ||
|
|
6b21fdbcc6 | ||
|
|
ee326c6fe3 | ||
|
|
8945fd163c |
13
.github/actions/entitlements.plist
vendored
Normal file
13
.github/actions/entitlements.plist
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- These are required for binaries built by PyInstaller -->
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
1
.github/actions/package_exclusions.txt
vendored
1
.github/actions/package_exclusions.txt
vendored
@@ -2,6 +2,5 @@ oauth2.txt
|
||||
nobrowser.txt
|
||||
enabledasa.txt
|
||||
lastupdatecheck.txt
|
||||
*.json
|
||||
*.lck
|
||||
*.csv
|
||||
|
||||
295
.github/workflows/build.yml
vendored
295
.github/workflows/build.yml
vendored
@@ -36,62 +36,57 @@ jobs:
|
||||
goal: build
|
||||
arch: x86_64
|
||||
openssl_archs: linux-x86_64
|
||||
- os: ubuntu-20.04
|
||||
- os: [self-hosted, linux, arm64]
|
||||
jid: 2
|
||||
goal: build
|
||||
arch: x86_64
|
||||
openssl_archs: linux-x86_64
|
||||
- os: [self-hosted, linux, arm64]
|
||||
arch: aarch64
|
||||
openssl_archs: linux-aarch64
|
||||
- os: ubuntu-22.04
|
||||
jid: 3
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: linux-aarch64
|
||||
- os: ubuntu-20.04
|
||||
jid: 4
|
||||
goal: build
|
||||
arch: x86_64
|
||||
openssl_archs: linux-x86_64
|
||||
staticx: yes
|
||||
- os: [self-hosted, linux, arm64]
|
||||
jid: 5
|
||||
jid: 4
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: linux-aarch64
|
||||
staticx: yes
|
||||
- os: macos-12
|
||||
jid: 6
|
||||
- os: macos-13
|
||||
jid: 5
|
||||
goal: build
|
||||
arch: x86_64
|
||||
openssl_archs: darwin64-x86_64
|
||||
- os: macos-14
|
||||
jid: 7
|
||||
jid: 6
|
||||
goal: build
|
||||
arch: aarch64
|
||||
openssl_archs: darwin64-arm64
|
||||
- os: windows-2022
|
||||
jid: 9
|
||||
jid: 7
|
||||
goal: build
|
||||
arch: Win64
|
||||
openssl_archs: VC-WIN64A
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.8"
|
||||
jid: 10
|
||||
python: "3.13"
|
||||
jid: 8
|
||||
arch: x86_64
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.9"
|
||||
jid: 11
|
||||
jid: 9
|
||||
arch: x86_64
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.10"
|
||||
jid: 12
|
||||
jid: 10
|
||||
arch: x86_64
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.11"
|
||||
jid: 8
|
||||
jid: 11
|
||||
arch: x86_64
|
||||
|
||||
steps:
|
||||
@@ -115,7 +110,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20240916
|
||||
key: gam-${{ matrix.jid }}-20241002
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
@@ -201,6 +196,14 @@ jobs:
|
||||
#brew install swig
|
||||
#brew install ncurses
|
||||
|
||||
- name: MacOS import developer certificates for signing
|
||||
if: runner.os == 'macOS'
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
with:
|
||||
keychain: signing_temp
|
||||
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
|
||||
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
|
||||
- name: Windows Configure VCode
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
if: runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
@@ -293,7 +296,8 @@ jobs:
|
||||
- name: Rename GNU link on Windows
|
||||
if: matrix.goal == 'build' && runner.os == 'Windows' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: mv /usr/bin/link /usr/bin/gnulink
|
||||
run: |
|
||||
mv -v /usr/bin/link /usr/bin/gnulink
|
||||
|
||||
- name: Make OpenSSL
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
@@ -311,7 +315,7 @@ jobs:
|
||||
cd "${GITHUB_WORKSPACE}/src/openssl-${openssl_arch}"
|
||||
# install_sw saves us ages processing man pages :-)
|
||||
$MAKE install_sw
|
||||
mv "${OPENSSL_INSTALL_PATH}" "${GITHUB_WORKSPACE}/bin/ssl-${openssl_arch}"
|
||||
mv -v "${OPENSSL_INSTALL_PATH}" "${GITHUB_WORKSPACE}/bin/ssl-${openssl_arch}"
|
||||
done
|
||||
mkdir -vp "${OPENSSL_INSTALL_PATH}/lib"
|
||||
mkdir -vp "${OPENSSL_INSTALL_PATH}/bin"
|
||||
@@ -521,61 +525,60 @@ 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}"
|
||||
export distpath="./dist/gam"
|
||||
mkdir -p -v "${distpath}"
|
||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
# brew OpenSSL gets picked up by PyInstaller breaking our self-compiled version
|
||||
# Tell our gam.spec to use our code sign certificate
|
||||
export codesign_identity="Jay Lee"
|
||||
# brew OpenSSL gets picked up by PyInstaller
|
||||
# breaking our self-compiled version
|
||||
brew uninstall --ignore-dependencies openssl
|
||||
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="$(dirname ${PYTHON}):/usr/bin"
|
||||
else
|
||||
export gampath=$(realpath "${gampath}")
|
||||
fi
|
||||
export gam="${gampath}/gam"
|
||||
echo "gampath=${gampath}" >> $GITHUB_ENV
|
||||
# TEMP force everything back to one file.
|
||||
export PYINSTALLER_BUILD_ONEFILE="yes"
|
||||
export distpath="./dist/gam"
|
||||
export gampath="${distpath}"
|
||||
#if ([ "${staticx}" != "yes" ] && [ "$RUNNER_OS" != "Windows" ]); then
|
||||
if [[ "$staticx" != "yes" ]]; then
|
||||
export PYINSTALLER_BUILD_ONEDIR=yes
|
||||
fi
|
||||
"${PYTHON}" -m PyInstaller --clean --noconfirm --distpath="${distpath}" gam.spec
|
||||
echo "WARNINGS FROM build/gam/warn-gam.txt"
|
||||
cat build/gam/warn-gam.txt
|
||||
echo "Analysis FROM build/gam/Analysis-00.toc"
|
||||
cat build/gam/Analysis-00.toc
|
||||
echo "EXE data FROM build/gam/EXE-00.toc"
|
||||
cat build/gam/EXE-00.toc
|
||||
if [ -x "$(command -v realpath)" ]; then
|
||||
realpath=realpath
|
||||
if [[ "$PYINSTALLER_BUILD_ONEDIR" == "yes" ]]; then
|
||||
mv -v "${distpath}/gam" "${distpath}/gam7"
|
||||
export gampath="${distpath}/gam7"
|
||||
else
|
||||
brew install coreutils
|
||||
realpath=grealpath
|
||||
mv -v "$distpath" "${distpath}7"
|
||||
export gampath="${distpath}7"
|
||||
fi
|
||||
export gam=$(realpath "$gam")
|
||||
export gampath=$(realpath "$gampath")
|
||||
echo "gampath ${gampath} results:"
|
||||
ls -alRF "$gampath"
|
||||
echo "---- WARNINGS FROM build/gam/warn-gam.txt"
|
||||
cat build/gam/warn-gam.txt
|
||||
echo "---- Analysis FROM build/gam/Analysis-00.toc"
|
||||
cat build/gam/Analysis-00.toc
|
||||
echo "---- EXE data FROM build/gam/EXE-00.toc"
|
||||
cat build/gam/EXE-00.toc
|
||||
export gam="${gampath}/gam"
|
||||
if [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
export gam=$(cygpath -w "$gam")
|
||||
echo "GAM on Windows at ${gam}"
|
||||
else
|
||||
export gam=$(realpath "$gam")
|
||||
fi
|
||||
echo "gampath=${gampath}" >> $GITHUB_ENV
|
||||
echo "gam=${gam}" >> $GITHUB_ENV
|
||||
echo -e "GAM: ${gam}\nGAMPATH: ${gampath}"
|
||||
|
||||
- name: Copy extra package files
|
||||
if: matrix.goal == 'build'
|
||||
run: |
|
||||
cp -v cacerts.pem $gampath
|
||||
cp -v LICENSE $gampath
|
||||
cp -v GamCommands.txt $gampath
|
||||
cp -v GamUpdate.txt $gampath
|
||||
cp -v cacerts.pem "$gampath"
|
||||
cp -v LICENSE "$gampath"
|
||||
cp -v GamCommands.txt "$gampath"
|
||||
cp -v GamUpdate.txt "$gampath"
|
||||
if [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
cp -v gam-setup.bat $gampath
|
||||
cp -v gam-setup.bat "$gampath"
|
||||
fi
|
||||
|
||||
- name: Install StaticX
|
||||
@@ -596,9 +599,21 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
echo "ldlib=${ldlib}"
|
||||
$PYTHON -m staticx -l "${ldlib}" "${gam}" "${gam}-staticx"
|
||||
rm -v "${gam}"
|
||||
mv -v "${gam}-staticx" "${gam}"
|
||||
$PYTHON -m staticx -l "${ldlib}" "$gam" "${gam}-staticx"
|
||||
rm -v "$gam"
|
||||
mv -v "${gam}-staticx" "$gam"
|
||||
|
||||
- name: MacOS send GAM binary for Apple notarization
|
||||
if: runner.os == 'macOS'
|
||||
env:
|
||||
ASP_NOTARIZE: ${{ secrets.ASP_NOTARIZE }}
|
||||
run: |
|
||||
# Apple wants some kind of "package" submitted so just add gam to a .zip
|
||||
# name it something we can track and link in Apple's notarize process
|
||||
zipfilename="./gam-${RUNNER_ARCH}-${GITHUB_RUN_ID}-${GITHUB_RUN_NUMBER}.zip"
|
||||
zip -r "$zipfilename" "$gampath"
|
||||
xcrun notarytool submit --apple-id "jay0lee@gmail.com" --password "$ASP_NOTARIZE" --team-id GZ85H2DRLM "$zipfilename"
|
||||
rm -v "$zipfilename"
|
||||
|
||||
- name: Basic Tests all jobs
|
||||
id: basictests
|
||||
@@ -609,7 +624,45 @@ jobs:
|
||||
echo "GAM Version ${GAMVERSION}"
|
||||
echo "GAMVERSION=${GAMVERSION}" >> $GITHUB_ENV
|
||||
|
||||
- name: Attest Binary Provenance
|
||||
- name: Configure service account auth
|
||||
id: configserviceaccount
|
||||
env:
|
||||
PASSCODE: ${{ secrets.PASSCODE }}
|
||||
run: |
|
||||
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*
|
||||
$gam create signjwtserviceaccount
|
||||
|
||||
- name: Upload gam.exe Windows for signing
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
run: |
|
||||
export folder_number=$(date +%s)
|
||||
export folder_id=$($gam user gam-win-signer@pdl.jaylee.us add drivefile drivefilename "UPLOADING_FOR_SIGN ${folder_number}" parentid "1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp" mimetype gfolder returnidonly)
|
||||
$gam user gam-win-signer@pdl.jaylee.us add drivefile localfile "$gam" parentid "$folder_id"
|
||||
$gam user gam-win-signer@pdl.jaylee.us update drivefile "$folder_id" newfilename "READYTOSIGN ${folder_number}"
|
||||
export signed_folder="SIGNED ${folder_number}"
|
||||
zero_results="gam-win-signer@pdl.jaylee.us,0"
|
||||
while true; do
|
||||
result_counts=$($gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" countsonly)
|
||||
echo "$result_counts"
|
||||
if [[ ! "$result_counts" =~ "$zero_results" ]]; then
|
||||
echo "looks like we have results"
|
||||
break
|
||||
fi
|
||||
echo "no results, sleeping 10..."
|
||||
sleep 10
|
||||
done
|
||||
# download signed gam.exe
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us print filelist query "'~~id~~' in parents and name = 'gam.exe'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us get drivefile ~id targetfolder "$gampath" targetname "signed-gam.exe" overwrite true acknowledgeabuse true
|
||||
# delete signed folder on drive
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us trash drivefile "~id"
|
||||
# remove unsigned gam.exe and rename signed-gam.exe
|
||||
rm -v -f "${gampath}/gam.exe"
|
||||
mv -v -f "${gampath}/signed-gam.exe" "${gampath}/gam.exe"
|
||||
#"/c/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64/signtool.exe" verify /v /pa "$gam"
|
||||
|
||||
- name: Attest gam executable was generated from this Action
|
||||
uses: actions/attest-build-provenance@v1
|
||||
if: matrix.goal == 'build'
|
||||
with:
|
||||
@@ -619,28 +672,84 @@ jobs:
|
||||
if: runner.os != 'Windows' && matrix.goal == 'build'
|
||||
run: |
|
||||
if [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||
GAM_ARCHIVE="gam-${GAMVERSION}-macos-${arch}.tar.xz"
|
||||
GAM_ARCHIVE="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-macos-${arch}.tar.xz"
|
||||
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
|
||||
if [[ "${staticx}" == "yes" ]]; then
|
||||
libver="legacy"
|
||||
else
|
||||
libver="glibc$(ldd --version | awk '/ldd/{print $NF}')"
|
||||
fi
|
||||
GAM_ARCHIVE="gam-${GAMVERSION}-linux-$(arch)-${libver}.tar.xz"
|
||||
GAM_ARCHIVE="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-linux-$(arch)-${libver}.tar.xz"
|
||||
fi
|
||||
echo "GAM Archive ${GAM_ARCHIVE}"
|
||||
tar -C dist/ --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam
|
||||
tar -C "${gampath}/.." --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam7
|
||||
|
||||
- name: Windows package
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
run: |
|
||||
cd dist/
|
||||
GAM_ARCHIVE="../gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.zip"
|
||||
/c/Program\ Files/7-Zip/7z.exe a -tzip $GAM_ARCHIVE gam "-xr@${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" -bb3
|
||||
cd ..
|
||||
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/candle.exe -arch "${WIX_ARCH}" gam.wxs
|
||||
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/light.exe -ext /c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/WixUIExtension.dll gam.wixobj -o "gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.msi" || true;
|
||||
echo "started in $(pwd)"
|
||||
cd "${gampath}/.."
|
||||
echo "moved to $(pwd)"
|
||||
GAM_ARCHIVE="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.zip"
|
||||
/c/Program\ Files/7-Zip/7z.exe a -tzip "$GAM_ARCHIVE" gam7 "-xr@${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" -bb3
|
||||
cd ../..
|
||||
echo "moved to $(pwd)"
|
||||
export MSI_FILENAME="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.msi"
|
||||
# auto-generate a lib.wxs based on the files PyInstaller created for the lib/ directory
|
||||
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/heat.exe dir "${gampath}/lib" -ke -srd -cg Lib -gg -dr lib -directoryid lib -out lib.wxs
|
||||
echo "-- begin lib.wxs --"
|
||||
cat lib.wxs
|
||||
echo "-- end lib.wxs --"
|
||||
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/candle.exe -arch "${WIX_ARCH}" gam.wxs lib.wxs
|
||||
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/light.exe -ext /c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/WixUIExtension.dll gam.wixobj lib.wixobj -b "${gampath}/lib" -o "$MSI_FILENAME" || true;
|
||||
rm -v -f *.wixpdb
|
||||
rm -v -f *.wixobj
|
||||
echo "MSI_FILENAME=${MSI_FILENAME}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload gam MSI Windows for signing
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
run: |
|
||||
export folder_number=$(date +%s)
|
||||
export folder_id=$($gam user gam-win-signer@pdl.jaylee.us add drivefile drivefilename "UPLOADING_FOR_SIGN ${folder_number}" parentid "1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp" mimetype gfolder returnidonly)
|
||||
$gam user gam-win-signer@pdl.jaylee.us add drivefile localfile "$MSI_FILENAME" parentid "$folder_id"
|
||||
rm -f -v "$MSI_FILENAME"
|
||||
$gam user gam-win-signer@pdl.jaylee.us update drivefile "$folder_id" newfilename "READYTOSIGN ${folder_number}"
|
||||
export signed_folder="SIGNED ${folder_number}"
|
||||
zero_results="gam-win-signer@pdl.jaylee.us,0"
|
||||
while true; do
|
||||
result_counts=$($gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" countsonly)
|
||||
echo "$result_counts"
|
||||
if [[ ! "$result_counts" =~ "$zero_results" ]]; then
|
||||
echo "looks like we have results"
|
||||
break
|
||||
fi
|
||||
echo "no results, sleeping 10..."
|
||||
sleep 10
|
||||
done
|
||||
# download signed package
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us print filelist query "'~~id~~' in parents and name contains '.msi'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us get drivefile ~id targetfolder "$GITHUB_WORKSPACE" targetname "$MSI_FILENAME" overwrite true acknowledgeabuse true
|
||||
# delete signed folder on drive
|
||||
$gam user gam-win-signer@pdl.jaylee.us print filelist query "name = '${signed_folder}' and '1Xz3hYq4Mfa_r6D8EcBZHLDtHDFurYSvp' in parents and mimeType = 'application/vnd.google-apps.folder'" id | $gam csv - gam user gam-win-signer@pdl.jaylee.us trash drivefile "~id"
|
||||
#"/c/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64/signtool.exe" verify /v /pa "$MSI_FILENAME"
|
||||
|
||||
- name: Attest that gam package files were generated from this Action
|
||||
uses: actions/attest-build-provenance@v1
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule') && matrix.goal == 'build'
|
||||
with:
|
||||
subject-path: |
|
||||
gam*.tar.xz
|
||||
gam*.zip
|
||||
gam*.msi
|
||||
|
||||
- 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: |
|
||||
gam*.tar.xz
|
||||
gam*.zip
|
||||
gam*.msi
|
||||
|
||||
- name: Basic Tests build jobs only
|
||||
if: matrix.goal != 'test' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
@@ -664,12 +773,7 @@ jobs:
|
||||
|
||||
- name: Live API tests push only
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule')
|
||||
env:
|
||||
PASSCODE: ${{ secrets.PASSCODE }}
|
||||
run: |
|
||||
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
|
||||
@@ -679,7 +783,6 @@ jobs:
|
||||
$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
|
||||
@@ -715,18 +818,18 @@ jobs:
|
||||
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-
|
||||
# 9/17/24 - temp create in root due to Google API issues creating users in new OUs
|
||||
$gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB- # ou "${newou}"
|
||||
$gam user $newuser add license workspaceenterpriseplus
|
||||
$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 user $gam_user sendemail recipient dev-null@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
|
||||
$gam config enable_dasa false save
|
||||
$gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary
|
||||
#$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()'
|
||||
@@ -734,7 +837,8 @@ jobs:
|
||||
$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
|
||||
# 9/17/24 temp disable due to Google API sluggishness to see new users for admin commands
|
||||
# $gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
|
||||
$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"
|
||||
@@ -858,7 +962,7 @@ jobs:
|
||||
echo "printer model count:"
|
||||
$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)}')
|
||||
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}"
|
||||
@@ -874,25 +978,6 @@ jobs:
|
||||
fi
|
||||
tar cJvvf cache.tar.xz $tar_folders
|
||||
|
||||
- name: Attest Build Archive Provenance
|
||||
uses: actions/attest-build-provenance@v1
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule') && matrix.goal == 'build'
|
||||
with:
|
||||
subject-path: |
|
||||
src/gam*.tar.xz
|
||||
src/gam*.zip
|
||||
src/gam*.msi
|
||||
|
||||
- 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/gam*.tar.xz
|
||||
src/gam*.zip
|
||||
src/gam*.msi
|
||||
|
||||
merge:
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -38,11 +38,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -67,4 +67,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
GAM is a command line tool for Google Workspace admins to manage domain and user settings quickly and easily.
|
||||
|
||||

|
||||
[](https://github.com/GAM-team/GAM/actions/workflows/build.yml)
|
||||
|
||||
# Quick Start
|
||||
|
||||
@@ -32,7 +32,7 @@ There is a public chat room hosted in Google Chat. [Instructions to join](https:
|
||||
|
||||
# Author
|
||||
|
||||
GAM is maintained by [Jay Lee](mailto:jay0lee@gmail.com). Please direct "how do I?" questions to [Google Groups].
|
||||
GAM is maintained by [Jay (James) Lee](mailto:jay0lee@gmail.com) and [Ross Scroggs](mailto:ross.scroggs@gmail.com). Please direct "how do I?" questions to [Google Groups].
|
||||
|
||||
[GAM release]: https://github.com/GAM-team/GAM/releases
|
||||
[GitHub Releases]: https://github.com/GAM-team/GAM/releases
|
||||
|
||||
@@ -786,7 +786,7 @@ There are several methods for generating private keys:
|
||||
* `localkeysize 1024` - Gam generates a 1024 bit key; this is not recommended
|
||||
* `localkeysize 2048` - Gam generates a 2048 bit key; this is the default
|
||||
* `localkeysize 4096` - Gam generates a 4096 bit key
|
||||
* `yubikey yubikey_pin yubikey_slot AUTHENTICATION|SIGNATURE yubikey_serialnumber <Number>)]` - [Using GAMADV-XTD3 with a YubiKey](Using-GAMADV-XTD3-with-a-YubiKey)
|
||||
* `yubikey yubikey_pin yubikey_slot AUTHENTICATION|SIGNATURE yubikey_serialnumber <Number>)]` - [Using GAM7 with a YubiKey](Using-GAM7-with-a-YubiKey)
|
||||
|
||||
When `localkeysize` is specified, the optional argument `validityhours <Number>` sets the length of time during which the key will be valid and should be used when the [GCP constraints/iam.serviceAccountKeyExpiryHours organization policy](https://cloud.google.com/resource-manager/docs/organization-policy/restricting-service-accounts#limit_key_expiry) is in use. Note that in order to account for system clock skew, GAM sets the key to be valid two minutes earlier than the current system time and thus it will also expire two minutes earlier.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Syntax
|
||||
|
||||
## BNF Syntax
|
||||
This Wiki describes the GAM command line syntax in modified BNF.
|
||||
This Wiki describes the GAM7 command line syntax in modified BNF.
|
||||
* https://en.wikipedia.org/wiki/Backus-Naur_Form
|
||||
|
||||
Skip the History section and start reading at Introduction.
|
||||
|
||||
@@ -176,6 +176,7 @@ Client access works when accessing Resource calendars.
|
||||
<AttendeeStatus> ::= accepted|declined|needsaction|tentative
|
||||
|
||||
<EventType> ::=
|
||||
birthday|
|
||||
default|
|
||||
focustime|
|
||||
fromgmail|
|
||||
@@ -241,6 +242,7 @@ Client access works when accessing Resource calendars.
|
||||
(attendee <EmailAddress>)|
|
||||
(attendeestatus [<AttendeeAttendance>] [<AttendeeStatus>] <EmailAddress>)|
|
||||
available|
|
||||
(birthday <Date>)|
|
||||
(color <EventColorName>)|
|
||||
(colorindex|colorid <EventColorIndex>)|
|
||||
(description <String>)|
|
||||
@@ -261,7 +263,7 @@ Client access works when accessing Resource calendars.
|
||||
(privateproperty <PropertyKey> <PropertyValue>)|
|
||||
(range <Date> <Date>)|
|
||||
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
|
||||
(reminder <Number> email|popup))|
|
||||
(reminder <Number> email|popup)|
|
||||
(selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)|
|
||||
(sequence <Integer>)|
|
||||
(sharedproperty <PropertyKey> <PropertyValue>)|
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
- [Definitions](#definitions)
|
||||
- [Display a specific Chrome policy schema](#display-a-specific-chrome-policy-schema)
|
||||
- [Display all or filtered Chrome policy schemas](#display-all-or-filtered-chrome-policy-schemas)
|
||||
- [Display Chrome policy schemas in same format as Standard GAM](#display-chrome-policy-schemas-in-same-format-as-standard-gam)
|
||||
- [Display Chrome policy schemas in same format as Legacy GAM](#display-chrome-policy-schemas-in-same-format-as-legacy-gam)
|
||||
- [Create a Chrome policy image](#create-a-chrome-policy-image)
|
||||
- [Update Chrome policy](#update-chrome-policy)
|
||||
- [Delete Chrome policy](#delete-chrome-policy)
|
||||
@@ -118,7 +118,7 @@ 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 Chrome policy schemas in same format as Standard GAM
|
||||
## Display Chrome policy schemas in same format as Legacy GAM
|
||||
```
|
||||
gam show chromeschemas std
|
||||
[filter <String>]
|
||||
|
||||
@@ -71,7 +71,7 @@ gam <Command> cros <CrOSEntity> ...
|
||||
```
|
||||
The first form allows more powerful selection of devices with `<CrOSTypeEntity>`.
|
||||
|
||||
The second form is backwards compatible with Standard GAM and selection with `<CrOSEntity>` is limited.
|
||||
The second form is backwards compatible with Legacy GAM and selection with `<CrOSEntity>` is limited.
|
||||
|
||||
## Definitions
|
||||
* [`<CrOSTypeEntity>`](Collections-of-ChromeOS-Devices)
|
||||
@@ -253,6 +253,9 @@ Enter `id:` as the operator. For example, if you are searching for the serial nu
|
||||
|
||||
Partial serial number searches are supported, as long as you enter at least three characters in the serial number.
|
||||
|
||||
All serial number searches are partial, be careful that you don't enter a partial serial number by mistake
|
||||
when actioning/modifying devices as you will affect multiple devices rather than the single desired device.
|
||||
|
||||
### Status
|
||||
To view all provisioned or deprovisioned devices, select the status from the left drop-down, and all of the devices that fit this criterion will appear in the view. Alternatively, you can do the following searches from the All devices view:
|
||||
|
||||
@@ -465,7 +468,7 @@ gam getcommand cros <CrOSEntity> commandid <CommandID> [times_to_check_status <I
|
||||
### Action Examples
|
||||
Remove user profile data from the device; the device will remain enrolled and connected.
|
||||
User data not synced to the Cloud including Downloads, Android app data and Crostini Linux VMs will be permanently lost.
|
||||
Commands with issuecommand directly after gam will work with standard GAM & GAMADV-XTD3, whereas commands where the issuecommand is after the cros <CrOSTypeEntity> will work only with GAMADV-XTD3.
|
||||
Commands with issuecommand directly after gam will work with Legacy GAM & GAM7, whereas commands where the issuecommand is after the cros <CrOSTypeEntity> will work only with GAM7.
|
||||
```
|
||||
gam issuecommand cros dd1d659a-0ea4-4e94-905e-4726c7a5f1e9 command wipe_users doit
|
||||
```
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
|
||||
<UserGoogleDoc> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>)
|
||||
|
||||
<SheetEntity> ::= <String>|id:<Number>
|
||||
<UserGoogleSheet> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>) <SheetEntity>
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
|
||||
<UserGoogleDoc> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>)
|
||||
|
||||
<SheetEntity> ::= <String>|id:<Number>
|
||||
<UserGoogleSheet> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>) <SheetEntity>
|
||||
```
|
||||
@@ -88,8 +90,6 @@
|
||||
<SharedDriveIDEntity> |
|
||||
<SharedDriveNameEntity>
|
||||
|
||||
<SheetEntity> ::= <String>|id:<Number>
|
||||
|
||||
<UserTypeEntity> ::=
|
||||
(all users|users_ns|users_susp|users_ns_susp)|
|
||||
(user <UserItem>)|
|
||||
|
||||
@@ -35,7 +35,7 @@ The log file being written to is always `gam.log`. When this log file is filled,
|
||||
|
||||
Commands are logged at completion with a timestamp, return code and the command line
|
||||
```
|
||||
2021-08-01T19:350:30.777-07:00,0,/Users/admin/bin/gamadv-xtd3/gam info domain
|
||||
2021-08-01T19:350:30.777-07:00,0,/Users/admin/bin/gam7/gam info domain
|
||||
```
|
||||
|
||||
Commands that generate sub-commands, `gam batch|tbatch|csv|loop`, log the initial command with a return code of `*`,
|
||||
@@ -44,14 +44,14 @@ the sub-command lines and the initial command with a numeric return code.
|
||||
$ gam redirect stdout usernames.csv multiprocess redirect stderr stdout csv users.csv gam info user "~primaryEmail" quick name
|
||||
2021-08-01T19:50:38.151-07:00,0/6,Using 6 processes...
|
||||
$ more ~/.gam/gam.log
|
||||
2021-08-01T19:50:38.120-07:00,*,/Users/admin/bin/gamadv-xtd3/gam redirect stdout usernames.csv multiprocess redirect stderr stdout csv users.csv showcmds false gam info user "~primaryEmail" quick name
|
||||
2021-08-01T19:50:38.120-07:00,*,/Users/admin/bin/gam7/gam redirect stdout usernames.csv multiprocess redirect stderr stdout csv users.csv showcmds false gam info user "~primaryEmail" quick name
|
||||
2021-08-01T19:50:39.144-07:00,0,gam info user testuser2 quick name
|
||||
2021-08-01T19:50:39.358-07:00,0,gam info user testuser3 quick name
|
||||
2021-08-01T19:50:39.358-07:00,0,gam info user testuser1 quick name
|
||||
2021-08-01T19:50:39.401-07:00,0,gam info user testuser5 quick name
|
||||
2021-08-01T19:50:39.459-07:00,56,gam info user testuserx quick name
|
||||
2021-08-01T19:50:39.470-07:00,0,gam info user testuser4 quick name
|
||||
2021-08-01T19:50:39.483-07:00,0,/Users/admin/bin/gamadv-xtd3/gam redirect stdout usernames.csv multiprocess redirect stderr stdout csv users.csv showcmds false gam info user "~primaryEmail" quick name
|
||||
2021-08-01T19:50:39.483-07:00,0,/Users/admin/bin/gam7/gam redirect stdout usernames.csv multiprocess redirect stderr stdout csv users.csv showcmds false gam info user "~primaryEmail" quick name
|
||||
```
|
||||
|
||||
## Command Progress
|
||||
|
||||
56
docs/Downloads-Installs-GAM7.md
Normal file
56
docs/Downloads-Installs-GAM7.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Downloads-Installs-GAM7
|
||||
You can download and install the current GAM7 release from the [GitHub Releases](https://github.com/GAM-team/GAM/releases/latest) page.
|
||||
Choose one of the following:
|
||||
|
||||
* Executable Archive, Automatic, Linux/Mac OS/Google Cloud Shell/Raspberry Pi/ChromeOS
|
||||
- Start a terminal session and execute one of the following commands:
|
||||
- New install, default path `$HOME/bin`
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install)`
|
||||
- New install, specify a path
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -d <Path>`
|
||||
- Update to latest version, do not create project or authorizations, default path `$HOME/bin`
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -l`
|
||||
- Update to latest version, do not create project or authorizations, specify a path
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -l -d <Path>`
|
||||
|
||||
By default, a folder, `gam7`, is created in the default or specified path and the files are downloaded into that folder.
|
||||
Add the `-s` option to the end of the above commands to suppress creating the `gam7` folder; the files are downloaded directly into the default or specified path.
|
||||
|
||||
* Executable Archive, Manual, Linux/Google Cloud Shell
|
||||
- `gam-7.wx.yz-linux-x86_64-glibc2.35.tar.xz`
|
||||
- `gam-7.wx.yz-linux-x86_64-glibc2.31.tar.xz`
|
||||
- `gam-7.wx.yz-linux-x86_64-legacy.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Raspberry Pi/ChromeOS ARM devices
|
||||
- `gam-7.wx.yz-linux-aarch-glibc2.31.tar.xz`
|
||||
- `gam-7.wx.yz-linux-aarch-legacy.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Mac OS versions Big Sur, Monterey, Ventura - M1/M2
|
||||
- `gam-7.wx.yz-macos-aarch.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Mac OS, versions Big Sur, Monterey, Ventura - Intel
|
||||
- `gam-7.wx.yz-macos-x86_64.tar.xz`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal session.
|
||||
|
||||
* Executable Archive, Manual, Windows 64 bit
|
||||
- `gam-7.wx.yz-windows-x86_64.zip`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
* Executable Installer, Manual, Windows 64 bit
|
||||
- `gam-7.wx.yz-windows-x86_64.msi`
|
||||
- Download the installer and run it.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
* Source, all platforms
|
||||
- `Source code(zip)`
|
||||
- `Source code(tar.gz)`
|
||||
- Download the archive, extract the contents into some directory.
|
||||
- Start a terminal/Command Prompt/PowerShell session.
|
||||
@@ -1,5 +1,5 @@
|
||||
# Downloads-Installs
|
||||
You can download and install the current GAMADV-XTD3 release from the [GitHub Releases](https://github.com/taers232c/GAMADV-XTD3/releases) page. Choose one of the following:
|
||||
You can download and install the current GAM7 release from the [GitHub Releases](https://github.com/taers232c/GAMADV-XTD3/releases) page. Choose one of the following:
|
||||
|
||||
* Executable Archive, Automatic, Linux/Mac OS/Google Cloud Shell/Raspberry Pi/ChromeOS
|
||||
- Start a terminal session and execute one of the following commands:
|
||||
|
||||
@@ -4,7 +4,7 @@ Many of the changes are internal to Gam and have no visible effect. Google has m
|
||||
A variable, `drive_v3_native_names` (default value is True), has been added to `gam.cfg` to control the field names on output: when True, the v3 native field names are used; when False, the v3 native field names are mapped to the v2 field names.
|
||||
|
||||
If you have scripts that process the output from these print commands, you may have to make modifications to your scripts.
|
||||
Run your print/show commands with a version of Standard Gam and save the output.
|
||||
Run your print/show commands with a version of Legacy Gam and save the output.
|
||||
With drive_v3_native_names = False, run your print/show commands with this version of Gam and compare the output to that saved in the previous run;
|
||||
modify your scripts that process the output as appropriate.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# GAM Return Codes
|
||||
|
||||
These are the return codes used by GAMADV-XTD3.
|
||||
These are the return codes used by GAM7.
|
||||
|
||||
```
|
||||
SUCCESS_RC = 0
|
||||
|
||||
16
docs/GAM7-on-Android-Devices.md
Normal file
16
docs/GAM7-on-Android-Devices.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# GAM7 on Android Devices
|
||||
GAM7 now runs on 64-bit Android devices such as Google's Pixel phones. The installation requires an app that adds the Linux environment to Android such as [UserLAnd](https://play.google.com/store/apps/details?id=tech.ula&hl=en_US).
|
||||
|
||||
_Note: Chromebooks / Chrome OS devices should install GAM7 using [these instructions](GAM7-on-Chrome-OS-Devices)._
|
||||
|
||||
1. Install the [UserLAnd](https://play.google.com/store/apps/details?id=tech.ula&hl=en_US) app.
|
||||
2. Click Debian to install a Debian environment.
|
||||
3. Set a username and password.
|
||||
4. Choose SSH for connection type.
|
||||
5. Once setup, login with the password to get to a Linux shell.
|
||||
6. Run the following commands to install prerequisites:
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install curl python3
|
||||
```
|
||||
7. [How to Install Advanced GAM](How-to-Install-Advanced-GAM)
|
||||
14
docs/GAM7-on-Chrome-OS-Devices.md
Normal file
14
docs/GAM7-on-Chrome-OS-Devices.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# GAM7 on Chrome OS Devices
|
||||
Chrome OS devices that [support Linux apps](https://support.google.com/chromebook/answer/9145439?hl=en) can run GAM7. This includes Intel/AMD x86_64 Chromebooks as well as ARM-based Chromebooks with Mediatek or Rockchip 64-bit CPUs.
|
||||
|
||||
1. [Set up Linux on your Chromebook](https://support.google.com/chromebook/answer/9145439?hl=en).
|
||||
1. From the Terminal app, run the following commands:
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install xz-utils
|
||||
```
|
||||
3. [How to Install Advanced GAM](How-to-Install-Advanced-GAM)
|
||||
|
||||
# Google cloud shell
|
||||
|
||||
Note that from a Chrome OS device, it might be just as easy to use [Google Cloud Shell](https://cloud.google.com/shell). Especially if you are concerned about network connectivity and/or bandwidth, using a shell instance within Google's server infrastructure is always going to be less resource intensive than sending data back and forth between a Google API and your local machine on your local network.
|
||||
@@ -1,14 +1,87 @@
|
||||
# Update GAMADV-XTD3 to latest version
|
||||
# Update GAM7 to latest version
|
||||
Automatic update to the latest version on Linux/Mac OS/Google Cloud Shell/Raspberry Pi/ChromeOS:
|
||||
- Do not create project or authorizations, default path `$HOME/bin`
|
||||
- `bash <(curl -s -S -L https://raw.githubusercontent.com/taers232c/GAMADV-XTD3/master/src/gam-install.sh) -l`
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -l`
|
||||
- Do not create project or authorizations, specify a path
|
||||
- `bash <(curl -s -S -L https://raw.githubusercontent.com/taers232c/GAMADV-XTD3/master/src/gam-install.sh) -l -d <Path>`
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -l -d <Path>`
|
||||
|
||||
By default, a folder, `gamadv-xtd3`, is created in the default or specified path and the files are downloaded into that folder.
|
||||
Add the `-s` option to the end of the above commands to suppress creating the `gamadv-xtd3` folder; the files are downloaded directly into the default or specified path.
|
||||
By default, a folder, `gam7`, is created in the default or specified path and the files are downloaded into that folder.
|
||||
Add the `-s` option to the end of the above commands to suppress creating the `gam7` folder; the files are downloaded directly into the default or specified path.
|
||||
|
||||
See [Downloads-Installs](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
See [Downloads-Installs-GAM7](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.00.11
|
||||
|
||||
Updated to Python 3.12.7 where possible.
|
||||
|
||||
### 7.00.10
|
||||
|
||||
Handled the following error that occurs when `gam create user` is immediateley followed by `gam update user`.
|
||||
```
|
||||
ERROR: 412: conditionNotMet - User creation is not complete.
|
||||
```
|
||||
|
||||
Updated support for `Folders with limited access`; this is a work in progress.
|
||||
|
||||
### 7.00.09
|
||||
|
||||
Added initial support for `Folders with limited access`; you must be enrolled in the Beta preview.
|
||||
|
||||
Updated `api_call_tries_limit` variable to `gam.cfg` that limits the number of tries
|
||||
for Google API calls that return an error that indicates a retry should be performed.
|
||||
The default value is 10 and the range of allowable values is 3-30.
|
||||
|
||||
### 7.00.08
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> delete groups` that caused the command to fail when `enable_dasa = true` in `gam.cfg`.
|
||||
|
||||
### 7.00.07
|
||||
|
||||
Updated `<PeopleContactAttribute>` fields `address,email,phone,url` to allow an empty type field.
|
||||
```
|
||||
address "" formatted "My Address" primary
|
||||
email "" user@gmail.com primary
|
||||
phone "" "510-555-1212" primary
|
||||
url "" "https://www.domain.com" primary
|
||||
```
|
||||
|
||||
### 7.00.06
|
||||
|
||||
Updated `gam <UserTypeEntity> create|update chatspace` to support the new permissions settings
|
||||
for Chat spaces that are in Developer Preview.
|
||||
|
||||
* See: https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces#Space.FIELDS.predefined_permission_settings
|
||||
|
||||
### 7.00.05
|
||||
|
||||
Fixed bug that caused an error when creating a calendar birthday event.
|
||||
|
||||
### 7.00.04
|
||||
|
||||
Improved performance of `gam report users orgunit <OrgUnitPath>` when `showorgunit` is not specified.
|
||||
|
||||
Added option `birthday <Date>` to `gam <UserTypeEntity> create event <UserCalendarEntity>` that adds
|
||||
an annual recurring event to the calendar.
|
||||
|
||||
Added `birthday` to `<EventType>` for use in various calendar event commands.
|
||||
|
||||
### 7.00.03
|
||||
|
||||
Updated `gam delete ou` and `gam print admins` to handle the following error:
|
||||
```
|
||||
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
|
||||
```
|
||||
|
||||
### 7.00.02
|
||||
|
||||
Added option `showlastmodification` to `gam <UserTypeEntity> print|show filecounts` that adds
|
||||
the following fields to the output: `lastModifiedFileId,lastModifiedFileName,lastModifyingUser,lastModifiedTime`;
|
||||
these are for the most recently modified file.
|
||||
|
||||
Added option `keepforever [<Boolean>]` to `gam <UserTypeEntity> update filerevisions` that allows setting
|
||||
`Keep forever` in revisions.
|
||||
|
||||
Upgraded to Python 3.12.6 where possible.
|
||||
|
||||
### 7.00.01
|
||||
|
||||
|
||||
@@ -25,6 +25,24 @@
|
||||
|
||||
## Definitions
|
||||
See [Collections of Items](Collections-of-Items)
|
||||
|
||||
* [Command data from Google Docs/Sheets/Storage](Command-Data-From-Google-Docs-Sheets-Storage)
|
||||
```
|
||||
<StorageBucketName> ::= <String>
|
||||
<StorageObjectName> ::= <String>
|
||||
<StorageBucketObjectName> ::=
|
||||
https://storage.cloud.google.com/<StorageBucketName>/<StorageObjectName>|
|
||||
https://storage.googleapis.com/<StorageBucketName>/<StorageObjectName>|
|
||||
gs://<StorageBucketName>/<StorageObjectName>|
|
||||
<StorageBucketName>/<StorageObjectName>
|
||||
|
||||
<UserGoogleDoc> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>)
|
||||
|
||||
<SheetEntity> ::= <String>|id:<Number>
|
||||
<UserGoogleSheet> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>) <SheetEntity>
|
||||
```
|
||||
```
|
||||
<DeliverySetting> ::=
|
||||
allmail|
|
||||
|
||||
61
docs/Home.md
61
docs/Home.md
@@ -1,70 +1,61 @@
|
||||
- [Introduction](#introduction)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation - First time GAM installation](#installation---first-time-gam-installation)
|
||||
- [Installation - Upgrading from a GAM version other than a prior version of GAMADV-X or GAMADV-XTD or GAMADV-XTD3](#installation---upgrading-from-a-gam-version-other-than-a-prior-version-of-gamadv-x-or-gamadv-xtd-or-gamadv-xtd3)
|
||||
- [Installation - Upgrading from a prior version of GAMADV-X or GAMADV-XTD or GAMADV-XTD3](#installation---upgrading-from-a-prior-version-of-gamadv-x-or-gamadv-xtd-or-gamadv-xtd3)
|
||||
- [Installation - First time GAM7 installation](#installation---first-time-gam7-installation)
|
||||
- [Installation - Upgrading from Legacy GAM](#installation---upgrading-from-legacy-gam)
|
||||
|
||||
# Introduction
|
||||
GAMADV-XTD3 is a free, open source command line tool for Google Workspace Administrators to manage domain and user settings quickly and easily.
|
||||
GAM7 is a free, open source command line tool for Google Workspace Administrators to manage domain and user settings quickly and easily.
|
||||
|
||||
GAMADV-XTD3 is built with Python 3; as Python 2 support ends on 2020-01-01, this is the version of Advanced GAM that new/existing users should install.
|
||||
This page provides simple instructions for downloading, installing and starting to use GAM7.
|
||||
|
||||
This page provides simple instructions for downloading, installing and starting to use GAMADV-XTD3.
|
||||
GAM7 requires paid, or Education/Non-profit, editions of Google Workspace. G Suite Legacy Free Edition has limited API support and not all GAM commands work.
|
||||
|
||||
GAMADV-XTD3 requires paid, or Education/Non-profit, editions of Google Workspace. G Suite Legacy Free Edition has limited API support and not all GAM commands work.
|
||||
GAM7 is a rewrite/extension of Jay Lee's [Legacy GAM], without his efforts, this version wouldn't exist.
|
||||
|
||||
GAMADV-XTD3 is a rewrite/extension of Jay Lee's [GAM], without his efforts, this version wouldn't exist.
|
||||
|
||||
GAMADV-XTD3 is backwards compatible with [GAM], meaning that if your command works with regular GAM, it will also work with GAMADV-XTD3. There may be differences in output, but the syntax is compatible.
|
||||
GAM7 is backwards compatible with [Legacy GAM], meaning that if your command works with Legacy GAM, it will also work with GAM7. There may be differences in output, but the syntax is compatible.
|
||||
|
||||
# Documentation
|
||||
Basic GAM documentation is hosted in the [GitHub Wiki]. Documentation specifically for GAMADV-XTD3 is hosted in the [GitHub GAMADV-XTD3 Wiki] and in Gam*.txt files.
|
||||
Documentation for GAM7 is hosted in the [GitHub GAM7 Wiki] and in Gam*.txt files.
|
||||
Legacy GAM documentation is hosted in the [GitHub Legacy Wiki].
|
||||
|
||||
# Mailing List / Discussion group
|
||||
The GAM mailing list / discussion group is hosted on [Google Groups]. You can join the list and interact via email, or just post from the web itself.
|
||||
|
||||
# Source Repository
|
||||
The official GAMADV-XTD3 source repository is on [GitHub] in the master branch.
|
||||
The official GAM7 source repository is on [GitHub] in the master branch.
|
||||
|
||||
# Author
|
||||
GAMADV-XTD3 is maintained by <a href="mailto:ross.scroggs@gmail.com">Ross Scroggs</a>.
|
||||
GAM7 is maintained by <a href="mailto:ross.scroggs@gmail.com">Ross Scroggs</a>.
|
||||
|
||||
# Requirements
|
||||
To run all commands properly, GAMADV-XTD3 requires three things:
|
||||
* An API project which identifies your install of GAMADV-XTD3 to Google and keeps track of API quotas.
|
||||
To run all commands properly, GAM7 requires three things:
|
||||
* An API project which identifies your install of GAM7 to Google and keeps track of API quotas.
|
||||
* Authorization to act as your Google Workspace Administrator in order to perform management functions like add users, modify group settings and membership and pull domain reports.
|
||||
* A special service account that is authorized to act on behalf of your users in order to modify user-specific settings and data such as Drive files, Calendars and Gmail messages and settings like signatures.
|
||||
|
||||
# Installation - First time GAM installation
|
||||
# Installation - First time GAM7 installation
|
||||
Use these steps if you have never used any version of GAM in your domain. They will create a GAM project
|
||||
and all necessary authentications.
|
||||
|
||||
* Download: [Downloads-Installs](Downloads-Installs)
|
||||
* Configuration: [GAM Configuration](gam.cfg)
|
||||
* Configuration: [GAM7 Configuration](gam.cfg)
|
||||
* Install: [How to Install Advanced GAM](How-to-Install-Advanced-GAM)
|
||||
|
||||
# Installation - Upgrading from a GAM version other than a prior version of GAMADV-X or GAMADV-XTD or GAMADV-XTD3
|
||||
Use these steps if you have used any version of GAM in your domain. They will update your GAM project
|
||||
# Installation - Upgrading from Legacy GAM
|
||||
Use these steps if you have used any version of Legacy GAM in your domain. They will update your GAM project
|
||||
and all necessary authentications.
|
||||
|
||||
* Download: [Downloads-Installs](Downloads-Installs)
|
||||
* Configuration: [GAM Configuration](gam.cfg)
|
||||
* Upgrade: [How to Upgrade from Standard GAM](How-to-Upgrade-from-Standard-GAM)
|
||||
* Configuration: [GAM7 Configuration](gam.cfg)
|
||||
* Upgrade: [How to Upgrade from Legacy GAM](How-to-Upgrade-from-Legacy-GAM)
|
||||
|
||||
# Installation - Upgrading from a prior version of GAMADV-X or GAMADV-XTD or GAMADV-XTD3
|
||||
Use these steps if you already use GAMADV-X or GAMADV-XTD or GAMADV-XTD3. The updates may tell you to update your GAM project
|
||||
or authentications because new features have been included.
|
||||
You can install multiple versions of GAM and GAM7 in different parallel directories.
|
||||
|
||||
* Updates: [GAM Updates]
|
||||
* Download: [Downloads-Installs](Downloads-Installs)
|
||||
|
||||
You can install multiple versions of GAM and GAMADV-XTD3 in different parallel directories.
|
||||
|
||||
[GAM]: https://github.com/GAM-team/GAM
|
||||
[GitHub Releases]: https://github.com/taers232c/GAMADV-XTD3/releases
|
||||
[GitHub]: https://github.com/taers232c/GAMADV-XTD3/tree/master
|
||||
[GitHub Wiki]: https://github.com/GAM-team/GAM/wiki/
|
||||
[GitHub GAMADV-XTD3 Wiki]: https://github.com/taers232c/GAMADV-XTD3/wiki/
|
||||
[Legacy GAM]: https://github.com/GAM-team/GAM/releases?q=6.58&expanded=true
|
||||
[GAM7]: https://github.com/GAM-team/GAM
|
||||
[GitHub Releases]: https://github.com/GAM-team/GAM/releases
|
||||
[GitHub]: https://github.com/GAM-team/GAM/tree/master
|
||||
[GitHub Legacy Wiki]: https://github.com/GAM-team/GAM/wiki/
|
||||
[GitHub GAM7 Wiki]: https://github.com/taers232c/GAMADV-XTD3/wiki/
|
||||
[Google Groups]: https://groups.google.com/group/google-apps-manager
|
||||
[GAM Updates]: https://github.com/taers232c/GAMADV-XTD3/wiki/GamUpdates
|
||||
|
||||
|
||||
938
docs/How-to-Install-GAM7.md
Normal file
938
docs/How-to-Install-GAM7.md
Normal file
@@ -0,0 +1,938 @@
|
||||
# Installing GAM7
|
||||
Use these steps if you have never used any version of GAM in your domain. They will create your GAM project
|
||||
and all necessary authentications.
|
||||
|
||||
- [Downloads-Installs](Downloads-Installs)
|
||||
- [Linux and MacOS and Google Cloud Shell](#linux-and-mac-os-and-google-cloud-shell)
|
||||
- [Windows](#windows)
|
||||
- [GAM Configuration](gam.cfg)
|
||||
|
||||
## Linux and MacOS and Google Cloud Shell
|
||||
|
||||
In these examples, your Google Super admin is shown as admin@domain.com; replace with the
|
||||
actual email adddress.
|
||||
|
||||
In these examples, the user home folder is shown as /Users/admin; adjust according to your
|
||||
specific situation; e.g., /home/administrator.
|
||||
|
||||
This example assumes that GAM7 has been installed in /Users/admin/bin/gam7.
|
||||
If you've installed GAM7 in another directory, substitute that value in the directions.
|
||||
|
||||
### Set a configuration directory
|
||||
|
||||
The default GAM configuration directory is /Users/admin/.gam; for more flexibility you
|
||||
probably want to select a non-hidden location. This example assumes that the GAM
|
||||
configuration directory will be /Users/admin/GAMConfig; If you've chosen another directory,
|
||||
substitute that value in the directions.
|
||||
|
||||
Make the directory:
|
||||
```
|
||||
mkdir -p /Users/admin/GAMConfig
|
||||
```
|
||||
|
||||
Add the following line:
|
||||
```
|
||||
export GAMCFGDIR="/Users/admin/GAMConfig"
|
||||
```
|
||||
to one of these files based on your shell:
|
||||
```
|
||||
~/.bash_profile
|
||||
~/.bashrc
|
||||
~/.zshrc
|
||||
~/.profile
|
||||
```
|
||||
|
||||
Issue the following command replacing `<Filename>` with the name of the file you edited:
|
||||
```
|
||||
source <Filename>
|
||||
```
|
||||
|
||||
You need to make sure the GAM configuration directory actually exists. Test that like this:
|
||||
```
|
||||
ls -l $GAMCFGDIR
|
||||
```
|
||||
|
||||
### Set a working directory
|
||||
|
||||
You should establish a GAM working directory; you will store your GAM related
|
||||
data in this folder and execute GAM commands from this folder. You should not use
|
||||
/Users/admin/bin/gam7 or /Users/admin/GAMConfig for this purpose.
|
||||
This example assumes that the GAM working directory will be /Users/admin/GAMWork; If you've chosen
|
||||
another directory, substitute that value in the directions.
|
||||
|
||||
Make the directory:
|
||||
```
|
||||
mkdir -p /Users/admin/GAMWork
|
||||
```
|
||||
|
||||
### Set an alias
|
||||
You should set an alias to point to /Users/admin/bin/gam7/gam so you can operate from the /Users/admin/GAMWork directory.
|
||||
Aliases aren't available in scripts, so you may want to set a symlink instead, see below.
|
||||
|
||||
Add the following line:
|
||||
```
|
||||
alias gam="/Users/admin/bin/gam7/gam"
|
||||
```
|
||||
to one of these files based on your shell:
|
||||
```
|
||||
~/.bash_aliases
|
||||
~/.bash_profile
|
||||
~/.bashrc
|
||||
~/.zshrc
|
||||
~/.profile
|
||||
```
|
||||
|
||||
Issue the following command replacing `<Filename>` with the name of the file you edited:
|
||||
```
|
||||
source <Filename>
|
||||
```
|
||||
|
||||
### Set a symlink
|
||||
Set a symlink in `/usr/local/bin` (or some other location on $PATH) to point to GAM.
|
||||
```
|
||||
ln -s "/Users/admin/bin/gam7/gam" /usr/local/bin/gam
|
||||
```
|
||||
|
||||
### Initialize GAM7; this should be the first GAM7 command executed.
|
||||
```
|
||||
admin@server:/Users/admin$ gam config drive_dir /Users/admin/GAMWork verify
|
||||
Created: /Users/admin/GAMConfig
|
||||
Created: /Users/admin/GAMConfig/gamcache
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Initialized
|
||||
Section: DEFAULT
|
||||
...
|
||||
cache_dir = /Users/admin/GAMConfig/gamcache
|
||||
...
|
||||
config_dir = /Users/admin/GAMConfig
|
||||
...
|
||||
drive_dir = /Users/admin/GAMWork
|
||||
...
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
### Verify initialization, this was a successful installation.
|
||||
```
|
||||
admin@server:/Users/admin$ ls -l $GAMCFGDIR
|
||||
total 48
|
||||
-rw-r-----+ 1 admin staff 1069 Mar 3 09:23 gam.cfg
|
||||
drwxr-x---+ 2 admin staff 68 Mar 3 09:23 gamcache
|
||||
-rw-rw-rw-+ 1 admin staff 0 Mar 3 09:23 oauth2.txt.lock
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
### Create your project with local browser
|
||||
```
|
||||
admin@server:/Users/admin$ gam create project
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: client_secrets_json, Value: /Users/admin/GAMConfig/client_secrets.json, Not Found
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: oauth2service_json, Value: /Users/admin/GAMConfig/oauth2service.json, Not Found
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com
|
||||
|
||||
Your browser has been opened to visit:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?client_id=CLI...response_type=code
|
||||
|
||||
If your browser is on a different machine then press CTRL+C,
|
||||
set no_browser = true in gam.cfg and re-run this command.
|
||||
|
||||
Authentication successful.
|
||||
Creating project "GAM Project"...
|
||||
Checking project status...
|
||||
Project: gam-project-abc-def-ghi, Enable 23 APIs
|
||||
API: admin.googleapis.com, Enabled (1/23)
|
||||
API: alertcenter.googleapis.com, Enabled (2/23)
|
||||
API: appsactivity.googleapis.com, Enabled (3/23)
|
||||
API: audit.googleapis.com, Enabled (4/23)
|
||||
API: calendar-json.googleapis.com, Enabled (5/23)
|
||||
API: chat.googleapis.com, Enabled (6/23)
|
||||
API: classroom.googleapis.com, Enabled (7/23)
|
||||
API: contacts.googleapis.com, Enabled (8/23)
|
||||
API: drive.googleapis.com, Enabled (9/23)
|
||||
API: driveactivity.googleapis.com, Enabled (10/23)
|
||||
API: gmail.googleapis.com, Enabled (11/23)
|
||||
API: groupsmigration.googleapis.com, Enabled (12/23)
|
||||
API: groupssettings.googleapis.com, Enabled (13/23)
|
||||
API: iam.googleapis.com, Enabled (14/23)
|
||||
API: iap.googleapis.com, Enabled (15/23)
|
||||
API: licensing.googleapis.com, Enabled (16/23)
|
||||
API: people.googleapis.com, Enabled (17/23)
|
||||
API: pubsub.googleapis.com, Enabled (18/23)
|
||||
API: reseller.googleapis.com, Enabled (19/23)
|
||||
API: sheets.googleapis.com, Enabled (20/23)
|
||||
API: siteverification.googleapis.com, Enabled (21/23)
|
||||
API: storage-api.googleapis.com, Enabled (22/23)
|
||||
API: vault.googleapis.com, Enabled (23/23)
|
||||
Setting GAM project consent screen...
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Enabled
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Generating new private key
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded
|
||||
Service Account OAuth2 File: /Users/admin/GAMConfig/oauth2service.json, Service Account Key: SVCACCTKEY, Updated
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key
|
||||
Please go to:
|
||||
|
||||
https://console.cloud.google.com/apis/credentials/oauthclient?project=gam-project-abc-def-ghi
|
||||
|
||||
1. Choose "Desktop App" or "Other" for "Application type".
|
||||
2. Enter "GAM" or another desired value for "Name".
|
||||
3. Click the blue "Create" button.
|
||||
4. Copy your "client ID" value that shows on the next page.
|
||||
|
||||
Enter your Client ID: CLIENTID
|
||||
|
||||
5. Go back to your browser and copy your "client secret" value.
|
||||
Enter your Client Secret: CLIENTSECRET
|
||||
6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open.
|
||||
That's it! Your GAM Project is created and ready to use.
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
### Create your project without local browser (Google Cloud Shell for instance)
|
||||
```
|
||||
admin@server:/Users/admin$ gam config no_browser true save
|
||||
admin@server:/Users/admin$ gam create project
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: client_secrets_json, Value: /Users/admin/GAMConfig/client_secrets.json, Not Found
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Item: oauth2service_json, Value: /Users/admin/GAMConfig/oauth2service.json, Not Found
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com
|
||||
|
||||
Go to the following link in a browser on other computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?re... m&prompt=consent
|
||||
|
||||
Enter verification code: abc...xyz
|
||||
|
||||
Authentication successful.
|
||||
Creating project "GAM Project"...
|
||||
Checking project status...
|
||||
Project: gam-project-abc-def-ghi, Enable 23 APIs
|
||||
API: admin.googleapis.com, Enabled (1/23)
|
||||
API: alertcenter.googleapis.com, Enabled (2/23)
|
||||
API: appsactivity.googleapis.com, Enabled (3/23)
|
||||
API: audit.googleapis.com, Enabled (4/23)
|
||||
API: calendar-json.googleapis.com, Enabled (5/23)
|
||||
API: chat.googleapis.com, Enabled (6/23)
|
||||
API: classroom.googleapis.com, Enabled (7/23)
|
||||
API: contacts.googleapis.com, Enabled (8/23)
|
||||
API: drive.googleapis.com, Enabled (9/23)
|
||||
API: driveactivity.googleapis.com, Enabled (10/23)
|
||||
API: gmail.googleapis.com, Enabled (11/23)
|
||||
API: groupsmigration.googleapis.com, Enabled (12/23)
|
||||
API: groupssettings.googleapis.com, Enabled (13/23)
|
||||
API: iam.googleapis.com, Enabled (14/23)
|
||||
API: iap.googleapis.com, Enabled (15/23)
|
||||
API: licensing.googleapis.com, Enabled (16/23)
|
||||
API: people.googleapis.com, Enabled (17/23)
|
||||
API: pubsub.googleapis.com, Enabled (18/23)
|
||||
API: reseller.googleapis.com, Enabled (19/23)
|
||||
API: sheets.googleapis.com, Enabled (20/23)
|
||||
API: siteverification.googleapis.com, Enabled (21/23)
|
||||
API: storage-api.googleapis.com, Enabled (22/23)
|
||||
API: vault.googleapis.com, Enabled (23/23)
|
||||
Setting GAM project consent screen...
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Enabled
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Generating new private key
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded
|
||||
Service Account OAuth2 File: /Users/admin/GAMConfig/oauth2service.json, Service Account Key: SVCACCTKEY, Updated
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key
|
||||
Please go to:
|
||||
|
||||
https://console.cloud.google.com/apis/credentials/oauthclient?project=gam-project-abc-def-ghi
|
||||
|
||||
1. Choose "Desktop App" or "Other" for "Application type".
|
||||
2. Enter "GAM" or another desired value for "Name".
|
||||
3. Click the blue "Create" button.
|
||||
4. Copy your "client ID" value that shows on the next page.
|
||||
|
||||
Enter your Client ID: CLIENTID
|
||||
|
||||
5. Go back to your browser and copy your "client secret" value.
|
||||
Enter your Client Secret: CLIENTSECRET
|
||||
6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open.
|
||||
That's it! Your GAM Project is created and ready to use.
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
### Enable GAM7 client access
|
||||
|
||||
You select a list of scopes, GAM uses a browser to get final authorization from Google for these scopes and
|
||||
writes the credentials into the file oauth2.txt.
|
||||
|
||||
```
|
||||
admin@server:/Users/admin$ gam oauth create
|
||||
|
||||
[*] 0) Calendar API (supports readonly)
|
||||
[*] 1) Chrome Browser Cloud Management 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)
|
||||
|
||||
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
|
||||
|
||||
Go to the following link in a browser on this computer or on another computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=423565144751-10lsdt2lgnsch9jmdhl35uq4617u1ifp&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2F&scope=...
|
||||
|
||||
If you use a browser on another computer, you will get a browser error that the site can't be reached AFTER you
|
||||
click the Allow button, paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
The authentication flow has completed.
|
||||
Client OAuth2 File: /Users/admin/GAMConfig/oauth2.txt, Created
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
|
||||
If clicking on the link in the instructions does not work (i.e. you get a 404 or 400 error message, instead of something about 'unable to connect') the URL in the link is too long. Most likely, you have selected all scopes. Try again with fewer scopes until it works. (there is no harm in repeatedly trying)
|
||||
|
||||
### Enable GAM7 service account access.
|
||||
```
|
||||
admin@server:/Users/admin$ gam user admin@domain.com check serviceaccount
|
||||
$ gam user admin@domain.com check serviceaccount
|
||||
System time status
|
||||
Your system time differs from www.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: 0 days PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels FAIL (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels FAIL (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
Some scopes FAILED!
|
||||
To authorize them, please go to:
|
||||
|
||||
https://admin.google.com/ac/owl/domainwidedelegation?clientScopeToAdd=https://mail.go...huser=admin@domain.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.
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
The link shown in the error message should take you directly to the authorization screen.
|
||||
If not, make sure that you are logged in as a domain admin, then re-enter the link.
|
||||
|
||||
### Verify GAM7 service account access.
|
||||
|
||||
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
|
||||
for the authorization to complete.
|
||||
```
|
||||
admin@server:/Users/admin$ gam user admin@domain.com check serviceaccount
|
||||
System time status:
|
||||
Your system time differs from www.googleapis.com by less than 1 second PASS
|
||||
Service Account Private Key Authentication:
|
||||
Authentication PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels PASS (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels PASS (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
All scopes PASSED!
|
||||
|
||||
Service Account Client name: SVCACCTID is fully authorized.
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
### Update gam.cfg with some basic values
|
||||
* `customer_id` - Having this data keeps Gam from having to make extra API calls
|
||||
* `domain` - This allows you to omit the domain portion of email addresses
|
||||
* `timezone local` - Gam will convert all UTC times to your local timezone
|
||||
```
|
||||
admin@server:/Users/admin$ gam info domain
|
||||
Customer ID: C01234567
|
||||
Primary Domain: domain.com
|
||||
Customer Creation Time: 2007-06-06T15:47:55.444Z
|
||||
Primary Domain Verified: True
|
||||
Default Language: en
|
||||
...
|
||||
|
||||
admin@server:/Users/admin$ gam config customer_id C01234567 domain domain.com timezone local save verify
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Saved
|
||||
Section: DEFAULT
|
||||
...
|
||||
customer_id = C01234567
|
||||
...
|
||||
domain = domain.com
|
||||
...
|
||||
timezone = local
|
||||
...
|
||||
|
||||
admin@server:/Users/admin$
|
||||
```
|
||||
|
||||
## Windows
|
||||
|
||||
In these examples, your Google Super admin is shown as admin@domain.com; replace with the
|
||||
actual email adddress.
|
||||
|
||||
This example assumes that GAM7 has been installed in C:\GAM7; if you've installed
|
||||
GAM7 in another directory, substitute that value in the directions.
|
||||
|
||||
These steps assume Command Prompt, adjust if you're using PowerShell.
|
||||
|
||||
### Set a configuration directory
|
||||
|
||||
The default GAM configuration directory is C:\Users\<UserName>\.gam; for more flexibility you
|
||||
probably want to select a non user-specific location. This example assumes that the GAM
|
||||
configuration directory will be C:\GAMConfig; If you've chosen another directory,
|
||||
substitute that value in the directions.
|
||||
* Make the C:\GAMConfig directory before proceeding.
|
||||
|
||||
### Set a working directory
|
||||
|
||||
You should extablish a GAM working directory; you will store your GAM related
|
||||
data in this folder and execute GAM commands from this folder. You should not use
|
||||
C:\GAM7 or C:\GAMConfig for this purpose.
|
||||
This example assumes that the GAM working directory will be C:\GAMWork; If you've chosen
|
||||
another directory, substitute that value in the directions.
|
||||
* Make the C:\GAMWork directory before proceeding.
|
||||
|
||||
### Set system path and GAM configuration directory
|
||||
You should set the system path to point to C:\GAM7 so you can operate from the C:\GAMWork directory.
|
||||
```
|
||||
Start Control Panel
|
||||
Click System
|
||||
Click Advanced system settings
|
||||
Click Environment Variables...
|
||||
Click Path under System variables
|
||||
Click Edit...
|
||||
If C:\GAM7 is already on the Path, skip the next three steps
|
||||
Click New
|
||||
Enter C:\GAM7
|
||||
Click OK
|
||||
Click New
|
||||
Set Variable name: GAMCFGDIR
|
||||
Set Variable value: C:\GAMConfig
|
||||
Click OK
|
||||
Click OK
|
||||
Click OK
|
||||
Exit Control Panel
|
||||
```
|
||||
|
||||
At this point, you should restart Command Prompt so that it has the updated path and environment variables.
|
||||
|
||||
### Initialize GAM7; this should be the first GAM7 command executed.
|
||||
```
|
||||
C:\>gam config drive_dir C:\GAMWork verify
|
||||
Created: C:\GAMConfig
|
||||
Created: C:\GAMConfig\gamcache
|
||||
Config File: C:\GAMConfig\gam.cfg, Initialized
|
||||
Section: DEFAULT
|
||||
...
|
||||
cache_dir = C:\GAMConfig\gamcache
|
||||
...
|
||||
config_dir = C:\GAMConfig
|
||||
...
|
||||
drive_dir = C:\GAMWork
|
||||
...
|
||||
|
||||
C:\>
|
||||
```
|
||||
### Verify initialization, this was a successful installation.
|
||||
```
|
||||
C:\>dir %GAMCFGDIR%
|
||||
Volume in drive C has no label.
|
||||
Volume Serial Number is 663F-DA8B
|
||||
|
||||
Directory of C:\GAMConfig
|
||||
|
||||
03/03/2017 10:16 AM <DIR> .
|
||||
03/03/2017 10:16 AM <DIR> ..
|
||||
03/03/2017 10:15 AM 1,125 gam.cfg
|
||||
03/03/2017 10:15 AM <DIR> gamcache
|
||||
03/03/2017 10:15 AM 0 oauth2.txt.lock
|
||||
2 File(s) 15,769 bytes
|
||||
3 Dir(s) 110,532,562,944 bytes free
|
||||
C:\>
|
||||
```
|
||||
|
||||
### Create your project with local browser
|
||||
```
|
||||
C:\>gam create project
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: client_secrets_json, Value: C:\GAMConfig\client_secrets.json, Not Found
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: oauth2service_json, Value: C:\GAMConfig\oauth2service.json, Not Found
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com
|
||||
|
||||
Your browser has been opened to visit:
|
||||
|
||||
https://accounts.google.com/o/oaut...pe=code
|
||||
|
||||
If your browser is on a different machine then press CTRL+C,
|
||||
set no_browser = true in gam.cfg and re-run this command.
|
||||
|
||||
Authentication successful.
|
||||
Creating project "GAM Project"...
|
||||
Checking project status...
|
||||
Project: gam-project-abc-def-ghi, Enable 23 APIs
|
||||
API: admin.googleapis.com, Enabled (1/23)
|
||||
API: alertcenter.googleapis.com, Enabled (2/23)
|
||||
API: appsactivity.googleapis.com, Enabled (3/23)
|
||||
API: audit.googleapis.com, Enabled (4/23)
|
||||
API: calendar-json.googleapis.com, Enabled (5/23)
|
||||
API: chat.googleapis.com, Enabled (6/23)
|
||||
API: classroom.googleapis.com, Enabled (7/23)
|
||||
API: contacts.googleapis.com, Enabled (8/23)
|
||||
API: drive.googleapis.com, Enabled (9/23)
|
||||
API: driveactivity.googleapis.com, Enabled (10/23)
|
||||
API: gmail.googleapis.com, Enabled (11/23)
|
||||
API: groupsmigration.googleapis.com, Enabled (12/23)
|
||||
API: groupssettings.googleapis.com, Enabled (13/23)
|
||||
API: iam.googleapis.com, Enabled (14/23)
|
||||
API: iap.googleapis.com, Enabled (15/23)
|
||||
API: licensing.googleapis.com, Enabled (16/23)
|
||||
API: people.googleapis.com, Enabled (17/23)
|
||||
API: pubsub.googleapis.com, Enabled (18/23)
|
||||
API: reseller.googleapis.com, Enabled (19/23)
|
||||
API: sheets.googleapis.com, Enabled (20/23)
|
||||
API: siteverification.googleapis.com, Enabled (21/23)
|
||||
API: storage-api.googleapis.com, Enabled (22/23)
|
||||
API: vault.googleapis.com, Enabled (23/23)
|
||||
Setting GAM project consent screen...
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Enabled
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Generating new private key
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded
|
||||
Service Account OAuth2 File: C:\GAMConfig\oauth2service.json, Service Account Key: SVCACCTKEY, Updated
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key
|
||||
Please go to:
|
||||
|
||||
https://console.cloud.google.com/apis/credentials/oauthclient?project=gam-project-abc-def-ghi
|
||||
|
||||
1. Choose "Desktop App" or "Other" for "Application type".
|
||||
2. Enter "GAM" or another desired value for "Name".
|
||||
3. Click the blue "Create" button.
|
||||
4. Copy your "client ID" value that shows on the next page.
|
||||
|
||||
Enter your Client ID: CLIENTID
|
||||
|
||||
5. Go back to your browser and copy your "client secret" value.
|
||||
Enter your Client Secret: CLIENTSECRET
|
||||
6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open.
|
||||
That's it! Your GAM Project is created and ready to use.
|
||||
|
||||
C:\>
|
||||
```
|
||||
### Create your project without local browser (headless server for instance)
|
||||
```
|
||||
C:\>gam config no_browser true save
|
||||
C:\>gam create project
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: client_secrets_json, Value: C:\GAMConfig\client_secrets.json, Not Found
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Item: oauth2service_json, Value: C:\GAMConfig\oauth2service.json, Not Found
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) admin@domain.com
|
||||
|
||||
Go to the following link in a browser on other computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=...
|
||||
|
||||
Enter verification code: abc...xyz
|
||||
|
||||
Authentication successful.
|
||||
Creating project "GAM Project"...
|
||||
Checking project status...
|
||||
Project: gam-project-abc-def-ghi, Enable 23 APIs
|
||||
API: admin.googleapis.com, Enabled (1/23)
|
||||
API: alertcenter.googleapis.com, Enabled (2/23)
|
||||
API: appsactivity.googleapis.com, Enabled (3/23)
|
||||
API: audit.googleapis.com, Enabled (4/23)
|
||||
API: calendar-json.googleapis.com, Enabled (5/23)
|
||||
API: chat.googleapis.com, Enabled (6/23)
|
||||
API: classroom.googleapis.com, Enabled (7/23)
|
||||
API: contacts.googleapis.com, Enabled (8/23)
|
||||
API: drive.googleapis.com, Enabled (9/23)
|
||||
API: driveactivity.googleapis.com, Enabled (10/23)
|
||||
API: gmail.googleapis.com, Enabled (11/23)
|
||||
API: groupsmigration.googleapis.com, Enabled (12/23)
|
||||
API: groupssettings.googleapis.com, Enabled (13/23)
|
||||
API: iam.googleapis.com, Enabled (14/23)
|
||||
API: iap.googleapis.com, Enabled (15/23)
|
||||
API: licensing.googleapis.com, Enabled (16/23)
|
||||
API: people.googleapis.com, Enabled (17/23)
|
||||
API: pubsub.googleapis.com, Enabled (18/23)
|
||||
API: reseller.googleapis.com, Enabled (19/23)
|
||||
API: sheets.googleapis.com, Enabled (20/23)
|
||||
API: siteverification.googleapis.com, Enabled (21/23)
|
||||
API: storage-api.googleapis.com, Enabled (22/23)
|
||||
API: vault.googleapis.com, Enabled (23/23)
|
||||
Setting GAM project consent screen...
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Enabled
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Generating new private key
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Extracting public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Done generating private key and public certificate
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Service Account Key: SVCACCTKEY, Uploaded
|
||||
Service Account OAuth2 File: C:\GAMConfig\oauth2service.json, Service Account Key: SVCACCTKEY, Updated
|
||||
Project: gam-project-abc-def-ghi, Service Account: gam-project-abc-def-ghi@gam-project-abc-def-ghi.iam.gserviceaccount.com, Has rights to rotate own private key
|
||||
Please go to:
|
||||
|
||||
https://console.cloud.google.com/apis/credentials/oauthclient?project=gam-project-abc-def-ghi
|
||||
|
||||
1. Choose "Desktop App" or "Other" for "Application type".
|
||||
2. Enter "GAM" or another desired value for "Name".
|
||||
3. Click the blue "Create" button.
|
||||
4. Copy your "client ID" value that shows on the next page.
|
||||
|
||||
Enter your Client ID: CLIENTID
|
||||
|
||||
5. Go back to your browser and copy your "client secret" value.
|
||||
Enter your Client Secret: CLIENTSECRET
|
||||
6. Go back to your browser and click OK to close the "OAuth client" popup if it's still open.
|
||||
That's it! Your GAM Project is created and ready to use.
|
||||
|
||||
C:\>
|
||||
```
|
||||
### Enable GAM7 client access
|
||||
|
||||
You select a list of scopes, GAM uses a browser to get final authorization from Google for these scopes and
|
||||
writes the credentials into the file oauth2.txt.
|
||||
|
||||
```
|
||||
C:\>gam oauth create
|
||||
|
||||
[*] 0) Calendar API (supports readonly)
|
||||
[*] 1) Chrome Browser Cloud Management 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)
|
||||
|
||||
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
|
||||
|
||||
Go to the following link in a browser on this computer or on another computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=423565144751-10lsdt2lgnsch9jmdhl35uq4617u1ifp&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2F&scope=...
|
||||
|
||||
If you use a browser on another computer, you will get a browser error that the site can't be reached AFTER you
|
||||
click the Allow button, paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
The authentication flow has completed.
|
||||
Client OAuth2 File: C:\GAMConfig\oauth2.txt, Created
|
||||
|
||||
C:\>
|
||||
```
|
||||
### Enable GAM7 service account access.
|
||||
```
|
||||
C:\>gam user admin@domain.com check serviceaccount
|
||||
System time status
|
||||
Your system time differs from www.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: 0 days PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels FAIL (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels FAIL (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
Some scopes FAILED!
|
||||
To authorize them, please go to:
|
||||
|
||||
https://admin.google.com/ac/owl/domainwide...thuser=admin@domain.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.
|
||||
|
||||
C:\>
|
||||
```
|
||||
The link shown in the error message should take you directly to the authorization screen.
|
||||
If not, make sure that you are logged in as a domain admin, then re-enter the link.
|
||||
|
||||
### Verify GAM7 service account access.
|
||||
|
||||
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
|
||||
for the authorization to complete.
|
||||
```
|
||||
C:\>gam user admin@domain.com check serviceaccount
|
||||
System time status:
|
||||
Your system time differs from www.googleapis.com by less than 1 second PASS
|
||||
Service Account Private Key Authentication:
|
||||
Authentication PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels PASS (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels PASS (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
All scopes PASSED!
|
||||
|
||||
Service Account Client name: SVCACCTID is fully authorized.
|
||||
|
||||
C:\>
|
||||
```
|
||||
### Update gam.cfg with some basic values
|
||||
* `customer_id` - Having this data keeps Gam from having to make extra API calls
|
||||
* `domain` - This allows you to omit the domain portion of email addresses
|
||||
* `timezone local` - Gam will convert all UTC times to your local timezone
|
||||
```
|
||||
C:\>gam info domain
|
||||
Customer ID: C01234567
|
||||
Primary Domain: domain.com
|
||||
Customer Creation Time: 2007-06-06T15:47:55.444Z
|
||||
Primary Domain Verified: True
|
||||
Default Language: en
|
||||
...
|
||||
|
||||
C:\>gam config customer_id C01234567 domain domain.com timezone local save verify
|
||||
Config File: C:\GAMConfig\gam.cfg, Saved
|
||||
Section: DEFAULT
|
||||
...
|
||||
customer_id = C01234567
|
||||
...
|
||||
domain = domain.com
|
||||
...
|
||||
timezone = local
|
||||
...
|
||||
|
||||
C:\>
|
||||
```
|
||||
127
docs/How-to-Uninstall-GAM7.md
Normal file
127
docs/How-to-Uninstall-GAM7.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Uninstalling GAM7
|
||||
|
||||
- [Get Project Info](#get-project-info)
|
||||
- [Remove Client API access](#remove-client-api-access)
|
||||
- [Remove Service Account API access](#remove-service-account-api-access)
|
||||
- [Delete GAM Project](#delete-gam-project)
|
||||
- [Linux and MacOS and Google Cloud Shell](#linux-and-mac-os-and-google-cloud-shell)
|
||||
- [Windows](#windows)
|
||||
|
||||
## Get Project Info
|
||||
```
|
||||
gam version
|
||||
```
|
||||
|
||||
Note the `Config File:` path to `gam.cfg`. In that folder will be a file `oauth2service.json`; look at its contents.
|
||||
You want these two lines:
|
||||
```
|
||||
"client_id": "123691089974044844789"
|
||||
"project_id": "gam-project-123-456-789"
|
||||
```
|
||||
|
||||
## Remove Client API access
|
||||
```
|
||||
gam oauth delete
|
||||
```
|
||||
|
||||
## Remove Service Account API access
|
||||
In a browser, go to `https://admin.google.com`, login and go to the Security/API Controls/Domain-wide Delegation page.
|
||||
Find the `Client ID` that matches the `client_id` value from `oauth2service.json`, hover over it and click `Delete`.
|
||||
|
||||
## Delete GAM Project
|
||||
In a browser, go to `https://console.cloud.google.com/cloud-resource-manager`, login. Find the `ID` that matches
|
||||
the `project_id` value from `oauth2service.json`; click the three dots at the right end of the line and click `Delete`.
|
||||
In the box that pops up, put the `project_id` value in ther `Project ID*` field and click `SHUT DOWN`
|
||||
|
||||
## Linux and MacOS and Google Cloud Shell
|
||||
|
||||
In these examples, the user home folder is shown as /Users/admin; adjust according to your
|
||||
specific situation; e.g., /home/administrator.
|
||||
|
||||
This example assumes that GAM7 has been installed in /Users/admin/bin/gam7.
|
||||
If you've installed GAM7 in another directory, substitute that value in the directions.
|
||||
|
||||
### Delete executable directory
|
||||
|
||||
```
|
||||
rm -fr /Users/admin/bin/gam7
|
||||
```
|
||||
|
||||
### Delete configuration directory
|
||||
|
||||
The default GAM configuration directory is /Users/admin/.gam; for more flexibility you
|
||||
probably want to select a non-hidden location. This example assumes that the GAM
|
||||
configuration directory will be /Users/admin/GAMConfig; If you've chosen another directory,
|
||||
substitute that value in the directions.
|
||||
```
|
||||
rm -fr /Users/admin/GAMConfig
|
||||
```
|
||||
|
||||
### Delete working directory
|
||||
|
||||
This example assumes that the GAM working directory is be /Users/admin/GAMWork; If you've chosen
|
||||
another directory, substitute that value in the directions.
|
||||
```
|
||||
rm -fr /Users/admin/GAMConfig
|
||||
```
|
||||
|
||||
### Remove executable alias and GAM configuration export
|
||||
|
||||
Remove the following line:
|
||||
```
|
||||
alias gam="/Users/admin/bin/gam7/gam"
|
||||
export GAMCFGDIR="/Users/admin/GAMConfig"
|
||||
```
|
||||
from these files based on your shell:
|
||||
```
|
||||
~/.bash_profile
|
||||
~/.bashrc
|
||||
~/.zshrc
|
||||
~/.profile
|
||||
```
|
||||
|
||||
## Windows
|
||||
|
||||
This example assumes that GAM7 has been installed in C:\GAM7; if you've installed
|
||||
GAM7 in another directory, substitute that value in the directions.
|
||||
|
||||
### Delete executable directory
|
||||
|
||||
In File Explorer, delete the `C:\GAM7` folder.
|
||||
|
||||
### Delete configuration directory
|
||||
|
||||
The default GAM configuration directory is C:\Users\<UserName>\.gam; for more flexibility you
|
||||
probably want to select a non user-specific location. This example assumes that the GAM
|
||||
configuration directory will be C:\GAMConfig; If you've chosen another directory,
|
||||
substitute that value in the directions.
|
||||
|
||||
In File Explorer, delete the `C:\GAMConfig` folder.
|
||||
|
||||
### Delete working directory
|
||||
|
||||
This example assumes that the GAM working directory will be C:\GAMWork; If you've chosen
|
||||
another directory, substitute that value in the directions.
|
||||
|
||||
In File Explorer, delete the `C:\GAMWork` folder.
|
||||
|
||||
### Reset system path and GAM configuration directory
|
||||
```
|
||||
Start Control Panel
|
||||
Click System
|
||||
Click Advanced system settings
|
||||
Click Environment Variables...
|
||||
Click Path under System variables
|
||||
Click Edit...
|
||||
If C:\GAM7 is not on the Path, click Cancel and skip the next three steps
|
||||
Click C:\GAM7
|
||||
Click Delete
|
||||
Click OK
|
||||
If GAMCFGDIR is not in System variables, skip the next two steps
|
||||
Click GAMCFGDIR
|
||||
Click Delete
|
||||
Click OK
|
||||
Click OK
|
||||
Exit Control Panel
|
||||
```
|
||||
|
||||
120
docs/How-to-Update-Advanced-GAM-to-GAM7.md
Normal file
120
docs/How-to-Update-Advanced-GAM-to-GAM7.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Installation - Update Advanced GAM to GAM7
|
||||
|
||||
- [Downloads-Installs-GAM7](Downloads-Installs-GAM7)
|
||||
- [Linux and MacOS and Google Cloud Shell](#linux-and-mac-os-and-google-cloud-shell)
|
||||
- [Windows](#windows)
|
||||
|
||||
## Linux and MacOS and Google Cloud Shell
|
||||
|
||||
This example assumes that GAMADV-XTD3 was installed in /Users/admin/bin/gamadv-xtd3.
|
||||
If GAMADV-XTD3 was installed in another directory, substitute that value in the directions.
|
||||
|
||||
Rename install directory.
|
||||
```
|
||||
mv /Users/admin/bin/gamadv-xtd3 /Users/admin/bin/gam7
|
||||
```
|
||||
|
||||
See: [Downloads-Installs-GAM7](Downloads-Installs-GAM7)
|
||||
|
||||
You can download and install the current GAM7 release from the [GitHub Releases](https://github.com/GAM-team/GAM/releases/latest) page. Choose one of the following:
|
||||
|
||||
* Executable Archive, Automatic, Linux/Mac OS/Google Cloud Shell/Raspberry Pi/ChromeOS
|
||||
- Start a terminal session and execute one of the following commands:
|
||||
- Update to latest version, do not create project or authorizations, default path `$HOME/bin`
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -l`
|
||||
- Update to latest version, do not create project or authorizations, specify a path
|
||||
- `bash <(curl -s -S -L https://git.io/gam-install) -l -d <Path>`
|
||||
|
||||
In these examples, the user home folder is shown as /Users/admin; adjust according to your
|
||||
specific situation; e.g., /home/administrator.
|
||||
|
||||
### Update gam alias
|
||||
You should set an alias to point to /Users/admin/bin/gam/gam so you can operate from the /Users/admin/GAMWork directory.
|
||||
Aliases aren't available in scripts, so you may want to set a symlink instead, see below.
|
||||
|
||||
Change the following line:
|
||||
```
|
||||
alias gam="/Users/admin/bin/gamadv-xtd3/gam"
|
||||
```
|
||||
to
|
||||
```
|
||||
alias gam="/Users/admin/bin/gam7/gam"
|
||||
```
|
||||
in one of these files based on your shell:
|
||||
```
|
||||
~/.bash_aliases
|
||||
~/.bash_profile
|
||||
~/.bashrc
|
||||
~/.zshrc
|
||||
~/.profile
|
||||
```
|
||||
|
||||
Issue the following command replacing `<Filename>` with the name of the file you edited:
|
||||
```
|
||||
source <Filename>
|
||||
```
|
||||
|
||||
### Set a symlink if desired
|
||||
Set a symlink in `/usr/local/bin` (or some other location on $PATH) to point to GAM.
|
||||
```
|
||||
ln -s "/Users/admin/bin/gam7/gam" /usr/local/bin/gam
|
||||
```
|
||||
|
||||
### Test
|
||||
```
|
||||
gam version
|
||||
```
|
||||
|
||||
## Windows
|
||||
|
||||
You can download and install the current GAM7 release from the [GitHub Releases](https://github.com/GAM-team/GAM/releases/latest) page.
|
||||
|
||||
This example assumes that GAMADV-XTD3 was installed in C:\GAMADV-XTD3.
|
||||
If GAMADV-XTD3 was installed in another directory, substitute that value in the directions.
|
||||
|
||||
These steps assume Command Prompt, adjust if you're using PowerShell.
|
||||
|
||||
Rename install directory.
|
||||
```
|
||||
ren C:\GAMADV-STD3 C:\GAM7
|
||||
```
|
||||
|
||||
See: [Downloads-Installs-GAM7](Downloads-Installs-GAM7)
|
||||
|
||||
* Executable Archive, Manual, Windows 64 bit
|
||||
- `gam-7.wx.yz-windows-x86_64.zip`
|
||||
- Download the archive, extract the contents into C:\GAM7.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
* Executable Installer, Manual, Windows 64 bit
|
||||
- `gam-7.wx.yz-windows-x86_64.msi`
|
||||
- Download the installer and run it.
|
||||
- Start a Command Prompt/PowerShell session.
|
||||
|
||||
### Update system path
|
||||
You should set the system path to point to C:\GAM7 so you can operate from the C:\GAMWork directory.
|
||||
```
|
||||
Start Control Panel
|
||||
Click System
|
||||
Click Advanced system settings
|
||||
Click Environment Variables...
|
||||
Click Path under System variables
|
||||
Click Edit...
|
||||
If you have an existing entry referencing GAMADV-XTD3:
|
||||
Click that entry
|
||||
Click Delete
|
||||
If C:\GAM7 is already on the Path, skip the next three steps
|
||||
Click New
|
||||
Enter C:\GAM7
|
||||
Click OK
|
||||
Click OK
|
||||
Click OK
|
||||
Exit Control Panel
|
||||
```
|
||||
|
||||
At this point, you should restart Command Prompt so that it has the updated path and environment variables.
|
||||
|
||||
### Test
|
||||
```
|
||||
gam version
|
||||
```
|
||||
581
docs/How-to-Update-GAM7.md
Normal file
581
docs/How-to-Update-GAM7.md
Normal file
@@ -0,0 +1,581 @@
|
||||
# Updating GAM7
|
||||
Use these steps to update your version of GAM7.
|
||||
|
||||
- [Downloads-Installs](Downloads-Installs)
|
||||
- [Linux and MacOS and Google Cloud Shell](#linux-and-mac-os-and-google-cloud-shell)
|
||||
- [Windows](#windows)
|
||||
- [GAM Configuration](gam.cfg)
|
||||
|
||||
## Linux and MacOS and Google Cloud Shell
|
||||
|
||||
### Download the latest version
|
||||
|
||||
This example assumes that GAM7 has been installed in /Users/admin/bin/gam7.
|
||||
If you've installed GAM7 in another directory, substitute that value in the directions when downloading.
|
||||
|
||||
See: [Downloads-Installs](Downloads-Installs)
|
||||
|
||||
In these examples, your Google Super admin is shown as admin@domain.com; replace with the
|
||||
actual email adddress.
|
||||
|
||||
In these examples, the user home folder is shown as /Users/admin; adjust according to your
|
||||
specific situation; e.g., /home/administrator.
|
||||
|
||||
### Update your project with local browser to include the additional APIs that GAM7 uses.
|
||||
This step may be omitted if you are updating from a recent version.
|
||||
```
|
||||
admin@server:/Users/admin/bin/gam7 gam update project
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s): gam-project-abc-123-xyz? admin@domain.com
|
||||
|
||||
Your browser has been opened to visit:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=...
|
||||
|
||||
If your browser is on a different machine then press CTRL+C,
|
||||
set no_browser = true in gam.cfg and re-run this command.
|
||||
|
||||
Authentication successful.
|
||||
API: admin.googleapis.com, already enabled...
|
||||
API: appsactivity.googleapis.com, already enabled...
|
||||
API: calendar-json.googleapis.com, already enabled...
|
||||
API: classroom.googleapis.com, already enabled...
|
||||
API: contacts.googleapis.com, already enabled...
|
||||
API: drive.googleapis.com, already enabled...
|
||||
API: gmail.googleapis.com, already enabled...
|
||||
API: groupssettings.googleapis.com, already enabled...
|
||||
API: licensing.googleapis.com, already enabled...
|
||||
API: plus.googleapis.com, already enabled...
|
||||
API: reseller.googleapis.com, already enabled...
|
||||
API: siteverification.googleapis.com, already enabled...
|
||||
API: vault.googleapis.com, already enabled...
|
||||
Enable 3 APIs
|
||||
API: audit.googleapis.com, Enabled (1/3)
|
||||
API: groupsmigration.googleapis.com, Enabled (2/3)
|
||||
API: sheets.googleapis.com, Enabled (3/3)
|
||||
|
||||
admin@server:/Users/admin/bin/gam7
|
||||
```
|
||||
### Update your project without local browser (Google Cloud Shell for instance) to include the additional APIs that GAM7 uses
|
||||
This step may be omitted if you are updating from a recent version.
|
||||
```
|
||||
admin@server:/Users/admin/bin/gam7 gam config no_browser true save
|
||||
admin@server:/Users/admin/bin/gam7 gam update project
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s): gam-project-abc-123-xyz? admin@domain.com
|
||||
|
||||
Go to the following link in a browser on other computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=...
|
||||
|
||||
Enter verification code: abc...xyz
|
||||
|
||||
Authentication successful.
|
||||
API: admin.googleapis.com, already enabled...
|
||||
API: appsactivity.googleapis.com, already enabled...
|
||||
API: calendar-json.googleapis.com, already enabled...
|
||||
API: classroom.googleapis.com, already enabled...
|
||||
API: contacts.googleapis.com, already enabled...
|
||||
API: drive.googleapis.com, already enabled...
|
||||
API: gmail.googleapis.com, already enabled...
|
||||
API: groupssettings.googleapis.com, already enabled...
|
||||
API: licensing.googleapis.com, already enabled...
|
||||
API: plus.googleapis.com, already enabled...
|
||||
API: reseller.googleapis.com, already enabled...
|
||||
API: siteverification.googleapis.com, already enabled...
|
||||
API: vault.googleapis.com, already enabled...
|
||||
Enable 3 APIs
|
||||
API: audit.googleapis.com, Enabled (1/3)
|
||||
API: groupsmigration.googleapis.com, Enabled (2/3)
|
||||
API: sheets.googleapis.com, Enabled (3/3)
|
||||
|
||||
admin@server:/Users/admin/bin/ga7
|
||||
```
|
||||
### Update GAM7 client access
|
||||
|
||||
You select a list of scopes, GAM7 uses a browser to get final authorization from Google for these scopes and
|
||||
writes the credentials into the file oauth2.txt.
|
||||
|
||||
```
|
||||
admin@server:/Users/admin/bin/gam7 ./gam oauth create
|
||||
|
||||
[*] 0) Calendar API (supports readonly)
|
||||
[*] 1) Chrome Browser Cloud Management 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)
|
||||
|
||||
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
|
||||
|
||||
Go to the following link in a browser on this computer or on another computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=423565144751-10lsdt2lgnsch9jmdhl35uq4617u1ifp&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2F&scope=...
|
||||
|
||||
If you use a browser on another computer, you will get a browser error that the site can't be reached AFTER you
|
||||
click the Allow button, paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
The authentication flow has completed.
|
||||
Client OAuth2 File: /Users/admin/GAMConfig/oauth2.txt, Created
|
||||
|
||||
admin@server:/Users/admin/bin/gam7
|
||||
```
|
||||
### Update GAM7 service account access.
|
||||
```
|
||||
admin@server:/Users/admin/bin/gam7 ./gam user admin@domain.com check serviceaccount
|
||||
$ gam user admin@domain.com check serviceaccount
|
||||
System time status
|
||||
Your system time differs from www.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: 0 days PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels FAIL (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels FAIL (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
Some scopes FAILED!
|
||||
To authorize them, please go to:
|
||||
|
||||
https://admin.google.com/ac/owl/domainwidedelegation?clientScopeToAdd=https://mail.google.com/,https://sites.google.com/feeds,https://www.googleapis.com/auth/apps.alerts,https://www.googleapis.com/auth/calendar,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.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/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/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,https://www.googleapis.com/auth/userinfo.email&clientIdToAdd=SVCACCTID&overwriteClientId=true&dn=domain.com&authuser=admin@domain.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.
|
||||
|
||||
admin@server:/Users/admin/bin/gam7
|
||||
```
|
||||
The link shown in the error message should take you directly to the authorization screen.
|
||||
If not, make sure that you are logged in as a domain admin, then re-enter the link.
|
||||
|
||||
### Verify GAM7 service account access.
|
||||
|
||||
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
|
||||
for the authorization to complete.
|
||||
```
|
||||
admin@server:/Users/admin/bin/gam7 ./gam user admin@domain.com check serviceaccount
|
||||
System time status:
|
||||
Your system time differs from www.googleapis.com by less than 1 second PASS
|
||||
Service Account Private Key Authentication:
|
||||
Authentication PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels PASS (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels PASS (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
All scopes PASSED!
|
||||
|
||||
Service Account Client name: SVCACCTID is fully authorized.
|
||||
|
||||
admin@server:/Users/admin/bin/gam7
|
||||
```
|
||||
|
||||
## Windows
|
||||
|
||||
### Download the latest version
|
||||
|
||||
This example assumes that GAM7 has been installed in C:\GAM7.
|
||||
If you've installed GAM7 in another directory, substitute that value in the directions when downloading.
|
||||
|
||||
See: [Downloads-Installs](Downloads-Installs)
|
||||
|
||||
In these examples, your Google Super admin is shown as admin@domain.com; replace with the
|
||||
actual email adddress.
|
||||
|
||||
This example assumes that GAM7 has been installed in C:\GAM7; if you've installed
|
||||
GAM7 in another directory, substitute that value in the directions.
|
||||
|
||||
These steps assume Command Prompt, adjust if you're using PowerShell.
|
||||
|
||||
### Update your project with local browser to include the additional APIs that GAM7 uses.
|
||||
This step may be omitted if you are updating from a recent version.
|
||||
```
|
||||
C:\GAM7>gam update project
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? admin@domain.com
|
||||
|
||||
Your browser has been opened to visit:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=...
|
||||
|
||||
Authentication successful.
|
||||
API: admin.googleapis.com, already enabled...
|
||||
API: appsactivity.googleapis.com, already enabled...
|
||||
API: calendar-json.googleapis.com, already enabled...
|
||||
API: classroom.googleapis.com, already enabled...
|
||||
API: contacts.googleapis.com, already enabled...
|
||||
API: drive.googleapis.com, already enabled...
|
||||
API: gmail.googleapis.com, already enabled...
|
||||
API: groupssettings.googleapis.com, already enabled...
|
||||
API: licensing.googleapis.com, already enabled...
|
||||
API: plus.googleapis.com, already enabled...
|
||||
API: reseller.googleapis.com, already enabled...
|
||||
API: siteverification.googleapis.com, already enabled...
|
||||
API: vault.googleapis.com, already enabled...
|
||||
Enable 3 APIs
|
||||
API: audit.googleapis.com, Enabled (1/3)
|
||||
API: groupsmigration.googleapis.com, Enabled (2/3)
|
||||
API: sheets.googleapis.com, Enabled (3/3)
|
||||
|
||||
C:\GAM7>
|
||||
```
|
||||
### Update your project without local browser (headless server for instance) to include the additional APIs that GAM7 uses
|
||||
This step may be omitted if you are updating from a recent version.
|
||||
```
|
||||
C:\GAM7>gam config no_browser true save
|
||||
C:\GAM7>gam update project
|
||||
|
||||
Enter your Google Workspace admin or GCP project manager email address authorized to manage project(s) gam-project-abc-123-xyz? admin@domain.com
|
||||
|
||||
Go to the following link in a browser on other computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=...
|
||||
|
||||
Enter verification code: abc...xyz
|
||||
|
||||
Authentication successful.
|
||||
API: admin.googleapis.com, already enabled...
|
||||
API: appsactivity.googleapis.com, already enabled...
|
||||
API: calendar-json.googleapis.com, already enabled...
|
||||
API: classroom.googleapis.com, already enabled...
|
||||
API: contacts.googleapis.com, already enabled...
|
||||
API: drive.googleapis.com, already enabled...
|
||||
API: gmail.googleapis.com, already enabled...
|
||||
API: groupssettings.googleapis.com, already enabled...
|
||||
API: licensing.googleapis.com, already enabled...
|
||||
API: plus.googleapis.com, already enabled...
|
||||
API: reseller.googleapis.com, already enabled...
|
||||
API: siteverification.googleapis.com, already enabled...
|
||||
API: vault.googleapis.com, already enabled...
|
||||
Enable 3 APIs
|
||||
API: audit.googleapis.com, Enabled (1/3)
|
||||
API: groupsmigration.googleapis.com, Enabled (2/3)
|
||||
API: sheets.googleapis.com, Enabled (3/3)
|
||||
|
||||
C:\GAM7>
|
||||
```
|
||||
### Update GAM7 client access
|
||||
|
||||
You select a list of scopes, GAM uses a browser to get final authorization from Google for these scopes and
|
||||
writes the credentials into the file oauth2.txt.
|
||||
|
||||
```
|
||||
C:\GAM7>gam oauth create
|
||||
|
||||
[*] 0) Calendar API (supports readonly)
|
||||
[*] 1) Chrome Browser Cloud Management 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)
|
||||
|
||||
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
|
||||
|
||||
Go to the following link in a browser on this computer or on another computer:
|
||||
|
||||
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=423565144751-10lsdt2lgnsch9jmdhl35uq4617u1ifp&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2F&scope=...
|
||||
|
||||
If you use a browser on another computer, you will get a browser error that the site can't be reached AFTER you
|
||||
click the Allow button, paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
Enter verification code or paste "Unable to connect" URL from other computer (only URL data up to &scope required):
|
||||
|
||||
The authentication flow has completed.
|
||||
Client OAuth2 File: C:\GAMConfig\oauth2.txt, Created
|
||||
|
||||
C:\GAM7>
|
||||
```
|
||||
### Update GAM7 service account access.
|
||||
```
|
||||
C:\GAM7>gam user admin@domain.com check serviceaccount
|
||||
System time status
|
||||
Your system time differs from www.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: 0 days PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels FAIL (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels FAIL (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
Some scopes FAILED!
|
||||
To authorize them, please go to:
|
||||
|
||||
https://admin.google.com/ac/owl/domainwidedelegation?clientScopeToAdd=https://mail.google.com/,https://sites.google.com/feeds,https://www.googleapis.com/auth/apps.alerts,https://www.googleapis.com/auth/calendar,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.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/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/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,https://www.googleapis.com/auth/userinfo.email&clientIdToAdd=SVCACCTID&overwriteClientId=true&dn=domain.com&authuser=admin@domain.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.
|
||||
|
||||
C:\GAM7>
|
||||
```
|
||||
The link shown in the error message should take you directly to the authorization screen.
|
||||
If not, make sure that you are logged in as a domain admin, then re-enter the link.
|
||||
|
||||
### Verify GAM7 service account access.
|
||||
|
||||
Wait a moment and then perform the following command; it it still fails, wait a bit longer, it can sometimes take serveral minutes
|
||||
for the authorization to complete.
|
||||
```
|
||||
C:\GAM7>gam user admin@domain.com check serviceaccount
|
||||
System time status:
|
||||
Your system time differs from www.googleapis.com by less than 1 second PASS
|
||||
Service Account Private Key Authentication:
|
||||
Authentication PASS
|
||||
Domain-wide Delegation authentication:, User: admin@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.rosters PASS (14/34)
|
||||
https://www.googleapis.com/auth/classroom.topics PASS (15/34)
|
||||
https://www.googleapis.com/auth/cloud-identity PASS (16/34)
|
||||
https://www.googleapis.com/auth/cloud-platform PASS (17/34)
|
||||
https://www.googleapis.com/auth/contacts PASS (18/34)
|
||||
https://www.googleapis.com/auth/contacts.other.readonly PASS (19/34)
|
||||
https://www.googleapis.com/auth/datastudio PASS (20/34)
|
||||
https://www.googleapis.com/auth/directory.readonly PASS (21/34)
|
||||
https://www.googleapis.com/auth/documents PASS (22/34)
|
||||
https://www.googleapis.com/auth/drive PASS (23/34)
|
||||
https://www.googleapis.com/auth/drive.activity PASS (24/34)
|
||||
https://www.googleapis.com/auth/drive.admin.labels PASS (25/34)
|
||||
https://www.googleapis.com/auth/drive.labels PASS (26/34)
|
||||
https://www.googleapis.com/auth/gmail.modify PASS (27/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.basic PASS (28/34)
|
||||
https://www.googleapis.com/auth/gmail.settings.sharing PASS (29/34)
|
||||
https://www.googleapis.com/auth/keep PASS (30/34)
|
||||
https://www.googleapis.com/auth/spreadsheets PASS (31/34)
|
||||
https://www.googleapis.com/auth/tasks PASS (32/34)
|
||||
https://www.googleapis.com/auth/userinfo.profile PASS (33/34)
|
||||
https://www.googleapis.com/auth/youtube.readonly PASS (34/34)
|
||||
All scopes PASSED!
|
||||
|
||||
Service Account Client name: SVCACCTID is fully authorized.
|
||||
|
||||
C:\GAM7>
|
||||
```
|
||||
1262
docs/How-to-Upgrade-from-Legacy-GAM.md
Normal file
1262
docs/How-to-Upgrade-from-Legacy-GAM.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
|
||||
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||
admin@server:/Users/admin$ 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 7.00.01 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 7.00.02 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.5 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -923,7 +923,7 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAMADV-XTD3 7.00.01 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 7.00.02 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.5 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
- [Display organizational unit counts](#display-organizational-unit-counts)
|
||||
- [Display indented organizational unit tree](#display-indented-organizational-unit-tree)
|
||||
- [Check organizational unit for contained items](#check-organizational-unit-for-contained-items)
|
||||
- [Delete Empty OUs](#delete-empty-ous)
|
||||
- [Special case handling for large number of organizational units](#special-case-handling-for-large-number-of-organizational-units)
|
||||
|
||||
## API documentation
|
||||
@@ -321,6 +322,17 @@ You can inspect the file and execute it if desired; substitute actual filenames
|
||||
gam redirect stdout CleanOuLog.txt multiproces redirect stderr stdout batch CleanOuBatch.txt
|
||||
```
|
||||
|
||||
### Delete Empty OUs
|
||||
```
|
||||
# Get list of OUs
|
||||
gam redirect csv ./OUs.csv print ous
|
||||
# Check status of each OU
|
||||
gam redirect csv ./CheckOUs.csv multiprocess redirect stderr - multiprocess csv OUs.csv gam check ou "~orgUnitId"
|
||||
# Delete empty OUs
|
||||
gam config csv_input_row_filter "empty:boolean:true" redirect stdout ./DeleteEmptyOUs.txt multiprocess redirect stderr stdout csv CheckOUs.csv gam delete ou "~orgUnitId"
|
||||
```
|
||||
Repeat the steps until no empty OUs remain.
|
||||
|
||||
## Special case handling for large number of organizational units
|
||||
|
||||
By default, the `print orgs` and `show orgtree` commands issue a single API call to get the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Other Resources
|
||||
|
||||
The following are links to contributions of others in support of GAMADV-XTD3.
|
||||
The following are links to contributions of others in support of GAM7.
|
||||
|
||||
Thank you.
|
||||
|
||||
@@ -12,8 +12,8 @@ Thank you.
|
||||
* James Seymour - https://sites.google.com/view/gam--commands/
|
||||
* Kevin Melillo - https://github.com/KevinMelilloIEEE/gam-script
|
||||
* Korey Rideout - https://chatgpt.com/g/g-PTxxnVPMG-gam-assist - A helpful tool to assist with, GAM (+Advance) and GYB commands to assist with syntax for Google Workspace Administrators.
|
||||
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Course on Udemy https://taming.tech/GAMCourse
|
||||
* Paul Ogier (Taming.Tech) - GAMADV-XTD3 Tutorials https://www.youtube.com/watch?v=g9LDeyXQNLI&list=PL_dLiK09pJVhKJxZHNk9CHK0q5hkZ856w
|
||||
* Paul Ogier (Taming.Tech) - GAM7 Course on Udemy https://taming.tech/GAMCourse
|
||||
* Paul Ogier (Taming.Tech) - GAM7 Tutorials https://www.youtube.com/watch?v=g9LDeyXQNLI&list=PL_dLiK09pJVhKJxZHNk9CHK0q5hkZ856w
|
||||
* Paul Ogier (Taming.Tech) - https://taming.tech/taming-gam-a-practical-guide-to-gam-and-gamadv-xtd3/
|
||||
* Steve Larsen - https://docs.google.com/spreadsheets/d/1MzzA-u-cmoQcJnQOovCnZcEKMjvOyFhfkdFdf10X_GI/edit
|
||||
* Workspace Admins YouTube Channel - https://youtube.com/@googleworkspaceadmins
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Rclone
|
||||
|
||||
GAMADV-XTD3 has the capability to upload and download single files between your local computer and Google Drive;
|
||||
GAM7 has the capability to upload and download single files between your local computer and Google Drive;
|
||||
it has no capability for uploading and dowloading folders. For this you can use Rclone: https://rclone.org/
|
||||
|
||||
## Authorization
|
||||
Rclone uses client and service account access to perform its operations; you can use your existing GAMADV-XTD3
|
||||
Rclone uses client and service account access to perform its operations; you can use your existing GAM7
|
||||
authorization for Rclone, you don't need to create a new project or service account within your project.
|
||||
|
||||
You can use your Client ID and Client Secret from `client_secrets.json` and you can use your `oauth2service.json` file with rclone.
|
||||
|
||||
76
docs/Running-GAM7-securely-on-a-Google-Compute-Engine.md
Normal file
76
docs/Running-GAM7-securely-on-a-Google-Compute-Engine.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Running GAM7 securely on a Google Compute Engine
|
||||
- [thanks](#thanks)
|
||||
- [Introduction](#introduction)
|
||||
- [Setup Steps](#setup-steps)
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to Jay Lee for the original version of this document.
|
||||
|
||||
## Introduction
|
||||
GAM7 can run on a Linux or Windows Google Compute Engine (GCE) VM and use the attached service account to access Google Workspace APIs. The advantage of this configuration is that no service account private key is accessible to GAM7 directly and there is no risk of the key being stolen/lost.
|
||||
|
||||
GAM7 version 6.50.00 or higher is required.
|
||||
|
||||
## Setup Steps
|
||||
1. Create a [GCP project](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
|
||||
|
||||
2. Create [a service account](https://cloud.google.com/iam/docs/creating-managing-service-accounts) which will be used by GAM7.
|
||||
* Enter a value in `Service account name`
|
||||
* Enter text in `Service account description`
|
||||
* Click `Create` and `Continue`
|
||||
* Click `Continue` under `Grant this service account access to project`
|
||||
* Click `Done` under `Grant users access to this service account`
|
||||
|
||||
3. Grant the service account rights to generate authentication tokens.
|
||||
* Go to [console.cloud.google.com](https://console.cloud.google.com).
|
||||
* Go to `IAM & Admin` > `Service accounts`
|
||||
* Click on the service account you created (not the default service account).
|
||||
* Copy the email address of your service account to the clipboard.
|
||||
* Click on the `Permissions` tab.
|
||||
* Click `Grant Access`.
|
||||
* In the `New principals` text box, paste the service account email you copied.
|
||||
* Give your service account the `Service Account Token Creator` and `View Service Accounts` roles.
|
||||
* Click `Save`
|
||||
|
||||
4. [Create a Windows or Linux virtual machine](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances).
|
||||
* Scroll down and start at Create a VM and attach the service account
|
||||
* Click `Go to VM instances`
|
||||
* Click `Create Instance`
|
||||
* Enter a value for `Name`
|
||||
* Configure `Manage Tags and Labels`
|
||||
* You can choose a region physically close to you though you may be limited in your choices if you want to use the free tier.
|
||||
* GAM7 can run on the minimal `e2-micro` [free tier VM](https://cloud.google.com/free/docs/free-cloud-features#compute) though performance may suffer. If you are performing batch operations, raising the CPU count will help performance. If you have a very large and busy Workspace instance downloading reports or Drive file lists may require more RAM.
|
||||
* Set `Service account` under `Identity and API access/API and identity management`; choose the service account you created above.
|
||||
* Select `Set access for each API`
|
||||
* Enable `Cloud Platform`
|
||||
* GAM7 does not use a significant amount of storage, unless you have specific storage needs the default disk size should suffice.
|
||||
* Leave other VM instance settings at their defaults unless you know what you are doing.
|
||||
* Click `Create`
|
||||
|
||||
5. Install GAM7 on the VM
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/How-to-Install-GAM7
|
||||
|
||||
6. Logout and log back in to the VM, you should now be able to run GAM7 commands like:
|
||||
```
|
||||
gam version
|
||||
```
|
||||
|
||||
7. Create the special `oauth2service.json` file GAM7 will use:
|
||||
```
|
||||
gam create gcpserviceaccount
|
||||
```
|
||||
If you'd like, take a look at the generated ```oauth2service.json``` file;
|
||||
you'll notice that while the file has some fields similar to a normal service account file, there is no `private_key` attribute containing an RSA private key.
|
||||
|
||||
8. Enable the Google APIs GAM7 will use:
|
||||
```
|
||||
gam enable apis
|
||||
```
|
||||
You are given the option to enable them automatically or manually. Automatic enablement will ask you to authenticate to GAM7. You should authenticate as a user with rights to manage project APIs, probably a project owner. If you are not the project owner you can choose manual enablement and GAM7 will provide two or more URLs which you can send to the project owner. When the owner opens these URLs, they'll be prompted to enable all the APIs GAM7 needs.
|
||||
|
||||
9. Perform admin actions (manage users, groups, orgunits, Chrome devices, etc)
|
||||
* [Configure delegated admin service account (DASA)](https://github.com/taers232c/GAMADV-XTD3/wiki/Using-GAMADV-XTD3-with-a-delegated-admin-service-account); start at step 4.
|
||||
|
||||
10. Manage user data
|
||||
* Run ```gam user user@domain.com check serviceaccount``` and follow the instructions to perform domain-wide delegation.
|
||||
@@ -1,7 +1,7 @@
|
||||
# Scripts
|
||||
|
||||
These scripts can be used to enhance GAM's capabilities; all are supported with Advanced GAM,
|
||||
many are supported with Standard GAM. They require that Python 3 be installed on you computer.
|
||||
many are supported with Legacy GAM. They require that Python 3 be installed on you computer.
|
||||
|
||||
* https://github.com/taers232c/GAM-Scripts3
|
||||
* https://www.python.org/
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
## Configuration
|
||||
|
||||
GAMADV-XTD3 uses a configuration file, gam.cfg, to store the values of the various environment variables
|
||||
GAM7 uses a configuration file, gam.cfg, to store the values of the various environment variables
|
||||
and signal files used by earlier versions of GAM. Configuration files client_secrets.json, oauth2.txt, oauth2service.json and extra_args.txt
|
||||
are moved to a version independent location. This should simplify upgrading GAM versions in the future.
|
||||
Additionally, if you support multiple clients/domains or have multiple users running GAM,
|
||||
@@ -39,7 +39,7 @@ See: [gam.cfg](gam.cfg)
|
||||
|
||||
## Syntax Checking
|
||||
|
||||
GAMADV-XTD3 produces better error messages when syntax errors are found on the command line.
|
||||
GAM7 produces better error messages when syntax errors are found on the command line.
|
||||
|
||||
## API error checking
|
||||
|
||||
@@ -48,14 +48,14 @@ was an operation on multiple items, the items after the failing item are not pro
|
||||
you produce a CSV file containing the items you want to process; as each item is an independent excution, API failures for some items
|
||||
do not affect other items. Capturing meaningful output from the CSV execution is hard and you have to create the CSV file as a separate step.
|
||||
|
||||
In GAMADV-XTD3, every API call is made with error handling; if an API call fails, a message is output and execution continues with additional items if possible.
|
||||
In GAM7, every API call is made with error handling; if an API call fails, a message is output and execution continues with additional items if possible.
|
||||
|
||||
## Batch files
|
||||
|
||||
GAM uses multiprocessing for processing batch files and CSV files; this offers better performance than using threads. Unfortunately, one
|
||||
multiprocess subprocess can not create another subprocess; this prevents using gam csv commands inside GAM batch files.
|
||||
|
||||
GAMADV-XTD3 supports two commands for processing batch files, batch and tbatch. gam batch uses multiprocessing and gam tbatch uses threads.
|
||||
GAM7 supports two commands for processing batch files, batch and tbatch. gam batch uses multiprocessing and gam tbatch uses threads.
|
||||
If you have a batch file that contains gam csv commands, gam tbatch can successfuly process the batch file.
|
||||
|
||||
See: [Bulk Processing](Bulk-Processing)
|
||||
@@ -69,13 +69,13 @@ gam csv File.csv gam <Command> > File.out 2>&1
|
||||
```
|
||||
Multiple processes are writing to File.out(.err) simultaneously resulting in interleaved output that can be hard to read.
|
||||
|
||||
With GAMADV-XTD3, you can capture the output from the multiple processes such that all of the output from each process is contiguous.
|
||||
With GAM7, you can capture the output from the multiple processes such that all of the output from each process is contiguous.
|
||||
```
|
||||
gam redirect stdout ./File.out multiprocess redirect stderr ./File.err multiprocess csv File.csv gam <Command>
|
||||
gam redirect stdout ./File.out multiprocess redirect stderr stderr csv File.csv gam <Command>
|
||||
```
|
||||
|
||||
You can choose to have GAMADV-XTD3 bracket the output from each process with lines that show the command being executed.
|
||||
You can choose to have GAM7 bracket the output from each process with lines that show the command being executed.
|
||||
```
|
||||
gam config show_multiprocess_info true redirect stdout ./File.out multiprocess redirect stderr ./File.err multiprocess csv File.csv gam <Command>
|
||||
gam config show_multiprocess_info true redirect stdout ./File.out multiprocess redirect stderr stderr csv File.csv gam <Command>
|
||||
@@ -85,7 +85,7 @@ See: [Meta Commands and File Redirection](Meta-Commands-and-File-Redirection)
|
||||
|
||||
## Data selection
|
||||
|
||||
GAMADV-XTD3 has many more ways to specify collections of ChromeOS devices, Users and other items.
|
||||
GAM7 has many more ways to specify collections of ChromeOS devices, Users and other items.
|
||||
|
||||
See: [Collections of ChromeOS Devices](Collections-of-ChromeOS-Devices)
|
||||
|
||||
@@ -97,7 +97,7 @@ See: [Collections of Items](Collections-of-Items)
|
||||
|
||||
GAM specifies drive files in different ways based on the command.
|
||||
|
||||
GAMADV-XTD3 has a consistent way of specifying Google Drive files for all commands.
|
||||
GAM7 has a consistent way of specifying Google Drive files for all commands.
|
||||
|
||||
See: [Drive File Selection](Drive-File-Selection)
|
||||
|
||||
@@ -106,17 +106,17 @@ See: [Drive File Selection](Drive-File-Selection)
|
||||
GAM allows no options when you use the todrive option with a gam print command; the file is always uploaded with a fixed name to the root folder of
|
||||
Google Drive for the Google Admin user named in oauth2.txt.
|
||||
|
||||
GAMADV-XTD3 allows you to specify the name, location and user for files uploaded with todrive; you can also save a local copy of the file.
|
||||
GAM7 allows you to specify the name, location and user for files uploaded with todrive; you can also save a local copy of the file.
|
||||
|
||||
See: [Todrive](Todrive)
|
||||
|
||||
## Calendars
|
||||
|
||||
GAM can manage the list of calendars a user can view; GAMADV-XTD3 can also create, modify and remove calendars.
|
||||
GAM can manage the list of calendars a user can view; GAM7 can also create, modify and remove calendars.
|
||||
|
||||
GAM can add and delete events; GAMADV-XTD3 can also update, move, show and print events.
|
||||
GAM can add and delete events; GAM7 can also update, move, show and print events.
|
||||
|
||||
GAM can add, update, delete and show calendar ACLs; GAMADV-XTD3 can also get ACLs for a single calendar and print a CSV file of calendar ACLs.
|
||||
GAM can add, update, delete and show calendar ACLs; GAM7 can also get ACLs for a single calendar and print a CSV file of calendar ACLs.
|
||||
|
||||
See: [Calendars - Access](Calendars-Access), [Calendars - Events](Calendars-Events)
|
||||
|
||||
@@ -130,7 +130,7 @@ See: [Users - Calendars - Transfer](Users-Calendars-Transfer)
|
||||
|
||||
## Contacts
|
||||
|
||||
GAMADV-XTD3 supports domain shared contacts and user contacts.
|
||||
GAM7 supports domain shared contacts and user contacts.
|
||||
|
||||
See: [Domain Shared Contacts](Contacts)
|
||||
|
||||
@@ -138,48 +138,48 @@ See: [Users - People - Contacts & Profiles](Users-People-Contacts-Profiles)
|
||||
|
||||
## Courses
|
||||
|
||||
When updating a course, GAM can only add/delete a single alias; GAMADV-XTD3 can add/delete multiple aliases.
|
||||
When updating a course, GAM can only add/delete a single alias; GAM7 can add/delete multiple aliases.
|
||||
|
||||
When updating a course's membership, GAM can only add/delete a single student/teacher; GAMADV-XTD3 can
|
||||
When updating a course's membership, GAM can only add/delete a single student/teacher; GAM7 can
|
||||
add/delete multiple students/teachers.
|
||||
|
||||
When creating/updating courses, GAMADV-XTD3 can copy settings from another course.
|
||||
When creating/updating courses, GAM7 can copy settings from another course.
|
||||
|
||||
See: [Courses](Courses)
|
||||
|
||||
## Data Studio
|
||||
|
||||
GAMADV-XTD3 supports commands to display Data Studio assets and display/manage Data Studio permissions
|
||||
GAM7 supports commands to display Data Studio assets and display/manage Data Studio permissions
|
||||
|
||||
See: [Users - Data Studio](Users-DataStudio)
|
||||
|
||||
## Drive File Copy and Move
|
||||
|
||||
GAMADV-XTD3 supports advanced file/folder copying/moving
|
||||
GAM7 supports advanced file/folder copying/moving
|
||||
|
||||
See: [Users - Drive - Copy/Move](Users-Drive-Copy-Move)
|
||||
|
||||
## Drive File Orphans
|
||||
|
||||
GAMADV-XTD3 allows collecting a user's orphaned files.
|
||||
GAM7 allows collecting a user's orphaned files.
|
||||
|
||||
See: [Users - Drive - Orphans](Users-Drive-Orphans)
|
||||
|
||||
## Drive File Ownership
|
||||
|
||||
GAMADV-XTD3 allows transferring ownership of selected folders of a source user to a target user.
|
||||
GAM7 allows transferring ownership of selected folders of a source user to a target user.
|
||||
|
||||
GAMADV-XTD3 allows claiming ownership of of selected folders to which the user has access.
|
||||
GAM7 allows claiming ownership of of selected folders to which the user has access.
|
||||
|
||||
See: [Users - Drive - Ownership](Users-Drive-Ownership)
|
||||
|
||||
## Drive File Revisions
|
||||
|
||||
GAMADV-XTD3 can manage drive file revisions.
|
||||
GAM7 can manage drive file revisions.
|
||||
|
||||
## Drive File Transfer
|
||||
|
||||
GAMADV-XTD3 has more capabilites for transferring the Google Drive of a source user to a target user.
|
||||
GAM7 has more capabilites for transferring the Google Drive of a source user to a target user.
|
||||
|
||||
See: [Users - Drive - Transfer](Users-Drive-Transfer)
|
||||
|
||||
@@ -187,63 +187,63 @@ See: [Users - Drive - Revisions](Users-Drive-Revisions)
|
||||
|
||||
## Send email messages
|
||||
|
||||
GAMADV-XTD3 can send email messages.
|
||||
GAM7 can send email messages.
|
||||
|
||||
See: [Send Email](Send-Email)
|
||||
|
||||
## Forms
|
||||
|
||||
GAMADV-XTD3 supports commands to manage and display Google Forms.
|
||||
GAM7 supports commands to manage and display Google Forms.
|
||||
|
||||
See: [Users - Forms](Users-Forms)
|
||||
|
||||
## Gmail
|
||||
|
||||
GAMADV-XTD3 has commands for displaying Gmail messages.
|
||||
GAM7 has commands for displaying Gmail messages.
|
||||
|
||||
GAMADV-XTD3 has commands for forwarding Gmail messages.
|
||||
GAM7 has commands for forwarding Gmail messages.
|
||||
|
||||
See: [Users - Gmail - Messages/Threads](Users-Gmail-Messages-Threads)
|
||||
|
||||
## Groups
|
||||
|
||||
GAMADV-XTD3 allows selecting fields with `info group`. The output is much easier to read.
|
||||
GAM7 allows selecting fields with `info group`. The output is much easier to read.
|
||||
|
||||
When creating/updating groups, GAMADV-XTD3 can copy settings from another group.
|
||||
When creating/updating groups, GAM7 can copy settings from another group.
|
||||
|
||||
See: [Groups](Groups)
|
||||
|
||||
GAMADV-XTD3 has a more powerful `print group-members` command.
|
||||
GAM7 has a more powerful `print group-members` command.
|
||||
|
||||
GAMADV-XTD3 has a more powerful ways of specifying changes to group membership.
|
||||
GAM7 has a more powerful ways of specifying changes to group membership.
|
||||
|
||||
See: [Groups Membership](Groups-Membership)
|
||||
|
||||
GAMADV-XTD3 has commands to display/manage a user's group membership.
|
||||
GAM7 has commands to display/manage a user's group membership.
|
||||
|
||||
See: [Users - Group Membership](Users-Group-Membership)
|
||||
|
||||
## Keep
|
||||
|
||||
GAMADV-XTD3 supports commands to manage and display Google Keep notes.
|
||||
GAM7 supports commands to manage and display Google Keep notes.
|
||||
|
||||
See: [Users - Keep](Users-Keep)
|
||||
|
||||
## Organizational Units
|
||||
|
||||
GAMADV-XTD3 supports updating multiple org units in a single command.
|
||||
GAM7 supports updating multiple org units in a single command.
|
||||
|
||||
See: [Organizational Units](Organizational-Units)
|
||||
|
||||
## Resource Calendars
|
||||
|
||||
GAMADV-XTD3 supports managing resource calendar ACLs.
|
||||
GAM7 supports managing resource calendar ACLs.
|
||||
|
||||
See: [Resource Calendars](Resource-Calendars)
|
||||
|
||||
## Shared Drives
|
||||
|
||||
GAMADV-XTD3 has more powerful commands for managing Shared Drives.
|
||||
GAM7 has more powerful commands for managing Shared Drives.
|
||||
|
||||
See: [Shared Drives](Shared-Drives)
|
||||
|
||||
@@ -251,12 +251,12 @@ See: [Users - Shared Drives](Users-Shared-Drives)
|
||||
|
||||
## Spreadsheets
|
||||
|
||||
GAMADV-XTD3 can manipulate Google Sheets.
|
||||
GAM7 can manipulate Google Sheets.
|
||||
|
||||
See: [Users - Spreadsheets](Users-Spreadsheets)
|
||||
|
||||
## Tasks
|
||||
|
||||
GAMADV-XTD3 supports commands to manage and display Google Tasks.
|
||||
GAM7 supports commands to manage and display Google Tasks.
|
||||
|
||||
See: [Users - Tasks](Users-Tasks)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* https://developers.google.com/calendar/v3/reference/events
|
||||
* https://developers.google.com/calendar/v3/reference/events/import
|
||||
* https://developers.google.com/calendar/api/guides/working-hours-and-location
|
||||
* https://developers.google.com/calendar/api/guides/event-types#birthday
|
||||
|
||||
## Definitions
|
||||
* [`<UserTypeEntity>`](Collections-of-Users)
|
||||
@@ -241,6 +242,7 @@
|
||||
```
|
||||
```
|
||||
<EventType> ::=
|
||||
birthday|
|
||||
default|
|
||||
focustime|
|
||||
fromgmail|
|
||||
@@ -306,6 +308,7 @@
|
||||
(attendee <EmailAddress>)|
|
||||
(attendeestatus [<AttendeeAttendance>] [<AttendeeStatus>] <EmailAddress>)|
|
||||
available|
|
||||
(birthday <Date>)|
|
||||
(color <EventColorName>)|
|
||||
(colorindex|colorid <EventColorIndex>)|
|
||||
(description <String>)|
|
||||
@@ -326,7 +329,7 @@
|
||||
(privateproperty <PropertyKey> <PropertyValue>)|
|
||||
(range <Date> <Date>)|
|
||||
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
|
||||
(reminder <Number> email|popup))|
|
||||
(reminder <Number> email|popup)|
|
||||
(selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)|
|
||||
(sequence <Integer>)|
|
||||
(sharedproperty <PropertyKey> <PropertyValue>)|
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Users - Chat
|
||||
- [API documentation](#api-documentation)
|
||||
- [Introduction](#introduction)
|
||||
- [Developer Preview Admin Access](#developer-preview-admin-access)
|
||||
- [Set up a Chat Bot](#set-up-a-chat-bot)
|
||||
- [Definitions](#definitions)
|
||||
- [Chat Space Permissions](#chat-space-permissions)
|
||||
- [Manage Chat Spaces](#manage-chat-spaces)
|
||||
- [Display Chat Spaces](#display-chat-spaces)
|
||||
- [Manage Chat Members](#manage-chat-members)
|
||||
@@ -20,7 +20,9 @@
|
||||
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/list
|
||||
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.spaceEvents/list
|
||||
* https://support.google.com/chat/answer/7655820
|
||||
* https://support.google.com/a/answer/13369245
|
||||
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces/search
|
||||
* https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces#Space.FIELDS.predefined_permission_settings
|
||||
|
||||
## Introduction
|
||||
These features were added in version 6.60.00.
|
||||
@@ -30,36 +32,11 @@ To use these commands you must update your service account authorization.
|
||||
gam user user@domain.com update serviceaccount
|
||||
|
||||
[*] 4) Chat API - Memberships (supports readonly)
|
||||
[*] 5) Chat API - Memberships Admin (supports readonly)
|
||||
[*] 6) Chat API - Messages (supports readonly)
|
||||
[*] 7) Chat API - Spaces (supports readonly)
|
||||
[*] 9) Chat API - Spaces Delete
|
||||
|
||||
```
|
||||
|
||||
## Developer Preview Admin Access
|
||||
The Chat API Developer Preview allows an admin to perform certain actions
|
||||
on all Chat Spaces. These commands were added in version 6.77.00.
|
||||
|
||||
You must be enrolled in the Developer Preview program for the CHAT API to use these commands.
|
||||
|
||||
```
|
||||
gam <UserItem> delete chatspace asadmin
|
||||
gam <UserItem> update chatspace asadmin
|
||||
gam <UserItem> info chatspace asadmin
|
||||
gam <UserItem> print|show chatspaces asadmin
|
||||
gam <UserItem> create chatmember asadmin
|
||||
gam <UserItem> delete|remove chatmember asadmin
|
||||
gam <UserItem> update|modify chatmember asadmin
|
||||
gam <UserItem> sync chatmembers asadmin
|
||||
gam <UserItem> info chatmember asadmin
|
||||
gam <UserItem> print|show chatmembers|asadmin
|
||||
```
|
||||
To use these commands you must update your service account authorization.
|
||||
```
|
||||
gam user user@domain.com update serviceaccount
|
||||
|
||||
[*] 5) Chat API - Memberships Admin (supports readonly)
|
||||
[*] 8) Chat API - Spaces Admin (supports readonly)
|
||||
[*] 9) Chat API - Spaces Delete
|
||||
[*] 10) Chat API - Spaces Delete Admin
|
||||
```
|
||||
|
||||
@@ -71,15 +48,6 @@ Added `use_chat_admin_access` Boolean variable to `gam.cfg`.
|
||||
* Default: False
|
||||
```
|
||||
|
||||
If your account is not enrolled in the Chat API Developer Preview, you will see errors like this:
|
||||
```
|
||||
$ gam user admin@domain.com show chatspaces asadmin
|
||||
Getting all Chat Spaces that match query (customer = "customers/my_customer" AND spaceType = "SPACE") for admin@domain.com(asadmin)
|
||||
Chat Admin: admin@domain.com(asadmin), Show Failed: Method not found.
|
||||
```
|
||||
|
||||
To enroll in the Developer Preview program, see: https://developers.google.com/workspace/preview
|
||||
|
||||
Google requires that you have a Chat Bot configured in order to use the Chat API; set up a Chat Bot as described in the next section.
|
||||
|
||||
## Set up a Chat Bot
|
||||
@@ -139,6 +107,7 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
lastactivetime|
|
||||
membershipcount|
|
||||
name|
|
||||
permissionsettings|
|
||||
singleuserbotdm|
|
||||
spacedetails|
|
||||
spacehistorystate|
|
||||
@@ -188,11 +157,36 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
|
||||
```
|
||||
|
||||
## Chat Space Permissions
|
||||
### Announcement
|
||||
| Keyword | Description | Allowed | Default |
|
||||
|---------|-------------|---------|---------|
|
||||
| manageapps | Manage apps | managers-immutable | managers |
|
||||
| managemembersandgroups | Manage members and groups | managers/members | managers |
|
||||
| managewebhooks | Manage web hooks | managers-immutable | managers |
|
||||
| modifyspacedetails | Modify space details | managers/members | managers |
|
||||
| postmessages | Post messages | managers-immutable | managers |
|
||||
| replymessages | Reply messages | members/managers | members |
|
||||
| togglehistory | Turn history on and off | managers/members | managers |
|
||||
| useatmentionall | Use @all | managers-immutable | managers |
|
||||
|
||||
### Collaboration
|
||||
| Keyword | Description | Allowed | Default |
|
||||
|---------|-------------|---------|---------|
|
||||
| manageapps | Manage apps | members-immutable | members |
|
||||
| managemembersandgroups | Manage members and groups | managers/members | members |
|
||||
| managewebhooks | Manage web hooks | managers/members | members |
|
||||
| modifyspacedetails | Modify space details | managers/members | members |
|
||||
| postmessages | Post messages | members-immutable | members |
|
||||
| replymessages | Reply messages | members-immutable | members |
|
||||
| togglehistory | Turn history on and off | managers/members | members |
|
||||
| useatmentionall | Use @all | managers/members | members |
|
||||
|
||||
## Manage Chat Spaces
|
||||
### Create a chat space
|
||||
```
|
||||
gam <UserTypeEntity> create chatspace
|
||||
[type <ChatSpaceType>]
|
||||
[type <ChatSpaceType>] [announcement|collaboration]
|
||||
[restricted|(audience <String>)]
|
||||
[externalusersallowed <Boolean>]
|
||||
[members <UserTypeEntity>]
|
||||
@@ -208,6 +202,7 @@ For `type space`, the following apply:
|
||||
* `description <String>` - Optional
|
||||
* `guidelines <String>` - Optional
|
||||
* `history <Boolean>` - Optional
|
||||
* `announcement|collaboration` - Initial permission settings; default is `collaboration`; this is in Developer Preview
|
||||
|
||||
For `type groupchat`, the following apply:
|
||||
* `members <UserTypeEntity>` - Required, must specify between 2 and 20 users
|
||||
@@ -229,8 +224,6 @@ 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
|
||||
|
||||
@@ -242,12 +235,29 @@ gam <UserTypeEntity> update chatspace <ChatSpace>
|
||||
[type space]
|
||||
[description <String>] [guidelines|rules <String>]
|
||||
[history <Boolean>])
|
||||
[managemembersandgroups managers|members]
|
||||
[modifyspacedetails managers|members]
|
||||
[togglehistory managers|members]
|
||||
[useatmentionall managers|members]
|
||||
[manageapps managers|members]
|
||||
[managewebhooks managers|members]
|
||||
[replymessages managers|members]
|
||||
[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.
|
||||
|
||||
You can manage permissions for chat spaces with the following options that are available with Developer Preview.
|
||||
[managemembersandgroups managers|members]
|
||||
[modifyspacedetails managers|members]
|
||||
[togglehistory managers|members]
|
||||
[useatmentionall managers|members]
|
||||
[manageapps managers|members]
|
||||
[managewebhooks managers|members]
|
||||
[postmessages managers|members]
|
||||
[replymessages managers|members]
|
||||
|
||||
|
||||
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.
|
||||
@@ -265,7 +275,6 @@ gam <UserItem> update chatspace asadmin <ChatSpace>
|
||||
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.
|
||||
@@ -398,7 +407,6 @@ 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.
|
||||
|
||||
|
||||
## Manage Chat Members
|
||||
### Add members to a user's chat space
|
||||
```
|
||||
|
||||
@@ -693,7 +693,8 @@ gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
|
||||
[filenamematchpattern <RegularExpression>]
|
||||
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
|
||||
[excludetrashed]
|
||||
[showsize] [showmimetypesize] (addcsvdata <FieldName> <String>)*
|
||||
[showsize] [showmimetypesize] [showlastmodification]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
[summary none|only|plus] [summaryuser <String>]
|
||||
gam <UserTypeEntity> show filecounts
|
||||
[((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>)
|
||||
@@ -707,13 +708,13 @@ gam <UserTypeEntity> show filecounts
|
||||
[filenamematchpattern <RegularExpression>]
|
||||
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
|
||||
[excludetrashed]
|
||||
[showsize] [showmimetypesize]
|
||||
[showsize] [showmimetypesize] [showlastmodification]
|
||||
[summary none|only|plus] [summaryuser <String>]
|
||||
```
|
||||
|
||||
By default, print filecounts displays counts of all files owned by the specified [`<UserTypeEntity>`](Collections-of-Users).
|
||||
|
||||
The option `continueoninvalidquery [<Boolean>] can be used in special cases where a query of the form
|
||||
The option `continueoninvalidquery [<Boolean>] can be used in special cases where a query of the form
|
||||
`query "'labels/mRoha85IbwCRl490E00xGLvBsSbkwIiuZ6PRNNEbwxyz' in labels" causes Google to issue an error
|
||||
saying that the query is invalid when, in fact, it is but the user does not have a license that suppprts drive file labels.
|
||||
When `continueoninvalidquery` is true, GAM prints an error message and proceeds to the next user rather that terminating
|
||||
@@ -721,7 +722,11 @@ as it does now. Of course, if the query really is invalid, you will get the mess
|
||||
|
||||
The `showsize` option displays the total size (in bytes) of the files counted.
|
||||
|
||||
The showmimetypesize' displays the total size (in bytes) of each MIME type counted.
|
||||
The `showmimetypesize` option displays the total size (in bytes) of each MIME type counted.
|
||||
|
||||
The option `showlastmodification` displays the following fields:
|
||||
`lastModifiedFileId,lastModifiedFileName,lastModifyingUser,lastModifiedTime`;
|
||||
these are for the most recently modified file.
|
||||
|
||||
For print filecouts, add additional columns of data from the command line to the output:
|
||||
* `addcsvdata <FieldName> <String>` - Add additional columns of data from the command line to the output
|
||||
|
||||
@@ -208,7 +208,7 @@ If `noduplicate` is specfied, GAM will issue a warning and not perform the creat
|
||||
exists in the parent folder.
|
||||
|
||||
By default, when files are uploaded from local content, they are created with `binary` format, i.e., the data is uploaded
|
||||
without any conversion. Standard GAM had an option `convert` that was passed to the Drive API v2 that it used.
|
||||
without any conversion. Legacy GAM had an option `convert` that was passed to the Drive API v2 that it used.
|
||||
* convert - Whether to convert this file to the corresponding Docs Editors format
|
||||
|
||||
Advanced GAM uses Drive API v3 that doesn't support the `convert` option; it uses the `mimetype` argument to cause conversions.
|
||||
|
||||
@@ -85,6 +85,8 @@ gam <UserTypeEntity> update filerevisions <DriveFileEntity> select <DriveFileRev
|
||||
```
|
||||
When `select <DriveFileRevisionIDEntity>` is omitted, all revisions are updated.
|
||||
|
||||
* `keepforever true` - Keep revision forever, even if it is no longer the head revision
|
||||
* `keepforever false` - Do not keep revision forever
|
||||
* `published true` - Publish these revision to the web
|
||||
* `published false` - Do not publish these revision to the web
|
||||
* `publishauto true` - Automaticaly publish subsequent revisions to the web
|
||||
|
||||
@@ -125,8 +125,15 @@ gam user user@domain.com check serviceaccount
|
||||
(subject <String>)|
|
||||
(suffix <String>)|
|
||||
(userdefinedfield clear|(<String> <String>))|
|
||||
(website clear|(app_install_page|blog|ftp|home|home_page|other|profile|reservations|work|<String> <URL> notprimary|primary))
|
||||
(url|website clear|(app_install_page|blog|ftp|home|home_page|other|profile|reservations|work|<String> <URL> notprimary|primary))
|
||||
|
||||
For address, email, phone and url, the type <String> can be empty.
|
||||
address "" formatted "My Address" primary
|
||||
email "" user@gmail.com primary
|
||||
phone "" "510-555-1212" primary
|
||||
url "" "https://www.domain.com" primary
|
||||
```
|
||||
```
|
||||
<PeopleFieldName> ::=
|
||||
addresses|
|
||||
ageranges|
|
||||
|
||||
@@ -469,8 +469,6 @@ gam csv SheetData.csv quotechar "'" gam user "~User" update sheetrange "~spreads
|
||||
```
|
||||
|
||||
## Repair an uneditable sheet within a spreadsheet
|
||||
This example requires GAMADV-XTD3 version 6.30.07.
|
||||
|
||||
Identify uneditable sheet; there is no `editors` field.
|
||||
```
|
||||
$ gam user owner@domain.com info sheet 1234-y9d0nbckO_cnb3xyZhsIh0Hxd9WaqpGPBwxyz fields sheets sheetsfields protectedranges
|
||||
|
||||
@@ -80,6 +80,22 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
|
||||
* [`<UserTypeEntity>`](Collections-of-Users)
|
||||
* [Command data from Google Docs/Sheets/Storage](Command-Data-From-Google-Docs-Sheets-Storage)
|
||||
```
|
||||
<StorageBucketName> ::= <String>
|
||||
<StorageObjectName> ::= <String>
|
||||
<StorageBucketObjectName> ::=
|
||||
https://storage.cloud.google.com/<StorageBucketName>/<StorageObjectName>|
|
||||
https://storage.googleapis.com/<StorageBucketName>/<StorageObjectName>|
|
||||
gs://<StorageBucketName>/<StorageObjectName>|
|
||||
<StorageBucketName>/<StorageObjectName>
|
||||
|
||||
<UserGoogleDoc> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>)
|
||||
|
||||
<SheetEntity> ::= <String>|id:<Number>
|
||||
<UserGoogleSheet> ::=
|
||||
<EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>|(<SharedDriveEntity> <SharedDriveFileNameEntity>) <SheetEntity>
|
||||
```
|
||||
```
|
||||
<DeliverySetting> ::=
|
||||
allmail|
|
||||
abridged|daily|
|
||||
@@ -734,9 +750,9 @@ When updating a user's name, always update both the `firstname/givenname` and th
|
||||
## Update a user's password
|
||||
When updating a user's password, you can send a message with the new password to an email address; this might be the user's secondary email address.
|
||||
|
||||
In versions of GAMADV-XTD3 prior to 5.07.00, if you do `gam update users <UserTypeEntity>` or `gam <UserTypeEntity> update users` and
|
||||
In versions of GAM7 prior to 5.07.00, if you do `gam update users <UserTypeEntity>` or `gam <UserTypeEntity> update users` and
|
||||
specify `password random`, all of the users in `<UserTypeEntity>` are assigned the same random password;
|
||||
this is the same behavior as in Standard GAM. If you would like each of the users in `<UserTypeEntity>` to be
|
||||
this is the same behavior as in Legacy GAM. If you would like each of the users in `<UserTypeEntity>` to be
|
||||
assigned a unique random password, specify `password uniquerandom`.
|
||||
|
||||
If you update a user with `password random|uniquerandom`, the `lograndompassword <FileName>` option causes GAM
|
||||
|
||||
72
docs/Using-GAM7-with-a-YubiKey.md
Normal file
72
docs/Using-GAM7-with-a-YubiKey.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Using GAM7 with a YubiKey
|
||||
- [Thanks](#thanks)
|
||||
- [Yubikey ykman PIV Commands](https://docs.yubico.com/software/yubikey/tools/ykman/PIV_Commands.html)
|
||||
- [Introduction](#introduction)
|
||||
- [FAQs](#faqs)
|
||||
- [Setup Steps](#setup-steps)
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to Jay Lee for the original version of this document.
|
||||
|
||||
## Introduction
|
||||
GAM7 supports using a [YubiKey](https://www.yubico.com/products/yubikey-5-overview/) to generate and store the service account's private RSA key. Private keys generated by the YubiKey cannot be exported even to the computer running GAM7. When compared to the plain text oauth2service.json file with the private key stored in text, the YubiKey offers a more secure option that prevents digital theft and copying of the private key. Instead of reading the private key from the oauth2service.json file and signing requests itself, GAM7 will simply send signing requests to the YubiKey and get back the signature.
|
||||
|
||||
GAM7 version 6.50.01 or higher is required. Best practice is to always use the [latest version of GAM7](https://github.com/taers232c/GAMADV-XTD3/wiki/How-to-Update-Advanced-GAM).
|
||||
|
||||
## FAQs
|
||||
### Can I use a Google Titan or other brand security key?
|
||||
No, while Titan keys are great as security keys / U2F / 2SV, that is not the protocol being used by GAM7 here. GAM7 uses the PIV app of YubiKeys to work with service accounts. You need to use [a genuine Yubikey.](https://yubico.com/genuine/).
|
||||
|
||||
### Does this protect the admin credentials GAM7 stores in oauth2.txt?
|
||||
No, the admin credentials GAM7 stores in oauth2.txt are not protected by the YubiKey as they are not using RSA private keys. Only the service account credentials normally stored in oauth2service.json are protected. The service account credentials are used for domain-wide delegation operations like managing Workspace user data in Drive, Gmail and Calendar. Note that GAM7 also has the ability to perform admin actions as a delegated admin service account (DASA). See [instructions for setting up DASA](https://github.com/taers232c/GAMADV-XTD3/wiki/Using-GAMADV-XTD3-with-a-delegated-admin-service-account.md). When DASA is setup, GAM7 will use the service account to authenticate which can be protected by the YubiKey.
|
||||
|
||||
### What if someone physically steals the YubiKey?
|
||||
The YubiKey can be configured with a PIN that must be entered in order for it to sign data with the private key. GAM7 stores this PIN string in the oauth2service.json file so it can use it as needed. What this means is that an attacker would need to steal *both* the physical YubiKey and the PIN stored in oauth2service.json. The recommendation is to store oauth2service.json and the rest of the GAM directory on an encrypted partition. The YubiKey itself should also be kept in a secure location.
|
||||
|
||||
### Can I require a physical touch of the YubiKey before the private key can be used?
|
||||
Yes but in practice this does not work very well with GAM7. The YubiKey will need to be touched every time there is a GAM7 command running which for batch or cron jobs may be constant. GAM7 can use a PIN configured on the YubiKey in order to offer an additional layer of protection.
|
||||
|
||||
### If I use a YubiKey, do I need to rotate the private key regularly?
|
||||
No, because the YubiKey generated the private key it cannot be digitally exported from the YubiKey so there is no chance for it to be copied and stolen. Instead you should physically secure the YubiKey from theft.
|
||||
|
||||
### What data does the service account private key have access to?
|
||||
When using domain-wide delegation with GAM7, the service account and anyone possessing the service account private key oauth2service.json file has access to the Gmail, Drive and Calendar data of ALL Workspace users in your domain. For this reason, whether using a YubiKey or not, you should take strong measures to protect the service account private key.
|
||||
|
||||
## Setup Steps
|
||||
1. Upgrade to at least GAM7 6.50.01.
|
||||
2. **If you are using a new YubiKey or don't care about the PIV app data on the YubiKey**
|
||||
1. Tell GAM7 to reset and configure the PIV app data on the YubiKey. This wipes all existing keys and configuration and then configures a private key and PIN for GAM7.
|
||||
* Single YubiKey - `gam yubikey reset_piv`
|
||||
* Multiple YubiKeys - `gam yubikey reset_piv yubikeyserialnumber <Number>`
|
||||
2. During the PIV reset, GAM7 will print out a PIN for the private key, record this key.
|
||||
4. **If you are already using the YubiKey and wish to preserve the PIV app data and keys**
|
||||
1. You need to configure one of the PIV slots for a private key GAM7 can use.
|
||||
* [ykman piv keys generate](https://docs.yubico.com/software/yubikey/tools/ykman/PIV_Commands.html#ykman-piv-keys-options-command-args)
|
||||
`ykman piv keys generate -P <Text> --pin-policy ALWAYS --touch-policy NEVER --algorithm RSA2048 9a new_pubkey.txt`
|
||||
* Use `9a` for the `AUTHENTICATION` slot, `9c` for the `SIGNATURE` slot
|
||||
2. You need to generate a certificate for that slot.
|
||||
* [ykman piv certificates generate](https://docs.yubico.com/software/yubikey/tools/ykman/PIV_Commands.html#ykman-piv-certificates-generate-options-slot-public-key)
|
||||
`ykman piv certificates generate -P <Text> --subject "GAM Service Account" -d 36500 9a new_pubkey.txt`
|
||||
* Use `9a` for the `AUTHENTICATION` slot, `9c` for the `SIGNATURE` slot
|
||||
|
||||
5. Now that you have a private key on your YubiKey, tell GAM7 to use that instead of the private_key stored in oauth2service.json. We can do that by rotating the key:
|
||||
```
|
||||
copy oauth2service.json to oauth2service.save
|
||||
gam create sakey yubikey yubikey_pin yubikey_slot AUTHENTICATION|SIGNATURE
|
||||
```
|
||||
The yubikey argument tells GAM7 to use a private key on a plugged in YubiKey. The yubikey_pin argument tells GAM7 to prompt you to input the PIN that was set in the previous step. The yubikey_slot argument tells GAM7 which PIV slot to use on the YubiKey.
|
||||
|
||||
If there are problems, you can go back to the original oauth2service.json.
|
||||
```
|
||||
copy oauth2service.json to oauth2service.yk
|
||||
copy oauth2service.save to oauth2service.json
|
||||
```
|
||||
|
||||
6. Now you should be able to run GAM7 commands like:
|
||||
```
|
||||
gam user admin@example.com check serviceaccount
|
||||
```
|
||||
and see the YubiKey lights flash as the YubiKey interacts with GAM7 to sign the GAM7 authentication requests. If you look at the oauth2service.json file, you'll see it contains some new fields like yubikey_serial and yubikey_pin but no longer contains the private_key field where GAM7 would normally store the private key data.
|
||||
|
||||
7. As a last step, since YubiKey-stored private keys do not need to be and should not be rotated, you can remove the service account's permissions to change it's own key. Navigate to the [Cloud Console](https://console.cloud.google.com/iam-admin/serviceaccounts) select the correct project and service account and on the Permissions tab, edit and remove the "Service Account Key Admin" permission that the service account has to itself.
|
||||
61
docs/Using-GAM7-with-a-delegated-admin-service-account.md
Normal file
61
docs/Using-GAM7-with-a-delegated-admin-service-account.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Using GAM7 with a delegated admin service account
|
||||
- [Thanks](#thanks)
|
||||
- [Introduction](#introduction)
|
||||
- [Advantages](#advantages)
|
||||
- [Disadvantages](#disadvantages)
|
||||
- [Setup Steps](#setup-steps)
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to Jay Lee for the original version of this document.
|
||||
|
||||
## Introduction
|
||||
Delegated admin service accounts (DASA) are regular [GCP service accounts](https://cloud.google.com/iam/docs/service-accounts#what_are_service_accounts) that are granted a Workspace [delegated admin role](https://support.google.com/a/answer/33325). Service accounts have an email address like `gam-project-xuw-sp1-c4b@gam-project-xuw-sp1-c4b.iam.gserviceaccount.com` and are not part of a Workspace or Cloud Identity domain even if they are owned by a project in the domain’s organization. Service accounts cannot login to Google web services interactively, they are only able to call Google APIs.
|
||||
|
||||
GAM7 version 6.50.00 or higher is required.
|
||||
|
||||
## Advantages
|
||||
* DASA accounts don’t require a Workspace or Cloud Identity license.
|
||||
* DASA accounts don’t have a password login that can be phished or captured, they use [RSA private keys](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) to sign authentication requests which makes them very secure. You should however [rotate the key](https://jaylee.us/qwm) on a regular basis and keep it safe and secured!
|
||||
* When a DASA account makes admin changes, the Admin audit log properly shows that the DASA account made the change. This is not the case when using domain-wide delegation.
|
||||
* DASA accounts are granted [Google admin roles and permissions](https://support.google.com/a/answer/1219251) so that they are only able to perform the actions they are given permissions to perform. This is a simpler model than using both API scopes and admin roles to determine if GAM7 can perform an action.
|
||||
* When using a DASA account, GAM7 does not need to worry about OAuth, scopes, token refresh, consent screens, etc. DASA accounts can [simply generate a JWT token signed by their private key](https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth) and use the JWT as the authorization header on Google API calls. This method is both faster and less complex than regular OAuth.
|
||||
|
||||
## Disadvantages
|
||||
* DASA accounts can only be delegated admins. [If a task requires super admin rights to perform](https://support.google.com/a/answer/2405986#:~:text=Only%20super%20administrators%20can...), DASA accounts won’t be able to do it.
|
||||
Not all Google Admin APIs work with DASA right now. For example, Google Vault API calls will fail with a DASA account.
|
||||
* DASA is a delegated admin and can make Workspace / Cloud Identity admin API calls, it does not replace domain-wide delegation (DwD) when using GAM7 commands that interact with Gmail, Drive and Calendar user data.
|
||||
* GAM7 support for DASA is still experimental and some things may fail. Please report your findings to the [GAM group](https://groups.google.com/g/google-apps-manager).
|
||||
|
||||
## Setup Steps
|
||||
1. Upgrade to at least GAM7 6.50.00. Best practice is to always use the [latest version of GAM7](https://github.com/taers232c/GAMADV-XTD3/wiki/How-to-Update-Advanced-GAM).
|
||||
|
||||
2. Follow the steps in `gam create project` up to the point where you are presented with a URL to the Cloud console to create a Client ID and secret. You don’t need to enter anything those, just press CTRL+C to quit the project creation.
|
||||
|
||||
3. GAM will have created a Google Cloud project for you and a service account. The service account is stored in oauth2service.json. If you look at the contents of this file you’ll see a couple important things:
|
||||
* client_email is the email address of your service account. Copy this address, we’ll use it to grant the service account delegated admin rights in your Workspace domain thus making it a DASA.
|
||||
* private_key is the cryptographic key which is used to sign authorization requests. Google has a copy of the public key and uses it to validate that the API call is being made by the DASA account. Keep oauth2service.json safe and private! It’s the only file needed to use the DASA account!
|
||||
|
||||
4. Now grant the service account delegated permissions. Head to [admin.google.com](https://admin.google.com/) > Account > Admin roles. If you don’t already have a delegated admin role created with the permissions you want the DASA account to have you can [use a system role or create your own](https://support.google.com/a/answer/33325).
|
||||
|
||||
**Pro tip** GAM now has the ability to create an admin role that has all delegate permissions (Super delegate which is not the same as a super admin) as well as an admin role that has all permissions that can be scoped to an OrgUnit (Super OU delegate). With a regular GAM setup, try running:
|
||||
```
|
||||
gam create adminrole "Super Delegate" privileges all
|
||||
```
|
||||
or to create an admin role with all privileges that can be scoped to an OrgUnit:
|
||||
```
|
||||
gam create adminrole "Super OU Delegate" privileges all_ou
|
||||
```
|
||||
|
||||
5. Now assign your service account the delegated admin role. You’ll need the service account email address from step 3. With the role opened in the admin console, click "Assign service accounts" and enter the email address.
|
||||
|
||||
6. Still in the admin console, head to Account > Account settings > Profile and record the Customer ID value. You’ll need this in the next steps.
|
||||
|
||||
7. Now we need to tell GAM which Workspace / Cloud Identity domain to use. Remember, the DASA account in oauth2service.json is not a member of your domain. We can tell GAM7 which domain to use with gam.cfg variables:
|
||||
The following variables in `gam.cfg` must be set when `enable_dasa` is True: `admin_email`, `customer_id` and `domain`,
|
||||
`customer_id` may not be set to `my_customer`.
|
||||
|
||||
|
||||
```
|
||||
gam config enable_dasa true admin_email admin@domain.com customer_id <Customer ID from step 6> domain domain.com save
|
||||
```
|
||||
@@ -3,9 +3,9 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAMADV-XTD3 7.00.01 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.5 64-bit final
|
||||
GAM 7.00.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.12.7 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -15,9 +15,9 @@ 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 7.00.01 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.5 64-bit final
|
||||
GAM 7.00.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.12.7 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -27,9 +27,9 @@ 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 7.00.01 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.5 64-bit final
|
||||
GAM 7.00.11 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.12.7 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
@@ -37,7 +37,7 @@ 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.5
|
||||
filelock 3.12.7
|
||||
google-api-python-client 2.88.0
|
||||
google-auth-httplib2 0.1.0
|
||||
google-auth-oauthlib 1.0.0
|
||||
@@ -55,7 +55,7 @@ Print the current and latest versions of Gam and:
|
||||
```
|
||||
gam version checkrc
|
||||
GAM 5.35.08 - https://github.com/taers232c/GAMADV-XTD3
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.8.1 64-bit final
|
||||
google-api-python-client 2.77.0
|
||||
httplib2 0.16.0
|
||||
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.00.01
|
||||
Latest: 7.00.11
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -72,7 +72,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.00.01
|
||||
7.00.11
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -82,9 +82,9 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.00.01 - https://github.com/taers232c/GAMADV-XTD3
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.5 64-bit final
|
||||
GAM 7.00.11 - https://github.com/taers232c/GAMADV-XTD3
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.12.7 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
|
||||
@@ -2,25 +2,25 @@ Update History
|
||||
* [GAM Updates](GamUpdates)
|
||||
|
||||
Installation
|
||||
* [How to Install Advanced GAM](How-to-Install-Advanced-GAM)
|
||||
* [How to Update Advanced GAM](How-to-Update-Advanced-GAM)
|
||||
* [How to Upgrade from Standard GAM](How-to-Upgrade-from-Standard-GAM)
|
||||
* [How to Upgrade from GAMADV-X or GAMADV-XTD](How-to-Upgrade-from-GAMADV-X-or-GAMADV-XTD)
|
||||
* [How to Install GAM7](How-to-Install-GAM7)
|
||||
* [How to Update Advanced GAM to GAM7](How-to-Update-Advanced-GAM-to-GAM7)
|
||||
* [How to Update GAM7](How-to-Update-GAM7)
|
||||
* [How to Upgrade from Legacy GAM](How-to-Upgrade-from-Legacy-GAM)
|
||||
* [Install GAM as Python Library](Install-GAM-as-Python-Library)
|
||||
* [GAMADV-XTD3 on Chrome OS Devices](GAMADV-XTD3-on-Chrome-OS-Devices)
|
||||
* [GAMADV-XTD3 on Android Devices](GAMADV-XTD3-on-Android-Devices)
|
||||
* [GAM7 on Chrome OS Devices](GAM7-on-Chrome-OS-Devices)
|
||||
* [GAM7 on Android Devices](GAM7-on-Android-Devices)
|
||||
* [Google Network Addresses](Google-Network-Addresses)
|
||||
* [HTTPS Proxy](HTTPS-Proxy)
|
||||
* [SSL Root CA Certificates](SSL-Root-CA-Certificates)
|
||||
* [How to Uninstall Advanced GAM](How-to-Uninstall-Advanced-GAM)
|
||||
* [How to Uninstall GAM7](How-to-Uninstall-GAM7)
|
||||
|
||||
Configuration
|
||||
* [Authorization](Authorization)
|
||||
* [GAM Configuration](gam.cfg)
|
||||
* [Multiple Customers and Domains](https://github.com/taers232c/GAMADV-XTD3/wiki/gam.cfg#multiple-customers-and-domains)
|
||||
* [Running GAMADV-XTD3 securely on a Google Compute Engine](Running-GAMADV-XTD3-securely-on-a-Google-Compute-Engine)
|
||||
* [Using GAMADV-XTD3 with a delegated admin service account](Using-GAMADV-XTD3-with-a-delegated-admin-service-account)
|
||||
* [Using GAMADV-XTD3 with a YubiKey](Using-GAMADV-XTD3-with-a-YubiKey)
|
||||
* [Running GAM7 securely on a Google Compute Engine](Running-GAM7-securely-on-a-Google-Compute-Engine)
|
||||
* [Using GAM7 with a delegated admin service account](Using-GAM7-with-a-delegated-admin-service-account)
|
||||
* [Using GAM7 with a YubiKey](Using-GAM7-with-a-YubiKey)
|
||||
|
||||
Notes and Information
|
||||
* [Upgrade Benefits](Upgrade-Benefits)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
## Introduction
|
||||
GAM uses a configuration file, gam.cfg, to store the values of the various environment variables
|
||||
and signal files used by Basic GAM. Configuration files client_secrets.json, oauth2.txt, oauth2service.json and extra_args.txt
|
||||
and signal files used by Legacy GAM. Configuration files client_secrets.json, oauth2.txt, oauth2service.json and extra_args.txt
|
||||
are moved to a version independent location. This should simplify upgrading GAM versions in the future.
|
||||
Additionally, if you support multiple clients/domains or have multiple users running GAM,
|
||||
gam.cfg lets you easily manage your configuration.
|
||||
@@ -34,7 +34,7 @@ Every once in a while, you edit gam.cfg to set some desired values and then you
|
||||
gam.cfg must be a plain text file, you can edit it with your favorite text editor (emacs, vi, TextWrangler,
|
||||
TextEdit, Notepad, Wordpad) as long as you wind up with a plain text file.
|
||||
|
||||
If you are upgrading from Basic GAM, set the environment variable OLDGAMPATH to OldGamPath. This is a one-time setting
|
||||
If you are upgrading from Legacy GAM, set the environment variable OLDGAMPATH to OldGamPath. This is a one-time setting
|
||||
to allow GAM to find your old signal files and to copy client_secrets.json, oauth2.txt, oauth2service.json, extra_args.txt
|
||||
from OldGamPath to GamConfigDir. To generate the initial gam.cfg, execute the command: gam select default verify.
|
||||
Once gam.cfg is created, no signal files are read and the only environment variable used is GAMCFGDIR.
|
||||
@@ -65,7 +65,7 @@ api_calls_tries_limit
|
||||
Limit the number of tries for Google API calls that return an error
|
||||
that indicates a retry should be performed
|
||||
Default: 10
|
||||
Range: 3-10
|
||||
Range: 3-30
|
||||
auto_batch_min
|
||||
Automatically generate gam batch command if number of users
|
||||
specified in gam users xxx command exceeds this number
|
||||
@@ -944,11 +944,11 @@ domain = goo.com
|
||||
customer_id = my_customer
|
||||
config_dir = goo
|
||||
```
|
||||
### Existing clients that have been accessed with Standard GAM.
|
||||
### Existing clients that have been accessed with Legacy GAM.
|
||||
You have two clients: foo and goo.
|
||||
Make sub-directories foo and goo in the same folder/directory as gam.cfg.
|
||||
For each client, copy the client_secrets.json and oauth2service.json files from their Standard GAM location
|
||||
to the appropriate sub-directory. If the Standard Gam files do not have these names,
|
||||
For each client, copy the client_secrets.json and oauth2service.json files from their Legacy GAM location
|
||||
to the appropriate sub-directory. If the Legacy Gam files do not have these names,
|
||||
rename them after copying them to the sub-directory.
|
||||
|
||||
Perform the following commands for each client (replace xxx with foo and goo).
|
||||
|
||||
@@ -1594,6 +1594,7 @@ gam calendar <CalendarEntity> printacl [todrive <ToDriveAttribute>*]
|
||||
<AttendeeStatus> ::= accepted|declined|needsaction|tentative
|
||||
|
||||
<EventType> ::=
|
||||
birthday|
|
||||
default|
|
||||
focustime|
|
||||
fromgmail|
|
||||
@@ -2047,6 +2048,7 @@ gam setup chat
|
||||
lastactivetime|
|
||||
membershipcount|
|
||||
name|
|
||||
permissionsettings|
|
||||
singleuserbotdm|
|
||||
spacedetails|
|
||||
spacehistorystate|
|
||||
@@ -5847,6 +5849,7 @@ gam <UserTypeEntity> transfer calendars|seccals <UserItem> [<UserCalendarEntity>
|
||||
<AttendeeStatus> ::= accepted|declined|needsaction|tentative
|
||||
|
||||
<EventType> ::=
|
||||
birthday|
|
||||
default|
|
||||
focustime|
|
||||
outofoffice|
|
||||
@@ -5896,13 +5899,15 @@ gam <UserTypeEntity> transfer calendars|seccals <UserItem> [<UserCalendarEntity>
|
||||
<AttendeeStatus> ::= accepted|declined|needsaction|tentative
|
||||
|
||||
<EventAttribute> ::=
|
||||
(allday <Date>)|
|
||||
(anyonecanaddself [<Boolean>])|
|
||||
(attachment <String> <URL>)|
|
||||
(attendee <EmailAddress>)|
|
||||
(attendeestatus [<AttendeeAttendance>] [<AttendeeStatus>] <EmailAddress>)|
|
||||
available|
|
||||
(birthday <Date>)|
|
||||
(color <EventColorName>)|
|
||||
(colorindex|colorid <EventColorIndex>))|
|
||||
(colorindex|colorid <EventColorIndex>)|
|
||||
(description <String>)|
|
||||
(end|endtime (allday <Date>)|<Time>)|
|
||||
(guestscaninviteothers <Boolean>)|
|
||||
@@ -5912,14 +5917,16 @@ gam <UserTypeEntity> transfer calendars|seccals <UserItem> [<UserCalendarEntity>
|
||||
guestscantseeotherguests|
|
||||
hangoutsmeet|
|
||||
<JSONData>|
|
||||
(jsonattendees [charset <Charset>] <String>)|(jsonattendees file <FileName> [charset <Charset>])|
|
||||
(jsonattendees [charset <Charset>] <String>)|
|
||||
(jsonattendees file <FileName> [charset <Charset>])|
|
||||
(location <String>)|
|
||||
(noreminders|(reminder email|popup <Number>))|
|
||||
(optionalattendee <EmailAddress>)|
|
||||
(originalstart|originalstarttime (allday <Date>)|<Time>)|
|
||||
(privateproperty <PropertyKey> <PropertyValue>)|
|
||||
(range <Date> <Date>)|
|
||||
(recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
|
||||
(reminder <Number> email|popup))|
|
||||
(reminder <Number> email|popup)|
|
||||
(selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>)|
|
||||
(sequence <Integer>)|
|
||||
(sharedproperty <PropertyKey> <PropertyValue>)|
|
||||
@@ -5928,6 +5935,7 @@ gam <UserTypeEntity> transfer calendars|seccals <UserItem> [<UserCalendarEntity>
|
||||
(status confirmed|tentative|cancelled)|
|
||||
(summary <String>)|
|
||||
tentative|
|
||||
(timerange <Time> <Time>)|
|
||||
(timezone <TimeZone>)|
|
||||
(transparency opaque|transparent)|
|
||||
(visibility default|public|private)
|
||||
@@ -6086,7 +6094,7 @@ gam <UserTypeEntity> print focustime|outofoffice|workinglocation
|
||||
<String> must contain only lowercase letters, numbers, and hyphens up to 56 characters in length.
|
||||
|
||||
gam <UserTypeEntity> create chatspace
|
||||
[type <ChatSpaceType>]
|
||||
[type <ChatSpaceType>] [announcement|collaboration]
|
||||
[restricted|(audience <String>)]
|
||||
[externalusersrallowed <Boolean>]
|
||||
[members <UserTypeEntity>]
|
||||
@@ -6101,6 +6109,13 @@ gam <UserTypeEntity> update chatspace <ChatSpace>
|
||||
[type space]
|
||||
[description <String>] [guidelines|rules <String>]
|
||||
[history <Boolean>])
|
||||
[managemembersandgroups managers|members]
|
||||
[modifyspacedetails managers|members]
|
||||
[togglehistory managers|members]
|
||||
[useatmentionall managers|members]
|
||||
[manageapps managers|members]
|
||||
[managewebhooks managers|members]
|
||||
[replymessages managers|members]
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> delete chatspace <ChatSpace>
|
||||
|
||||
@@ -7043,7 +7058,8 @@ gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
|
||||
[filenamematchpattern <RegularExpression>]
|
||||
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
|
||||
[excludetrashed]
|
||||
[showsize] [showmimetypesize] (addcsvdata <FieldName> <String>)*
|
||||
[showsize] [showmimetypesize] [showlastmodification]
|
||||
(addcsvdata <FieldName> <String>)*
|
||||
[summary none|only|plus] [summaryuser <String>]
|
||||
gam <UserTypeEntity> show filecounts
|
||||
[((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>)
|
||||
@@ -7057,7 +7073,7 @@ gam <UserTypeEntity> show filecounts
|
||||
[filenamematchpattern <RegularExpression>]
|
||||
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
|
||||
[excludetrashed]
|
||||
[showsize] [showmimetypesize]
|
||||
[showsize] [showmimetypesize] [showlastmodification]
|
||||
[summary none|only|plus] [summaryuser <String>]
|
||||
|
||||
gam <UserTypeEntity> print filesharecounts [todrive <ToDriveAttribute>*]
|
||||
@@ -7886,7 +7902,7 @@ gam <UserItem> print meettranscripts <MeetConferenceName> [todrive <ToDriveAttri
|
||||
(subject <String>)|
|
||||
(suffix <String>)|
|
||||
(userdefinedfield clear|(<String> <String>))|
|
||||
(website clear|(app_install_page|blog|ftp|home|home_page|other|profile|reservations|work|<String> <URL> notprimary|primary))
|
||||
(url|website clear|(app_install_page|blog|ftp|home|home_page|other|profile|reservations|work|<String> <URL> notprimary|primary))
|
||||
|
||||
<PeopleUserContactSelection> ::=
|
||||
[(selectcontactgroup <PeopleContactGroupItem>)|
|
||||
|
||||
@@ -1,9 +1,81 @@
|
||||
7.00.11
|
||||
|
||||
Updated to Python 3.12.7 where possible.
|
||||
|
||||
7.00.10
|
||||
|
||||
Handled the following error that occurs when `gam create user` is immediateley followed by `gam update user`.
|
||||
```
|
||||
ERROR: 412: conditionNotMet - User creation is not complete.
|
||||
```
|
||||
|
||||
Updated support for `Folders with limited access`; this is a work in progress.
|
||||
|
||||
7.00.09
|
||||
|
||||
Added initial support for `Folders with limited access`; you must be enrolled in the Beta preview.
|
||||
|
||||
Updated `api_call_tries_limit` variable to `gam.cfg` that limits the number of tries
|
||||
for Google API calls that return an error that indicates a retry should be performed.
|
||||
The default value is 10 and the range of allowable values is 3-30.
|
||||
|
||||
7.00.08
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> delete groups` that caused the command to fail when `enable_dasa = true` in `gam.cfg`.
|
||||
|
||||
7.00.07
|
||||
|
||||
Updated `<PeopleContactAttribute>` fields `address,email,phone,url` to allow an empty type field.
|
||||
```
|
||||
address "" formatted "My Address" primary
|
||||
email "" user@gmail.com primary
|
||||
phone "" "510-555-1212" primary
|
||||
url "" "https://www.domain.com" primary
|
||||
```
|
||||
|
||||
7.00.06
|
||||
|
||||
Updated `gam <UserTypeEntity> create|update chatspace` to support the new permissions settings
|
||||
for Chat spaces that are in Developer Preview.
|
||||
|
||||
* See: https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces#Space.FIELDS.predefined_permission_settings
|
||||
|
||||
7.00.05
|
||||
|
||||
Fixed bug that caused an error when creating a calendar birthday event.
|
||||
|
||||
7.00.04
|
||||
|
||||
Improved performance of `gam report users orgunit <OrgUnitPath>` when `showorgunit` is not specified.
|
||||
|
||||
Added option `birthday <Date>` to `gam <UserTypeEntity> create event <UserCalendarEntity>` that adds
|
||||
an annual recurring event to the calendar.
|
||||
|
||||
Added `birthday` to `<EventType>` for use in various calendar event commands.
|
||||
|
||||
7.00.03
|
||||
|
||||
Updated `gam delete ou` and `gam print admins` to handle the following error:
|
||||
```
|
||||
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
|
||||
```
|
||||
|
||||
7.00.02
|
||||
|
||||
Added option `showlastmodification` to `gam <UserTypeEntity> print|show filecounts` that adds
|
||||
the following fields to the output: `lastModifiedFileId,lastModifiedFileName,lastModifyingUser,lastModifiedTime`;
|
||||
these are for the most recently modified file.
|
||||
|
||||
Added option `keepforever [<Boolean>]` to `gam <UserTypeEntity> update filerevisions` that allows setting
|
||||
`Keep forever` in revisions.
|
||||
|
||||
Upgraded to Python 3.12.6 where possible.
|
||||
|
||||
7.00.01
|
||||
|
||||
Added option `shownames` to `gam <UserTypeEntity> print|show sheet` that causes GAM
|
||||
to make an additional API call to get and display the sheet file name that is not supplied by the Sheets API.
|
||||
|
||||
|
||||
7.00.00
|
||||
|
||||
Merged GAM-Team version
|
||||
|
||||
4880
src/chat-v1.json
4880
src/chat-v1.json
File diff suppressed because it is too large
Load Diff
5057
src/drive-v3beta.json
Normal file
5057
src/drive-v3beta.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ EOF
|
||||
}
|
||||
|
||||
target_dir="$HOME/bin"
|
||||
target_gam="gam/gam"
|
||||
target_gam="gam7/gam"
|
||||
gamarch=$(uname -m)
|
||||
gamos=$(uname -s)
|
||||
osversion=""
|
||||
@@ -141,25 +141,28 @@ case $gamos in
|
||||
;;
|
||||
[Mm]ac[Oo][sS]|[Dd]arwin)
|
||||
gamos="macos"
|
||||
fullversion=$(sw_vers -productVersion)
|
||||
osversion=${fullversion:0:2}
|
||||
case $gamarch in
|
||||
x86_64)
|
||||
fullversion=$(sw_vers -productVersion)
|
||||
osversion=${fullversion:0:2}
|
||||
case ${osversion:0:2} in
|
||||
11|12|13|14)
|
||||
gamfile="macos-x86_64.tar.xz";;
|
||||
*)
|
||||
echo_red "Sorry, this version ($fullversion) of MacOS is not supported. Exiting."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
gamfile="macos-x86_64.tar.xz"
|
||||
minimum_version=13
|
||||
;;
|
||||
arm|arm64|aarch64)
|
||||
gamfile="macos-aarch64.tar.xz";;
|
||||
gamfile="macos-aarch64.tar.xz"
|
||||
minimum_version=14
|
||||
;;
|
||||
*)
|
||||
echo_red "ERROR: this installer currently only supports x86_64 and arm64 MacOS. Looks like you're running on $gamarch. Exiting."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
if [[ "$osversion" -ge "$minimum_version" ]]; then
|
||||
echo_green "You are running MacOS ${fullversion}, good. Using GAM with ${gamfile}."
|
||||
else
|
||||
echo_red "Sorry, you are running MacOS ${fullversion} but GAM on ${gamarch} requires MacOS ${minimum_version}. Exiting."
|
||||
exit
|
||||
fi
|
||||
;;
|
||||
MINGW64_NT*)
|
||||
gamos="windows"
|
||||
|
||||
84
src/gam.spec
84
src/gam.spec
@@ -12,16 +12,16 @@ for pkg in GAM_VER_LIBS:
|
||||
datas += copy_metadata(pkg, recursive=True)
|
||||
datas += [('admin-directory_v1.1beta1.json', '.')]
|
||||
datas += [('cbcm-v1.1beta1.json', '.')]
|
||||
datas += [('chat-v1.json', '.')]
|
||||
datas += [('contactdelegation-v1.json', '.')]
|
||||
datas += [('datastudio-v1.json', '.')]
|
||||
datas += [('drive-v3beta.json', '.')]
|
||||
datas += [('serviceaccountlookup-v1.json', '.')]
|
||||
datas += [('cacerts.pem', '.')]
|
||||
hiddenimports = [
|
||||
'gam.gamlib.yubikey',
|
||||
]
|
||||
|
||||
print(f"datas before analysis:\n{datas}")
|
||||
runtime_hooks = []
|
||||
a = Analysis(
|
||||
['gam/__main__.py'],
|
||||
pathex=[],
|
||||
@@ -30,30 +30,35 @@ a = Analysis(
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
runtime_hooks=runtime_hooks,
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=None,
|
||||
noarchive=False,
|
||||
)
|
||||
print(f"datas from analysis:\n{a.datas}")
|
||||
#print(f"datas from analysis:\n{a.datas}")
|
||||
for d in a.datas:
|
||||
if 'pyconfig' in d[0]:
|
||||
a.datas.remove(d)
|
||||
break
|
||||
print(f"datas after pyconfig cleanup:\n{a.datas}")
|
||||
#print(f"datas after pyconfig cleanup:\n{a.datas}")
|
||||
pyz = PYZ(a.pure,
|
||||
a.zipped_data,
|
||||
cipher=None)
|
||||
# requires Python 3.10+ but no one should be compiling
|
||||
# GAM with older versions anyway
|
||||
target_arch = None
|
||||
codesign_identity = None
|
||||
entitlements_file = None
|
||||
match platform:
|
||||
case "darwin":
|
||||
if getenv('arch') == 'universal2':
|
||||
target_arch = "universal2"
|
||||
else:
|
||||
target_arch = None
|
||||
|
||||
codesign_identity = getenv('codesign_identity')
|
||||
if codesign_identity:
|
||||
entitlements_file = '../.github/actions/entitlements.plist'
|
||||
strip = True
|
||||
case "win32":
|
||||
target_arch = None
|
||||
@@ -68,9 +73,38 @@ upx = False
|
||||
console = True
|
||||
disable_windowed_traceback = False
|
||||
argv_emulation = False
|
||||
codesign_identity = None
|
||||
entitlements_file = None
|
||||
if not getenv('PYINSTALLER_BUILD_ONEDIR') == 'yes':
|
||||
if getenv('PYINSTALLER_BUILD_ONEDIR') == 'yes':
|
||||
# Build one directory
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name=name,
|
||||
debug=debug,
|
||||
bootloader_ignore_signals=bootloader_ignore_signals,
|
||||
strip=strip,
|
||||
upx=upx,
|
||||
console=console,
|
||||
# put most everyting under a lib/ subfolder
|
||||
contents_directory='lib',
|
||||
disable_windowed_traceback=disable_windowed_traceback,
|
||||
argv_emulation=argv_emulation,
|
||||
target_arch=target_arch,
|
||||
codesign_identity=codesign_identity,
|
||||
entitlements_file=entitlements_file,
|
||||
)
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=strip,
|
||||
upx=upx,
|
||||
upx_exclude=[],
|
||||
name=name,
|
||||
)
|
||||
else:
|
||||
# Build one file
|
||||
exe = EXE(
|
||||
pyz,
|
||||
@@ -91,32 +125,4 @@ if not getenv('PYINSTALLER_BUILD_ONEDIR') == 'yes':
|
||||
codesign_identity=codesign_identity,
|
||||
entitlements_file=entitlements_file,
|
||||
)
|
||||
else:
|
||||
# Build one folder
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name=name,
|
||||
debug=debug,
|
||||
bootloader_ignore_signals=bootloader_ignore_signals,
|
||||
strip=strip,
|
||||
upx=upx,
|
||||
console=console,
|
||||
disable_windowed_traceback=disable_windowed_traceback,
|
||||
argv_emulation=argv_emulation,
|
||||
target_arch=target_arch,
|
||||
codesign_identity=codesign_identity,
|
||||
entitlements_file=entitlements_file,
|
||||
)
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=strip,
|
||||
upx=upx,
|
||||
upx_exclude=[],
|
||||
name=name,
|
||||
)
|
||||
|
||||
|
||||
10
src/gam.wxs
10
src/gam.wxs
@@ -32,8 +32,11 @@
|
||||
<SetDirectory Id="WINDOWSVOLUME" Value="[WindowsVolume]"/>
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="WINDOWSVOLUME">
|
||||
<Directory Id="INSTALLFOLDER" Name="GAM7" />
|
||||
</Directory>
|
||||
<Directory Id="INSTALLFOLDER" Name="GAM7">
|
||||
<Directory Id="lib" Name="lib">
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Fragment>
|
||||
|
||||
@@ -42,7 +45,7 @@
|
||||
<ComponentGroup
|
||||
Id="ProductComponents"
|
||||
Directory="INSTALLFOLDER"
|
||||
Source="dist/gam">
|
||||
Source="dist/gam/gam7">
|
||||
<Component Id="gam_exe" Guid="d046ea24-c9f8-40ca-84db-70b0119933ff">
|
||||
<File Name="gam.exe" KeyPath="yes" />
|
||||
<Environment Id="PATH" Name="PATH" Value="[INSTALLFOLDER]" Permanent="yes" Part="last" Action="set" System="yes" />
|
||||
@@ -62,6 +65,7 @@
|
||||
<Component Id="cacerts_pem" Guid="61fe2b2d-1646-4bed-b844-193965e97727">
|
||||
<File Name="cacerts.pem" KeyPath="yes" />
|
||||
</Component>
|
||||
<ComponentGroupRef Id="Lib" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GAM
|
||||
# GAM7
|
||||
#
|
||||
# Copyright 2024, All Rights Reserved.
|
||||
#
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.00.01'
|
||||
__version__ = '7.00.11'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -4662,12 +4662,16 @@ def clearServiceCache(service):
|
||||
|
||||
DISCOVERY_URIS = [googleapiclient.discovery.V1_DISCOVERY_URI, googleapiclient.discovery.V2_DISCOVERY_URI]
|
||||
|
||||
# Used for API.CLOUDRESOURCEMANAGER, API.SERVICEUSAGE, API.IAM, API.IAP
|
||||
def getAPIService(api, httpObj):
|
||||
api, version, v2discovery = API.getVersion(api)
|
||||
return googleapiclient.discovery.build(api, version, http=httpObj, cache_discovery=False,
|
||||
discoveryServiceUrl=DISCOVERY_URIS[v2discovery], static_discovery=False)
|
||||
|
||||
def getService(api, httpObj):
|
||||
### Drive v3beta
|
||||
if api == API.DRIVE3 and GC.Values[GC.DRIVE_V3_BETA]:
|
||||
api = API.DRIVE3B
|
||||
hasLocalJSON = API.hasLocalJSON(api)
|
||||
api, version, v2discovery = API.getVersion(api)
|
||||
if api in GM.Globals[GM.CURRENT_API_SERVICES] and version in GM.Globals[GM.CURRENT_API_SERVICES][api]:
|
||||
@@ -4728,6 +4732,8 @@ def defaultSvcAcctScopes():
|
||||
saScopes[API.DRIVE2] = saScopes[API.DRIVE3]
|
||||
saScopes[API.DRIVETD] = saScopes[API.DRIVE3]
|
||||
saScopes[API.SHEETSTD] = saScopes[API.SHEETS]
|
||||
### Drive v3beta
|
||||
saScopes[API.DRIVE3B] = saScopes[API.DRIVE3]
|
||||
return saScopes
|
||||
|
||||
def _getSvcAcctData():
|
||||
@@ -9190,6 +9196,7 @@ MACOS_CODENAMES = {
|
||||
12: 'Monterey',
|
||||
13: 'Ventura',
|
||||
14: 'Sonoma',
|
||||
15: 'Sequoia',
|
||||
}
|
||||
|
||||
def getOSPlatform():
|
||||
@@ -9231,7 +9238,7 @@ def doCheckConnection():
|
||||
api_hosts.append(host)
|
||||
hosts.extend(sorted(api_hosts))
|
||||
host_count = len(hosts)
|
||||
httpObj = getHttpObj(timeout=10)
|
||||
httpObj = getHttpObj(timeout=30)
|
||||
httpObj.follow_redirects = False
|
||||
headers = {'user-agent': GAM_USER_AGENT}
|
||||
okay = createGreenText('OK')
|
||||
@@ -12438,7 +12445,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
|
||||
def waitForCompletion(i):
|
||||
sleep_time = i*5
|
||||
if i > 3:
|
||||
sys.stdout.write(Msg.WAITING_FOR_SERVICE_ACCOUNT_CREATION_TO_COMPLETE_SLEEPING.format(sleep_time))
|
||||
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
|
||||
time.sleep(sleep_time)
|
||||
|
||||
local_key_size = 2048
|
||||
@@ -13803,7 +13810,8 @@ def doReport():
|
||||
Ent.SetGetting(Ent.REPORT)
|
||||
elif userKey == 'all':
|
||||
if orgUnitId:
|
||||
userOrgUnits = getUserOrgUnits(cd, orgUnit, orgUnitId)
|
||||
if showOrgUnit:
|
||||
userOrgUnits = getUserOrgUnits(cd, orgUnit, orgUnitId)
|
||||
forWhom = f'users in orgUnit {orgUnit}'
|
||||
else:
|
||||
forWhom = 'all users'
|
||||
@@ -13989,7 +13997,8 @@ def doReport():
|
||||
orgUnitId = None
|
||||
elif userKey == 'all':
|
||||
if orgUnitId:
|
||||
userOrgUnits = getUserOrgUnits(cd, orgUnit, orgUnitId)
|
||||
if showOrgUnit:
|
||||
userOrgUnits = getUserOrgUnits(cd, orgUnit, orgUnitId)
|
||||
printGettingEntityItemForWhom(Ent.REPORT, f'users in orgUnit {orgUnit}')
|
||||
else:
|
||||
printGettingEntityItemForWhom(Ent.REPORT, 'all users')
|
||||
@@ -16623,13 +16632,15 @@ def doPrintShowAdmins():
|
||||
try:
|
||||
admins = callGAPIpages(cd.roleAssignments(), 'list', 'items',
|
||||
pageMessage=getPageMessage(),
|
||||
throwReasons=[GAPI.INVALID, GAPI.USER_NOT_FOUND, GAPI.BAD_REQUEST,
|
||||
GAPI.CUSTOMER_NOT_FOUND, GAPI.FORBIDDEN],
|
||||
throwReasons=[GAPI.INVALID, GAPI.USER_NOT_FOUND,
|
||||
GAPI.FORBIDDEN, GAPI.SERVICE_NOT_AVAILABLE,
|
||||
GAPI.BAD_REQUEST, GAPI.CUSTOMER_NOT_FOUND],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
customer=GC.Values[GC.CUSTOMER_ID], fields=fields, **kwargs)
|
||||
except (GAPI.invalid, GAPI.userNotFound):
|
||||
entityUnknownWarning(Ent.ADMINISTRATOR, userKey)
|
||||
return
|
||||
except GAPI.forbidden as e:
|
||||
except (GAPI.forbidden, GAPI.serviceNotAvailable) as e:
|
||||
entityActionFailedExit([Ent.ADMINISTRATOR, userKey, Ent.ADMIN_ROLE, roleId], str(e))
|
||||
except (GAPI.badRequest, GAPI.customerNotFound):
|
||||
accessErrorExit(cd)
|
||||
@@ -17334,14 +17345,17 @@ def _doDeleteOrgs(entityList):
|
||||
try:
|
||||
orgUnitPath = makeOrgUnitPathAbsolute(orgUnitPath)
|
||||
callGAPI(cd.orgunits(), 'delete',
|
||||
throwReasons=[GAPI.CONDITION_NOT_MET, GAPI.INVALID_ORGUNIT, GAPI.ORGUNIT_NOT_FOUND, GAPI.BACKEND_ERROR, GAPI.BAD_REQUEST, GAPI.INVALID_CUSTOMER_ID, GAPI.LOGIN_REQUIRED],
|
||||
throwReasons=[GAPI.CONDITION_NOT_MET, GAPI.INVALID_ORGUNIT, GAPI.ORGUNIT_NOT_FOUND, GAPI.BACKEND_ERROR,
|
||||
GAPI.INVALID_CUSTOMER_ID, GAPI.SERVICE_NOT_AVAILABLE,
|
||||
GAPI.BAD_REQUEST, GAPI.LOGIN_REQUIRED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
customerId=GC.Values[GC.CUSTOMER_ID], orgUnitPath=encodeOrgUnitPath(makeOrgUnitPathRelative(orgUnitPath)))
|
||||
entityActionPerformed([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], i, count)
|
||||
except GAPI.conditionNotMet:
|
||||
entityActionFailedWarning([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], Msg.HAS_CHILD_ORGS.format(Ent.Plural(Ent.ORGANIZATIONAL_UNIT)), i, count)
|
||||
except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.backendError):
|
||||
entityActionFailedWarning([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], Msg.DOES_NOT_EXIST, i, count)
|
||||
except GAPI.invalidCustomerId as e:
|
||||
except (GAPI.invalidCustomerId, GAPI.serviceNotAvailable) as e:
|
||||
### Check for my_customer
|
||||
entityActionFailedWarning([Ent.ORGANIZATIONAL_UNIT, orgUnitPath, Ent.CUSTOMER_ID, GC.Values[GC.CUSTOMER_ID]], str(e), i, count)
|
||||
except (GAPI.badRequest, GAPI.loginRequired):
|
||||
@@ -20702,6 +20716,9 @@ class PeopleManager():
|
||||
}
|
||||
}
|
||||
|
||||
# Fields that allow an empty type
|
||||
EMPTY_TYPE_ALLOWED_FIELDS = {PEOPLE_ADDRESSES, PEOPLE_EMAIL_ADDRESSES, PEOPLE_PHONE_NUMBERS, PEOPLE_URLS}
|
||||
|
||||
# Fields with just a URL
|
||||
# URL_FIELDS = {
|
||||
# PEOPLE_COVER_PHOTOS,
|
||||
@@ -20745,14 +20762,14 @@ class PeopleManager():
|
||||
person[fieldName].append({})
|
||||
return person[fieldName][0]
|
||||
|
||||
def InitArrayFieldEntry(choices):
|
||||
def InitArrayFieldEntry(choices, typeMinLen=1):
|
||||
entry = {'metadata': {'primary': False}}
|
||||
if choices is not None:
|
||||
ftype = getChoice(choices, mapChoice=True, defaultChoice=None)
|
||||
if ftype:
|
||||
entry['type'] = ftype
|
||||
else:
|
||||
entry['type'] = getString(Cmd.OB_STRING)
|
||||
entry['type'] = getString(Cmd.OB_STRING, minLen=typeMinLen)
|
||||
return entry
|
||||
|
||||
def GetMultiFieldEntry(fieldName):
|
||||
@@ -20803,7 +20820,7 @@ class PeopleManager():
|
||||
if fieldName == PEOPLE_ADDRESSES:
|
||||
if CheckClearPersonField(fieldName):
|
||||
continue
|
||||
entry = InitArrayFieldEntry(PeopleManager.TYPE_VALUE_PNP_FIELDS[fieldName])
|
||||
entry = InitArrayFieldEntry(PeopleManager.TYPE_VALUE_PNP_FIELDS[fieldName], typeMinLen=0)
|
||||
while Cmd.ArgumentsRemaining():
|
||||
argument = getArgument()
|
||||
if argument in PeopleManager.ADDRESS_ARGUMENT_TO_FIELD_MAP:
|
||||
@@ -20884,7 +20901,8 @@ class PeopleManager():
|
||||
elif fieldName in PeopleManager.TYPE_VALUE_PNP_FIELDS:
|
||||
if CheckClearPersonField(fieldName):
|
||||
continue
|
||||
entry = InitArrayFieldEntry(PeopleManager.TYPE_VALUE_PNP_FIELDS[fieldName])
|
||||
entry = InitArrayFieldEntry(PeopleManager.TYPE_VALUE_PNP_FIELDS[fieldName],
|
||||
typeMinLen=0 if fieldName in PeopleManager.EMPTY_TYPE_ALLOWED_FIELDS else 1)
|
||||
if fieldName == PEOPLE_IM_CLIENTS:
|
||||
checkBlankField = None
|
||||
entry['protocol'] = getChoice(PeopleManager.IM_PROTOCOLS, mapChoice=True)
|
||||
@@ -25622,13 +25640,18 @@ CHAT_SPACE_TYPE_MAP = {
|
||||
'directmessage': 'DIRECT_MESSAGE',
|
||||
}
|
||||
|
||||
CHAT_SPACE_PREDEFINED_PERMS_MAP = {
|
||||
'announcement': 'ANNOUNCEMENT_SPACE',
|
||||
'collaboration': 'COLLABORATION_SPACE',
|
||||
}
|
||||
|
||||
CHAT_SPACE_MIN_MAX_MEMBERS = {
|
||||
'SPACE': {'min': 0, 'max': 20},
|
||||
'GROUP_CHAT': {'min': 2, 'max': 20},
|
||||
'DIRECT_MESSAGE': {'min': 1, 'max': 1},
|
||||
}
|
||||
# gam <UserTypeEntity> create chatspace
|
||||
# [type <ChatSpaceType>]
|
||||
# [type <ChatSpaceType>] [announcement|collaboration]
|
||||
# [restricted|(audience <String>)]
|
||||
# [externalusersallowed <Boolean>]
|
||||
# [members <UserTypeEntity>]
|
||||
@@ -25639,9 +25662,7 @@ CHAT_SPACE_MIN_MAX_MEMBERS = {
|
||||
# [formatjson|returnidonly]
|
||||
def createChatSpace(users):
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
body = {'space': {'spaceType': CHAT_SPACE_TYPE_MAP['space'], 'displayName': ''},
|
||||
'requestId': str(uuid.uuid4()),
|
||||
'memberships': []}
|
||||
body = {'space': {'spaceType': CHAT_SPACE_TYPE_MAP['space'], 'displayName': ''}, 'requestId': str(uuid.uuid4())}
|
||||
members = []
|
||||
tbody = {}
|
||||
returnIdOnly = False
|
||||
@@ -25650,6 +25671,8 @@ def createChatSpace(users):
|
||||
myarg = getArgument()
|
||||
if getChatSpaceParameters(myarg, body['space'], CHAT_SPACE_TYPE_MAP, updateMask):
|
||||
pass
|
||||
elif myarg in CHAT_SPACE_PREDEFINED_PERMS_MAP:
|
||||
body['space']['predefinedPermissionSettings'] = CHAT_SPACE_PREDEFINED_PERMS_MAP[myarg]
|
||||
elif myarg == 'externalusersallowed':
|
||||
body['space']['externalUserAllowed'] = getBoolean()
|
||||
elif myarg == 'members':
|
||||
@@ -25670,17 +25693,21 @@ def createChatSpace(users):
|
||||
CHAT_SPACE_MIN_MAX_MEMBERS[spaceType]['min'],
|
||||
CHAT_SPACE_MIN_MAX_MEMBERS[spaceType]['max']))
|
||||
mtype = CHAT_MEMBER_TYPE_MAP['human']
|
||||
for member in members:
|
||||
name = normalizeEmailAddressOrUID(member)
|
||||
body['memberships'].append({'member': {'name': f'users/{name}', 'type': mtype}})
|
||||
if members:
|
||||
body['memberships'] = []
|
||||
for member in members:
|
||||
name = normalizeEmailAddressOrUID(member)
|
||||
body['memberships'].append({'member': {'name': f'users/{name}', 'type': mtype}})
|
||||
if spaceType == 'SPACE':
|
||||
if not body['space']['displayName']:
|
||||
missingArgumentExit('displayname')
|
||||
elif spaceType == 'GROUP_CHAT':
|
||||
body['space'].pop('displayName', None)
|
||||
body['space'].pop('predefinedPermissionSettings', None)
|
||||
else: # DIRECT_MESSAGE
|
||||
body['space'].pop('displayName', None)
|
||||
body['space'].pop('spaceDetails', None)
|
||||
body['space'].pop('predefinedPermissionSettings', None)
|
||||
body['space']['singleUserBotDm'] = False
|
||||
if tbody:
|
||||
trimChatMessageIfRequired(tbody)
|
||||
@@ -25729,12 +25756,34 @@ CHAT_UPDATE_SPACE_TYPE_MAP = {
|
||||
'space': 'SPACE',
|
||||
}
|
||||
|
||||
CHAT_SPACE_ROLE_PERMISSIONS_MAP = {
|
||||
'managers': 'managersAllowed',
|
||||
'members': 'membersAllowed',
|
||||
}
|
||||
|
||||
CHAT_UPDATE_SPACE_PERMISSIONS_MAP = {
|
||||
'managemembersandgroups': 'manageMembersAndGroups',
|
||||
'modifyspacedetails': 'modifySpaceDetails',
|
||||
'togglehistory': 'toggleHistory',
|
||||
'useatmentionall': 'useAtMentionAll',
|
||||
'manageapps': 'manageApps',
|
||||
'managewebhooks': 'manageWebhooks',
|
||||
'replymessages': 'replyMessages',
|
||||
}
|
||||
|
||||
# gam <UserTypeEntity> update chatspace <ChatSpace>
|
||||
# [restricted|(audience <String>)]|
|
||||
# ([displayname <String>]
|
||||
# [type space]
|
||||
# [description <String>] [guidelines|rules <String>]
|
||||
# [history <Boolean>])
|
||||
# managemembersandgroups managers|members
|
||||
# modifyspacedetails managers|members
|
||||
# togglehistory managers|members
|
||||
# useatmentionall managers|members
|
||||
# manageapps managers|members
|
||||
# managewebhooks managers|members
|
||||
# replymessages managers|members
|
||||
# [formatjson]
|
||||
def updateChatSpace(users):
|
||||
FJQC = FormatJSONQuoteChar()
|
||||
@@ -25748,6 +25797,14 @@ def updateChatSpace(users):
|
||||
name = getSpaceName(myarg)
|
||||
elif getChatSpaceParameters(myarg, body, CHAT_UPDATE_SPACE_TYPE_MAP, updateMask):
|
||||
pass
|
||||
elif myarg in CHAT_UPDATE_SPACE_PERMISSIONS_MAP:
|
||||
body.setdefault('permissionSettings', {})
|
||||
permissionSetting = CHAT_UPDATE_SPACE_PERMISSIONS_MAP[myarg]
|
||||
role = getChoice(CHAT_SPACE_ROLE_PERMISSIONS_MAP, mapChoice=True)
|
||||
body['permissionSettings'][permissionSetting] = {'managersAllowed': True}
|
||||
if role == 'membersAllowed':
|
||||
body['permissionSettings'][permissionSetting].update({'membersAllowed': True})
|
||||
updateMask.add(f'permissionSettings.{permissionSetting}')
|
||||
else:
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
if not name:
|
||||
@@ -25815,6 +25872,7 @@ CHAT_SPACES_FIELDS_CHOICE_MAP = {
|
||||
"lastactivetime": "lastActiveTime",
|
||||
"membershipcount": "membershipCount",
|
||||
"name": "name",
|
||||
"permissionsettings": "permissionSettings",
|
||||
"singleuserbotdm": "singleUserBotDm",
|
||||
"spacedetails": "spaceDetails",
|
||||
"spacehistorystate": "spaceHistoryState",
|
||||
@@ -37335,6 +37393,7 @@ def doCalendarsPrintShowACLs(calIds):
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Calendar ACLs')
|
||||
|
||||
EVENT_TYPE_BIRTHDAY = 'birthday'
|
||||
EVENT_TYPE_DEFAULT = 'default'
|
||||
EVENT_TYPE_FOCUSTIME = 'focusTime'
|
||||
EVENT_TYPE_FROMGMAIL = 'fromGmail'
|
||||
@@ -37342,6 +37401,7 @@ EVENT_TYPE_OUTOFOFFICE = 'outOfOffice'
|
||||
EVENT_TYPE_WORKINGLOCATION = 'workingLocation'
|
||||
|
||||
EVENT_TYPES_CHOICE_MAP = {
|
||||
'birthday': EVENT_TYPE_BIRTHDAY,
|
||||
'default': EVENT_TYPE_DEFAULT,
|
||||
'focustime': EVENT_TYPE_FOCUSTIME,
|
||||
'fromgmail': EVENT_TYPE_FROMGMAIL,
|
||||
@@ -37349,20 +37409,6 @@ EVENT_TYPES_CHOICE_MAP = {
|
||||
'workinglocation': EVENT_TYPE_WORKINGLOCATION,
|
||||
}
|
||||
|
||||
#EVENT_TYPE_DEFAULT_PROPERTIES_MAP = {
|
||||
# EVENT_TYPE_DEFAULT: {'eventType': EVENT_TYPE_DEFAULT},
|
||||
# EVENT_TYPE_FOCUSTIME: {'eventType': EVENT_TYPE_FOCUSTIME,
|
||||
# 'focusTimeProperties': {'autoDeclineMode': 'declineNone', 'declineMessage': 'Declined', 'chatStatus': 'doNotDisturb'},
|
||||
# 'transparency':'opaque'},
|
||||
# EVENT_TYPE_FROMGMAIL: {'eventType': EVENT_TYPE_FROMGMAIL},
|
||||
# EVENT_TYPE_OUTOFOFFICE: {'eventType': EVENT_TYPE_OUTOFOFFICE,
|
||||
# 'outOfOfficeProperties': {'autoDeclineMode': 'declineOnlyNewConflictingInvitations', 'declineMessage': 'Declined'},
|
||||
# 'transparency':'opaque'},
|
||||
# EVENT_TYPE_WORKINGLOCATION: {'eventType': EVENT_TYPE_WORKINGLOCATION,
|
||||
# 'workingLocationProperties': {},
|
||||
# 'visibility': 'public', 'transparency':'transparent'},
|
||||
# }
|
||||
|
||||
EVENT_TYPE_PROPERTIES_NAME_MAP = {
|
||||
EVENT_TYPE_DEFAULT: None,
|
||||
EVENT_TYPE_FOCUSTIME: f'{EVENT_TYPE_FOCUSTIME}Properties',
|
||||
@@ -37372,6 +37418,7 @@ EVENT_TYPE_PROPERTIES_NAME_MAP = {
|
||||
}
|
||||
|
||||
EVENT_TYPE_ENTITY_MAP = {
|
||||
EVENT_TYPE_BIRTHDAY: Ent.EVENT_BIRTHDAY,
|
||||
EVENT_TYPE_DEFAULT: None,
|
||||
EVENT_TYPE_FOCUSTIME: Ent.EVENT_FOCUSTIME,
|
||||
EVENT_TYPE_FROMGMAIL: None,
|
||||
@@ -37605,6 +37652,16 @@ def _getCalendarEventAttribute(myarg, body, parameters, function):
|
||||
elif myarg == 'timerange':
|
||||
body['start'] = {'dateTime': getTimeOrDeltaFromNow()}
|
||||
body['end'] = {'dateTime': getTimeOrDeltaFromNow()}
|
||||
elif myarg == 'birthday':
|
||||
body['eventType'] = EVENT_TYPE_BIRTHDAY
|
||||
body['visibility'] = 'private'
|
||||
body['transparency'] = 'transparent'
|
||||
bday = getYYYYMMDD(returnDateTime=True)
|
||||
body['start'] = body['end'] = {'date': bday.strftime(YYYYMMDD_FORMAT)}
|
||||
if bday.month != 2 or bday.day != 29:
|
||||
body['recurrence'] = ['RRULE:FREQ=YEARLY']
|
||||
else:
|
||||
body['recurrence'] = ['RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=-1']
|
||||
elif myarg == 'attachment':
|
||||
body.setdefault('attachments', [])
|
||||
body['attachments'].append({'title': getString(Cmd.OB_STRING), 'fileUrl': getString(Cmd.OB_URL)})
|
||||
@@ -38015,12 +38072,14 @@ def _createCalendarEvents(user, origCal, function, calIds, count, body, paramete
|
||||
if function == 'insert':
|
||||
event = callGAPI(cal.events(), 'insert',
|
||||
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT,
|
||||
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN, GAPI.MALFORMED_WORKING_LOCATION_EVENT],
|
||||
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN,
|
||||
GAPI.MALFORMED_WORKING_LOCATION_EVENT, GAPI.BAD_REQUEST],
|
||||
calendarId=calId, conferenceDataVersion=1, sendUpdates=parameters['sendUpdates'], supportsAttachments=True, body=body, fields=fields)
|
||||
else:
|
||||
event = callGAPI(cal.events(), 'import_',
|
||||
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.INVALID, GAPI.REQUIRED, GAPI.TIME_RANGE_EMPTY, GAPI.EVENT_DURATION_EXCEEDS_LIMIT,
|
||||
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN, GAPI.MALFORMED_WORKING_LOCATION_EVENT,
|
||||
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.DUPLICATE, GAPI.FORBIDDEN,
|
||||
GAPI.MALFORMED_WORKING_LOCATION_EVENT, GAPI.BAD_REQUEST,
|
||||
GAPI.PARTICIPANT_IS_NEITHER_ORGANIZER_NOR_ATTENDEE],
|
||||
calendarId=calId, conferenceDataVersion=1, supportsAttachments=True, body=body, fields=fields)
|
||||
if parameters['csvPF'] is None:
|
||||
@@ -38030,7 +38089,8 @@ def _createCalendarEvents(user, origCal, function, calIds, count, body, paramete
|
||||
_getEventDaysOfWeek(event)
|
||||
_printCalendarEvent(user, calId, event, parameters['csvPF'], parameters['FJQC'])
|
||||
except (GAPI.invalid, GAPI.required, GAPI.timeRangeEmpty, GAPI.eventDurationExceedsLimit,
|
||||
GAPI.requiredAccessLevel, GAPI.participantIsNeitherOrganizerNorAttendee, GAPI.malformedWorkingLocationEvent) as e:
|
||||
GAPI.requiredAccessLevel, GAPI.participantIsNeitherOrganizerNorAttendee,
|
||||
GAPI.malformedWorkingLocationEvent, GAPI.badRequest) as e:
|
||||
entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, event['id']], str(e), i, count)
|
||||
except GAPI.duplicate as e:
|
||||
entityActionFailedWarning([Ent.CALENDAR, calId, Ent.EVENT, event['id']], str(e), i, count)
|
||||
@@ -43092,8 +43152,14 @@ def verifyUserPrimaryEmail(cd, user, createIfNotFound, i, count):
|
||||
# [notifyonupdate [<Boolean>]]
|
||||
# [lograndompassword <FileName>] [ignorenullpassword]
|
||||
def updateUsers(entityList):
|
||||
def waitingForCreationToComplete(sleep_time):
|
||||
writeStderr(Ind.Spaces()+Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.USER), sleep_time))
|
||||
time.sleep(sleep_time)
|
||||
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
ci = None
|
||||
errorRetries = 5
|
||||
updateRetryDelay = 5
|
||||
body, notify, tagReplacements, addGroups, addAliases, PwdOpts, \
|
||||
updatePrimaryEmail, notFoundBody, groupOrgUnitMap, \
|
||||
parameters, resolveConflictAccount = getUserAttributes(cd,
|
||||
@@ -43168,51 +43234,63 @@ def updateUsers(entityList):
|
||||
continue
|
||||
if PwdOpts.makeUniqueRandomPassword:
|
||||
PwdOpts.AssignPassword(body, notify, notFoundBody, parameters['createIfNotFound'])
|
||||
try:
|
||||
result = callGAPI(cd.users(), 'update',
|
||||
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND, GAPI.FORBIDDEN, GAPI.BAD_REQUEST,
|
||||
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
||||
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.DUPLICATE,
|
||||
GAPI.INSUFFICIENT_ARCHIVED_USER_LICENSES, GAPI.CONFLICT],
|
||||
userKey=userKey, body=body, fields=fields)
|
||||
entityActionPerformed([Ent.USER, user], i, count)
|
||||
if PwdOpts.filename and PwdOpts.password:
|
||||
writeFile(PwdOpts.filename, f'{userKey},{PwdOpts.password}\n', mode='a', continueOnError=True)
|
||||
if parameters['notifyOnUpdate'] and notify.get('recipients') and notify['password']:
|
||||
sendCreateUpdateUserNotification(result, notify, tagReplacements, i, count, createMessage=False)
|
||||
except GAPI.userNotFound:
|
||||
if parameters['createIfNotFound']:
|
||||
if notFoundBody and (count == 1) and not vfe and ('password' in notFoundBody) and ('name' in body) and ('givenName' in body['name']) and ('familyName' in body['name']):
|
||||
if 'primaryEmail' not in body:
|
||||
body['primaryEmail'] = user
|
||||
body.update(notFoundBody)
|
||||
if parameters['setChangePasswordOnCreate']:
|
||||
body['changePasswordAtNextLogin'] = True
|
||||
Act.Set(Act.CREATE)
|
||||
try:
|
||||
result = callGAPI(cd.users(), 'insert',
|
||||
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND, GAPI.FORBIDDEN,
|
||||
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
||||
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.CONDITION_NOT_MET],
|
||||
body=body,
|
||||
fields=fields,
|
||||
resolveConflictAccount=resolveConflictAccount)
|
||||
entityActionPerformed([Ent.USER, body['primaryEmail']], i, count)
|
||||
if PwdOpts.filename and PwdOpts.notFoundPassword:
|
||||
writeFile(PwdOpts.filename, f'{user},{PwdOpts.notFoundPassword}\n', mode='a', continueOnError=True)
|
||||
if addGroups:
|
||||
createUserAddToGroups(cd, result['primaryEmail'], addGroups, i, count)
|
||||
if addAliases:
|
||||
createUserAddAliases(cd, result['primaryEmail'], addAliases, i, count)
|
||||
if notify.get('recipients'):
|
||||
notify['password'] = notify['notFoundPassword']
|
||||
sendCreateUpdateUserNotification(result, notify, tagReplacements, i, count)
|
||||
except GAPI.duplicate:
|
||||
duplicateAliasGroupUserWarning(cd, [Ent.USER, body['primaryEmail']], i, count)
|
||||
retry = 0
|
||||
while True:
|
||||
try:
|
||||
result = callGAPI(cd.users(), 'update',
|
||||
throwReasons=[GAPI.CONDITION_NOT_MET, GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
|
||||
GAPI.FORBIDDEN, GAPI.BAD_REQUEST,
|
||||
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
||||
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.DUPLICATE,
|
||||
GAPI.INSUFFICIENT_ARCHIVED_USER_LICENSES, GAPI.CONFLICT],
|
||||
userKey=userKey, body=body, fields=fields)
|
||||
entityActionPerformed([Ent.USER, user], i, count)
|
||||
if PwdOpts.filename and PwdOpts.password:
|
||||
writeFile(PwdOpts.filename, f'{userKey},{PwdOpts.password}\n', mode='a', continueOnError=True)
|
||||
if parameters['notifyOnUpdate'] and notify.get('recipients') and notify['password']:
|
||||
sendCreateUpdateUserNotification(result, notify, tagReplacements, i, count, createMessage=False)
|
||||
break
|
||||
except GAPI.conditionNotMet as e:
|
||||
retry += 1
|
||||
if ('User creation is not complete' not in str(e)) or retry > errorRetries:
|
||||
entityActionFailedWarning([Ent.USER, user], str(e), i, count)
|
||||
break
|
||||
waitingForCreationToComplete(updateRetryDelay)
|
||||
continue
|
||||
except GAPI.userNotFound:
|
||||
if parameters['createIfNotFound']:
|
||||
if notFoundBody and (count == 1) and not vfe and ('password' in notFoundBody) and ('name' in body) and ('givenName' in body['name']) and ('familyName' in body['name']):
|
||||
if 'primaryEmail' not in body:
|
||||
body['primaryEmail'] = user
|
||||
body.update(notFoundBody)
|
||||
if parameters['setChangePasswordOnCreate']:
|
||||
body['changePasswordAtNextLogin'] = True
|
||||
Act.Set(Act.CREATE)
|
||||
try:
|
||||
result = callGAPI(cd.users(), 'insert',
|
||||
throwReasons=[GAPI.DUPLICATE, GAPI.DOMAIN_NOT_FOUND, GAPI.FORBIDDEN,
|
||||
GAPI.INVALID, GAPI.INVALID_INPUT, GAPI.INVALID_PARAMETER,
|
||||
GAPI.INVALID_ORGUNIT, GAPI.INVALID_SCHEMA_VALUE, GAPI.CONDITION_NOT_MET],
|
||||
body=body,
|
||||
fields=fields,
|
||||
resolveConflictAccount=resolveConflictAccount)
|
||||
entityActionPerformed([Ent.USER, body['primaryEmail']], i, count)
|
||||
if PwdOpts.filename and PwdOpts.notFoundPassword:
|
||||
writeFile(PwdOpts.filename, f'{user},{PwdOpts.notFoundPassword}\n', mode='a', continueOnError=True)
|
||||
if addGroups:
|
||||
createUserAddToGroups(cd, result['primaryEmail'], addGroups, i, count)
|
||||
if addAliases:
|
||||
createUserAddAliases(cd, result['primaryEmail'], addAliases, i, count)
|
||||
if notify.get('recipients'):
|
||||
notify['password'] = notify['notFoundPassword']
|
||||
sendCreateUpdateUserNotification(result, notify, tagReplacements, i, count)
|
||||
except GAPI.duplicate:
|
||||
duplicateAliasGroupUserWarning(cd, [Ent.USER, body['primaryEmail']], i, count)
|
||||
else:
|
||||
entityActionFailedWarning([Ent.USER, user], Msg.UNABLE_TO_CREATE_NOT_FOUND_USER, i, count)
|
||||
else:
|
||||
entityActionFailedWarning([Ent.USER, user], Msg.UNABLE_TO_CREATE_NOT_FOUND_USER, i, count)
|
||||
else:
|
||||
entityUnknownWarning(Ent.USER, user, i, count)
|
||||
entityUnknownWarning(Ent.USER, user, i, count)
|
||||
break
|
||||
else:
|
||||
entityActionNotPerformedWarning([Ent.USER, user], Msg.NO_CHANGES, i, count)
|
||||
except GAPI.userNotFound:
|
||||
@@ -51080,7 +51158,7 @@ def createStatusEvent(users, eventType):
|
||||
missingArgumentExit('|'.join(WORKING_LOCATION_CHOICE_MAP))
|
||||
elif eventType == EVENT_TYPE_OUTOFOFFICE:
|
||||
getOutOfOfficeProperties(body, parameters, dateList)
|
||||
else: # eventType == EVENT_TYPE_FOCUSTIME
|
||||
else: # elif eventType == EVENT_TYPE_FOCUSTIME:
|
||||
getFocusTimeProperties(body, parameters, dateList)
|
||||
if not dateList:
|
||||
missingChoiceExit(STATUS_EVENTS_DATETIME_CHOICES)
|
||||
@@ -52424,6 +52502,8 @@ def getDriveFileCopyAttribute(myarg, body, parameters):
|
||||
else:
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.REASON_ONLY_VALID_WITH_CONTENTRESTRICTIONS_READONLY_TRUE)
|
||||
elif myarg == 'inheritedpermissionsdisabled':
|
||||
body['inheritedPermissionsDisabled'] = getBoolean()
|
||||
elif myarg == 'property':
|
||||
driveprop = getDriveFileProperty()
|
||||
body.setdefault(driveprop['visibility'], {})
|
||||
@@ -53240,6 +53320,7 @@ DRIVE_FIELDS_CHOICE_MAP = {
|
||||
'iconlink': 'iconLink',
|
||||
'id': 'id',
|
||||
'imagemediametadata': 'imageMediaMetadata',
|
||||
'inheritedpermissionsdisabled': 'inheritedPermissionsDisabled',
|
||||
'isappauthorized': 'isAppAuthorized',
|
||||
'labelinfo': 'labelInfo',
|
||||
'labels': ['modifiedByMe', 'copyRequiresWriterPermission', 'starred', 'trashed', 'viewedByMe'],
|
||||
@@ -53322,8 +53403,10 @@ DRIVE_CAPABILITIES_SUBFIELDS_CHOICE_MAP = {
|
||||
'candelete': 'canDelete',
|
||||
'candeletechildren': 'canDeleteChildren',
|
||||
'candeletedrive': 'canDeleteDrive',
|
||||
'candisableinheritedpermissions': 'canDisableInheritedPermissions',
|
||||
'candownload': 'canDownload',
|
||||
'canedit': 'canEdit',
|
||||
'canenableinheritedpermissions': 'canEnableInheritedPermissions',
|
||||
'canlistchildren': 'canListChildren',
|
||||
'canmanagemembers': 'canManageMembers',
|
||||
'canmodifycontent': 'canModifyContent',
|
||||
@@ -53398,6 +53481,7 @@ DRIVE_PERMISSIONS_SUBFIELDS_CHOICE_MAP = {
|
||||
'expirationdate': 'expirationTime',
|
||||
'expirationtime': 'expirationTime',
|
||||
'id': 'id',
|
||||
'inheritedpermissionsdisabled': 'inheritedPermissionsDisabled',
|
||||
'name': 'displayName',
|
||||
'pendingowner': 'pendingOwner',
|
||||
'permissiondetails': 'permissionDetails',
|
||||
@@ -53967,12 +54051,14 @@ def deleteFileRevisions(users):
|
||||
Ind.Decrement()
|
||||
|
||||
REVISIONS_FIELDS_CHOICE_MAP = {
|
||||
'keepforever': 'keepForever',
|
||||
'published': 'published',
|
||||
'publishauto': 'publishAuto',
|
||||
'publishedoutsidedomain': 'publishedOutsideDomain'
|
||||
}
|
||||
# gam <UserTypeEntity> update filerevisions <DriveFileEntity> select <DriveFileRevisionIdEntity> [previewupdate]
|
||||
# [published [<Boolean>]] [publishauto [<Boolean>]] [publishedoutsidedomain [<Boolean>]]
|
||||
# [keepforever [<Boolean>]}
|
||||
# [showtitles] [doit] [max_to_update <Number>]
|
||||
def updateFileRevisions(users):
|
||||
fileIdEntity = getDriveFileEntity()
|
||||
@@ -56118,7 +56204,8 @@ def printFileParentTree(users):
|
||||
# [filenamematchpattern <RegularExpression>]
|
||||
# <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
|
||||
# [excludetrashed] (addcsvdata <FieldName> <String>)*
|
||||
# [showsize] [showmimetypesize]
|
||||
# [showsize] [showmimetypesize] [showlastmodification]
|
||||
# (addcsvdata <FieldName> <String>)*
|
||||
# [summary none|only|plus] [summaryuser <String>]
|
||||
# gam <UserTypeEntity> show filecounts
|
||||
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*]
|
||||
@@ -56131,7 +56218,7 @@ def printFileParentTree(users):
|
||||
# [filenamematchpattern <RegularExpression>]
|
||||
# <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
|
||||
# [excludetrashed]
|
||||
# [showsize] [showmimetypesize]
|
||||
# [showsize] [showmimetypesize] [showlastmodification]
|
||||
# [summary none|only|plus] [summaryuser <String>]
|
||||
def printShowFileCounts(users):
|
||||
def _setSelectionFields():
|
||||
@@ -56139,6 +56226,8 @@ def printShowFileCounts(users):
|
||||
fieldsList.extend(OWNED_BY_ME_FIELDS_TITLES)
|
||||
if showSize or (DLP.minimumFileSize is not None) or (DLP.maximumFileSize is not None):
|
||||
fieldsList.append(sizeField)
|
||||
if showLastModification:
|
||||
fieldsList.extend(['id,name,modifiedTime,lastModifyingUser(emailAddress)'])
|
||||
if DLP.filenameMatchPattern:
|
||||
fieldsList.append('name')
|
||||
if DLP.excludeTrashed:
|
||||
@@ -56148,7 +56237,7 @@ def printShowFileCounts(users):
|
||||
if DLP.onlySharedDrives or getPermissionsForSharedDrives:
|
||||
fieldsList.append('driveId')
|
||||
|
||||
def showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, i, count):
|
||||
def showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, lastModification, i, count):
|
||||
if summary != FILECOUNT_SUMMARY_NONE:
|
||||
if count != 0:
|
||||
for mimeType, mtinfo in iter(mimeTypeInfo.items()):
|
||||
@@ -56173,6 +56262,10 @@ def printShowFileCounts(users):
|
||||
dataList.extend(['Item cap', f"{countTotal/SHARED_DRIVE_MAX_FILES_FOLDERS:.2%}"])
|
||||
printEntityKVList(kvList, dataList, i, count)
|
||||
Ind.Increment()
|
||||
if showLastModification:
|
||||
printKeyValueList(['lastModifiedFile', f"{lastModification['lastModifiedFileName']}({lastModification['lastModifiedFileId']})",
|
||||
'lastModifyingUser', lastModification['lastModifyingUser'],
|
||||
'lastModifiedTime', formatLocalTime(lastModification['lastModifiedTime'])])
|
||||
for mimeType, mtinfo in sorted(iter(mimeTypeInfo.items())):
|
||||
if not showMimeTypeSize:
|
||||
printKeyValueList([mimeType, mtinfo['count']])
|
||||
@@ -56186,6 +56279,11 @@ def printShowFileCounts(users):
|
||||
row = {'User': user, 'Total': countTotal}
|
||||
if showSize:
|
||||
row['Size'] = sizeTotal
|
||||
if showLastModification:
|
||||
row.update({'lastModifiedFileId': lastModification['lastModifiedFileId'],
|
||||
'lastModifiedFileName': lastModification['lastModifiedFileName'],
|
||||
'lastModifyingUser': lastModification['lastModifyingUser'],
|
||||
'lastModifiedTime': formatLocalTime(lastModification['lastModifiedTime'])})
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
for mimeType, mtinfo in sorted(iter(mimeTypeInfo.items())):
|
||||
@@ -56200,13 +56298,16 @@ def printShowFileCounts(users):
|
||||
fieldsList = ['mimeType']
|
||||
DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': True, 'allowQuery': True, 'mimeTypeInQuery': True})
|
||||
sharedDriveId = sharedDriveName = ''
|
||||
continueOnInvalidQuery = showSize = showMimeTypeSize = False
|
||||
continueOnInvalidQuery = showSize = showLastModification = showMimeTypeSize = False
|
||||
sizeField = 'quotaBytesUsed'
|
||||
summary = FILECOUNT_SUMMARY_NONE
|
||||
summaryUser = FILECOUNT_SUMMARY_USER
|
||||
summaryMimeTypeInfo = {}
|
||||
fileIdEntity = {}
|
||||
addCSVData = {}
|
||||
summaryLastModification = {
|
||||
'lastModifiedFileId': '', 'lastModifiedFileName': '',
|
||||
'lastModifyingUser': '', 'lastModifiedTime': NEVER_TIME}
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
@@ -56221,6 +56322,8 @@ def printShowFileCounts(users):
|
||||
showSize = True
|
||||
elif myarg == 'sizefield':
|
||||
sizeField = getChoice(SIZE_FIELD_CHOICE_MAP, mapChoice=True)
|
||||
elif myarg == 'showlastmodification':
|
||||
showLastModification = True
|
||||
elif myarg == 'showmimetypesize':
|
||||
showMimeTypeSize = showSize = True
|
||||
elif myarg == 'summary':
|
||||
@@ -56252,6 +56355,8 @@ def printShowFileCounts(users):
|
||||
sortTitles = ['User', 'id', 'name', 'Total', 'Item cap'] if fileIdEntity.get('shareddrive') else ['User', 'Total']
|
||||
if showSize:
|
||||
sortTitles.insert(sortTitles.index('Total')+1, 'Size')
|
||||
if showLastModification:
|
||||
sortTitles.extend(['lastModifiedFileId', 'lastModifiedFileName', 'lastModifyingUser', 'lastModifiedTime'])
|
||||
if addCSVData:
|
||||
sortTitles.extend(sorted(addCSVData.keys()))
|
||||
csvPF.SetTitles(sortTitles)
|
||||
@@ -56269,6 +56374,9 @@ def printShowFileCounts(users):
|
||||
else:
|
||||
sharedDriveName = ''
|
||||
mimeTypeInfo = {}
|
||||
userLastModification = {
|
||||
'lastModifiedFileId': '', 'lastModifiedFileName': '',
|
||||
'lastModifyingUser': '', 'lastModifiedTime': NEVER_TIME}
|
||||
printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, user, i, count, query=DLP.fileIdEntity['query'])
|
||||
try:
|
||||
feed = yieldGAPIpages(drive.files(), 'list', 'files',
|
||||
@@ -56309,7 +56417,15 @@ def printShowFileCounts(users):
|
||||
mimeTypeInfo.setdefault(f_file['mimeType'], {'count': 0, 'size': 0})
|
||||
mimeTypeInfo[f_file['mimeType']]['count'] += 1
|
||||
mimeTypeInfo[f_file['mimeType']]['size'] += int(f_file.get(sizeField, '0'))
|
||||
showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, i, count)
|
||||
if showLastModification:
|
||||
if f_file.get('modifiedTime', NEVER_TIME) > userLastModification['lastModifiedTime'] and 'lastModifyingUser' in f_file:
|
||||
userLastModification['lastModifiedFileId'] = f_file['id']
|
||||
userLastModification['lastModifiedFileName'] = _stripControlCharsFromName(f_file['name'])
|
||||
userLastModification['lastModifiedTime'] = f_file['modifiedTime']
|
||||
userLastModification['lastModifyingUser'] = f_file['lastModifyingUser'].get('emailAddress', UNKNOWN)
|
||||
showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, userLastModification, i, count)
|
||||
if showLastModification and userLastModification['lastModifiedTime'] > summaryLastModification['lastModifiedTime']:
|
||||
summaryLastModification = userLastModification.copy()
|
||||
except (GAPI.invalidQuery, GAPI.invalid, GAPI.badRequest):
|
||||
entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE_OR_FOLDER, None], invalidQuery(DLP.fileIdEntity['query']), i, count)
|
||||
if not continueOnInvalidQuery:
|
||||
@@ -56324,7 +56440,9 @@ def printShowFileCounts(users):
|
||||
continue
|
||||
if summary != FILECOUNT_SUMMARY_NONE:
|
||||
showMimeTypeInfo(summaryUser, summaryMimeTypeInfo,
|
||||
'' if count > 1 else sharedDriveId, '' if count > 1 else sharedDriveName, 0, 0)
|
||||
'' if count > 1 else sharedDriveId,
|
||||
'' if count > 1 else sharedDriveName,
|
||||
summaryLastModification, 0, 0)
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Drive File Counts')
|
||||
|
||||
@@ -64136,7 +64254,7 @@ def _moveSharedDriveToOU(orgUnit, orgUnitId, driveId, user, i, count, ci, return
|
||||
# [(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*) | returnidonly]
|
||||
def createSharedDrive(users, useDomainAdminAccess=False):
|
||||
def waitingForCreationToComplete(sleep_time):
|
||||
writeStderr(Ind.Spaces()+Msg.WAITING_FOR_SHARED_DRIVE_CREATION_TO_COMPLETE_SLEEPING.format(sleep_time))
|
||||
writeStderr(Ind.Spaces()+Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SHAREDDRIVE), sleep_time))
|
||||
time.sleep(sleep_time)
|
||||
|
||||
requestId = str(uuid.uuid4())
|
||||
@@ -65652,6 +65770,7 @@ def deleteUserFromGroups(users):
|
||||
matchPattern = {}
|
||||
kwargs = _getUserGroupOptionalDomainCustomerId()
|
||||
if not kwargs:
|
||||
kwargs = {'customer': GC.Values[GC.CUSTOMER_ID]}
|
||||
deleteGroups = {}
|
||||
if Cmd.ArgumentsRemaining():
|
||||
if not checkArgumentPresent('emailmatchpattern'):
|
||||
@@ -65726,6 +65845,7 @@ def updateUserGroups(users):
|
||||
baseRole = getChoice(GROUP_ROLES_MAP, defaultChoice=Ent.ROLE_MEMBER, mapChoice=True)
|
||||
baseDeliverySettings = getDeliverySettings()
|
||||
if not kwargs:
|
||||
kwargs = {'customer': GC.Values[GC.CUSTOMER_ID]}
|
||||
if Cmd.ArgumentsRemaining():
|
||||
groupKeys = getEntityList(Cmd.OB_GROUP_ENTITY)
|
||||
subkeyRoleField = GM.Globals[GM.CSV_SUBKEY_FIELD]
|
||||
@@ -65786,6 +65906,8 @@ def updateUserGroups(users):
|
||||
def syncUserWithGroups(users):
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
kwargs = _getUserGroupOptionalDomainCustomerId()
|
||||
if not kwargs:
|
||||
kwargs = {'customer': GC.Values[GC.CUSTOMER_ID]}
|
||||
baseRole = getChoice(GROUP_ROLES_MAP, defaultChoice=Ent.ROLE_MEMBER, mapChoice=True)
|
||||
baseDeliverySettings = getDeliverySettings()
|
||||
groupKeys = getEntityList(Cmd.OB_GROUP_ENTITY)
|
||||
@@ -71878,14 +72000,16 @@ def _processSendAs(user, i, count, entityType, emailAddress, j, jcount, gmail, f
|
||||
result = callGAPI(gmail.users().settings().sendAs(), function,
|
||||
throwReasons=GAPI.GMAIL_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.ALREADY_EXISTS, GAPI.DUPLICATE,
|
||||
GAPI.CANNOT_DELETE_PRIMARY_SENDAS, GAPI.INVALID_ARGUMENT,
|
||||
GAPI.FAILED_PRECONDITION, GAPI.PERMISSION_DENIED],
|
||||
GAPI.FAILED_PRECONDITION, GAPI.PERMISSION_DENIED,
|
||||
GAPI.INSUFFICIENT_PERMISSIONS],
|
||||
userId='me', **kwargs)
|
||||
if function == 'get':
|
||||
_showSendAs(result, j, jcount, sigReplyFormat, verifyOnly)
|
||||
else:
|
||||
entityActionPerformed([Ent.USER, user, entityType, emailAddress], j, jcount)
|
||||
except (GAPI.notFound, GAPI.alreadyExists, GAPI.duplicate,
|
||||
GAPI.cannotDeletePrimarySendAs, GAPI.invalidArgument, GAPI.failedPrecondition, GAPI.permissionDenied) as e:
|
||||
GAPI.cannotDeletePrimarySendAs, GAPI.invalidArgument,
|
||||
GAPI.failedPrecondition, GAPI.permissionDenied, GAPI.insufficientPermissions) as e:
|
||||
entityActionFailedWarning([Ent.USER, user, entityType, emailAddress], str(e), j, jcount)
|
||||
except (GAPI.serviceNotAvailable, GAPI.badRequest):
|
||||
entityServiceNotApplicableWarning(Ent.USER, user, i, count)
|
||||
|
||||
4880
src/gam/chat-v1.json
4880
src/gam/chat-v1.json
File diff suppressed because it is too large
Load Diff
5057
src/gam/drive-v3beta.json
Normal file
5057
src/gam/drive-v3beta.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,7 @@ DIRECTORY_BETA = 'directory_beta'
|
||||
DOCS = 'docs'
|
||||
DRIVE2 = 'drive2'
|
||||
DRIVE3 = 'drive3'
|
||||
DRIVE3B = 'drive3b'
|
||||
DRIVETD = 'drivetd'
|
||||
DRIVEACTIVITY = 'driveactivity'
|
||||
DRIVELABELS = 'drivelabels'
|
||||
@@ -206,15 +207,15 @@ _INFO = {
|
||||
ANALYTICS_ADMIN: {'name': 'Analytics Admin API', 'version': 'v1beta', 'v2discovery': True},
|
||||
CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
|
||||
CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
|
||||
CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True, 'localjson': True},
|
||||
CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS_ADMIN: {'name': 'Chat API - Memberships Admin', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_MESSAGES: {'name': 'Chat API - Messages', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES: {'name': 'Chat API - Spaces', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_ADMIN: {'name': 'Chat API - Spaces Admin', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_DELETE: {'name': 'Chat API - Spaces Delete', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_DELETE_ADMIN: {'name': 'Chat API - Spaces Delete Admin', 'version': 'v1', 'v2discovery': True, 'localjson': True, 'mappedAPI': CHAT},
|
||||
CHAT: {'name': 'Chat API', 'version': 'v1', 'v2discovery': True},
|
||||
CHAT_EVENTS: {'name': 'Chat API - Events', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS: {'name': 'Chat API - Memberships', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MEMBERSHIPS_ADMIN: {'name': 'Chat API - Memberships Admin', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_MESSAGES: {'name': 'Chat API - Messages', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES: {'name': 'Chat API - Spaces', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_ADMIN: {'name': 'Chat API - Spaces Admin', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_DELETE: {'name': 'Chat API - Spaces Delete', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CHAT_SPACES_DELETE_ADMIN: {'name': 'Chat API - Spaces Delete Admin', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHAT},
|
||||
CLASSROOM: {'name': 'Classroom API', 'version': 'v1', 'v2discovery': True},
|
||||
CHROMEMANAGEMENT: {'name': 'Chrome Management API', 'version': 'v1', 'v2discovery': True},
|
||||
CHROMEMANAGEMENT_APPDETAILS: {'name': 'Chrome Management API - AppDetails', 'version': 'v1', 'v2discovery': True, 'mappedAPI': CHROMEMANAGEMENT},
|
||||
@@ -237,6 +238,7 @@ _INFO = {
|
||||
DOCS: {'name': 'Docs API', 'version': 'v1', 'v2discovery': True},
|
||||
DRIVE2: {'name': 'Drive API v2', 'version': 'v2', 'v2discovery': False, 'mappedAPI': 'drive'},
|
||||
DRIVE3: {'name': 'Drive API v3', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
|
||||
DRIVE3B: {'name': 'Drive API v3beta', 'version': 'v3beta', 'v2discovery': False, 'mappedAPI': 'drive', 'localjson': True},
|
||||
DRIVETD: {'name': 'Drive API v3 - todrive', 'version': 'v3', 'v2discovery': False, 'mappedAPI': 'drive'},
|
||||
DRIVEACTIVITY: {'name': 'Drive Activity API v2', 'version': 'v2', 'v2discovery': True},
|
||||
DRIVELABELS_ADMIN: {'name': 'Drive Labels API v2beta - Admin', 'version': 'v2beta', 'v2discovery': True, 'mappedAPI': DRIVELABELS},
|
||||
|
||||
@@ -151,6 +151,8 @@ DOMAIN = 'domain'
|
||||
DRIVE_DIR = 'drive_dir'
|
||||
# When retrieving lists of Drive files/folders from API, how many should be retrieved in each chunk
|
||||
DRIVE_MAX_RESULTS = 'drive_max_results'
|
||||
# Use Drive V3 beta
|
||||
DRIVE_V3_BETA = 'drive_v3_beta'
|
||||
# Use Drive V3 ntive names
|
||||
DRIVE_V3_NATIVE_NAMES = 'drive_v3_native_names'
|
||||
# When processing email messages in batches, how many should be processed in each batch
|
||||
@@ -366,6 +368,7 @@ Defaults = {
|
||||
DOMAIN: '',
|
||||
DRIVE_DIR: '',
|
||||
DRIVE_MAX_RESULTS: '1000',
|
||||
DRIVE_V3_BETA: FALSE,
|
||||
DRIVE_V3_NATIVE_NAMES: TRUE,
|
||||
EMAIL_BATCH_SIZE: '50',
|
||||
ENABLE_DASA: FALSE,
|
||||
@@ -479,7 +482,7 @@ VAR_INFO = {
|
||||
ADMIN_EMAIL: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GA_ADMIN_EMAIL', VAR_LIMITS: (0, None)},
|
||||
API_CALLS_RATE_CHECK: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
API_CALLS_RATE_LIMIT: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (50, None)},
|
||||
API_CALLS_TRIES_LIMIT: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (3, 10)},
|
||||
API_CALLS_TRIES_LIMIT: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (3, 30)},
|
||||
AUTO_BATCH_MIN: {VAR_TYPE: TYPE_INTEGER, VAR_ENVVAR: 'GAM_AUTOBATCH', VAR_LIMITS: (0, 100)},
|
||||
BAIL_ON_INTERNAL_ERROR_TRIES: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 10)},
|
||||
BATCH_SIZE: {VAR_TYPE: TYPE_INTEGER, VAR_ENVVAR: 'GAM_BATCH_SIZE', VAR_LIMITS: (1, 1000)},
|
||||
@@ -528,6 +531,7 @@ VAR_INFO = {
|
||||
DOMAIN: {VAR_TYPE: TYPE_STRING, VAR_ENVVAR: 'GA_DOMAIN', VAR_LIMITS: (0, None)},
|
||||
DRIVE_DIR: {VAR_TYPE: TYPE_DIRECTORY, VAR_ENVVAR: 'GAMDRIVEDIR'},
|
||||
DRIVE_MAX_RESULTS: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 1000)},
|
||||
DRIVE_V3_BETA: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
DRIVE_V3_NATIVE_NAMES: {VAR_TYPE: TYPE_BOOLEAN},
|
||||
EMAIL_BATCH_SIZE: {VAR_TYPE: TYPE_INTEGER, VAR_LIMITS: (1, 100)},
|
||||
ENABLE_DASA: {VAR_TYPE: TYPE_BOOLEAN, VAR_SIGFILE: 'enabledasa.txt', VAR_SFFT: (FALSE, TRUE)},
|
||||
|
||||
@@ -215,6 +215,7 @@ class GamEntity():
|
||||
END_TIME = 'endt'
|
||||
ENTITY = 'enti'
|
||||
EVENT = 'evnt'
|
||||
EVENT_BIRTHDAY = 'evbd'
|
||||
EVENT_FOCUSTIME = 'evft'
|
||||
EVENT_OUTOFOFFICE = 'evoo'
|
||||
EVENT_WORKINGLOCATION = 'evwl'
|
||||
@@ -565,6 +566,7 @@ class GamEntity():
|
||||
END_TIME: ['End Times', 'End Time'],
|
||||
ENTITY: ['Entities', 'Entity'],
|
||||
EVENT: ['Events', 'Event'],
|
||||
EVENT_BIRTHDAY: ['Borthday Events', 'Birthday Event'],
|
||||
EVENT_FOCUSTIME: ['Focus Time Events', 'Focus Time Event'],
|
||||
EVENT_OUTOFOFFICE: ['Out of Office Events', 'Out of Office Event'],
|
||||
EVENT_WORKINGLOCATION: ['Working Location Events', 'Working Location Event'],
|
||||
|
||||
@@ -510,8 +510,7 @@ 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'
|
||||
WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING = 'Waiting for {0} creation to complete. Sleeping {1} seconds\n'
|
||||
WHAT_IS_YOUR_PROJECT_ID = '\nWhat is your project ID? '
|
||||
WILL_RERUN_WITH_NO_BROWSER_TRUE = 'Will re-run command with no_browser true\n'
|
||||
WITH = 'with'
|
||||
|
||||
@@ -1170,9 +1170,11 @@ def createMethod(methodName, methodDesc, rootDesc, schema):
|
||||
elif "response" not in methodDesc:
|
||||
model = RawModel()
|
||||
|
||||
api_version = methodDesc.get("apiVersion", None)
|
||||
|
||||
headers = {}
|
||||
headers, params, query, body = model.request(
|
||||
headers, actual_path_params, actual_query_params, body_value
|
||||
headers, actual_path_params, actual_query_params, body_value, api_version
|
||||
)
|
||||
|
||||
expanded_url = uritemplate.expand(pathUrl, params)
|
||||
|
||||
@@ -27,10 +27,18 @@ import json
|
||||
import logging
|
||||
import platform
|
||||
import urllib
|
||||
import warnings
|
||||
|
||||
from googleapiclient import version as googleapiclient_version
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
try:
|
||||
from google.api_core.version_header import API_VERSION_METADATA_KEY
|
||||
|
||||
HAS_API_VERSION = True
|
||||
except ImportError:
|
||||
HAS_API_VERSION = False
|
||||
|
||||
_LIBRARY_VERSION = googleapiclient_version.__version__
|
||||
_PY_VERSION = platform.python_version()
|
||||
|
||||
@@ -121,7 +129,7 @@ class BaseModel(Model):
|
||||
LOGGER.info("query: %s", query)
|
||||
LOGGER.info("--request-end--")
|
||||
|
||||
def request(self, headers, path_params, query_params, body_value):
|
||||
def request(self, headers, path_params, query_params, body_value, api_version=None):
|
||||
"""Updates outgoing requests with a serialized body.
|
||||
|
||||
Args:
|
||||
@@ -129,7 +137,10 @@ class BaseModel(Model):
|
||||
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.
|
||||
serializable by json.
|
||||
api_version: str, The precise API version represented by this request,
|
||||
which will result in an API Version header being sent along with the
|
||||
HTTP request.
|
||||
Returns:
|
||||
A tuple of (headers, path_params, query, body)
|
||||
|
||||
@@ -155,6 +166,15 @@ class BaseModel(Model):
|
||||
_PY_VERSION,
|
||||
)
|
||||
|
||||
if api_version and HAS_API_VERSION:
|
||||
headers[API_VERSION_METADATA_KEY] = api_version
|
||||
elif api_version:
|
||||
warnings.warn(
|
||||
"The `api_version` argument is ignored as a newer version of "
|
||||
"`google-api-core` is required to use this feature."
|
||||
"Please upgrade `google-api-core` to 2.19.0 or newer."
|
||||
)
|
||||
|
||||
if body_value is not None:
|
||||
headers["content-type"] = self.content_type
|
||||
body_value = self.serialize(body_value)
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "2.124.0"
|
||||
__version__ = "2.146.0"
|
||||
|
||||
@@ -13,10 +13,10 @@ keywords = google, oauth2, gsuite, google-apps, google-admin-sdk, google-drive,
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Programming Language :: Python :: 3.12
|
||||
License :: OSI Approved :: Apache License
|
||||
|
||||
[options]
|
||||
|
||||
58
src/tools/gen-wix-xml-filelist.py
Normal file
58
src/tools/gen-wix-xml-filelist.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
source_dir = sys.argv[1]
|
||||
template_file = sys.argv[2]
|
||||
target_file = sys.argv[3]
|
||||
|
||||
existing_components = {
|
||||
'gam.exe': ''' <Component Id="gam_exe" Guid="d046ea24-c9f8-40ca-84db-70b0119933ff">
|
||||
<File Name="gam.exe" KeyPath="yes" />
|
||||
<Environment Id="PATH" Name="PATH" Value="[INSTALLFOLDER]" Permanent="yes" Part="last" Action="set" System="yes" />
|
||||
</Component>
|
||||
''',
|
||||
'LICENSE': ''' <Component Id="license" Guid="c76864c5-d005-44d5-bb7c-a27e5923792d">
|
||||
<File Name="LICENSE" KeyPath="yes" />
|
||||
</Component>
|
||||
''',
|
||||
'gam-setup.bat': ''' <Component Id="gam_setup_bat" Guid="5e6bbacb-d86f-4d80-a10b-89b81ee63fcb">
|
||||
<File Name="gam-setup.bat" KeyPath="yes" />
|
||||
</Component>
|
||||
''',
|
||||
'GamCommands.txt': ''' <Component Id="GamCommands_txt" Guid="a2dca862-b222-469e-a637-95ea2a1c53e7">
|
||||
<File Name="GamCommands.txt" KeyPath="yes" />
|
||||
</Component>
|
||||
''',
|
||||
'GamUpdate.txt': ''' <Component Id="GamUpdate_txt" Guid="1b7cdd48-0fff-4943-a219-102fcd14c755">
|
||||
<File Name="GamUpdate.txt" KeyPath="yes" />
|
||||
</Component>
|
||||
''',
|
||||
'cacerts.pem': ''' <Component Id="cacerts_pem" Guid="61fe2b2d-1646-4bed-b844-193965e97727">
|
||||
<File Name="cacerts.pem" KeyPath="yes" />
|
||||
</Component>
|
||||
''',
|
||||
}
|
||||
|
||||
component_xml = ''
|
||||
all_files = []
|
||||
for root, dirs, files in os.walk(source_dir):
|
||||
for filename in files:
|
||||
relpath = os.path.relpath(root, source_dir)
|
||||
if relpath == '.':
|
||||
all_files.append(filename)
|
||||
else:
|
||||
all_files.append(os.path.join(relpath, filename))
|
||||
all_files.sort()
|
||||
for filename in all_files:
|
||||
component_xml += existing_components.get(filename,
|
||||
f' <Component>\n <File Name="{filename}" KeyPath="yes"/>\n </Component>\n')
|
||||
|
||||
with open(template_file, 'r') as f:
|
||||
template = f.read()
|
||||
|
||||
full_xml = template.replace('REPLACE_ME_WITH_FILE_COMPONENTS', component_xml)
|
||||
|
||||
with open(target_file, 'w') as f:
|
||||
f.write(full_xml)
|
||||
|
||||
Reference in New Issue
Block a user