mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-08 08:11:37 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a00256ee9f | ||
|
|
970697ec65 | ||
|
|
06d131ec55 | ||
|
|
094616e482 | ||
|
|
cbfae9226a | ||
|
|
c35cdcf4c3 | ||
|
|
d87ece177d | ||
|
|
41535666b6 | ||
|
|
20d1b18009 | ||
|
|
c27e48dd5c | ||
|
|
44fe8a22e0 | ||
|
|
21df315887 | ||
|
|
3a7c470e6e | ||
|
|
22feec5136 | ||
|
|
a30f8c325f | ||
|
|
0770c20992 | ||
|
|
cc7fb0df7b | ||
|
|
fec061c250 | ||
|
|
aef3b23061 | ||
|
|
3518fc8ad3 | ||
|
|
e5dab74336 | ||
|
|
3aef51781e | ||
|
|
23deb2526c | ||
|
|
1a77bbf706 | ||
|
|
40b8e58266 | ||
|
|
733110120a | ||
|
|
68b8c9108d | ||
|
|
9ddeaba79b | ||
|
|
582c1e4fa2 | ||
|
|
28383c1391 | ||
|
|
7ab959f27c | ||
|
|
a877ca6139 | ||
|
|
33da8016a2 | ||
|
|
36b2849f20 | ||
|
|
377201614b | ||
|
|
ff11bf33d1 | ||
|
|
59463dcc9a | ||
|
|
23b5eb6fd6 | ||
|
|
8f4aa19f13 | ||
|
|
6410691c0e | ||
|
|
1ad1f9b96c | ||
|
|
636e8dd11e | ||
|
|
caeab48dda | ||
|
|
1364991e5d | ||
|
|
6bdea8fa54 | ||
|
|
da24220d87 | ||
|
|
a7d537ebe2 | ||
|
|
74b285959c | ||
|
|
c138bc44f0 | ||
|
|
13f56afcd2 | ||
|
|
ba8242f480 | ||
|
|
01985d4381 | ||
|
|
77511b79c9 | ||
|
|
06f653db8f | ||
|
|
cea2099537 | ||
|
|
67a6d3f4de | ||
|
|
7987a94aab | ||
|
|
e6494b6747 | ||
|
|
401f5095e1 | ||
|
|
93323d12d3 | ||
|
|
c3e23fabf1 | ||
|
|
95eb36c5c2 | ||
|
|
17105d51f1 | ||
|
|
8dbc455407 | ||
|
|
7e7b8416a4 | ||
|
|
ed81501bf2 | ||
|
|
428f8f5987 |
534
.github/workflows/build.yml
vendored
534
.github/workflows/build.yml
vendored
@@ -86,18 +86,23 @@ jobs:
|
||||
freethreaded: false
|
||||
goal: build
|
||||
name: Build x86_64 macOS 15
|
||||
- os: macos-26
|
||||
- os: macos-26-intel
|
||||
jid: 11
|
||||
freethreaded: false
|
||||
goal: build
|
||||
name: Build x86_64 macOS 26
|
||||
- os: macos-26
|
||||
jid: 12
|
||||
freethreaded: false
|
||||
goal: build
|
||||
name: Build Arm MacOS 26
|
||||
- os: windows-2025-vs2026
|
||||
jid: 12
|
||||
jid: 13
|
||||
freethreaded: false
|
||||
goal: build
|
||||
name: Build Intel Windows
|
||||
- os: windows-11-arm
|
||||
jid: 13
|
||||
jid: 14
|
||||
freethreaded: false
|
||||
goal: build
|
||||
name: Build Arm Windows
|
||||
@@ -105,36 +110,42 @@ jobs:
|
||||
goal: test
|
||||
python: "3.10"
|
||||
freethreaded: false
|
||||
jid: 14
|
||||
jid: 15
|
||||
name: Test Python 3.10
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.11"
|
||||
freethreaded: false
|
||||
jid: 15
|
||||
jid: 16
|
||||
name: Test Python 3.11
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.12"
|
||||
freethreaded: false
|
||||
jid: 16
|
||||
jid: 17
|
||||
name: Test Python 3.12
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.13"
|
||||
freethreaded: false
|
||||
jid: 18
|
||||
name: Test Python 3.13
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.15-dev"
|
||||
freethreaded: false
|
||||
jid: 17
|
||||
jid: 19
|
||||
name: Test Python 3.15-dev
|
||||
- os: ubuntu-24.04
|
||||
goal: test
|
||||
python: "3.14"
|
||||
freethreaded: true
|
||||
jid: 18
|
||||
jid: 20
|
||||
name: Test Python 3.14 freethread
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@@ -148,12 +159,12 @@ jobs:
|
||||
|
||||
- name: Cache multiple paths
|
||||
if: matrix.goal == 'build'
|
||||
uses: actions/cache@638ed79f9dc94c1de1baef91bcab5edaa19451f4 # v4.2.4
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
id: cache-python-ssl
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20260213
|
||||
key: gam-${{ matrix.jid }}-20260227
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
@@ -163,7 +174,7 @@ jobs:
|
||||
|
||||
- name: Use pre-compiled Python for testing
|
||||
if: matrix.python != ''
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
allow-prereleases: true
|
||||
@@ -247,7 +258,7 @@ jobs:
|
||||
|
||||
- name: MacOS import developer certificates for signing
|
||||
if: runner.os == 'macOS'
|
||||
uses: apple-actions/import-codesign-certs@11e1bb2d3771ad8ffa8459dfe527bc26b2dd4b62 # v5.0.3
|
||||
uses: apple-actions/import-codesign-certs@b610f78488812c1e56b20e6df63ec42d833f2d14 # v6.0.0
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
|
||||
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
@@ -471,7 +482,7 @@ jobs:
|
||||
|
||||
- name: Run Python
|
||||
run: |
|
||||
"${PYTHON}" -V
|
||||
"${PYTHON}" -VV
|
||||
"${PYTHON}" -c "import ssl; print(f'Using {ssl.OPENSSL_VERSION}')"
|
||||
|
||||
- name: Create and use Python venv
|
||||
@@ -732,7 +743,7 @@ jobs:
|
||||
$gam create signjwtserviceaccount
|
||||
|
||||
- name: Attest gam executable was generated from this Action
|
||||
uses: actions/attest-build-provenance@0b6e9809265278d02c58acf52849a95818a5a306 # v3.0.0
|
||||
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
|
||||
if: matrix.goal == 'build'
|
||||
with:
|
||||
subject-path: ${{ env.gam }}
|
||||
@@ -753,10 +764,10 @@ jobs:
|
||||
echo "GAM Archive ${GAM_ARCHIVE}"
|
||||
tar -C "${gampath}/.." --create --verbose --exclude-from "${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" --file $GAM_ARCHIVE --xz gam7
|
||||
|
||||
- name: Install Wix on Win ARM64
|
||||
if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
||||
run: |
|
||||
choco install wixtoolset
|
||||
# - name: Install Wix on Win ARM64
|
||||
# if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
||||
# run: |
|
||||
# choco install wixtoolset
|
||||
|
||||
- name: Windows package zip
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
@@ -767,54 +778,80 @@ jobs:
|
||||
GAM_ARCHIVE="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-windows-${arch}.zip"
|
||||
/c/Program\ Files/7-Zip/7z.exe a -tzip "$GAM_ARCHIVE" gam7 "-xr@${GITHUB_WORKSPACE}/.github/actions/package_exclusions.txt" -bb3
|
||||
|
||||
- name: Windows package MSI
|
||||
- name: Windows package exe with Inno Setup
|
||||
if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
run: |
|
||||
export MSI_FILENAME="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-windows-${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
|
||||
$PYTHON tools/gen-wix-xml-filelist.py 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
|
||||
choco install innosetup
|
||||
export signtool="C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe"
|
||||
iscc \
|
||||
/S"gamsigntool=$signtool sign /sha1 $WINDOWS_CODESIGN_CERT_HASH /tr http://time.certum.pl /td SHA256 /fd SHA256 /v \$f" \
|
||||
/O"$GITHUB_WORKSPACE" \
|
||||
gam.iss
|
||||
|
||||
- name: Sign GAM MSI
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
write-Host "Signing ${env:MSI_FILENAME}...."
|
||||
#- name: Windows package MSI
|
||||
# if: runner.os == 'Windows' && matrix.goal != 'test'
|
||||
# run: |
|
||||
# export MSI_FILENAME="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-windows-${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
|
||||
# $PYTHON tools/gen-wix-xml-filelist.py 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: Sign GAM MSI
|
||||
# if: runner.os == 'Windows'
|
||||
# shell: pwsh
|
||||
# run: |
|
||||
# write-Host "Signing ${env:MSI_FILENAME}...."
|
||||
# Always explicitely use x64 version os signtool.exe, arm64 version apparently can't
|
||||
# see Certum certs since SimplySignDesktop is x64-only today.
|
||||
Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "$env:WINDOWS_CODESIGN_CERT_HASH", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:MSI_FILENAME"
|
||||
write-Host "Verifying signature of ${env:MSI_FILENAME}...."
|
||||
# verify signature. If we failed to sign we should fail to verify and die.
|
||||
& 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:MSI_FILENAME"
|
||||
# Start-Process -Wait -NoNewWindow -ErrorAction Continue -FilePath 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' -ArgumentList "sign", "/sha1", "$env:WINDOWS_CODESIGN_CERT_HASH", "/tr", "http://time.certum.pl", "/td", "SHA256", "/fd", "SHA256", "/v", "$env:MSI_FILENAME"
|
||||
# write-Host "Verifying signature of ${env:MSI_FILENAME}...."
|
||||
# # verify signature. If we failed to sign we should fail to verify and die.
|
||||
# & 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' verify /pa /v "$env:MSI_FILENAME"
|
||||
|
||||
- name: Attest that gam package files were generated from this Action
|
||||
uses: actions/attest-build-provenance@0b6e9809265278d02c58acf52849a95818a5a306 # v3.0.0
|
||||
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal == 'build'
|
||||
with:
|
||||
subject-path: |
|
||||
gam*.tar.xz
|
||||
gam*.zip
|
||||
gam*.msi
|
||||
gam*.exe
|
||||
# gam*.msi
|
||||
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
|
||||
#if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.goal != 'test'
|
||||
if: always()
|
||||
- name: Archive tar.xz artifacts
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
|
||||
if: runner.os != 'Windows'
|
||||
with:
|
||||
name: gam-binaries-${{ env.GAMOS }}-${{ env.arch }}-${{ matrix.jid }}
|
||||
archive: false
|
||||
if-no-files-found: ignore
|
||||
path: |
|
||||
gam*.tar.xz
|
||||
|
||||
- name: Archive zip artifacts
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
|
||||
if: runner.os == 'Windows'
|
||||
with:
|
||||
archive: false
|
||||
if-no-files-found: ignore
|
||||
path: |
|
||||
gam*.zip
|
||||
gam*.msi
|
||||
*.png
|
||||
|
||||
- name: Archive exe artifacts
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
|
||||
if: runner.os == 'Windows'
|
||||
with:
|
||||
archive: false
|
||||
if-no-files-found: ignore
|
||||
path: |
|
||||
gam*.exe
|
||||
|
||||
- name: Basic Tests build jobs only
|
||||
if: matrix.goal != 'test' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
@@ -839,19 +876,46 @@ jobs:
|
||||
- name: Live API tests
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
|
||||
run: |
|
||||
run_gam() {
|
||||
local allowed_codes="0"
|
||||
if [[ "$1" == "-a" ]]; then
|
||||
allowed_codes="$2"
|
||||
shift 2
|
||||
fi
|
||||
echo "::group::Executing: gam $*"
|
||||
local exit_code=0
|
||||
$gam "$@" || exit_code=$?
|
||||
echo "::endgroup::"
|
||||
allowed_codes="${allowed_codes//,/ }"
|
||||
local passed=false
|
||||
for code in $allowed_codes; do
|
||||
if [ "$exit_code" -eq "$code" ]; then
|
||||
passed=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$passed" = true ]; then
|
||||
echo "| \`gam $*\` | 🟢 Pass | $exit_code |" >> $GITHUB_STEP_SUMMARY
|
||||
return 0 # Mask the allowed non-zero exit code so GHA continues
|
||||
else
|
||||
echo "| \`gam $*\` | 🔴 Fail | $exit_code |" >> $GITHUB_STEP_SUMMARY
|
||||
exit $exit_code # Hard fail the step for unapproved errors
|
||||
fi
|
||||
}
|
||||
|
||||
export gam_user="gam-gha-${JID}@pdl.jaylee.us"
|
||||
echo "gam_user=${gam_user}" >> $GITHUB_ENV
|
||||
$gam config customer_id "C03uzfv2s" save
|
||||
$gam config domain "pdl.jaylee.us" save
|
||||
$gam config admin_email "${gam_user}" save
|
||||
$gam config enable_dasa false save
|
||||
$gam oauth info
|
||||
$gam oauth refresh
|
||||
$gam config enable_dasa true save
|
||||
$gam checkconn
|
||||
$gam user "$gam_user" check serviceaccount
|
||||
$gam info domain
|
||||
$gam info user
|
||||
run_gam config customer_id "C03uzfv2s" save
|
||||
run_gam config domain "pdl.jaylee.us" save
|
||||
run_gam config admin_email "${gam_user}" save
|
||||
run_gam config enable_dasa false save
|
||||
run_gam oauth info
|
||||
run_gam oauth refresh
|
||||
run_gam config enable_dasa true save
|
||||
run_gam checkconn
|
||||
run_gam user "$gam_user" check serviceaccount
|
||||
run_gam info domain
|
||||
run_gam info user
|
||||
export tstamp=$($PYTHON -c "import time; print(time.time_ns())")
|
||||
export newbase="gha_test_${JID}_${tstamp}"
|
||||
export newuser="${newbase}@pdl.jaylee.us"
|
||||
@@ -860,24 +924,39 @@ jobs:
|
||||
export newbuilding="${newbase}-building"
|
||||
export newresource="${newbase}-resource"
|
||||
export newou="aaaGithub Actions/${newbase}"
|
||||
|
||||
|
||||
echo "### GAM Execution Report" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Command | Status |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| :--- | :---: |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# cleanup old runs
|
||||
$gam config enable_dasa false save
|
||||
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultholds | $gam csv - gam delete vaulthold "id:~~holdId~~" matter "id:~~matterId~~" || if [ $? != 55 ]; then exit $?; fi
|
||||
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultmatters matterstate OPEN | $gam csv - gam update vaultmatter "id:~~matterId~~" action close
|
||||
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print vaultmatters matterstate CLOSED | $gam csv - gam update vaultmatter "id:~~matterId~~" action delete
|
||||
$gam config csv_output_row_filter "Emails.1.address:regex:^gha_test-${JID}_" print contacts | $gam csv - gam delete contact ~ContactID
|
||||
$gam config enable_dasa true save
|
||||
$gam config csv_output_row_filter "name:regex:gha_test_${JID}_" print features | $gam csv - gam delete feature ~name
|
||||
$gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" user $gam_user print shareddrives asadmin | $gam csv - gam user $gam_user delete shareddrive ~id nukefromorbit
|
||||
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail
|
||||
$gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" print ous fromparent "aaaGithub Actions" | $gam csv - gam delete ou ~orgUnitId
|
||||
$gam config csv_output_row_filter "email:regex:^gha_test_${JID}_" print cigroups | $gam csv - gam delete cigroup ~email
|
||||
$gam config csv_output_row_filter "resourceId:regex:^gha_test_${JID}_" print resources | $gam csv - gam delete resource ~resourceId
|
||||
$gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" print buildings | $gam csv - gam delete building ~buildingId
|
||||
run_gam config enable_dasa false save
|
||||
run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./vh.csv print vaultholds
|
||||
run_gam -a "0 55" csv ./vh.csv gam delete vaulthold "id:~~holdId~~" matter "id:~~matterId~~"
|
||||
run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./vm-open.csv print vaultmatters matterstate OPEN
|
||||
run_gam csv ./vm-open.csv gam update vaultmatter "id:~~matterId~~" action close
|
||||
run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./vm-closed.csv print vaultmatters matterstate CLOSED
|
||||
run_gam csv ./vm-closed.csv gam update vaultmatter "id:~~matterId~~" action delete
|
||||
run_gam config csv_output_row_filter "Emails.1.address:regex:^gha_test-${JID}_" redirect csv ./contacts.csv print contacts
|
||||
run_gam csv ./contacts.csv gam delete contact ~ContactID
|
||||
run_gam config enable_dasa true save
|
||||
run_gam config csv_output_row_filter "name:regex:gha_test_${JID}_" redirect csv ./features.csv print features
|
||||
run_gam csv ./features.csv gam delete feature ~name
|
||||
run_gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" redirect csv ./sd.csv user $gam_user print shareddrives asadmin
|
||||
run_gam csv ./sd.csv gam user $gam_user delete shareddrive ~id nukefromorbit
|
||||
run_gam redirect csv ./users.csv print users query "gha.jid=$JID"
|
||||
run_gam csv ./users.csv gam delete user ~primaryEmail
|
||||
run_gam config csv_output_row_filter "name:regex:^gha_test_${JID}_" redirect csv ./ous.csv print ous fromparent "aaaGithub Actions"
|
||||
run_gam csv ./ous.csv gam delete ou ~orgUnitId
|
||||
run_gam config csv_output_row_filter "email:regex:^gha_test_${JID}_" redirect csv ./cigroups.csv print cigroups
|
||||
run_gam csv ./cigroups.csv gam delete cigroup ~email
|
||||
run_gam config csv_output_row_filter "resourceId:regex:^gha_test_${JID}_" redirect csv ./resources.csv print resources
|
||||
run_gam csv ./resources.csv gam delete resource ~resourceId
|
||||
run_gam config csv_output_row_filter "buildingId:regex:^gha_test_${JID}_" redirect csv ./buildings.csv print buildings
|
||||
run_gam csv ./buildings.csv gam delete building ~buildingId
|
||||
|
||||
echo "Creating OrgUnit ${newou}"
|
||||
$gam create ou "${newou}"
|
||||
run_gam create ou "${newou}"
|
||||
export GAM_THREADS=5
|
||||
echo email > sample.csv;
|
||||
for i in {1..10}; do
|
||||
@@ -885,156 +964,165 @@ 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 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/98x98/000/fff.jpg
|
||||
$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 dev-null@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
|
||||
$gam config enable_dasa false save
|
||||
run_gam create user $newuser firstname GHA lastname $JID displayname "Github Actions ${JID}" password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com gha.jid $JID languages en+,en-GB- ou "${newou}"
|
||||
run_gam user $newuser add license workspaceenterpriseplus
|
||||
run_gam user $newuser update photo https://dummyimage.com/98x98/000/fff.jpg
|
||||
run_gam user $newuser get photo
|
||||
run_gam user $newuser delete photo
|
||||
run_gam create alias $newalias user $newuser
|
||||
run_gam create group $newgroup name "GHA $JID group" description "This is a description" isarchived true
|
||||
run_gam user $gam_user sendemail recipient dev-null@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
|
||||
run_gam config enable_dasa false save
|
||||
# don't expose policy output
|
||||
$gam show policies > policies.csv
|
||||
$gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary
|
||||
$gam print contacts
|
||||
$gam print privileges
|
||||
$gam config enable_dasa true save
|
||||
$gam update cigroup $newgroup security memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
|
||||
$gam info cigroup $newgroup
|
||||
$gam update group $newgroup add owner $gam_user
|
||||
$gam update group $newgroup add member $newuser
|
||||
$gam config enable_dasa false save
|
||||
run_gam show policies > policies.csv
|
||||
run_gam create contact firstname GHA lastname "$JID" email work "${newbase}@example.com" primary
|
||||
run_gam print contacts
|
||||
run_gam print privileges
|
||||
run_gam config enable_dasa true save
|
||||
run_gam update cigroup $newgroup security memberrestriction 'member.type == 1 || member.customer_id == groupCustomerId()'
|
||||
run_gam info cigroup $newgroup
|
||||
run_gam update group $newgroup add owner $gam_user
|
||||
run_gam update group $newgroup add member $newuser
|
||||
run_gam config enable_dasa false save
|
||||
# 9/17/24 temp disable due to Google API sluggishness to see new users for admin commands
|
||||
# $gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
|
||||
# run_gam create admin $newuser _GROUPS_EDITOR_ROLE CUSTOMER # condition nonsecuritygroup
|
||||
# 9/13/25 temp disable due to hangs
|
||||
# $gam create admin $newgroup _HELP_DESK_ADMIN_ROLE org_unit "${newou}"
|
||||
# $gam config csv_output_row_filter "assignedToUser:regex:${newuser}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
|
||||
# $gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | $gam csv - gam delete admin "~roleAssignmentId"
|
||||
$gam config enable_dasa false save
|
||||
$gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID ou "${newou}"
|
||||
$gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random displayname "GitHub Actions Bulk ${JID}"
|
||||
$gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail ""
|
||||
$gam config enable_dasa false save
|
||||
$gam csv sample.csv gam user ~email add license workspaceenterpriseplus
|
||||
#$gam user $newuser add contactdelegate "${newbase}-bulkuser-1"
|
||||
#$gam user $newuser print contactdelegates
|
||||
$gam config enable_dasa true save
|
||||
$gam csv sample.csv gam user $gam_user sendemail recipient ~~email~~@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
|
||||
$gam csv sample.csv gam update group $newgroup add member ~email
|
||||
$gam info group $newgroup
|
||||
$gam info cigroup $newgroup membertree
|
||||
# run_gam create admin $newgroup _HELP_DESK_ADMIN_ROLE org_unit "${newou}"
|
||||
# run_gam config csv_output_row_filter "assignedToUser:regex:${newuser}" print admins | run_gam csv - gam delete admin "~roleAssignmentId"
|
||||
# run_gam config csv_output_row_filter "assignedToGroup:regex:${newgroup}" print admins | run_gam csv - gam delete admin "~roleAssignmentId"
|
||||
run_gam config enable_dasa false save
|
||||
run_gam csv sample.csv gam create user ~~email~~ firstname "GHA Bulk" lastname ~~email~~ gha.jid $JID ou "${newou}"
|
||||
run_gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random displayname "GitHub Actions Bulk ${JID}"
|
||||
run_gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail ""
|
||||
run_gam config enable_dasa false save
|
||||
run_gam csv sample.csv gam user ~email add license workspaceenterpriseplus
|
||||
#run_gam user $newuser add contactdelegate "${newbase}-bulkuser-1"
|
||||
#run_gam user $newuser print contactdelegates
|
||||
run_gam config enable_dasa true save
|
||||
run_gam csv sample.csv gam user $gam_user sendemail recipient ~~email~~@pdl.jaylee.us subject "test message $newbase" message "GHA test message"
|
||||
run_gam csv sample.csv gam update group $newgroup add member ~email
|
||||
run_gam info group $newgroup
|
||||
run_gam info cigroup $newgroup membertree
|
||||
# confirm mailbox is provisoned before continuing
|
||||
$gam user $newuser waitformailbox retries 50
|
||||
$gam user $newuser imap on
|
||||
$gam user $newuser show imap
|
||||
$gam user $newuser show delegates
|
||||
run_gam user $newuser waitformailbox retries 50
|
||||
run_gam user $newuser imap on
|
||||
run_gam user $newuser show imap
|
||||
run_gam user $newuser show delegates
|
||||
export biohazard=$(echo -e '\xe2\x98\xa3')
|
||||
$gam user $newuser label "$biohazard unicode biohazard $biohazard"
|
||||
$gam user $newuser show labels
|
||||
$gam user $newuser show labels > labels.txt
|
||||
$gam user $gam_user importemail subject "GHA import $newbase" message "This is a test import" labels IMPORTANT,UNREAD,INBOX,STARRED
|
||||
$gam user $gam_user insertemail subject "GHA insert $newbase" file gam.py labels INBOX,UNREAD # yep body is gam code
|
||||
$gam user $gam_user sendemail recipient admin@pdl.jaylee.us subject "GHA send $gam_user $newbase" file gam.py
|
||||
$gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
|
||||
$gam csvfile sample.csv:email waitformailbox retries 20
|
||||
$gam user $newuser delegate to "${newbase}-bulkuser-1" || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (delegation failed)
|
||||
$gam users "$gam_user $newbase-bulkuser-1 $newbase-bulkuser-2 $newbase-bulkuser-3" delete messages query in:anywhere maxtodelete 99999 doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages)
|
||||
$gam users "$newbase-bulkuser-4 $newbase-bulkuser-5 $newbase-bulkuser-6" trash messages query in:anywhere maxtotrash 99999 doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages)
|
||||
$gam users "$newbase-bulkuser-7 $newbase-bulkuser-8 $newbase-bulkuser-9" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit || if [ $? != 60 ]; then exit $?; fi # expect a 60 return code (no messages)
|
||||
$gam user $newuser delete label --ALL_LABELS--
|
||||
$gam config csv_output_row_filter "name:regex:gha-test-${JID}" print features | $gam csv - gam delete feature ~name
|
||||
$gam create feature name VC-$newbase
|
||||
$gam create feature name Whiteboard-$newbase
|
||||
$gam create building "My Building - $newbase" id $newbuilding floors 1,2,3,4,5,6,7,8,9,10,11,12,14,15 description "No 13th floor here..."
|
||||
$gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room
|
||||
$gam info resource $newresource
|
||||
$gam user $newuser add drivefile drivefilename "TPS Reports" mimetype gfolder
|
||||
$gam user $newuser show filelist
|
||||
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id # clear ACLs
|
||||
$gam calendar $gam_user add read domain
|
||||
$gam calendar $gam_user add freebusy default
|
||||
$gam calendar $gam_user add editor $newuser
|
||||
$gam calendar $gam_user showacl
|
||||
$gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete ~id
|
||||
$gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all
|
||||
$gam calendar $gam_user printevents after -0d
|
||||
$gam config enable_dasa false save
|
||||
run_gam user $newuser label "$biohazard unicode biohazard $biohazard"
|
||||
run_gam user $newuser show labels
|
||||
run_gam user $newuser show labels > labels.txt
|
||||
run_gam user $gam_user importemail subject "GHA import $newbase" message "This is a test import" labels IMPORTANT,UNREAD,INBOX,STARRED
|
||||
run_gam user $gam_user insertemail subject "GHA insert $newbase" file gam.py labels INBOX,UNREAD # yep body is gam code
|
||||
run_gam user $gam_user sendemail recipient admin@pdl.jaylee.us subject "GHA send $gam_user $newbase" file gam.py
|
||||
run_gam user $gam_user draftemail subject "GHA draft $newbase" message "Draft message test"
|
||||
run_gam csvfile sample.csv:email waitformailbox retries 20
|
||||
run_gam user $newuser delegate to "${newbase}-bulkuser-1" || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (delegation failed)
|
||||
run_gam -a "0 60" users "$gam_user $newbase-bulkuser-1 $newbase-bulkuser-2 $newbase-bulkuser-3" delete messages query in:anywhere maxtodelete 99999 doit
|
||||
run_gam -a "0 60" users "$newbase-bulkuser-4 $newbase-bulkuser-5 $newbase-bulkuser-6" trash messages query in:anywhere maxtotrash 99999 doit
|
||||
run_gam -a "0 60" users "$newbase-bulkuser-7 $newbase-bulkuser-8 $newbase-bulkuser-9" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit
|
||||
run_gam user $newuser delete label --ALL_LABELS--
|
||||
run_gam config csv_output_row_filter "name:regex:gha-test-${JID}" redirect csv ./features.csv print features
|
||||
run_gam csv ./features.csv gam delete feature ~name
|
||||
run_gam create feature name VC-$newbase
|
||||
run_gam create feature name Whiteboard-$newbase
|
||||
run_gam create building "My Building - $newbase" id $newbuilding floors 1,2,3,4,5,6,7,8,9,10,11,12,14,15 description "No 13th floor here..."
|
||||
run_gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room
|
||||
run_gam info resource $newresource
|
||||
run_gam user $newuser add drivefile drivefilename "TPS Reports" mimetype gfolder
|
||||
run_gam user $newuser show filelist
|
||||
run_gam redirect csv ./cal-acl.csv calendar $gam_user printacl
|
||||
run_gam csv ./cal-acl.csv gam calendar $gam_user delete ~id # clear ACLs
|
||||
run_gam calendar $gam_user add read domain
|
||||
run_gam calendar $gam_user add freebusy default
|
||||
run_gam calendar $gam_user add editor $newuser
|
||||
run_gam calendar $gam_user showacl
|
||||
run_gam redirect csv ./cal-acl.csv calendar $gam_user printacl
|
||||
run_gam csv ./cal-acl.csv gam calendar $gam_user delete ~id
|
||||
run_gam calendar $gam_user addevent summary "GHA test event" start +1h end +2h attendee $newgroup hangoutsmeet guestscanmodify true sendupdates all
|
||||
run_gam calendar $gam_user printevents after -0d
|
||||
run_gam config enable_dasa false save
|
||||
matterid=uid:$($gam create vaultmatter name "GHA matter $newbase" description "test matter" returnidonly)
|
||||
$gam create vaulthold matter $matterid name "GHA hold ${newbase}" corpus mail ou "$newou"
|
||||
$gam print vaultmatters matterstate open
|
||||
$gam print vaultholds matter $matterid
|
||||
$gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser
|
||||
$gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail ou "$newou"
|
||||
$gam print exports matter $matterid | $gam csv - gam info export $matterid id:~~id~~
|
||||
$gam config enable_dasa true save
|
||||
$gam csv sample.csv gam user ~email add calendar id:$newresource
|
||||
$gam delete resource $newresource
|
||||
$gam delete feature Whiteboard-$newbase
|
||||
$gam delete feature VC-$newbase
|
||||
$gam delete building $newbuilding
|
||||
$gam delete group $newgroup
|
||||
$gam config enable_dasa false save
|
||||
run_gam create vaulthold matter "$matterid" name "GHA hold ${newbase}" corpus mail ou "$newou"
|
||||
run_gam print vaultmatters matterstate open
|
||||
run_gam print vaultholds matter $matterid
|
||||
run_gam print vaultcount matter $matterid corpus mail everyone todrive tdnobrowser
|
||||
run_gam create vaultexport matter $matterid name "GHA export $newbase" corpus mail ou "$newou"
|
||||
run_gam redirect csv ./exports.csv print exports matter $matterid
|
||||
run_gam csv ./exports.csv gam info export $matterid id:~~id~~
|
||||
run_gam config enable_dasa true save
|
||||
run_gam csv sample.csv gam user ~email add calendar id:$newresource
|
||||
run_gam delete resource $newresource
|
||||
run_gam delete feature Whiteboard-$newbase
|
||||
run_gam delete feature VC-$newbase
|
||||
run_gam delete building $newbuilding
|
||||
run_gam delete group $newgroup
|
||||
run_gam config enable_dasa false save
|
||||
echo start
|
||||
$gam user $newuser delete license workspaceenterpriseplus
|
||||
run_gam user $newuser delete license workspaceenterpriseplus
|
||||
echo finish
|
||||
$gam config enable_dasa true save
|
||||
$gam whatis $newuser || if [ $? != 20 ]; then exit $?; fi # expect a 20 return code (is a user)
|
||||
$gam user $gam_user show tokens
|
||||
$gam config enable_dasa false save
|
||||
run_gam config enable_dasa true save
|
||||
run_gam -a "0 20" whatis $newuser
|
||||
run_gam user $gam_user show tokens
|
||||
run_gam config enable_dasa false save
|
||||
download_dir="${RUNNER_TEMP}/TEMP_DELETE_ME"
|
||||
mkdir -v "$download_dir"
|
||||
$gam print exports matter $matterid | $gam csv - gam download export $matterid id:~~id~~ targetfolder "$download_dir"
|
||||
run_gam redirect csv ./exports.csv print exports matter $matterid
|
||||
run_gam csv ./exports.csv gam download export $matterid id:~~id~~ targetfolder "$download_dir"
|
||||
rm -rvf "$download_dir"
|
||||
$gam delete hold "GHA hold $newbase" matter $matterid
|
||||
$gam update matter $matterid action close
|
||||
$gam update matter $matterid action delete
|
||||
run_gam delete hold "GHA hold $newbase" matter $matterid
|
||||
run_gam update matter $matterid action close
|
||||
run_gam update matter $matterid action delete
|
||||
# shakes off vault hold on user so we can delete
|
||||
$gam print users query "email:${newuser}" orgunitpath | $gam csv - gam update user ~primaryEmail ou ~orgUnitPath
|
||||
$gam user $newuser show holds || if [ $? != 55 ]; then exit $?; fi # expect a 55 return code
|
||||
run_gam redirect csv ./users.csv print users query "email:${newuser}" orgunitpath
|
||||
run_gam csv ./users.csv gam update user ~primaryEmail ou ~orgUnitPath
|
||||
run_gam user $newuser show holds || if [ $? != 55 ]; then exit $?; fi # expect a 55 return code
|
||||
export sn="$JID$JID$JID$JID-$(openssl rand -base64 32 | sed 's/[^a-zA-Z0-9]//g')"
|
||||
$gam create device serialnumber $sn devicetype android
|
||||
$gam delete contacts emailmatchpattern "^${newbase}@example.com$"
|
||||
$gam config enable_dasa true save
|
||||
$gam print users query "gha.jid=$JID" | $gam csv - gam delete user ~primaryEmail || if [ $? != 50 ]; then exit $?; fi # expect a 50 return code (vault hold on user)
|
||||
$gam print mobile
|
||||
$gam print devices clientstates
|
||||
$gam print browsers
|
||||
$gam print cros allfields orderby serialnumber
|
||||
$gam show crostelemetry storagepercentonly
|
||||
$gam report usageparameters customer
|
||||
$gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
|
||||
$gam report customer todrive tdnobrowser
|
||||
#$gam report users fields accounts:is_less_secure_apps_access_allowed,gmail:last_imap_time,gmail:last_pop_time filters "accounts:last_login_time>2025-01-01T00:00:00.000Z" todrive tdnobrowser
|
||||
$gam report users todrive tdnobrowser
|
||||
$gam report admin start -3d todrive tdnobrowser
|
||||
$gam print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-" | $gam csv - gam delete device id ~name
|
||||
$gam config enable_dasa false save
|
||||
$gam print userinvitations
|
||||
$gam print userinvitations | $gam csv - gam send userinvitation ~name
|
||||
$gam config enable_dasa false save
|
||||
$gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition
|
||||
$gam print caalevels
|
||||
$gam delete caalevel "zzz_${newbase}"
|
||||
$gam user $gam_user add drivefile localfile gam.py parentid "${driveid}"
|
||||
$gam user $gam_user update shareddrive "${driveid}" ou "${newou}"
|
||||
$gam user $gam_user show shareddrives asadmin
|
||||
$gam user $gam_user update shareddrive "${driveid}" ou "aaaGithub Actions" # so we can delete our OU...
|
||||
$gam user $gam_user delete shareddrive "${driveid}" nukefromorbit
|
||||
ssoprofile=$($gam config debug_level 1 create inboundssoprofile name "El Goog ${newbase}" loginurl https://www.google.com logouturl https://www.google.com changepasswordurl https://www.google.com entityid ElGoog return_name_only)
|
||||
run_gam create device serialnumber $sn devicetype android
|
||||
run_gam delete contacts emailmatchpattern "^${newbase}@example.com$"
|
||||
run_gam config enable_dasa true save
|
||||
run_gam redirect csv ./users.csv print users query "gha.jid=$JID"
|
||||
run_gam -a "0 50" csv ./users.csv gam delete user ~primaryEmail
|
||||
run_gam print mobile
|
||||
run_gam print devices clientstates
|
||||
run_gam print browsers
|
||||
run_gam print cros allfields orderby serialnumber
|
||||
run_gam show crostelemetry storagepercentonly
|
||||
run_gam report usageparameters customer
|
||||
run_gam report usage customer parameters gmail:num_emails_sent,accounts:num_1day_logins
|
||||
run_gam report customer todrive tdnobrowser
|
||||
#run_gam report users fields accounts:is_less_secure_apps_access_allowed,gmail:last_imap_time,gmail:last_pop_time filters "accounts:last_login_time>2025-01-01T00:00:00.000Z" todrive tdnobrowser
|
||||
run_gam report users todrive tdnobrowser
|
||||
run_gam report admin start -3d todrive tdnobrowser
|
||||
run_gam redirect csv ./devices.csv print devices nopersonaldevices nodeviceusers filter "serial:$JID$JID$JID$JID-"
|
||||
run_gam csv ./devices.csv gam delete device id ~name
|
||||
run_gam config enable_dasa false save
|
||||
run_gam print userinvitations
|
||||
run_gam redirect csv ./invitations.csv print userinvitations
|
||||
run_gam csv ./invitations.csv gam send userinvitation ~name
|
||||
run_gam config enable_dasa false save
|
||||
run_gam create caalevel "zzz_${newbase}" basic condition ipsubnetworks 1.1.1.1/32,2.2.2.2/32 endcondition
|
||||
run_gam print caalevels
|
||||
run_gam delete caalevel "zzz_${newbase}"
|
||||
run_gam user $gam_user add drivefile localfile gam.py parentid "${driveid}"
|
||||
run_gam user $gam_user update shareddrive "${driveid}" ou "${newou}"
|
||||
run_gam user $gam_user show shareddrives asadmin
|
||||
run_gam user $gam_user update shareddrive "${driveid}" ou "aaaGithub Actions" # so we can delete our OU...
|
||||
run_gam user $gam_user delete shareddrive "${driveid}" nukefromorbit
|
||||
ssoprofile=$(run_gam config debug_level 1 create inboundssoprofile name "El Goog ${newbase}" loginurl https://www.google.com logouturl https://www.google.com changepasswordurl https://www.google.com entityid ElGoog return_name_only)
|
||||
if [ ${ssoprofile} != 'inProgress' ]; then
|
||||
$gam create inboundssocredential profile "id:${ssoprofile}" generate_key
|
||||
#$gam create inboundssoassignment profile "id:${ssoprofile}" orgunit "${newou}" mode SAML_SSO
|
||||
#$gam delete inboundssoassignment "orgunit:${newou}"
|
||||
$gam delete inboundssoprofile "id:${ssoprofile}"
|
||||
run_gam create inboundssocredential profile "id:${ssoprofile}" generate_key
|
||||
#run_gam create inboundssoassignment profile "id:${ssoprofile}" orgunit "${newou}" mode SAML_SSO
|
||||
#run_gam delete inboundssoassignment "orgunit:${newou}"
|
||||
run_gam delete inboundssoprofile "id:${ssoprofile}"
|
||||
fi
|
||||
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)}')
|
||||
$gam info printer "$printerid"
|
||||
$gam delete printer "$printerid"
|
||||
$gam delete ou "${newou}"
|
||||
run_gam print printermodels | wc -l
|
||||
run_gam print printers
|
||||
printerid=$($gam create printer displayname "${newbase}" uri ipp://localhost:631 driverless description "made by ${gam_user}" ou "${newou}" returnIdOnly)
|
||||
run_gam info printer "$printerid"
|
||||
run_gam delete printer "$printerid"
|
||||
run_gam delete ou "${newou}"
|
||||
|
||||
- name: Tar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit != 'true'
|
||||
@@ -1048,24 +1136,10 @@ jobs:
|
||||
echo '.git*' > ./excludes.txt
|
||||
tar cJvvf cache.tar.xz --exclude-from=excludes.txt $tar_folders
|
||||
|
||||
merge:
|
||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
|
||||
runs-on: ubuntu-24.04
|
||||
needs: build
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
steps:
|
||||
- name: Merge Artifacts
|
||||
uses: actions/upload-artifact/merge@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: gam-binaries
|
||||
pattern: gam-binaries-*
|
||||
|
||||
publish:
|
||||
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
runs-on: ubuntu-24.04
|
||||
needs: merge
|
||||
needs: build
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
@@ -1073,13 +1147,17 @@ jobs:
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # 5.0.0
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
path: gam-binaries/
|
||||
merge-multiple: true
|
||||
skip-decompress: true
|
||||
|
||||
- name: VirusTotal Scan
|
||||
uses: crazy-max/ghaction-virustotal@d34968c958ae283fe976efed637081b9f9dcf74f # 4.2.0
|
||||
@@ -1096,7 +1174,7 @@ jobs:
|
||||
echo "dateversion=${dateversion}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish draft release
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
||||
with:
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
48
.github/workflows/get-cacerts.yml
vendored
48
.github/workflows/get-cacerts.yml
vendored
@@ -17,7 +17,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
check-certs:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
|
||||
with:
|
||||
@@ -30,9 +30,51 @@ jobs:
|
||||
echo "Current hash is: ${CURRENT_HASH}"
|
||||
echo "CURRENT_HASH=${CURRENT_HASH}" >> $GITHUB_ENV
|
||||
|
||||
- name: Get latest cacerts.pem file from Google
|
||||
- name: Generate GAM-specific bundle with LE + Google roots
|
||||
run: |
|
||||
curl -o ./cacerts.pem -vvvv https://pki.goog/roots.pem
|
||||
OUTPUT_FILE="cacerts.pem"
|
||||
> "$OUTPUT_FILE"
|
||||
|
||||
process_cert() {
|
||||
local url="$1"
|
||||
local op_ca="$2"
|
||||
local label="$3"
|
||||
local tmp_cert=$(mktemp)
|
||||
curl "$url" > "$tmp_cert"
|
||||
local issuer=$(openssl x509 -noout -issuer -in "$tmp_cert" | sed -e 's/^issuer= *//')
|
||||
local subject=$(openssl x509 -noout -subject -in "$tmp_cert" | sed -e 's/^subject= *//')
|
||||
local serial_hex=$(openssl x509 -noout -serial -in "$tmp_cert" | sed -e 's/^serial=//')
|
||||
local serial_dec=$(python3 -c "print(int('$serial_hex', 16))")
|
||||
local md5=$(openssl x509 -noout -fingerprint -md5 -in "$tmp_cert" | sed -e 's/.*=//' | tr '[:upper:]' '[:lower:]')
|
||||
local sha1=$(openssl x509 -noout -fingerprint -sha1 -in "$tmp_cert" | sed -e 's/.*=//' | tr '[:upper:]' '[:lower:]')
|
||||
local sha256=$(openssl x509 -noout -fingerprint -sha256 -in "$tmp_cert" | sed -e 's/.*=//' | tr '[:upper:]' '[:lower:]')
|
||||
echo "# Operating CA: $op_ca" >> "$OUTPUT_FILE"
|
||||
echo "# Issuer: $issuer" >> "$OUTPUT_FILE"
|
||||
echo "# Subject: $subject" >> "$OUTPUT_FILE"
|
||||
echo "# Label: \"$label\"" >> "$OUTPUT_FILE"
|
||||
echo "# Serial: $serial_dec" >> "$OUTPUT_FILE"
|
||||
echo "# MD5 Fingerprint: $md5" >> "$OUTPUT_FILE"
|
||||
echo "# SHA1 Fingerprint: $sha1" >> "$OUTPUT_FILE"
|
||||
echo "# SHA256 Fingerprint: $sha256" >> "$OUTPUT_FILE"
|
||||
cat "$tmp_cert" >> "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
rm "$tmp_cert"
|
||||
}
|
||||
|
||||
echo "#" >> "$OUTPUT_FILE"
|
||||
echo "# This is a custom certificate authority bundle for GAM" >> "$OUTPUT_FILE"
|
||||
echo "# It's composed of Let's Encrypt Root CAs and Google's" >> "$OUTPUT_FILE"
|
||||
echo "# certificate bundle. This should be the minimal list of" >> "$OUTPUT_FILE"
|
||||
echo "# CAs required to talk to Google and Github." >> "$OUTPUT_FILE"
|
||||
echo"" >> "$OUTPUT_FILE"
|
||||
echo "Processing Let's Encrypt ISRG Root X1..."
|
||||
process_cert "https://letsencrypt.org/certs/isrgrootx1.pem" "Let's Encrypt" "ISRG Root X1"
|
||||
echo "Processing Let's Encrypt ISRG Root X2..."
|
||||
process_cert "https://letsencrypt.org/certs/isrg-root-x2.pem" "Let's Encrypt" "ISRG Root X2"
|
||||
|
||||
echo "Appending Google's roots.pem..."
|
||||
curl -s https://pki.goog/roots.pem >> "$OUTPUT_FILE"
|
||||
echo "Done! The new bundle has been saved to $OUTPUT_FILE."
|
||||
|
||||
- name: Compare hashes
|
||||
run: |
|
||||
|
||||
@@ -11,7 +11,7 @@ authors = [
|
||||
#significant compile dependencies.
|
||||
dependencies = [
|
||||
"arrow>=1.3.0",
|
||||
"chardet>=5.2.0",
|
||||
"chardet==5.2.0",
|
||||
"cryptography>=46.0.5",
|
||||
"distro; sys_platform=='linux'",
|
||||
"filelock>=3.18.0",
|
||||
@@ -31,11 +31,11 @@ requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
license = {text = "Apache License (2.0)"}
|
||||
|
||||
@@ -4568,8 +4568,8 @@ gam check ou|org <OrgUnitItem> [todrive <ToDriveAttribute>*]
|
||||
usedriverlessconfig|
|
||||
<PrinterFieldNameList> ::= "<PrinterFieldName>(,<PrinterFieldName>)*"
|
||||
|
||||
gam create printer <PrinterAttribute>+
|
||||
gam update printer <PrinterID> <PrinterAttribute>+
|
||||
gam create printer <PrinterAttribute>+ [nodetails|returnidonly]
|
||||
gam update printer <PrinterID> <PrinterAttribute>+ [nodetails|returnidonly]
|
||||
gam delete printer
|
||||
<PrinterIDList>|
|
||||
<FileSelector>|
|
||||
@@ -5693,6 +5693,7 @@ gam download storagefile <StorageBucketObjectName>
|
||||
fullname|
|
||||
gender|
|
||||
givenname|firstname|
|
||||
guestaccountinfo|
|
||||
id|
|
||||
ims|im|
|
||||
includeinglobaladdresslist|gal|
|
||||
@@ -5700,6 +5701,7 @@ gam download storagefile <StorageBucketObjectName>
|
||||
isdelegatedadmin|admin|isadmin|
|
||||
isenforcedin2sv|is2svenforced|
|
||||
isenrolledin2sv|is2svenrolled|
|
||||
isguestuser|
|
||||
ismailboxsetup|
|
||||
keyword|keywords|
|
||||
language|languages|
|
||||
|
||||
@@ -1,3 +1,58 @@
|
||||
7.35.00
|
||||
|
||||
Updated cacerts.pem to avoid to following error in `gam checkconn`.
|
||||
```
|
||||
Checking raw.githubusercontent.com (185.199.110.133) (2)... ERROR
|
||||
Certificate verification failed. If you are behind a firewall / proxy server that does TLS / SSL inspection you may need to point GAM at your certificate authority file by setting cacerts_pem = /path/to/your/certauth.pem in gam.cfg.
|
||||
```
|
||||
|
||||
7.34.13
|
||||
|
||||
Fixed bug in `gam info policies <CIPolicyNameEntity> ... formatjson` where extraneous line
|
||||
`Show Info 1 Policy` was displayed.
|
||||
|
||||
7.34.12
|
||||
|
||||
Fixed build errors that prevented Windows zip files from being created.
|
||||
|
||||
Added option `returnidonly` to `gam create|update printer` that causes GAM to return just the ID
|
||||
of the printer.
|
||||
|
||||
7.34.11
|
||||
|
||||
Updated gam-install.sh script for macOS/Linux to properly config GAM when the answer to the following question is No.
|
||||
```
|
||||
Can you run a full browser on this machine? (usually Y for macOS, N for Linux if you SSH into this machine)
|
||||
```
|
||||
|
||||
7.34.10
|
||||
|
||||
Fixed bug where `formatjson quotechar <Character>` on the command line did not override `redirect csv <FileName> multiprocess quotechar <Character>`.
|
||||
|
||||
7.34.09
|
||||
|
||||
Updated `gam <UserTypeEntity> update photo` to delete the user's existing photo
|
||||
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
|
||||
|
||||
7.34.08
|
||||
|
||||
Rebuild to avoid the following error:
|
||||
```
|
||||
requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
|
||||
```
|
||||
|
||||
7.34.07
|
||||
|
||||
Added the following command to create a guest user.
|
||||
* See: https://support.google.com/a/answer/16558545
|
||||
```
|
||||
gam create guestuser <EmailAddress>
|
||||
```
|
||||
|
||||
Added the following items to `<UserFieldName>`:
|
||||
* `guestaccountinfo` - Additional guest-related metadata fields
|
||||
* `isguestuser` - Indicates if the inserted user is a guest
|
||||
|
||||
7.34.06
|
||||
|
||||
Added option `copyfolderpermissions [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`.
|
||||
@@ -1499,7 +1554,7 @@ Re-run the command specify a new service account name with: saname <ServiceAccou
|
||||
|
||||
Native support for Windows 11 Arm-based devices.
|
||||
|
||||
Renamed some MacOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".
|
||||
Renamed some macOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".
|
||||
|
||||
7.06.05
|
||||
|
||||
@@ -2108,7 +2163,7 @@ for `[R] 35) Meet API (supports readonly)` as it is a special case.
|
||||
|
||||
7.00.39
|
||||
|
||||
Supported MacOS versions are now in the download filename.
|
||||
Supported macOS versions are now in the download filename.
|
||||
|
||||
Minor code fixes.
|
||||
|
||||
@@ -3911,11 +3966,11 @@ See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#fil
|
||||
|
||||
6.65.12
|
||||
|
||||
Additional updates on MacOS when a `gam csv` command is interrupted with a contol-C.
|
||||
Additional updates on macOS when a `gam csv` command is interrupted with a contol-C.
|
||||
|
||||
6.65.11
|
||||
|
||||
Updated multiprocessing to handle the following error that occurs on MacOS when a `gam csv` command
|
||||
Updated multiprocessing to handle the following error that occurs on macOS when a `gam csv` command
|
||||
is interrupted with a contol-C.
|
||||
```
|
||||
multiprocessing/resource_tracker.py:224: UserWarning: resource_tracker: There appear to be N leaked semaphore objects to clean up at shutdown
|
||||
@@ -6076,7 +6131,7 @@ Improved code for `gam [<UserTypeEntity>] create teamdrive <Name> ou <OrgUnitIte
|
||||
|
||||
6.29.04
|
||||
|
||||
Updated multiprocessing on MacOS to use `spawn` instead of `fork` when starting subprocesses
|
||||
Updated multiprocessing on macOS to use `spawn` instead of `fork` when starting subprocesses
|
||||
as `fork` was unreliable when large numbers (>20) of threads were used; subprocesses would
|
||||
hang and never complete.
|
||||
|
||||
@@ -6198,7 +6253,7 @@ then filters the list to only those in `<PeopleContactGroupItem>`; quota limits
|
||||
|
||||
6.28.03
|
||||
|
||||
Build MacOS x86_64 and arm64 executables.
|
||||
Build macOS x86_64 and arm64 executables.
|
||||
|
||||
6.28.02
|
||||
|
||||
@@ -6545,7 +6600,7 @@ Added command that allows checking if a user is a member of specific groups and
|
||||
|
||||
6.26.00
|
||||
|
||||
Build MacOS universal version.
|
||||
Build macOS universal version.
|
||||
|
||||
* Upgraded to OpenSSL 3.0.5 where possible.
|
||||
|
||||
@@ -11387,7 +11442,7 @@ ID of the created Team Drive as output. This will be useful in scripts that crea
|
||||
want to perform subsequent GAM command on the Team Drive. This ID will only be valid when the return code
|
||||
of the command is 0; program accordingly.
|
||||
```
|
||||
Linux/MacOS
|
||||
Linux/macOS
|
||||
teamDriveId=`gam user user@domain.com create teamdrive ... returnidonly`
|
||||
Windows PowerShell
|
||||
$teamDriveId = & gam user user@domain.com create teamdrive ... returnidonly`
|
||||
@@ -11479,7 +11534,7 @@ file ID of the created file as output. This will be useful in scripts that creat
|
||||
want to perform subsequent GAM command on the file. This file ID will only be valid when the return code
|
||||
of the command is 0; program accordingly.
|
||||
```
|
||||
Linux/MacOS
|
||||
Linux/macOS
|
||||
fileId=`gam user user@domain.com create drivefile ... returnidonly`
|
||||
Windows PowerShell
|
||||
$fileId = & gam user user@domain.com create drivefile ... returnidonly`
|
||||
@@ -15562,7 +15617,7 @@ gam print group-members [todrive [<ToDriveAttribute>]]
|
||||
|
||||
4.55.44
|
||||
|
||||
Improve MacOS version of GAM's use of OpenSSL 1.0.2n.
|
||||
Improve macOS version of GAM's use of OpenSSL 1.0.2n.
|
||||
Recode pyinstaller .spec files.
|
||||
|
||||
4.55.43
|
||||
@@ -15589,7 +15644,7 @@ Fixed bug that made some gam print commands throw an exception.
|
||||
|
||||
4.55.40
|
||||
|
||||
Update MacOS version of GAM to use OpenSSL 1.0.2n.
|
||||
Update macOS version of GAM to use OpenSSL 1.0.2n.
|
||||
|
||||
4.55.39
|
||||
|
||||
@@ -18415,7 +18470,7 @@ Changed gam info user formatjson to show licenses in SKU ID (SKU Display Name) f
|
||||
4.42.00
|
||||
|
||||
Fixed problem where control-C was not recognized when multiple processes were running via gam batch/csv.
|
||||
Gam terminates cleanly on Linux/MacOS when you hit control-C in this situation; on Windows exceptions are
|
||||
Gam terminates cleanly on Linux/macOS when you hit control-C in this situation; on Windows exceptions are
|
||||
thrown but Gam does terminate.
|
||||
|
||||
4.41.08
|
||||
|
||||
@@ -10,7 +10,7 @@ OPTIONS:
|
||||
-d Directory where gam folder will be installed. Default is \$HOME/bin/
|
||||
-a Architecture to install (x86_64, arm64). Default is to detect your arch with "uname -m".
|
||||
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
|
||||
-b OS version. Default is to detect on MacOS and Linux.
|
||||
-b OS version. Default is to detect on macOS and Linux.
|
||||
-l Just upgrade GAM to latest version. Skips project creation and auth.
|
||||
-p Profile update (true, false). Should script add gam command to environment. Default is true.
|
||||
-u Admin user email address to use with GAM. Default is to prompt.
|
||||
@@ -247,7 +247,7 @@ case $gamos in
|
||||
archgrep="-arm64\|-aarch64"
|
||||
;;
|
||||
*)
|
||||
echo_red "ERROR: this installer currently only supports x86_64 and arm64 MacOS. Looks like you're running on ${gamarch}. Exiting."
|
||||
echo_red "ERROR: this installer currently only supports x86_64 and arm64 macOS. Looks like you're running on ${gamarch}. Exiting."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
@@ -256,19 +256,19 @@ case $gamos in
|
||||
versionless_urls=$(echo -e "$gam_macos_urls" | \
|
||||
grep -e "-macos-")
|
||||
if [ "$versionless_urls" == "" ]; then
|
||||
# versions after 7.00.38 include MacOS version info
|
||||
# versions after 7.00.38 include macOS version info
|
||||
gam_macos_vers=$(echo -e "$gam_macos_urls" | \
|
||||
grep --only-matching -e '-macos[0-9\.]*' | \
|
||||
cut -c 7-10)
|
||||
for gam_mac_ver in $gam_macos_vers; do
|
||||
if version_gt $currentversion $gam_mac_ver; then
|
||||
download_url=$(echo -e "$gam_macos_urls" | grep "$gam_mac_ver")
|
||||
echo_green "You are running MacOS ${currentversion} Using GAM compiled against ${gam_mac_ver}"
|
||||
echo_green "You are running macOS ${currentversion} Using GAM compiled against ${gam_mac_ver}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z ${download_url+x} ]; then
|
||||
echo_red "Sorry, you are running MacOS ${osversion} but GAM on ${gamarch} requires MacOS ${gam_mac_ver} or newer. Exiting."
|
||||
echo_red "Sorry, you are running macOS ${osversion} but GAM on ${gamarch} requires macOS ${gam_mac_ver} or newer. Exiting."
|
||||
exit
|
||||
fi
|
||||
else
|
||||
@@ -283,13 +283,13 @@ case $gamos in
|
||||
esac
|
||||
download_url=$(echo -e "$download_urls" | grep -e $archgrep)
|
||||
if version_gt "$osversion" "$minimum_version"; then
|
||||
echo_green "You are running MacOS ${osversion}, good. Downloading GAM from ${download_url}."
|
||||
echo_green "You are running macOS ${osversion}, good. Downloading GAM from ${download_url}."
|
||||
else
|
||||
echo_red "Sorry, you are running MacOS ${osversion} but GAM on ${gamarch} requires MacOS ${minimum_version}. Exiting."
|
||||
echo_red "Sorry, you are running macOS ${osversion} but GAM on ${gamarch} requires macOS ${minimum_version}. Exiting."
|
||||
exit
|
||||
fi
|
||||
if [ -z ${download_url+x} ]; then
|
||||
echo_red "Sorry, you are running MacOS ${currentversion} but GAM on ${gamarch} requires MacOS ${minimum_version}. Exiting."
|
||||
echo_red "Sorry, you are running macOS ${currentversion} but GAM on ${gamarch} requires macOS ${minimum_version}. Exiting."
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
@@ -302,7 +302,7 @@ case $gamos in
|
||||
grep ".zip")
|
||||
;;
|
||||
*)
|
||||
echo_red "Sorry, this installer currently only supports Linux and MacOS. Looks like you're running on ${gamos}. Exiting."
|
||||
echo_red "Sorry, this installer currently only supports Linux and macOS. Looks like you're running on ${gamos}. Exiting."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
@@ -368,18 +368,15 @@ if [ "$upgrade_only" = true ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Set config command
|
||||
#config_cmd="config no_browser false"
|
||||
|
||||
while true; do
|
||||
read -p "Can you run a full browser on this machine? (usually Y for MacOS, N for Linux if you SSH into this machine) " yn
|
||||
read -p "Can you run a full browser on this machine? (usually Y for macOS, N for Linux if you SSH into this machine) " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
"$target_gam" config no_browser false save
|
||||
break
|
||||
;;
|
||||
[Nn]*)
|
||||
# config_cmd="config no_browser true"
|
||||
touch "$target_folder/nobrowser.txt" > /dev/null 2>&1
|
||||
"$target_gam" config no_browser true save
|
||||
break
|
||||
;;
|
||||
*)
|
||||
@@ -397,7 +394,6 @@ while true; do
|
||||
if [ "$adminuser" == "" ]; then
|
||||
read -p "Please enter your Google Workspace admin email address: " adminuser
|
||||
fi
|
||||
# "$target_gam" $config_cmd create project $adminuser
|
||||
"$target_gam" create project $adminuser
|
||||
rc=$?
|
||||
if (( $rc == 0 )); then
|
||||
@@ -423,7 +419,6 @@ while $project_created; do
|
||||
read -p "Are you ready to authorize GAM to perform Google Workspace management operations as your admin account? (yes or no) " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
# "$target_gam" $config_cmd oauth create $adminuser
|
||||
"$target_gam" oauth create $adminuser
|
||||
rc=$?
|
||||
if (( $rc == 0 )); then
|
||||
@@ -453,7 +448,6 @@ while $admin_authorized; do
|
||||
read -p "Please enter the email address of a regular Google Workspace user: " regularuser
|
||||
fi
|
||||
echo_yellow "Great! Checking service account scopes.This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console."
|
||||
# "$target_gam" $config_cmd user $regularuser check serviceaccount
|
||||
"$target_gam" user $regularuser check serviceaccount
|
||||
rc=$?
|
||||
if (( $rc == 0 )); then
|
||||
@@ -475,7 +469,6 @@ while $admin_authorized; do
|
||||
done
|
||||
|
||||
echo_green "Here's information about your new GAM installation:"
|
||||
#"$target_gam" $config_cmd save version extended
|
||||
"$target_gam" version extended
|
||||
rc=$?
|
||||
if (( $rc != 0 )); then
|
||||
|
||||
116
src/gam.iss
Normal file
116
src/gam.iss
Normal file
@@ -0,0 +1,116 @@
|
||||
; --- 1. PREPROCESSOR DEFINITIONS ---
|
||||
#define AppVersion GetEnv("GAMVERSION")
|
||||
#if AppVersion == ""
|
||||
#define AppVersion "7.0.0"
|
||||
#endif
|
||||
|
||||
; Pull architecture directly from GitHub Actions environment variable
|
||||
#define RunnerArch GetEnv("RUNNER_ARCH")
|
||||
|
||||
[Setup]
|
||||
; --- 2. CORE APPLICATION INFO ---
|
||||
AppId={{D86B52B2-EFE9-4F9D-8BA3-9D84B9B2D319}
|
||||
AppName=GAM7
|
||||
AppVersion={#AppVersion}
|
||||
AppPublisher=GAM Team - google-apps-manager@googlegroups.com
|
||||
DefaultDirName={sd}\GAM7
|
||||
LicenseFile=dist\gam\gam7\LICENSE
|
||||
PrivilegesRequired=admin
|
||||
ChangesEnvironment=yes
|
||||
|
||||
; Tell Inno Setup to use a custom signtool defined via the command line
|
||||
SignTool=gamsigntool
|
||||
|
||||
; --- 3. COMPRESSION & OPTIMIZATION ---
|
||||
Compression=lzma2/ultra64
|
||||
SolidCompression=yes
|
||||
|
||||
; --- 4. DYNAMIC ARCHITECTURE CONFIGURATION ---
|
||||
; GitHub Actions RUNNER_ARCH is typically uppercase "ARM64" or "X64"
|
||||
#if RunnerArch == "ARM64" || RunnerArch == "arm64"
|
||||
ArchitecturesAllowed=arm64
|
||||
ArchitecturesInstallIn64BitMode=arm64
|
||||
OutputBaseFilename=gam-{#AppVersion}-windows-arm64
|
||||
#else
|
||||
ArchitecturesAllowed=x64compatible
|
||||
ArchitecturesInstallIn64BitMode=x64compatible
|
||||
OutputBaseFilename=gam-{#AppVersion}-windows-x86_64
|
||||
#endif
|
||||
|
||||
[Messages]
|
||||
; Custom error if an admin tries to run the ARM64 installer on an Intel machine
|
||||
#if RunnerArch == "ARM64" || RunnerArch == "arm64"
|
||||
WindowsVersionNotSupported=You downloaded the ARM64 version of GAM, but this computer has an Intel or AMD processor.%n%nPlease go back to the release page and download the x86_64 installer instead.
|
||||
#endif
|
||||
|
||||
[Files]
|
||||
; --- 5. DYNAMIC FILE INCLUSION ---
|
||||
Source: "dist\gam\gam7\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Registry]
|
||||
; --- 6. PATH ENVIRONMENT VARIABLE ---
|
||||
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
|
||||
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; \
|
||||
Check: NeedsAddPath(ExpandConstant('{app}'))
|
||||
|
||||
[Code]
|
||||
const
|
||||
ERROR_SUCCESS = 0;
|
||||
|
||||
function MsiEnumRelatedProducts(lpUpgradeCode: string; dwReserved: Integer; iProductIndex: Integer; lpProductBuf: string): Integer;
|
||||
external 'MsiEnumRelatedProductsW@msi.dll stdcall';
|
||||
|
||||
function UninstallWixMSI(): Boolean;
|
||||
var
|
||||
UpgradeCode: string;
|
||||
ProductCode: string;
|
||||
ResultCode: Integer;
|
||||
begin
|
||||
UpgradeCode := '{D86B52B2-EFE9-4F9D-8BA3-9D84B9B2D319}';
|
||||
ProductCode := StringOfChar(' ', 39);
|
||||
|
||||
ResultCode := MsiEnumRelatedProducts(UpgradeCode, 0, 0, ProductCode);
|
||||
|
||||
if ResultCode = ERROR_SUCCESS then
|
||||
begin
|
||||
ProductCode := Trim(ProductCode);
|
||||
Exec('msiexec.exe', '/x ' + ProductCode + ' /qn /norestart', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function InitializeSetup(): Boolean;
|
||||
begin
|
||||
// --- Architecture Warning for Emulation ---
|
||||
#if RunnerArch != "ARM64" && RunnerArch != "arm64"
|
||||
if IsArm64() then
|
||||
begin
|
||||
if MsgBox('Notice: You are installing the Intel (x86_64) build of GAM on an ARM processor.' + #13#10#13#10 +
|
||||
'While this will work via Windows emulation, it will perform worse than the native ARM64 version.' + #13#10#13#10 +
|
||||
'Do you want to continue with the installation anyway?',
|
||||
mbConfirmation, MB_YESNO) = idNo then
|
||||
begin
|
||||
Result := False;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
#endif
|
||||
|
||||
UninstallWixMSI();
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function NeedsAddPath(Param: string): boolean;
|
||||
var
|
||||
OrigPath: string;
|
||||
begin
|
||||
if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
|
||||
'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
|
||||
'Path', OrigPath)
|
||||
then begin
|
||||
Result := True;
|
||||
exit;
|
||||
end;
|
||||
Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
|
||||
end;
|
||||
@@ -8,7 +8,7 @@
|
||||
Manufacturer="GAM Team - google-apps-manager@googlegroups.com"
|
||||
UpgradeCode="D86B52B2-EFE9-4F9D-8BA3-9D84B9B2D319">
|
||||
<Package
|
||||
InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
|
||||
InstallerVersion="500" Compressed="yes" InstallScope="perMachine" />
|
||||
|
||||
<MajorUpgrade
|
||||
DowngradeErrorMessage=
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.34.06'
|
||||
__version__ = '7.35.00'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
@@ -4688,7 +4688,7 @@ def writeClientCredentials(creds, filename):
|
||||
if filename != '-':
|
||||
writeFile(filename, json.dumps(creds_data, indent=2, sort_keys=True)+'\n')
|
||||
else:
|
||||
writeStdout(json.dumps(creds_data, ensure_ascii=False, sort_keys=True, indent=2)+'\n')
|
||||
writeStdout(json.dumps(creds_data, ensure_ascii=False, indent=2, sort_keys=True)+'\n')
|
||||
|
||||
URL_SHORTENER_ENDPOINT = 'https://gam-shortn.appspot.com/create'
|
||||
|
||||
@@ -9499,6 +9499,33 @@ def getOSPlatform():
|
||||
pltfrm = platform.platform()
|
||||
return f'{myos} {pltfrm}'
|
||||
|
||||
def inspect_untrusted_cert(url):
|
||||
"""Bypasses validation momentarily to extract the untrusted Issuer."""
|
||||
parsed = urlparse(url if '://' in url else f'https://{url}')
|
||||
host = parsed.hostname
|
||||
port = parsed.port or 443
|
||||
# Create an unverified context purely for diagnostic extraction
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
try:
|
||||
with socket.create_connection((host, port), timeout=5) as sock:
|
||||
with ctx.wrap_socket(sock, server_hostname=host) as ssock:
|
||||
der_cert = ssock.getpeercert(binary_form=True)
|
||||
cert = x509.load_der_x509_certificate(der_cert, default_backend())
|
||||
issuer = cert.issuer.rfc4514_string()
|
||||
subject = cert.subject.rfc4514_string()
|
||||
try:
|
||||
san_ext = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
|
||||
# Loop through the list of SANs (DNS names, IP addresses, etc.)
|
||||
sans = [str(name.value) for name in san_ext.value]
|
||||
san_str = ", ".join(sans)
|
||||
except x509.ExtensionNotFound:
|
||||
san_str = "None"
|
||||
return f"Untrusted Issuer: {issuer}\n Server Subject: {subject}\n SANs: {san_str}"
|
||||
except Exception as e:
|
||||
return f"Failed to retrieve diagnostic certificate: {e}"
|
||||
|
||||
# gam checkconnection
|
||||
def doCheckConnection():
|
||||
|
||||
@@ -9534,6 +9561,10 @@ def doCheckConnection():
|
||||
writeStdout(f'{not_okay}\n Connection reset by peer. {gen_firewall}\n')
|
||||
except httplib2.error.ServerNotFoundError:
|
||||
writeStdout(f'{not_okay}\n Failed to find server. Your DNS is probably misconfigured.\n')
|
||||
except ssl.SSLCertVerificationError as e:
|
||||
diag_info = inspect_untrusted_cert(host)
|
||||
# e.verify_message contains the specific OpenSSL error string
|
||||
writeStdout(f'{not_okay}\n Certificate verification failed: {e.verify_message}\n Diagnostic Info:\n {diag_info}\nIf you are behind a firewall / proxy server that does TLS / SSL inspection you may need to point GAM at your certificate authority file by setting cacerts_pem = /path/to/your/certauth.pem in gam.cfg.\n')
|
||||
except ssl.SSLError as e:
|
||||
if e.reason == 'SSLV3_ALERT_HANDSHAKE_FAILURE':
|
||||
writeStdout(f'{not_okay}\n GAM expects to connect with TLS 1.3 or newer and that failed. If your firewall / proxy server is not compatible with TLS 1.3 then you can tell GAM to allow TLS 1.2 by setting tls_min_version = TLSv1.2 in gam.cfg.\n')
|
||||
@@ -9725,8 +9756,6 @@ def CSVFileQueueHandler(mpQueue, mpQueueStdout, mpQueueStderr, csvPF, datetimeNo
|
||||
GC.Values[GC.TIMEZONE] = tzinfo
|
||||
GC.Values[GC.OUTPUT_TIMEFORMAT] = output_timeformat
|
||||
clearRowFilters = False
|
||||
# if sys.platform.startswith('win'):
|
||||
# signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
if multiprocessing.get_start_method() != 'fork':
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
Cmd = glclargs.GamCLArgs()
|
||||
@@ -9776,7 +9805,7 @@ def CSVFileQueueHandler(mpQueue, mpQueueStdout, mpQueueStderr, csvPF, datetimeNo
|
||||
GC.Values = dataItem
|
||||
csvPF.SetColumnDelimiter(GC.Values[GC.CSV_OUTPUT_COLUMN_DELIMITER])
|
||||
csvPF.SetNoEscapeChar(GC.Values[GC.CSV_OUTPUT_NO_ESCAPE_CHAR])
|
||||
csvPF.SetQuoteChar(GC.Values[GC.CSV_OUTPUT_QUOTE_CHAR])
|
||||
# csvPF.SetQuoteChar(GC.Values[GC.CSV_OUTPUT_QUOTE_CHAR])
|
||||
csvPF.SetSortHeaders(GC.Values[GC.CSV_OUTPUT_SORT_HEADERS])
|
||||
csvPF.SetTimestampColumn(GC.Values[GC.CSV_OUTPUT_TIMESTAMP_COLUMN])
|
||||
csvPF.SetHeaderFilter(GC.Values[GC.CSV_OUTPUT_HEADER_FILTER])
|
||||
@@ -9843,8 +9872,6 @@ def StdQueueHandler(mpQueue, stdtype, gmGlobals, gcValues):
|
||||
except IOError as e:
|
||||
systemErrorExit(FILE_ERROR_RC, fdErrorMessage(fd, GM.Globals[stdtype][GM.REDIRECT_NAME], e))
|
||||
|
||||
# if sys.platform.startswith('win'):
|
||||
# signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
if multiprocessing.get_start_method() != 'fork':
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
GM.Globals = gmGlobals.copy()
|
||||
@@ -9938,7 +9965,6 @@ def ProcessGAMCommandMulti(pid, numItems, logCmd, mpQueueCSVFile, mpQueueStdout,
|
||||
|
||||
with mplock:
|
||||
initializeLogging()
|
||||
# if sys.platform.startswith('win'):
|
||||
if multiprocessing.get_start_method() != 'fork':
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
GM.Globals[GM.API_CALLS_RETRY_DATA] = {}
|
||||
@@ -12480,7 +12506,7 @@ def checkServiceAccount(users):
|
||||
saScopes[API.DRIVE2] = saScopes[API.DRIVE3]
|
||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA][API.OAUTH2SA_SCOPES] = saScopes
|
||||
writeFile(GC.Values[GC.OAUTH2SERVICE_JSON],
|
||||
json.dumps(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA], ensure_ascii=False, sort_keys=True, indent=2),
|
||||
json.dumps(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA], ensure_ascii=False, indent=2, sort_keys=True),
|
||||
continueOnError=False)
|
||||
checkScopes = sorted(checkScopesSet)
|
||||
jcount = len(checkScopes)
|
||||
@@ -12967,7 +12993,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
|
||||
except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e:
|
||||
invalidOauth2serviceJsonExit(str(e))
|
||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA][API.OAUTH2SA_SCOPES] = GM.Globals[GM.SVCACCT_SCOPES]
|
||||
oauth2service_data = json.dumps(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA], ensure_ascii=False, sort_keys=True, indent=2)
|
||||
oauth2service_data = json.dumps(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA], ensure_ascii=False, indent=2, sort_keys=True)
|
||||
writeFile(GC.Values[GC.OAUTH2SERVICE_JSON], oauth2service_data, continueOnError=False)
|
||||
Act.Set(Act.UPDATE)
|
||||
entityActionPerformed([Ent.OAUTH2SERVICE_JSON_FILE, GC.Values[GC.OAUTH2SERVICE_JSON],
|
||||
@@ -13133,7 +13159,7 @@ def doCreateGCPServiceAccount():
|
||||
except GAPI.invalid as e:
|
||||
systemErrorExit(API_ACCESS_DENIED_RC, str(e))
|
||||
sa_info['client_id'] = token_info['issued_to']
|
||||
sa_output = json.dumps(sa_info, ensure_ascii=False, sort_keys=True, indent=2)
|
||||
sa_output = json.dumps(sa_info, ensure_ascii=False, indent=2, sort_keys=True)
|
||||
writeStdout(f'Writing SignJWT service account data:\n\n{sa_output}\n')
|
||||
writeFile(GC.Values[GC.OAUTH2SERVICE_JSON], sa_output, continueOnError=False)
|
||||
|
||||
@@ -31661,6 +31687,7 @@ UPDATE_PRINTER_JSON_SKIP_FIELDS = ['id', 'name', 'createTime', 'orgUnitId', 'org
|
||||
def _getPrinterAttributes(cd, jsonDeleteFields):
|
||||
'''get printer attributes for create/update commands'''
|
||||
body = {}
|
||||
returnIdOnly = False
|
||||
showDetails = True
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
@@ -31679,13 +31706,15 @@ def _getPrinterAttributes(cd, jsonDeleteFields):
|
||||
body['useDriverlessConfig'] = getBoolean()
|
||||
elif myarg == 'nodetails':
|
||||
showDetails = False
|
||||
elif myarg == 'returnidonly':
|
||||
returnIdOnly = True
|
||||
elif myarg == 'json':
|
||||
body.update(getJSON(jsonDeleteFields))
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
if body.get('makeAndModel'):
|
||||
body.pop('useDriverlessConfig', None)
|
||||
return (body, showDetails)
|
||||
return (body, showDetails, returnIdOnly)
|
||||
|
||||
PRINTER_FIELDS_CHOICE_MAP = {
|
||||
'auxiliarymessages': 'auxiliaryMessages',
|
||||
@@ -31731,33 +31760,39 @@ def _showPrinter(cd, printer, FJQC, orgUnitId=None, showInherited=False, i=0, co
|
||||
showJSON(None, printer, timeObjects=PRINTER_TIME_OBJECTS)
|
||||
Ind.Decrement()
|
||||
|
||||
# gam create printer <PrinterAttribute>+ [nodetails]
|
||||
# gam create printer <PrinterAttribute>+ [nodetails|returnidonly]
|
||||
def doCreatePrinter():
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
parent = _getCustomersCustomerIdWithC()
|
||||
body, showDetails = _getPrinterAttributes(cd, CREATE_PRINTER_JSON_SKIP_FIELDS)
|
||||
body, showDetails, returnIdOnly = _getPrinterAttributes(cd, CREATE_PRINTER_JSON_SKIP_FIELDS)
|
||||
if not body.get('orgUnitId'):
|
||||
missingArgumentExit('orgunit')
|
||||
try:
|
||||
printer = callGAPI(cd.customers().chrome().printers(), 'create',
|
||||
throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
parent=parent, body=body)
|
||||
if returnIdOnly:
|
||||
writeStdout(f"{printer['id']}\n")
|
||||
return
|
||||
entityActionPerformed([Ent.PRINTER, printer['id']])
|
||||
if showDetails:
|
||||
_showPrinter(cd, printer, None)
|
||||
except (GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
entityActionFailedWarning([Ent.PRINTER, None], str(e))
|
||||
|
||||
# gam update printer <PrinterID> <PrinterAttribute>+ [nodetails]
|
||||
# gam update printer <PrinterID> <PrinterAttribute>+ [nodetails|returnidonly]
|
||||
def doUpdatePrinter():
|
||||
name, printerId, cd = _getPrinterID()
|
||||
body, showDetails = _getPrinterAttributes(cd, UPDATE_PRINTER_JSON_SKIP_FIELDS)
|
||||
body, showDetails, returnIdOnly = _getPrinterAttributes(cd, UPDATE_PRINTER_JSON_SKIP_FIELDS)
|
||||
updateMask = ','.join(list(body.keys()))
|
||||
# note clearMask seems unnecessary. Updating field to '' clears it.
|
||||
try:
|
||||
printer = callGAPI(cd.customers().chrome().printers(), 'patch',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
name=name, updateMask=updateMask, body=body)
|
||||
if returnIdOnly:
|
||||
writeStdout(f"{printer['id']}\n")
|
||||
return
|
||||
entityActionPerformed([Ent.PRINTER, printerId])
|
||||
if showDetails:
|
||||
_showPrinter(cd, printer, None)
|
||||
@@ -37770,8 +37805,7 @@ def _cleanPolicy(policy, add_warnings, no_appnames,
|
||||
def _showPolicy(policy, FJQC, i=0, count=0):
|
||||
if FJQC is not None and FJQC.formatJSON:
|
||||
printLine(json.dumps(cleanJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS),
|
||||
ensure_ascii=False,
|
||||
sort_keys=True))
|
||||
ensure_ascii=False, sort_keys=True))
|
||||
return
|
||||
printEntity([Ent.POLICY, policy['name']], i, count)
|
||||
Ind.Increment()
|
||||
@@ -37784,10 +37818,11 @@ def _showPolicies(policies, FJQC, add_warnings, no_appnames,
|
||||
groupEmailPattern, orgUnitPathPattern,
|
||||
cd, groups_ci):
|
||||
count = len(policies)
|
||||
if groupEmailPattern is None and orgUnitPathPattern is None:
|
||||
performActionNumItems(count, Ent.POLICY)
|
||||
else:
|
||||
performActionModifierNumItems(Msg.MAXIMUM_OF, count, Ent.POLICY)
|
||||
if FJQC is None or not FJQC.formatJSON:
|
||||
if groupEmailPattern is None and orgUnitPathPattern is None:
|
||||
performActionNumItems(count, Ent.POLICY)
|
||||
else:
|
||||
performActionModifierNumItems(Msg.MAXIMUM_OF, count, Ent.POLICY)
|
||||
Ind.Increment()
|
||||
i = 0
|
||||
for policy in policies:
|
||||
@@ -37998,8 +38033,7 @@ def doPrintShowCIPolicies():
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'name': policy['name'],
|
||||
'JSON': json.dumps(cleanJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS),
|
||||
ensure_ascii=False,
|
||||
sort_keys=True)})
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
|
||||
_checkPoliciesWithDASA()
|
||||
ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY)
|
||||
@@ -39636,8 +39670,7 @@ def doPrintShowBuildings():
|
||||
else:
|
||||
if (not csvPF.rowFilter and not csvPF.rowDropFilter) or csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'buildingId': building['buildingId'],
|
||||
'JSON': json.dumps(cleanJSON(building),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
'JSON': json.dumps(cleanJSON(building), ensure_ascii=False, sort_keys=True)})
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Buildings')
|
||||
|
||||
@@ -40545,8 +40578,8 @@ def _printShowCalendarACLs(cal, user, entityType, calId, i, count, csvPF, FJQC,
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
row = {'calendarId': calId, 'JSON': json.dumps(cleanJSON(rule),
|
||||
ensure_ascii=False, sort_keys=False)}
|
||||
row = {'calendarId': calId,
|
||||
'JSON': json.dumps(cleanJSON(rule), ensure_ascii=False, sort_keys=False)}
|
||||
if user:
|
||||
row['primaryEmail'] = user
|
||||
if addCSVData:
|
||||
@@ -40565,8 +40598,8 @@ def _printShowCalendarACLs(cal, user, entityType, calId, i, count, csvPF, FJQC,
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
row = {'resourceId': user, 'resourceEmail': calId, 'JSON': json.dumps(cleanJSON(rule),
|
||||
ensure_ascii=False, sort_keys=False)}
|
||||
row = {'resourceId': user, 'resourceEmail': calId,
|
||||
'JSON': json.dumps(cleanJSON(rule), ensure_ascii=False, sort_keys=False)}
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
@@ -46009,10 +46042,13 @@ def doCreateGuestUser():
|
||||
checkForExtraneousArguments()
|
||||
try:
|
||||
result = callGAPI(cd.users(), 'createGuest',
|
||||
throwReasons=[GAPI.FAILED_PRECONDITION],
|
||||
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.INVALID_ARGUMENT],
|
||||
body=body)
|
||||
entityActionPerformed([Ent.GUEST_USER, result['primaryGuestEmail']])
|
||||
except (GAPI.failedPrecondition) as e:
|
||||
entityActionPerformed([Ent.GUEST_USER, body['primaryGuestEmail']])
|
||||
Ind.Increment()
|
||||
showJSON(None, result)
|
||||
Ind.Decrement()
|
||||
except (GAPI.failedPrecondition, GAPI.invalidArgument) as e:
|
||||
entityActionFailedExit([Ent.GUEST_USER, body['primaryGuestEmail']], str(e))
|
||||
|
||||
# gam <UserTypeEntity> update user <UserAttribute>*
|
||||
@@ -46624,8 +46660,9 @@ USER_FIELDS_CHOICE_MAP = {
|
||||
'firstname': 'name.givenName',
|
||||
'fullname': 'name.fullName',
|
||||
'gal': 'includeInGlobalAddressList',
|
||||
'givenname': 'name.givenName',
|
||||
'gender': ['gender.type', 'gender.customGender', 'gender.addressMeAs'],
|
||||
'givenname': 'name.givenName',
|
||||
'guestaccountinfo': 'guestAccountInfo',
|
||||
'id': 'id',
|
||||
'im': 'ims',
|
||||
'ims': 'ims',
|
||||
@@ -46635,6 +46672,7 @@ USER_FIELDS_CHOICE_MAP = {
|
||||
'isdelegatedadmin': ['isAdmin', 'isDelegatedAdmin'],
|
||||
'isenforcedin2sv': 'isEnforcedIn2Sv',
|
||||
'isenrolledin2sv': 'isEnrolledIn2Sv',
|
||||
'isguestuser': 'isGuestUser',
|
||||
'is2svenforced': 'isEnforcedIn2Sv',
|
||||
'is2svenrolled': 'isEnrolledIn2Sv',
|
||||
'ismailboxsetup': 'isMailboxSetup',
|
||||
@@ -48318,8 +48356,7 @@ def doPrintShowInboundSSOProfiles():
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'name': profile['name'],
|
||||
'JSON': json.dumps(cleanJSON(profile),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
'JSON': json.dumps(cleanJSON(profile), ensure_ascii=False, sort_keys=True)})
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Inbound SSO Profiles')
|
||||
|
||||
@@ -48800,8 +48837,7 @@ def doPrintShowInboundSSOAssignments():
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
csvPF.WriteRowNoFilter({'name': assignment['name'],
|
||||
'JSON': json.dumps(cleanJSON(assignment),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
'JSON': json.dumps(cleanJSON(assignment), ensure_ascii=False, sort_keys=True)})
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Inbound SSO Assignments')
|
||||
|
||||
@@ -68168,8 +68204,7 @@ def printShowDriveLabelPermissions(users, useAdminAccess=False):
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
row = {'User': user, 'name': labelperm['name']}
|
||||
row['JSON'] = json.dumps(cleanJSON(labelperm),
|
||||
ensure_ascii=False, sort_keys=True)
|
||||
row['JSON'] = json.dumps(cleanJSON(labelperm), ensure_ascii=False, sort_keys=True)
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
except (GAPI.permissionDenied, GAPI.notFound) as e:
|
||||
entityActionFailedWarning(kvList, str(e), j, jcount)
|
||||
@@ -70905,8 +70940,7 @@ def printShowGroupTree(users):
|
||||
row = {'User': user, 'Group': groupEmail, 'Name': group['name']}
|
||||
if rolesSet:
|
||||
row['Role'] = role
|
||||
row['JSON'] = json.dumps(cleanJSON(groupInfo),
|
||||
ensure_ascii=False, sort_keys=True)
|
||||
row['JSON'] = json.dumps(cleanJSON(groupInfo), ensure_ascii=False, sort_keys=True)
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
Ind.Decrement()
|
||||
if csvPF:
|
||||
@@ -71335,6 +71369,13 @@ def updatePhoto(users):
|
||||
continue
|
||||
body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)}
|
||||
try:
|
||||
try:
|
||||
callGAPI(cd.users().photos(), 'delete',
|
||||
bailOnInternalError=True,
|
||||
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.PHOTO_NOT_FOUND, GAPI.INTERNAL_ERROR],
|
||||
userKey=user)
|
||||
except (GAPI.photoNotFound, GAPI.internalError):
|
||||
pass
|
||||
callGAPI(cd.users().photos(), 'update',
|
||||
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT, GAPI.CONDITION_NOT_MET],
|
||||
userKey=user, body=body, fields='')
|
||||
@@ -78628,7 +78669,8 @@ def _showTask(tasklist, task, j=0, jcount=0, FJQC=None, compact=False):
|
||||
task['tasklistId'] = tasklist
|
||||
task['taskId'] = f"{tasklist}/{task['id']}"
|
||||
if FJQC is not None and FJQC.formatJSON:
|
||||
printLine(json.dumps(cleanJSON(task, skipObjects=TASK_SKIP_OBJECTS, timeObjects=TASK_TIME_OBJECTS), ensure_ascii=False, sort_keys=True))
|
||||
printLine(json.dumps(cleanJSON(task, skipObjects=TASK_SKIP_OBJECTS, timeObjects=TASK_TIME_OBJECTS),
|
||||
ensure_ascii=False, sort_keys=True))
|
||||
return
|
||||
printEntity([Ent.TASK, task['taskId']], j, jcount)
|
||||
Ind.Increment()
|
||||
@@ -78972,7 +79014,8 @@ TASKLIST_TIME_OBJECTS = ['updated']
|
||||
|
||||
def _showTasklist(tasklist, j=0, jcount=0, FJQC=None):
|
||||
if FJQC is not None and FJQC.formatJSON:
|
||||
printLine(json.dumps(cleanJSON(tasklist, skipObjects=TASKLIST_SKIP_OBJECTS, timeObjects=TASKLIST_TIME_OBJECTS), ensure_ascii=False, sort_keys=True))
|
||||
printLine(json.dumps(cleanJSON(tasklist, skipObjects=TASKLIST_SKIP_OBJECTS, timeObjects=TASKLIST_TIME_OBJECTS),
|
||||
ensure_ascii=False, sort_keys=True))
|
||||
return
|
||||
printEntity([Ent.TASKLIST, tasklist['id']], j, jcount)
|
||||
Ind.Increment()
|
||||
|
||||
@@ -1,3 +1,72 @@
|
||||
#
|
||||
# This is a custom certificate authority bundle for GAM
|
||||
# It's composed of Let's Encrypt Root CAs and Google's
|
||||
# certificate bundle. This should be the minimal list of
|
||||
# CAs required to talk to Google and Github.
|
||||
|
||||
# Operating CA: Let's Encrypt
|
||||
# Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1
|
||||
# Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1
|
||||
# Label: "ISRG Root X1"
|
||||
# Serial: 172886928669790476064670243504169061120
|
||||
# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e
|
||||
# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8
|
||||
# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: Let's Encrypt
|
||||
# Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2
|
||||
# Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X2
|
||||
# Label: "ISRG Root X2"
|
||||
# Serial: 87493402998870891108772069816698636114
|
||||
# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5
|
||||
# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af
|
||||
# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
|
||||
CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
|
||||
R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
|
||||
MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT
|
||||
ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw
|
||||
EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW
|
||||
+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9
|
||||
ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
|
||||
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI
|
||||
zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
|
||||
tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
|
||||
/q4AaOeMSQ+2b1tbFfLn
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Operating CA: DigiCert
|
||||
# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
\deftab720
|
||||
\pard\pardeftab720\sl276\slmult1\sa200\qc\partightenfactor0
|
||||
|
||||
\f0\fs22 \cf0 Copyright 2025 Jay Lee\
|
||||
\f0\fs22 \cf0 Copyright 2026 Jay Lee\
|
||||
\pard\pardeftab720\sa200\qc\partightenfactor0
|
||||
|
||||
\f1\b \cf0 Licensed under the Apache License, Version 2.0 (the "License");\
|
||||
|
||||
@@ -99,14 +99,25 @@ Typically, you will enclose the entire list in double quotes and quote each item
|
||||
## Manage printers
|
||||
When creating a printer you must specify: `displayname`, `ou`, `uri` and `makeandmodel` or `driverless`.
|
||||
```
|
||||
gam create printer <PrinterAttribute>+ [nodetails]
|
||||
gam update printer <PrinterID> <PrinterAttribute>+ [nodetails]
|
||||
gam create printer <PrinterAttribute>+ [nodetails|returnidonly]
|
||||
gam update printer <PrinterID> <PrinterAttribute>+ [nodetails|returnidonly]
|
||||
gam delete printer
|
||||
<PrinterIDList>|
|
||||
<FileSelector>|
|
||||
<CSVFileSelector>
|
||||
```
|
||||
By default, when a printer is created/updated, GAM outputs details of the printer; the `nodetails` option suppresses this output.
|
||||
By default, when a printer is created/updated, GAM outputs details of the printer.
|
||||
* `nodetails` - Suppress the datails output.
|
||||
* `returnidonly` - Display just the printer ID of the created printer as output
|
||||
|
||||
To retrieve the printer ID with `returnidonly`:
|
||||
```
|
||||
Linux/MacOS
|
||||
printerId=$(gam create printer ... returnidonly)
|
||||
Windows PowerShell
|
||||
$printerId = & gam create printer ... returnidonly
|
||||
```
|
||||
The printer ID will only be valid when the return code of the command is 0; program accordingly.
|
||||
|
||||
## Display printers
|
||||
Display information about a single printer.
|
||||
|
||||
@@ -10,6 +10,73 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.34.13
|
||||
|
||||
Fixed bug in `gam info policies <CIPolicyNameEntity> ... formatjson` where extraneous line
|
||||
`Show Info 1 Policy` was displayed.
|
||||
|
||||
### 7.34.12
|
||||
|
||||
Fixed build errors that prevented Windows zip files from being created.
|
||||
|
||||
Added option `returnidonly` to `gam create|update printer` that causes GAM to return just the ID
|
||||
of the printer.
|
||||
|
||||
### 7.34.11
|
||||
|
||||
Updated gam-install.sh script for macOS/Linux to properly config GAM when the answer to the following question is No.
|
||||
```
|
||||
Can you run a full browser on this machine? (usually Y for macOS, N for Linux if you SSH into this machine)
|
||||
```
|
||||
|
||||
### 7.34.10
|
||||
|
||||
Fixed bug where `formatjson quotechar <Character>` on the command line did not override `redirect csv <FileName> multiprocess quotechar <Character>`.
|
||||
|
||||
### 7.34.09
|
||||
|
||||
Updated `gam <UserTypeEntity> update photo` to delete the user's existing photo
|
||||
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
|
||||
|
||||
### 7.34.08
|
||||
|
||||
Rebuild to avoid the following error:
|
||||
```
|
||||
requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
|
||||
```
|
||||
|
||||
### 7.34.07
|
||||
|
||||
Added the following command to create a guest user.
|
||||
* See: https://support.google.com/a/answer/16558545
|
||||
```
|
||||
gam create guestuser <EmailAddress>
|
||||
```
|
||||
|
||||
Added the following items to `<UserFieldName>`:
|
||||
* `guestaccountinfo` - Additional guest-related metadata fields
|
||||
* `isguestuser` - Indicates if the inserted user is a guest
|
||||
|
||||
### 7.34.06
|
||||
|
||||
Added option `copyfolderpermissions [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`.
|
||||
|
||||
When `copyfolderpermissions false` is specified, no folder permissions are copied; this simplifies
|
||||
disabling all folder permission copying.
|
||||
|
||||
When not specified or `copyfolderpermissions [true]` is specified, folder permissions are copied based on the following options:
|
||||
```
|
||||
copymergewithparentfolderpermissions [<Boolean>]
|
||||
copymergedtopfolderpermissions [<Boolean>]
|
||||
copytopfolderpermissions [<Boolean>]
|
||||
copytopfolderiheritedpermissions [<Boolean>]
|
||||
copytopfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
|
||||
copymergedsubfolderpermissions [<Boolean>]
|
||||
copysubfolderpermissions [<Boolean>]
|
||||
copysubfolderinheritedpermissions [<Boolean>]
|
||||
copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
|
||||
```
|
||||
|
||||
### 7.34.05
|
||||
|
||||
Updated `gam report <ActivityApplictionName>` to perform a reverse chronological sort
|
||||
|
||||
@@ -252,7 +252,7 @@ writes the credentials into the file oauth2.txt.
|
||||
gamteam@server:/Users/gamteam$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
|
||||
gamteam@server:/Users/gamteam$ gam version
|
||||
WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/gamteam/GAMConfig/oauth2.txt, Not Found
|
||||
GAM 7.34.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.13 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -1036,7 +1036,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
|
||||
GAM 7.34.05 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.34.13 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
Windows 11 10.0.26200 AMD64
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Organizational Units
|
||||
- [API documentation](#api-documentation)
|
||||
- [Definitions](#definitions)
|
||||
- [Special character issues](#special-character-issues)
|
||||
- [Special quoting](#special-quoting)
|
||||
- [Manage organizational units](#manage-organizational-units)
|
||||
- [Add users to an organizational unit](#add-users-to-an-organizational-unit)
|
||||
@@ -50,6 +51,15 @@ For `<UserTypeEntity>`, see: [Collections of Users](Collections-Of-Users)
|
||||
|
||||
For `<CrOSTypeEntity>`, see: [Collections of ChromeOS Devices](Collections-of-ChromeOS-Devices)
|
||||
|
||||
## Special character issues
|
||||
If an organizational unit name contains a `#` or a `+`, these commands will not work due to a bug
|
||||
that Google does not plan to fix.
|
||||
```
|
||||
gam update org|ou <OrgUnitPath>
|
||||
gam delete org|ou <OrgUnitPath>
|
||||
gam info org|ou <OrgUnitPath>
|
||||
```
|
||||
|
||||
## Special quoting
|
||||
You specify a single organizational unit with `org <OrgUnitPath>` and a list of organizationsl units with `orgs <OrgUnitList>`.
|
||||
As organizational unit paths can contain spaces, some care must be used when entering `<OrgUnitPath>` and `<OrgUnitList>`.
|
||||
|
||||
@@ -120,6 +120,7 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
[copyfilepermissions [<Boolean>]]
|
||||
[copyfileinheritedpermissions [<Boolean>]
|
||||
[copyfilenoninheritedpermissions [<Boolean>]
|
||||
[copyfolderpermissions [<Boolean>]]
|
||||
[copymergewithparentfolderpermissions [<Boolean>]]
|
||||
[copymergedtopfolderpermissions [<Boolean>]]
|
||||
[copytopfolderpermissions [<Boolean>]]
|
||||
@@ -294,6 +295,8 @@ When a folder is copied, its permissions are not copied; these options control c
|
||||
of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When copied, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions.
|
||||
* `copyfolderpermissions false` - The permissions of the source folders are not copied to the target folder.
|
||||
* `copyfolderpermissions true` - The permissions of the source folders are copied to the target folder based on the following options; this is the default action.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
@@ -571,6 +574,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
|
||||
[createshortcutsfornonmovablefiles [<Boolean>]]
|
||||
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
|
||||
[duplicatefolders merge|duplicatename|uniquename|skip]
|
||||
[copyfolderpermissions [<Boolean>]]
|
||||
[copymergewithparentfolderpermissions [<Boolean>]]
|
||||
[copymergedtopfolderpermissions [<Boolean>]]
|
||||
[copytopfolderpermissions [<Boolean>]]
|
||||
@@ -660,6 +664,8 @@ When a folder is moved by recreating it, its permissions are not copied by the D
|
||||
For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions;
|
||||
* `copyfolderpermissions false` - The permissions of the source folders are not copied to the target folder.
|
||||
* `copyfolderpermissions true` - The permissions of the source folders are copied to the target folder based on the following options; this is the default action.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Users - Photo
|
||||
- [API documentation](#api-documentation)
|
||||
- [Notes](#notes)
|
||||
- [Definitions](#definitions)
|
||||
- [Upload a user's photo from a default file](#upload-a-users-photo-from-a-default-file)
|
||||
- [Upload a user's photo specifying file name](#upload-a-users-photo-specifying-file-name)
|
||||
@@ -7,11 +8,16 @@
|
||||
- [Upload a user's photo specifying a Google Drive owner and file name](#upload-a-users-photo-specifying-a-google-drive-owner-and-file-name)
|
||||
- [Download a user's photo](#download-a-users-photo)
|
||||
- [Delete a user's photo](#delete-a-users-photo)
|
||||
- [Update photo fails to change user's photo](#update-photo-fails-to-change-users-photo)
|
||||
- [Download a user's profile photo](Users-Profile-Photo)
|
||||
|
||||
## API documentation
|
||||
* [Directory API - Users Photos](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users.photos)
|
||||
|
||||
## Notes
|
||||
As of version 7.34.09, `gam <UserTypeEntity> update photo` was updated to delete the user's existing photo
|
||||
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
|
||||
|
||||
## Definitions
|
||||
* [`<DriveFileEntity>`](Drive-File-Selection)
|
||||
* [`<UserTypeEntity>`](Collections-of-Users)
|
||||
@@ -81,3 +87,7 @@ By default, the Base64 encoded data is dumped to stdout.
|
||||
```
|
||||
gam <UserTypeEntity> delete|del photo
|
||||
```
|
||||
|
||||
## Update photo fails to change user's photo
|
||||
If you use `gam <UserTypeEntity> update photo ...` to change a user's photo and the command succeeds
|
||||
but the photo doesn't change, use `gam <UserTypeEntity> delete photo` first and then do the update.
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
- [Print user list](#print-user-list)
|
||||
- [Display user counts](#display-user-counts)
|
||||
- [Verify domain membership](#verify-domain-membership)
|
||||
- [Guest Users](#guest-users)
|
||||
|
||||
## API documentation
|
||||
* [Directory API - Users](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users)
|
||||
@@ -169,6 +170,7 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
|
||||
fullname|
|
||||
gender|
|
||||
givenname|firstname|
|
||||
guestaccountinfo|
|
||||
id|
|
||||
ims|im|
|
||||
includeinglobaladdresslist|gal|
|
||||
@@ -176,6 +178,7 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
|
||||
isdelegatedadmin|admin|isadmin|
|
||||
isenforcedin2sv|is2svenforced|
|
||||
isenrolledin2sv|is2svenrolled|
|
||||
isguestuser|
|
||||
ismailboxsetup|
|
||||
keyword|keywords|
|
||||
language|languages|
|
||||
@@ -1384,3 +1387,11 @@ testuser1@domain.com,118080758787650801331,True,Test User 1
|
||||
testuserxxx@domain.com,,False,Test User XXX
|
||||
testuser2@domain.com,107344800159717682514,True,Test User 2
|
||||
```
|
||||
|
||||
## Guest Users
|
||||
* See: https://support.google.com/a/answer/16558545
|
||||
```
|
||||
gam create guestuser <EmailAddress>
|
||||
```
|
||||
|
||||
Guest users are in the OU "/Workspace guests".
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Version and Help
|
||||
\# Version and Help
|
||||
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.34.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.13 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -15,7 +15,7 @@ Time: 2026-02-15T07:51:00-08:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.34.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.13 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -27,7 +27,7 @@ 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
|
||||
GAM 7.34.05 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.13 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -68,7 +68,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.34.05
|
||||
Latest: 7.34.13
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -76,7 +76,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.34.05
|
||||
7.34.13
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -86,7 +86,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.34.05 - https://github.com/GAM-team/GAM
|
||||
GAM 7.34.13 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
|
||||
Reference in New Issue
Block a user