mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-29 18:31:38 +00:00
Compare commits
31 Commits
v7.06.06
...
20250425.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e95fcbaa38 | ||
|
|
a7b31550f3 | ||
|
|
ed19f877a5 | ||
|
|
0ab08c968e | ||
|
|
02a7a1a106 | ||
|
|
170a2e593b | ||
|
|
8339b92537 | ||
|
|
ce16aa252e | ||
|
|
8a70470281 | ||
|
|
981301a878 | ||
|
|
13cfb77811 | ||
|
|
458e08645d | ||
|
|
98d4d3c06f | ||
|
|
2204c35193 | ||
|
|
87827badb8 | ||
|
|
319bedd338 | ||
|
|
b3e4541b9d | ||
|
|
9d17ea2d68 | ||
|
|
9c4b348909 | ||
|
|
a8fafd0dcc | ||
|
|
ac31042576 | ||
|
|
a0d695c57d | ||
|
|
bf742ec88a | ||
|
|
f2206d02e4 | ||
|
|
c3add48f2a | ||
|
|
119047bf2b | ||
|
|
662b7d857c | ||
|
|
3bb9724e50 | ||
|
|
b450716c23 | ||
|
|
73333f921d | ||
|
|
c5d194489f |
18
.github/workflows/build.yml
vendored
18
.github/workflows/build.yml
vendored
@@ -28,6 +28,8 @@ env:
|
|||||||
OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl
|
OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl
|
||||||
PYTHON_INSTALL_PATH: ${{ github.workspace }}/bin/python
|
PYTHON_INSTALL_PATH: ${{ github.workspace }}/bin/python
|
||||||
PYTHON_SOURCE_PATH: ${{ github.workspace }}/src/cpython
|
PYTHON_SOURCE_PATH: ${{ github.workspace }}/src/cpython
|
||||||
|
CRYPTOGRAPHY_BUILD_OPENSSL_NO_LEGACY: 1
|
||||||
|
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -124,7 +126,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
cache.tar.xz
|
cache.tar.xz
|
||||||
key: gam-${{ matrix.jid }}-20250408-01
|
key: gam-${{ matrix.jid }}-20250422
|
||||||
|
|
||||||
- name: Untar Cache archive
|
- name: Untar Cache archive
|
||||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||||
@@ -197,7 +199,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "RUNNING: apt update..."
|
echo "RUNNING: apt update..."
|
||||||
sudo apt-get -qq --yes update
|
sudo apt-get -qq --yes update
|
||||||
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev libsqlite3-dev
|
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev libsqlite3-dev libffi-dev pkg-config
|
||||||
|
|
||||||
- name: MacOS install tools
|
- name: MacOS install tools
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
@@ -450,6 +452,9 @@ jobs:
|
|||||||
"$PYTHON" -m pip install --upgrade pip
|
"$PYTHON" -m pip install --upgrade pip
|
||||||
"$PYTHON" -m pip install --upgrade wheel
|
"$PYTHON" -m pip install --upgrade wheel
|
||||||
"$PYTHON" -m pip install --upgrade setuptools
|
"$PYTHON" -m pip install --upgrade setuptools
|
||||||
|
"$PYTHON" -m pip install --upgrade importlib-metadata
|
||||||
|
"$PYTHON" -m pip install --upgrade setuptools-scm
|
||||||
|
"$PYTHON" -m pip list
|
||||||
|
|
||||||
- name: Custom wheels for Win arm64
|
- name: Custom wheels for Win arm64
|
||||||
if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
||||||
@@ -462,7 +467,14 @@ jobs:
|
|||||||
echo "Downloading ${latest_crypt_whl}..."
|
echo "Downloading ${latest_crypt_whl}..."
|
||||||
curl -O -L "$latest_crypt_whl"
|
curl -O -L "$latest_crypt_whl"
|
||||||
"$PYTHON" -m pip install cryptography*.whl
|
"$PYTHON" -m pip install cryptography*.whl
|
||||||
|
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
|
||||||
|
# - name: Compile cryptography from source (no legacy)
|
||||||
|
# if: runner.os != 'Windows' || runner.arch != 'ARM64'
|
||||||
|
# run: |
|
||||||
|
# pip install --no-binary ":all:" --force cryptography
|
||||||
|
|
||||||
- name: Install pip requirements
|
- name: Install pip requirements
|
||||||
run: |
|
run: |
|
||||||
echo "before anything..."
|
echo "before anything..."
|
||||||
|
|||||||
2
.github/workflows/pypi.yml
vendored
2
.github/workflows/pypi.yml
vendored
@@ -31,3 +31,5 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish package distributions to PyPI
|
- name: Publish package distributions to PyPI
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
with:
|
||||||
|
attestation: true
|
||||||
|
|||||||
@@ -7,19 +7,21 @@ authors = [
|
|||||||
{ name="Jay Lee", email="jay0lee@gmail.com" },
|
{ name="Jay Lee", email="jay0lee@gmail.com" },
|
||||||
{ name="Ross Scroggs", email="Ross.Scroggs@gmail.com" },
|
{ name="Ross Scroggs", email="Ross.Scroggs@gmail.com" },
|
||||||
]
|
]
|
||||||
|
# # The following files should be edited to match: setup.cfg, requirements.txt
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chardet",
|
"chardet>=5.2.0",
|
||||||
"cryptography",
|
"cryptography>=44.0.2",
|
||||||
"distro; sys_platform=='linux'",
|
"distro; sys_platform=='linux'",
|
||||||
"filelock",
|
"filelock>=3.18.0",
|
||||||
"google-api-python-client>=2.1",
|
"google-api-python-client>=2.167.0",
|
||||||
"google-auth-httplib2",
|
"google-auth-httplib2>=0.2.0",
|
||||||
"google-auth-oauthlib>=0.4.1",
|
"google-auth-oauthlib>=1.2.2",
|
||||||
"google-auth>=2.3.2",
|
"google-auth>=2.39.0",
|
||||||
"httplib2>=0.17.0",
|
"httplib2>=0.22.0",
|
||||||
"lxml",
|
"lxml>=5.4.0",
|
||||||
"passlib>=1.7.2",
|
"passlib>=1.7.4",
|
||||||
"pathvalidate",
|
"pathvalidate>=3.2.3",
|
||||||
|
"pyscard==2.2.1",
|
||||||
"python-dateutil",
|
"python-dateutil",
|
||||||
]
|
]
|
||||||
description = "CLI tool to manage Google Workspace"
|
description = "CLI tool to manage Google Workspace"
|
||||||
@@ -39,7 +41,7 @@ license = {text = "Apache License (2.0)"}
|
|||||||
license-files = ["LICEN[CS]E*"]
|
license-files = ["LICEN[CS]E*"]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
yubikey = ["yubikey-manager>=5.0"]
|
yubikey = ["yubikey-manager>=5.6.1"]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
gam = "gam.__main__:main"
|
gam = "gam.__main__:main"
|
||||||
|
|||||||
@@ -322,7 +322,8 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
|
wsess | workspaceesentials | gsuiteessentials | essentials | d4e | driveenterprise | drive4enterprise | 1010060001 | Google Workspace Essentials |
|
||||||
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
|
wsessplus | workspaceessentialsplus | 1010060005 | Google Workspace Essentials Plus |
|
||||||
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
|
wsflw | workspacefrontline | workspacefrontlineworker | 1010020030 | Google Workspace Frontline Starter |
|
||||||
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard
|
wsflwstan | workspacefrontlinestan | workspacefrontlineworkerstan | 1010020031 | Google Workspace Frontline Standard |
|
||||||
|
wsflwplus | workspacefrontlineplus | workspacefrontlineworkerplus | 1010020034 | Google Workspace Frontline Plus
|
||||||
|
|
||||||
## Items built from primitives
|
## Items built from primitives
|
||||||
|
|
||||||
@@ -782,7 +783,7 @@ Items, separated by spaces, with spaces, commas or single quotes in the items th
|
|||||||
|
|
||||||
## Collections of ChromeOS Devices
|
## Collections of ChromeOS Devices
|
||||||
|
|
||||||
Specify a collection of ChromeOS devices by directly specifying them or by specifiying items that will yield a list of ChromeOS devices.
|
Specify a collection of ChromeOS devices by directly specifying them or by specifying items that will yield a list of ChromeOS devices.
|
||||||
|
|
||||||
<CrOSTypeEntity> ::=
|
<CrOSTypeEntity> ::=
|
||||||
(all cros)|
|
(all cros)|
|
||||||
@@ -865,7 +866,7 @@ Specify a collection of ChromeOS devices by directly specifying them or by speci
|
|||||||
|
|
||||||
## Collections of Users
|
## Collections of Users
|
||||||
|
|
||||||
Specify a collection of Users by directly specifying them or by specifiying items that will yield a list of users.
|
Specify a collection of Users by directly specifying them or by specifying items that will yield a list of users.
|
||||||
|
|
||||||
<UserTypeEntity> ::=
|
<UserTypeEntity> ::=
|
||||||
(all users|users_ns|users_susp|users_ns_susp)|
|
(all users|users_ns|users_susp|users_ns_susp)|
|
||||||
@@ -1522,17 +1523,6 @@ gam print alias|aliases [todrive <ToDriveAttribute>*]
|
|||||||
|
|
||||||
gam whatis <EmailItem> [noinfo] [noinivitablecheck]
|
gam whatis <EmailItem> [noinfo] [noinivitablecheck]
|
||||||
|
|
||||||
# Analytics UA
|
|
||||||
|
|
||||||
gam <UserTypeEntity> print analyticuaproperties [todrive <ToDriveAttribute>*]
|
|
||||||
accountid [accounts/]<String>
|
|
||||||
[maxresults <Integer>]
|
|
||||||
[formatjson [quotechar <Character>]]
|
|
||||||
gam <UserTypeEntity> show analyticuaproperties
|
|
||||||
accountid [accounts/]<String>
|
|
||||||
[maxresults <Integer>]
|
|
||||||
[formatjson]
|
|
||||||
|
|
||||||
# Analytics Admin
|
# Analytics Admin
|
||||||
|
|
||||||
gam <UserTypeEntity> print analyticaccounts [todrive <ToDriveAttribute>*]
|
gam <UserTypeEntity> print analyticaccounts [todrive <ToDriveAttribute>*]
|
||||||
@@ -4458,6 +4448,7 @@ gam report usage customer [todrive <ToDriveAttribute>*]
|
|||||||
domain|
|
domain|
|
||||||
drive|doc|docs|
|
drive|doc|docs|
|
||||||
gcp|
|
gcp|
|
||||||
|
gemini|geminiforworkspace|
|
||||||
groups|group|
|
groups|group|
|
||||||
groupsenterprise|enterprisegroups|
|
groupsenterprise|enterprisegroups|
|
||||||
jamboard|
|
jamboard|
|
||||||
|
|||||||
@@ -1,7 +1,51 @@
|
|||||||
|
7.06.12
|
||||||
|
|
||||||
|
Deleted commands to display Analytic UA properties; the API has been deprecated.
|
||||||
|
```
|
||||||
|
gam <UserTypeEntity> print|show analyticuaproperties
|
||||||
|
```
|
||||||
|
|
||||||
|
7.06.11
|
||||||
|
|
||||||
|
Improved `gam checkconn`.
|
||||||
|
|
||||||
|
Updated `gam print group-members` and `gam print cigroup-members` to recognize members
|
||||||
|
that are groups representing chat spaces. For now, these groups are not expanded when
|
||||||
|
`recursive` is specified.
|
||||||
|
|
||||||
|
7.06.10
|
||||||
|
|
||||||
|
Added the following license SKU.
|
||||||
|
```
|
||||||
|
1010020034 - Google Workspace Frontline Plus
|
||||||
|
```
|
||||||
|
|
||||||
|
7.06.09
|
||||||
|
|
||||||
|
Added `gemini` and `geminiforworkspace` to `<ActivityApplicationName>` for use in
|
||||||
|
`gam report <ActivityApplicationName>`.
|
||||||
|
|
||||||
|
7.06.08
|
||||||
|
|
||||||
|
Fixed problem where Yubikeys caused a trap.
|
||||||
|
|
||||||
|
7.06.07
|
||||||
|
|
||||||
|
Updated private key rotation progress messages in `gam create|use|update project`
|
||||||
|
and `gam upload sakey`.
|
||||||
|
|
||||||
|
Updated `gam use project` to display the following error message when the specifed project
|
||||||
|
already has a service account.
|
||||||
|
```
|
||||||
|
Re-run the command specify a new service account name with: saname <ServiceAccountName>'
|
||||||
|
```
|
||||||
|
|
||||||
7.06.06
|
7.06.06
|
||||||
|
|
||||||
Native support for Windows 11 Arm-based devices.
|
Native support for Windows 11 Arm-based devices.
|
||||||
|
|
||||||
|
Renamed some MacOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".
|
||||||
|
|
||||||
7.06.05
|
7.06.05
|
||||||
|
|
||||||
Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
|
Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ GAM installation script.
|
|||||||
OPTIONS:
|
OPTIONS:
|
||||||
-h show help.
|
-h show help.
|
||||||
-d Directory where gam folder will be installed. Default is \$HOME/bin/
|
-d Directory where gam folder will be installed. Default is \$HOME/bin/
|
||||||
-a Architecture to install (i386, x86_64, x86_64_legacy, arm, arm64). Default is to detect your arch with "uname -m".
|
-a Architecture to install (x86_64, arm64). Default is to detect your arch with "uname -m".
|
||||||
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
|
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
|
||||||
-b OS version. Default is to detect on MacOS and Linux.
|
-b OS version. Default is to detect on MacOS and Linux.
|
||||||
-l Just upgrade GAM to latest version. Skips project creation and auth.
|
-l Just upgrade GAM to latest version. Skips project creation and auth.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||||
__version__ = '7.06.06'
|
__version__ = '7.06.12'
|
||||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||||
|
|
||||||
#pylint: disable=wrong-import-position
|
#pylint: disable=wrong-import-position
|
||||||
@@ -95,6 +95,8 @@ import wsgiref.simple_server
|
|||||||
import wsgiref.util
|
import wsgiref.util
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
# disable legacy stuff we don't use and isn't secure
|
||||||
|
os.environ['CRYPTOGRAPHY_OPENSSL_NO_LEGACY'] = "1"
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import hashes, serialization
|
from cryptography.hazmat.primitives import hashes, serialization
|
||||||
@@ -9358,32 +9360,9 @@ def getOSPlatform():
|
|||||||
|
|
||||||
# gam checkconnection
|
# gam checkconnection
|
||||||
def doCheckConnection():
|
def doCheckConnection():
|
||||||
hosts = ['api.github.com',
|
|
||||||
'raw.githubusercontent.com',
|
def check_host(host):
|
||||||
'accounts.google.com',
|
nonlocal try_count, okay, not_okay, success_count
|
||||||
'workspace.google.com',
|
|
||||||
'oauth2.googleapis.com',
|
|
||||||
'www.googleapis.com']
|
|
||||||
fix_hosts = {'calendar-json.googleapis.com': 'www.googleapis.com',
|
|
||||||
'storage-api.googleapis.com': 'storage.googleapis.com'}
|
|
||||||
api_hosts = ['apps-apis.google.com',
|
|
||||||
'sites.google.com',
|
|
||||||
'versionhistory.googleapis.com',
|
|
||||||
'www.google.com']
|
|
||||||
for host in API.PROJECT_APIS:
|
|
||||||
host = fix_hosts.get(host, host)
|
|
||||||
if host not in api_hosts and host not in hosts:
|
|
||||||
api_hosts.append(host)
|
|
||||||
hosts.extend(sorted(api_hosts))
|
|
||||||
host_count = len(hosts)
|
|
||||||
httpObj = getHttpObj(timeout=30)
|
|
||||||
httpObj.follow_redirects = False
|
|
||||||
headers = {'user-agent': GAM_USER_AGENT}
|
|
||||||
okay = createGreenText('OK')
|
|
||||||
not_okay = createRedText('ERROR')
|
|
||||||
try_count = 0
|
|
||||||
success_count = 0
|
|
||||||
for host in hosts:
|
|
||||||
try_count += 1
|
try_count += 1
|
||||||
dns_err = None
|
dns_err = None
|
||||||
ip = 'unknown'
|
ip = 'unknown'
|
||||||
@@ -9393,12 +9372,12 @@ def doCheckConnection():
|
|||||||
dns_err = f'{not_okay}\n DNS failure: {str(e)}\n'
|
dns_err = f'{not_okay}\n DNS failure: {str(e)}\n'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
dns_err = f'{not_okay}\n Unknown DNS failure: {str(e)}\n'
|
dns_err = f'{not_okay}\n Unknown DNS failure: {str(e)}\n'
|
||||||
check_line = f'Checking {host} ({ip}) ({try_count}/{host_count})...'
|
check_line = f'Checking {host} ({ip}) ({try_count})...'
|
||||||
writeStdout(f'{check_line:<100}')
|
writeStdout(f'{check_line:<100}')
|
||||||
flushStdout()
|
flushStdout()
|
||||||
if dns_err:
|
if dns_err:
|
||||||
writeStdout(dns_err)
|
writeStdout(dns_err)
|
||||||
continue
|
return
|
||||||
gen_firewall = 'You probably have security software or a firewall on your machine or network that is preventing GAM from making Internet connections. Check your network configuration or try running GAM on a hotspot or home network to see if the problem exists only on your organization\'s network.'
|
gen_firewall = 'You probably have security software or a firewall on your machine or network that is preventing GAM from making Internet connections. Check your network configuration or try running GAM on a hotspot or home network to see if the problem exists only on your organization\'s network.'
|
||||||
try:
|
try:
|
||||||
if host.startswith('http'):
|
if host.startswith('http'):
|
||||||
@@ -9427,7 +9406,54 @@ def doCheckConnection():
|
|||||||
writeStdout(f'{not_okay}\n Timed out trying to connect to host\n')
|
writeStdout(f'{not_okay}\n Timed out trying to connect to host\n')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
writeStdout(f'{not_okay}\n {str(e)}\n')
|
writeStdout(f'{not_okay}\n {str(e)}\n')
|
||||||
if success_count == host_count:
|
|
||||||
|
try_count = 0
|
||||||
|
httpObj = getHttpObj(timeout=30)
|
||||||
|
httpObj.follow_redirects = False
|
||||||
|
headers = {'user-agent': GAM_USER_AGENT}
|
||||||
|
okay = createGreenText('OK')
|
||||||
|
not_okay = createRedText('ERROR')
|
||||||
|
success_count = 0
|
||||||
|
initial_hosts = ['api.github.com',
|
||||||
|
'raw.githubusercontent.com',
|
||||||
|
'accounts.google.com',
|
||||||
|
'oauth2.googleapis.com',
|
||||||
|
'www.googleapis.com']
|
||||||
|
for host in initial_hosts:
|
||||||
|
check_host(host)
|
||||||
|
api_hosts = ['apps-apis.google.com',
|
||||||
|
'www.google.com']
|
||||||
|
for host in api_hosts:
|
||||||
|
check_host(host)
|
||||||
|
# For v2 discovery APIs, GAM gets discovery file from <api>.googleapis.com so
|
||||||
|
# add those domains.
|
||||||
|
disc_hosts = []
|
||||||
|
for api, config in API._INFO.items():
|
||||||
|
if config.get('v2discovery') and not config.get('localdiscovery'):
|
||||||
|
if mapped_api := config.get('mappedAPI'):
|
||||||
|
api = mapped_api
|
||||||
|
host = f'{api}.googleapis.com'
|
||||||
|
if host not in disc_hosts:
|
||||||
|
disc_hosts.append(host)
|
||||||
|
for host in disc_hosts:
|
||||||
|
check_host(host)
|
||||||
|
checked_hosts = initial_hosts + api_hosts + disc_hosts
|
||||||
|
# now we need to "build" each API and check it's base URL host
|
||||||
|
# if we haven't already. This may not be any hosts at all but
|
||||||
|
# to ensure we are checking all hosts GAM may use we should
|
||||||
|
# keep this.
|
||||||
|
for api in API._INFO:
|
||||||
|
if api in [API.CONTACTS, API.EMAIL_AUDIT]:
|
||||||
|
continue
|
||||||
|
svc = getService(api, httpObj)
|
||||||
|
base_url = svc._rootDesc.get('baseUrl')
|
||||||
|
parsed_base_url = urlparse(base_url)
|
||||||
|
base_host = parsed_base_url.netloc
|
||||||
|
if base_host not in checked_hosts:
|
||||||
|
writeStdout(f'Checking {base_host} for {api}\n')
|
||||||
|
check_host(base_host)
|
||||||
|
checked_hosts.append(base_host)
|
||||||
|
if success_count == try_count:
|
||||||
writeStdout(createGreenText('All hosts passed!\n'))
|
writeStdout(createGreenText('All hosts passed!\n'))
|
||||||
else:
|
else:
|
||||||
systemErrorExit(3, createYellowText('Some hosts failed to connect! Please follow the recommendations for those hosts to correct any issues and try again.'))
|
systemErrorExit(3, createYellowText('Some hosts failed to connect! Please follow the recommendations for those hosts to correct any issues and try again.'))
|
||||||
@@ -11384,25 +11410,26 @@ def _waitForSvcAcctCompletion(i):
|
|||||||
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
|
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
|
||||||
time.sleep(sleep_time)
|
time.sleep(sleep_time)
|
||||||
|
|
||||||
def _grantRotateRights(iam, projectId, service_account, email, account_type='serviceAccount'):
|
def _grantRotateRights(iam, projectId, service_account, account_type='serviceAccount'):
|
||||||
body = {'policy': {'bindings': [{'role': 'roles/iam.serviceAccountKeyAdmin',
|
body = {'policy': {'bindings': [{'role': 'roles/iam.serviceAccountKeyAdmin',
|
||||||
'members': [f'{account_type}:{email}']}]}}
|
'members': [f'{account_type}:{service_account}']}]}}
|
||||||
maxRetries = 10
|
maxRetries = 10
|
||||||
printEntityMessage([Ent.PROJECT, projectId, Ent.SVCACCT, email],
|
kvList = [Ent.PROJECT, projectId, Ent.SVCACCT, service_account]
|
||||||
Msg.HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY.format(email, service_account))
|
printEntityMessage(kvList, Msg.GRANTING_RIGHTS_TO_ROTATE_ITS_OWN_PRIVATE_KEY.format('Granting'))
|
||||||
for retry in range(1, maxRetries+1):
|
for retry in range(1, maxRetries+1):
|
||||||
try:
|
try:
|
||||||
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy',
|
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy',
|
||||||
throwReasons=[GAPI.INVALID_ARGUMENT],
|
throwReasons=[GAPI.INVALID_ARGUMENT],
|
||||||
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body)
|
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body)
|
||||||
|
printEntityMessage(kvList, Msg.GRANTING_RIGHTS_TO_ROTATE_ITS_OWN_PRIVATE_KEY.format('Granted'))
|
||||||
return True
|
return True
|
||||||
except GAPI.invalidArgument as e:
|
except GAPI.invalidArgument as e:
|
||||||
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
|
entityActionFailedWarning(kvList, str(e))
|
||||||
if 'does not exist' not in str(e) or retry == maxRetries:
|
if 'does not exist' not in str(e) or retry == maxRetries:
|
||||||
return False
|
return False
|
||||||
_waitForSvcAcctCompletion(retry)
|
_waitForSvcAcctCompletion(retry)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
|
entityActionFailedWarning(kvList, str(e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True):
|
def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True):
|
||||||
@@ -11420,6 +11447,7 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
|
|||||||
return False
|
return False
|
||||||
except GAPI.alreadyExists as e:
|
except GAPI.alreadyExists as e:
|
||||||
entityActionFailedWarning([Ent.PROJECT, projectInfo['projectId'], Ent.SVCACCT, svcAcctInfo['name']], str(e))
|
entityActionFailedWarning([Ent.PROJECT, projectInfo['projectId'], Ent.SVCACCT, svcAcctInfo['name']], str(e))
|
||||||
|
writeStderr(Msg.RERUN_THE_COMMAND_AND_SPECIFY_A_NEW_SANAME)
|
||||||
return False
|
return False
|
||||||
GM.Globals[GM.SVCACCT_SCOPES_DEFINED] = False
|
GM.Globals[GM.SVCACCT_SCOPES_DEFINED] = False
|
||||||
if create_key and not doProcessSvcAcctKeys(mode='retainexisting', iam=iam,
|
if create_key and not doProcessSvcAcctKeys(mode='retainexisting', iam=iam,
|
||||||
@@ -11428,7 +11456,7 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
|
|||||||
clientId=service_account['uniqueId']):
|
clientId=service_account['uniqueId']):
|
||||||
return False
|
return False
|
||||||
sa_email = service_account['name'].rsplit('/', 1)[-1]
|
sa_email = service_account['name'].rsplit('/', 1)[-1]
|
||||||
return _grantRotateRights(iam, projectInfo['projectId'], sa_email, sa_email)
|
return _grantRotateRights(iam, projectInfo['projectId'], sa_email)
|
||||||
|
|
||||||
def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key=True):
|
def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key=True):
|
||||||
def _checkClientAndSecret(csHttpObj, client_id, client_secret):
|
def _checkClientAndSecret(csHttpObj, client_id, client_secret):
|
||||||
@@ -11921,9 +11949,7 @@ def doUpdateProject():
|
|||||||
continue
|
continue
|
||||||
iam = getAPIService(API.IAM, httpObj)
|
iam = getAPIService(API.IAM, httpObj)
|
||||||
_getSvcAcctData() # needed to read in GM.OAUTH2SERVICE_JSON_DATA
|
_getSvcAcctData() # needed to read in GM.OAUTH2SERVICE_JSON_DATA
|
||||||
_grantRotateRights(iam, projectId,
|
_grantRotateRights(iam, projectId, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email'])
|
||||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email'],
|
|
||||||
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email'])
|
|
||||||
Ind.Decrement()
|
Ind.Decrement()
|
||||||
|
|
||||||
# gam delete project [[admin] <EmailAddress>] [<ProjectIDEntity>]
|
# gam delete project [[admin] <EmailAddress>] [<ProjectIDEntity>]
|
||||||
@@ -12786,7 +12812,7 @@ def doUploadSvcAcctKeys():
|
|||||||
iam = getAPIService(API.IAM, httpObj)
|
iam = getAPIService(API.IAM, httpObj)
|
||||||
if doProcessSvcAcctKeys(mode='upload', iam=iam):
|
if doProcessSvcAcctKeys(mode='upload', iam=iam):
|
||||||
sa_email = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email']
|
sa_email = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['client_email']
|
||||||
_grantRotateRights(iam, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'], sa_email, sa_email)
|
_grantRotateRights(iam, GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'], sa_email)
|
||||||
sys.stdout.write(Msg.YOUR_GAM_PROJECT_IS_CREATED_AND_READY_TO_USE)
|
sys.stdout.write(Msg.YOUR_GAM_PROJECT_IS_CREATED_AND_READY_TO_USE)
|
||||||
|
|
||||||
# gam delete sakeys <ServiceAccountKeyList>
|
# gam delete sakeys <ServiceAccountKeyList>
|
||||||
@@ -13491,6 +13517,8 @@ REPORT_CHOICE_MAP = {
|
|||||||
'drive': 'drive',
|
'drive': 'drive',
|
||||||
'enterprisegroups': 'groups_enterprise',
|
'enterprisegroups': 'groups_enterprise',
|
||||||
'gcp': 'gcp',
|
'gcp': 'gcp',
|
||||||
|
'gemini': 'gemini_for_workspace',
|
||||||
|
'geminiforworkspace': 'gemini_for_workspace',
|
||||||
'gplus': 'gplus',
|
'gplus': 'gplus',
|
||||||
'google+': 'gplus',
|
'google+': 'gplus',
|
||||||
'group': 'groups',
|
'group': 'groups',
|
||||||
@@ -13788,6 +13816,20 @@ def doReport():
|
|||||||
csvPF.WriteRow(row)
|
csvPF.WriteRow(row)
|
||||||
return (True, lastDate)
|
return (True, lastDate)
|
||||||
|
|
||||||
|
# dynamically extend our choices with other reports Google dynamically adds
|
||||||
|
rep = buildGAPIObject(API.REPORTS)
|
||||||
|
dyn_choices = rep._rootDesc \
|
||||||
|
.get('resources', {}) \
|
||||||
|
.get('activities', {}) \
|
||||||
|
.get('methods', {}) \
|
||||||
|
.get('list', {}) \
|
||||||
|
.get('parameters', {}) \
|
||||||
|
.get('applicationName', {}) \
|
||||||
|
.get('enum', [])
|
||||||
|
for dyn_choice in dyn_choices:
|
||||||
|
if dyn_choice.replace('_', '') not in REPORT_CHOICE_MAP and \
|
||||||
|
dyn_choice not in REPORT_CHOICE_MAP.values():
|
||||||
|
REPORT_CHOICE_MAP[dyn_choice.replace('_', '')] = dyn_choice
|
||||||
report = getChoice(REPORT_CHOICE_MAP, mapChoice=True)
|
report = getChoice(REPORT_CHOICE_MAP, mapChoice=True)
|
||||||
if report == 'usage':
|
if report == 'usage':
|
||||||
doReportUsage()
|
doReportUsage()
|
||||||
@@ -13795,7 +13837,6 @@ def doReport():
|
|||||||
if report == 'usageparameters':
|
if report == 'usageparameters':
|
||||||
doReportUsageParameters()
|
doReportUsageParameters()
|
||||||
return
|
return
|
||||||
rep = buildGAPIObject(API.REPORTS)
|
|
||||||
customerId = GC.Values[GC.CUSTOMER_ID]
|
customerId = GC.Values[GC.CUSTOMER_ID]
|
||||||
if customerId == GC.MY_CUSTOMER:
|
if customerId == GC.MY_CUSTOMER:
|
||||||
customerId = None
|
customerId = None
|
||||||
@@ -15763,27 +15804,13 @@ ANALYTIC_ENTITY_MAP = {
|
|||||||
'pageSize': 50,
|
'pageSize': 50,
|
||||||
'maxPageSize': 200,
|
'maxPageSize': 200,
|
||||||
},
|
},
|
||||||
Ent.ANALYTIC_UA_PROPERTY:
|
|
||||||
{'titles': ['User', 'accountId', 'name', 'id', 'created', 'updated'],
|
|
||||||
'JSONtitles': ['User', 'accountId', 'name', 'id', 'JSON'],
|
|
||||||
'timeObjects': ['created', 'updated'],
|
|
||||||
'items': 'items',
|
|
||||||
'pageSize': 50,
|
|
||||||
'maxPageSize': 200,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def printShowAnalyticItems(users, entityType):
|
def printShowAnalyticItems(users, entityType):
|
||||||
analyticEntityMap = ANALYTIC_ENTITY_MAP[entityType]
|
analyticEntityMap = ANALYTIC_ENTITY_MAP[entityType]
|
||||||
csvPF = CSVPrintFile(analyticEntityMap['titles'], 'sortall') if Act.csvFormat() else None
|
csvPF = CSVPrintFile(analyticEntityMap['titles'], 'sortall') if Act.csvFormat() else None
|
||||||
FJQC = FormatJSONQuoteChar(csvPF)
|
FJQC = FormatJSONQuoteChar(csvPF)
|
||||||
if entityType != Ent.ANALYTIC_UA_PROPERTY:
|
kwargs = {'pageSize': analyticEntityMap['pageSize']}
|
||||||
kwargs = {'pageSize': analyticEntityMap['pageSize']}
|
|
||||||
api = API.ANALYTICS_ADMIN
|
|
||||||
else:
|
|
||||||
# kwargs = {'webPropertyId': '~all'}
|
|
||||||
kwargs = {}
|
|
||||||
api = API.ANALYTICS
|
|
||||||
if entityType in {Ent.ANALYTIC_ACCOUNT, Ent.ANALYTIC_PROPERTY}:
|
if entityType in {Ent.ANALYTIC_ACCOUNT, Ent.ANALYTIC_PROPERTY}:
|
||||||
kwargs['showDeleted'] = False
|
kwargs['showDeleted'] = False
|
||||||
while Cmd.ArgumentsRemaining():
|
while Cmd.ArgumentsRemaining():
|
||||||
@@ -15796,16 +15823,12 @@ def printShowAnalyticItems(users, entityType):
|
|||||||
kwargs['showDeleted'] = getBoolean()
|
kwargs['showDeleted'] = getBoolean()
|
||||||
elif entityType == Ent.ANALYTIC_PROPERTY and myarg == 'filter':
|
elif entityType == Ent.ANALYTIC_PROPERTY and myarg == 'filter':
|
||||||
kwargs['filter'] = getString(Cmd.OB_STRING)
|
kwargs['filter'] = getString(Cmd.OB_STRING)
|
||||||
elif entityType == Ent.ANALYTIC_UA_PROPERTY and myarg == 'accountid':
|
|
||||||
kwargs['accountId'] = getString(Cmd.OB_STRING).replace('accounts/', '')
|
|
||||||
elif entityType == Ent.ANALYTIC_DATASTREAM and myarg == 'parent':
|
elif entityType == Ent.ANALYTIC_DATASTREAM and myarg == 'parent':
|
||||||
kwargs['parent'] = getString(Cmd.OB_STRING)
|
kwargs['parent'] = getString(Cmd.OB_STRING)
|
||||||
else:
|
else:
|
||||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||||
if entityType == Ent.ANALYTIC_PROPERTY and 'filter' not in kwargs:
|
if entityType == Ent.ANALYTIC_PROPERTY and 'filter' not in kwargs:
|
||||||
missingArgumentExit('filter')
|
missingArgumentExit('filter')
|
||||||
if entityType == Ent.ANALYTIC_UA_PROPERTY and 'accountId' not in kwargs:
|
|
||||||
missingArgumentExit('accountid')
|
|
||||||
if entityType == Ent.ANALYTIC_DATASTREAM and 'parent' not in kwargs:
|
if entityType == Ent.ANALYTIC_DATASTREAM and 'parent' not in kwargs:
|
||||||
missingArgumentExit('parent')
|
missingArgumentExit('parent')
|
||||||
if csvPF and FJQC.formatJSON:
|
if csvPF and FJQC.formatJSON:
|
||||||
@@ -15813,7 +15836,7 @@ def printShowAnalyticItems(users, entityType):
|
|||||||
i, count, users = getEntityArgument(users)
|
i, count, users = getEntityArgument(users)
|
||||||
for user in users:
|
for user in users:
|
||||||
i += 1
|
i += 1
|
||||||
user, analytics = buildGAPIServiceObject(api, user, i, count)
|
user, analytics = buildGAPIServiceObject(API.ANALYTICS_ADMIN, user, i, count)
|
||||||
if not analytics:
|
if not analytics:
|
||||||
continue
|
continue
|
||||||
if entityType == Ent.ANALYTIC_ACCOUNT:
|
if entityType == Ent.ANALYTIC_ACCOUNT:
|
||||||
@@ -15822,11 +15845,8 @@ def printShowAnalyticItems(users, entityType):
|
|||||||
service = analytics.accountSummaries()
|
service = analytics.accountSummaries()
|
||||||
elif entityType == Ent.ANALYTIC_DATASTREAM:
|
elif entityType == Ent.ANALYTIC_DATASTREAM:
|
||||||
service = analytics.properties().dataStreams()
|
service = analytics.properties().dataStreams()
|
||||||
elif entityType == Ent.ANALYTIC_PROPERTY:
|
else: # entityType == Ent.ANALYTIC_PROPERTY:
|
||||||
service = analytics.properties()
|
service = analytics.properties()
|
||||||
else: #Ent.ANALYTIC_UA_PROPERTY:
|
|
||||||
service = analytics.management().webproperties()
|
|
||||||
# service = analytics.management().profiles()
|
|
||||||
if csvPF:
|
if csvPF:
|
||||||
printGettingAllEntityItemsForWhom(entityType, user, i, count)
|
printGettingAllEntityItemsForWhom(entityType, user, i, count)
|
||||||
pageMessage = getPageMessageForWhom()
|
pageMessage = getPageMessageForWhom()
|
||||||
@@ -15867,10 +15887,7 @@ def printShowAnalyticItems(users, entityType):
|
|||||||
if not FJQC.formatJSON:
|
if not FJQC.formatJSON:
|
||||||
csvPF.WriteRowTitles(row)
|
csvPF.WriteRowTitles(row)
|
||||||
elif csvPF.CheckRowTitles(row):
|
elif csvPF.CheckRowTitles(row):
|
||||||
if entityType != Ent.ANALYTIC_UA_PROPERTY:
|
row = {'User': user, 'name': item['name'], 'displayName': item['displayName']}
|
||||||
row = {'User': user, 'name': item['name'], 'displayName': item['displayName']}
|
|
||||||
else:
|
|
||||||
row = {'User': user, 'accountId': item['accountId'], 'id': item['id'], 'name': item['name']}
|
|
||||||
for field in analyticEntityMap['JSONtitles'][2:-1]:
|
for field in analyticEntityMap['JSONtitles'][2:-1]:
|
||||||
row[field] = item[field]
|
row[field] = item[field]
|
||||||
row['JSON'] = json.dumps(cleanJSON(item, timeObjects=analyticEntityMap['timeObjects']),
|
row['JSON'] = json.dumps(cleanJSON(item, timeObjects=analyticEntityMap['timeObjects']),
|
||||||
@@ -15908,17 +15925,6 @@ def printShowAnalyticAccountSummaries(users):
|
|||||||
def printShowAnalyticProperties(users):
|
def printShowAnalyticProperties(users):
|
||||||
printShowAnalyticItems(users, Ent.ANALYTIC_PROPERTY)
|
printShowAnalyticItems(users, Ent.ANALYTIC_PROPERTY)
|
||||||
|
|
||||||
# gam <UserTypeEntity> print analyticuaproperties [todrive <ToDriveAttribute>*]
|
|
||||||
# accountid [accounts/]<String>
|
|
||||||
# [maxresults <Integer>]
|
|
||||||
# [formatjson [quotechar <Character>]]
|
|
||||||
# gam <UserTypeEntity> show analyticuaproperties
|
|
||||||
# accountid [accounts/]<String>
|
|
||||||
# [maxresults <Integer>]
|
|
||||||
# [formatjson]
|
|
||||||
def printShowAnalyticUAProperties(users):
|
|
||||||
printShowAnalyticItems(users, Ent.ANALYTIC_UA_PROPERTY)
|
|
||||||
|
|
||||||
# gam <UserTypeEntity> print analyticdatastreams [todrive <ToDriveAttribute>*]
|
# gam <UserTypeEntity> print analyticdatastreams [todrive <ToDriveAttribute>*]
|
||||||
# parent <String>
|
# parent <String>
|
||||||
# [maxresults <Integer>]
|
# [maxresults <Integer>]
|
||||||
@@ -34164,7 +34170,8 @@ def getGroupMembers(cd, groupEmail, memberRoles, membersList, membersSet, i, cou
|
|||||||
elif memberOptions[MEMBEROPTION_NODUPLICATES]:
|
elif memberOptions[MEMBEROPTION_NODUPLICATES]:
|
||||||
groupMemberList = []
|
groupMemberList = []
|
||||||
for member in groupMembers:
|
for member in groupMembers:
|
||||||
if member['type'] != Ent.TYPE_GROUP:
|
namespace = member['email'].find('@') == -1
|
||||||
|
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||||
if ((member['type'] in typesSet and
|
if ((member['type'] in typesSet and
|
||||||
checkMemberMatch(member, memberOptions) and
|
checkMemberMatch(member, memberOptions) and
|
||||||
_checkMemberRoleIsSuspendedIsArchived(member, validRoles, memberOptions[MEMBEROPTION_ISSUSPENDED], memberOptions[MEMBEROPTION_ISARCHIVED]) and
|
_checkMemberRoleIsSuspendedIsArchived(member, validRoles, memberOptions[MEMBEROPTION_ISSUSPENDED], memberOptions[MEMBEROPTION_ISARCHIVED]) and
|
||||||
@@ -34193,7 +34200,8 @@ def getGroupMembers(cd, groupEmail, memberRoles, membersList, membersSet, i, cou
|
|||||||
memberOptions, memberDisplayOptions, level+1, typesSet)
|
memberOptions, memberDisplayOptions, level+1, typesSet)
|
||||||
else:
|
else:
|
||||||
for member in groupMembers:
|
for member in groupMembers:
|
||||||
if member['type'] != Ent.TYPE_GROUP:
|
namespace = member['email'].find('@') == -1
|
||||||
|
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||||
if ((member['type'] in typesSet) and
|
if ((member['type'] in typesSet) and
|
||||||
checkMemberMatch(member, memberOptions) and
|
checkMemberMatch(member, memberOptions) and
|
||||||
_checkMemberRoleIsSuspendedIsArchived(member, validRoles,
|
_checkMemberRoleIsSuspendedIsArchived(member, validRoles,
|
||||||
@@ -36292,7 +36300,8 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
|
|||||||
for member in groupMembers:
|
for member in groupMembers:
|
||||||
getCIGroupMemberRoleFixType(member)
|
getCIGroupMemberRoleFixType(member)
|
||||||
memberName = member.get('preferredMemberKey', {}).get('id', '')
|
memberName = member.get('preferredMemberKey', {}).get('id', '')
|
||||||
if member['type'] != Ent.TYPE_GROUP:
|
namespace = member.get('preferredMemberKey', {}).get('namespace', '')
|
||||||
|
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||||
if (member['type'] in typesSet and
|
if (member['type'] in typesSet and
|
||||||
checkCIMemberMatch(member, memberOptions) and
|
checkCIMemberMatch(member, memberOptions) and
|
||||||
_checkMemberRole(member, validRoles) and
|
_checkMemberRole(member, validRoles) and
|
||||||
@@ -36320,7 +36329,8 @@ def getCIGroupMembers(ci, groupName, memberRoles, membersList, membersSet, i, co
|
|||||||
for member in groupMembers:
|
for member in groupMembers:
|
||||||
getCIGroupMemberRoleFixType(member)
|
getCIGroupMemberRoleFixType(member)
|
||||||
memberName = member.get('preferredMemberKey', {}).get('id', '')
|
memberName = member.get('preferredMemberKey', {}).get('id', '')
|
||||||
if member['type'] != Ent.TYPE_GROUP:
|
namespace = member.get('preferredMemberKey', {}).get('namespace', '')
|
||||||
|
if member['type'] != Ent.TYPE_GROUP or namespace:
|
||||||
if (member['type'] in typesSet and
|
if (member['type'] in typesSet and
|
||||||
checkCIMemberMatch(member, memberOptions) and
|
checkCIMemberMatch(member, memberOptions) and
|
||||||
_checkMemberRole(member, validRoles) and
|
_checkMemberRole(member, validRoles) and
|
||||||
@@ -76671,7 +76681,6 @@ USER_COMMANDS_WITH_OBJECTS = {
|
|||||||
Cmd.ARG_ANALYTICACCOUNTSUMMARY: printShowAnalyticAccountSummaries,
|
Cmd.ARG_ANALYTICACCOUNTSUMMARY: printShowAnalyticAccountSummaries,
|
||||||
Cmd.ARG_ANALYTICDATASTREAM: printShowAnalyticDatastreams,
|
Cmd.ARG_ANALYTICDATASTREAM: printShowAnalyticDatastreams,
|
||||||
Cmd.ARG_ANALYTICPROPERTY: printShowAnalyticProperties,
|
Cmd.ARG_ANALYTICPROPERTY: printShowAnalyticProperties,
|
||||||
Cmd.ARG_ANALYTICUAPROPERTY: printShowAnalyticUAProperties,
|
|
||||||
Cmd.ARG_ASP: printShowASPs,
|
Cmd.ARG_ASP: printShowASPs,
|
||||||
Cmd.ARG_BACKUPCODE: printShowBackupCodes,
|
Cmd.ARG_BACKUPCODE: printShowBackupCodes,
|
||||||
Cmd.ARG_CALENDAR: printShowCalendars,
|
Cmd.ARG_CALENDAR: printShowCalendars,
|
||||||
@@ -76778,7 +76787,6 @@ USER_COMMANDS_WITH_OBJECTS = {
|
|||||||
Cmd.ARG_ANALYTICACCOUNTSUMMARY: printShowAnalyticAccountSummaries,
|
Cmd.ARG_ANALYTICACCOUNTSUMMARY: printShowAnalyticAccountSummaries,
|
||||||
Cmd.ARG_ANALYTICDATASTREAM: printShowAnalyticDatastreams,
|
Cmd.ARG_ANALYTICDATASTREAM: printShowAnalyticDatastreams,
|
||||||
Cmd.ARG_ANALYTICPROPERTY: printShowAnalyticProperties,
|
Cmd.ARG_ANALYTICPROPERTY: printShowAnalyticProperties,
|
||||||
Cmd.ARG_ANALYTICUAPROPERTY: printShowAnalyticUAProperties,
|
|
||||||
Cmd.ARG_ASP: printShowASPs,
|
Cmd.ARG_ASP: printShowASPs,
|
||||||
Cmd.ARG_BACKUPCODE: printShowBackupCodes,
|
Cmd.ARG_BACKUPCODE: printShowBackupCodes,
|
||||||
Cmd.ARG_CALENDAR: printShowCalendars,
|
Cmd.ARG_CALENDAR: printShowCalendars,
|
||||||
@@ -76991,7 +76999,6 @@ USER_COMMANDS_OBJ_ALIASES = {
|
|||||||
Cmd.ARG_ANALYTICACCOUNTSUMMARIES: Cmd.ARG_ANALYTICACCOUNTSUMMARY,
|
Cmd.ARG_ANALYTICACCOUNTSUMMARIES: Cmd.ARG_ANALYTICACCOUNTSUMMARY,
|
||||||
Cmd.ARG_ANALYTICDATASTREAMS: Cmd.ARG_ANALYTICDATASTREAM,
|
Cmd.ARG_ANALYTICDATASTREAMS: Cmd.ARG_ANALYTICDATASTREAM,
|
||||||
Cmd.ARG_ANALYTICPROPERTIES: Cmd.ARG_ANALYTICPROPERTY,
|
Cmd.ARG_ANALYTICPROPERTIES: Cmd.ARG_ANALYTICPROPERTY,
|
||||||
Cmd.ARG_ANALYTICUAPROPERTIES: Cmd.ARG_ANALYTICUAPROPERTY,
|
|
||||||
Cmd.ARG_ASPS: Cmd.ARG_ASP,
|
Cmd.ARG_ASPS: Cmd.ARG_ASP,
|
||||||
Cmd.ARG_BACKUPCODES: Cmd.ARG_BACKUPCODE,
|
Cmd.ARG_BACKUPCODES: Cmd.ARG_BACKUPCODE,
|
||||||
Cmd.ARG_CALENDARS: Cmd.ARG_CALENDAR,
|
Cmd.ARG_CALENDARS: Cmd.ARG_CALENDAR,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
# APIs
|
# APIs
|
||||||
ACCESSCONTEXTMANAGER = 'accesscontextmanager'
|
ACCESSCONTEXTMANAGER = 'accesscontextmanager'
|
||||||
ALERTCENTER = 'alertcenter'
|
ALERTCENTER = 'alertcenter'
|
||||||
ANALYTICS = 'analytics'
|
|
||||||
ANALYTICS_ADMIN = 'analyticsadmin'
|
ANALYTICS_ADMIN = 'analyticsadmin'
|
||||||
CALENDAR = 'calendar'
|
CALENDAR = 'calendar'
|
||||||
CBCM = 'cbcm'
|
CBCM = 'cbcm'
|
||||||
@@ -162,7 +161,6 @@ PROJECT_APIS = [
|
|||||||
'accesscontextmanager.googleapis.com',
|
'accesscontextmanager.googleapis.com',
|
||||||
'admin.googleapis.com',
|
'admin.googleapis.com',
|
||||||
'alertcenter.googleapis.com',
|
'alertcenter.googleapis.com',
|
||||||
'analytics.googleapis.com',
|
|
||||||
'analyticsadmin.googleapis.com',
|
'analyticsadmin.googleapis.com',
|
||||||
# 'audit.googleapis.com',
|
# 'audit.googleapis.com',
|
||||||
'calendar-json.googleapis.com',
|
'calendar-json.googleapis.com',
|
||||||
@@ -201,7 +199,6 @@ PROJECT_APIS = [
|
|||||||
_INFO = {
|
_INFO = {
|
||||||
ACCESSCONTEXTMANAGER: {'name': 'Access Context Manager API', 'version': 'v1', 'v2discovery': True},
|
ACCESSCONTEXTMANAGER: {'name': 'Access Context Manager API', 'version': 'v1', 'v2discovery': True},
|
||||||
ALERTCENTER: {'name': 'AlertCenter API', 'version': 'v1beta1', 'v2discovery': True},
|
ALERTCENTER: {'name': 'AlertCenter API', 'version': 'v1beta1', 'v2discovery': True},
|
||||||
ANALYTICS: {'name': 'Analytics API', 'version': 'v3', 'v2discovery': False},
|
|
||||||
ANALYTICS_ADMIN: {'name': 'Analytics Admin API', 'version': 'v1beta', 'v2discovery': True},
|
ANALYTICS_ADMIN: {'name': 'Analytics Admin API', 'version': 'v1beta', 'v2discovery': True},
|
||||||
CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
|
CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': True, 'mappedAPI': 'calendar-json'},
|
||||||
CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
|
CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True},
|
||||||
@@ -244,7 +241,7 @@ _INFO = {
|
|||||||
EMAIL_AUDIT: {'name': 'Email Audit API', 'version': 'v1', 'v2discovery': False},
|
EMAIL_AUDIT: {'name': 'Email Audit API', 'version': 'v1', 'v2discovery': False},
|
||||||
FORMS: {'name': 'Forms API', 'version': 'v1', 'v2discovery': True},
|
FORMS: {'name': 'Forms API', 'version': 'v1', 'v2discovery': True},
|
||||||
GMAIL: {'name': 'Gmail API', 'version': 'v1', 'v2discovery': True},
|
GMAIL: {'name': 'Gmail API', 'version': 'v1', 'v2discovery': True},
|
||||||
GROUPSMIGRATION: {'name': 'Groups Migration API', 'version': 'v1', 'v2discovery': False},
|
GROUPSMIGRATION: {'name': 'Groups Migration API', 'version': 'v1', 'v2discovery': True},
|
||||||
GROUPSSETTINGS: {'name': 'Groups Settings API', 'version': 'v1', 'v2discovery': True},
|
GROUPSSETTINGS: {'name': 'Groups Settings API', 'version': 'v1', 'v2discovery': True},
|
||||||
IAM: {'name': 'Identity and Access Management API', 'version': 'v1', 'v2discovery': True},
|
IAM: {'name': 'Identity and Access Management API', 'version': 'v1', 'v2discovery': True},
|
||||||
IAM_CREDENTIALS: {'name': 'Identity and Access Management Credentials API', 'version': 'v1', 'v2discovery': True},
|
IAM_CREDENTIALS: {'name': 'Identity and Access Management Credentials API', 'version': 'v1', 'v2discovery': True},
|
||||||
@@ -532,10 +529,6 @@ _SVCACCT_SCOPES = [
|
|||||||
'api': ALERTCENTER,
|
'api': ALERTCENTER,
|
||||||
'subscopes': [],
|
'subscopes': [],
|
||||||
'scope': 'https://www.googleapis.com/auth/apps.alerts'},
|
'scope': 'https://www.googleapis.com/auth/apps.alerts'},
|
||||||
{'name': 'Analytics API - read only',
|
|
||||||
'api': ANALYTICS,
|
|
||||||
'subscopes': [],
|
|
||||||
'scope': 'https://www.googleapis.com/auth/analytics.readonly'},
|
|
||||||
{'name': 'Analytics Admin API - read only',
|
{'name': 'Analytics Admin API - read only',
|
||||||
'api': ANALYTICS_ADMIN,
|
'api': ANALYTICS_ADMIN,
|
||||||
'subscopes': [],
|
'subscopes': [],
|
||||||
|
|||||||
@@ -423,8 +423,6 @@ class GamCLArgs():
|
|||||||
ARG_ANALYTICDATASTREAMS = 'analyticdatastreams'
|
ARG_ANALYTICDATASTREAMS = 'analyticdatastreams'
|
||||||
ARG_ANALYTICPROPERTY = 'analyticproperty'
|
ARG_ANALYTICPROPERTY = 'analyticproperty'
|
||||||
ARG_ANALYTICPROPERTIES = 'analyticproperties'
|
ARG_ANALYTICPROPERTIES = 'analyticproperties'
|
||||||
ARG_ANALYTICUAPROPERTY = 'analyticuaproperty'
|
|
||||||
ARG_ANALYTICUAPROPERTIES = 'analyticuaproperties'
|
|
||||||
ARG_API = 'api'
|
ARG_API = 'api'
|
||||||
ARG_APIS = 'apis'
|
ARG_APIS = 'apis'
|
||||||
ARG_APIPROJECT = 'apiproject'
|
ARG_APIPROJECT = 'apiproject'
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ class GamEntity():
|
|||||||
ANALYTIC_ACCOUNT_SUMMARY = 'anas'
|
ANALYTIC_ACCOUNT_SUMMARY = 'anas'
|
||||||
ANALYTIC_DATASTREAM = 'anad'
|
ANALYTIC_DATASTREAM = 'anad'
|
||||||
ANALYTIC_PROPERTY = 'anap'
|
ANALYTIC_PROPERTY = 'anap'
|
||||||
ANALYTIC_UA_PROPERTY = 'anau'
|
|
||||||
API = 'api '
|
API = 'api '
|
||||||
APP_ACCESS_SETTINGS = 'apps'
|
APP_ACCESS_SETTINGS = 'apps'
|
||||||
APP_ID = 'appi'
|
APP_ID = 'appi'
|
||||||
@@ -412,7 +411,6 @@ class GamEntity():
|
|||||||
ANALYTIC_ACCOUNT_SUMMARY: ['Analytic Account Summaries', 'Analytic Account Summary'],
|
ANALYTIC_ACCOUNT_SUMMARY: ['Analytic Account Summaries', 'Analytic Account Summary'],
|
||||||
ANALYTIC_DATASTREAM: ['Analytic Datastreams', 'Analytic Datastream'],
|
ANALYTIC_DATASTREAM: ['Analytic Datastreams', 'Analytic Datastream'],
|
||||||
ANALYTIC_PROPERTY: ['Analytic GA4 Properties', 'Analytic GA4 Property'],
|
ANALYTIC_PROPERTY: ['Analytic GA4 Properties', 'Analytic GA4 Property'],
|
||||||
ANALYTIC_UA_PROPERTY: ['Analytic UA Properties', 'Analytic UA Property'],
|
|
||||||
API: ['APIs', 'API'],
|
API: ['APIs', 'API'],
|
||||||
APP_ACCESS_SETTINGS: ['Application Access Settings', 'Application Access Settings'],
|
APP_ACCESS_SETTINGS: ['Application Access Settings', 'Application Access Settings'],
|
||||||
APP_ID: ['Application IDs', 'Application ID'],
|
APP_ID: ['Application IDs', 'Application ID'],
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Please go to:
|
|||||||
24. Paste it at the "Enter your Client Secret: " prompt in your terminal
|
24. Paste it at the "Enter your Client Secret: " prompt in your terminal
|
||||||
25. Press return/enter in your terminal
|
25. Press return/enter in your terminal
|
||||||
26. Switch back to the browser
|
26. Switch back to the browser
|
||||||
27. Click "CANCEL"
|
27. Click "OK"
|
||||||
28. These steps are complete
|
28. These steps are complete
|
||||||
'''
|
'''
|
||||||
ENTER_YOUR_CLIENT_ID = '\nEnter your Client ID: '
|
ENTER_YOUR_CLIENT_ID = '\nEnter your Client ID: '
|
||||||
@@ -287,6 +287,7 @@ GAM_OUT_OF_MEMORY = 'GAM has run out of memory. If this is a large Google Worksp
|
|||||||
GENERATING_NEW_PRIVATE_KEY = 'Generating new private key'
|
GENERATING_NEW_PRIVATE_KEY = 'Generating new private key'
|
||||||
GETTING = 'Getting'
|
GETTING = 'Getting'
|
||||||
GETTING_ALL = 'Getting all'
|
GETTING_ALL = 'Getting all'
|
||||||
|
GRANTING_RIGHTS_TO_ROTATE_ITS_OWN_PRIVATE_KEY = '{0} rights to rotate its own private key'
|
||||||
GOOGLE_DELEGATION_ERROR = 'Google delegation error, delegator and delegate both exist and are valid for delegation'
|
GOOGLE_DELEGATION_ERROR = 'Google delegation error, delegator and delegate both exist and are valid for delegation'
|
||||||
GOT = 'Got'
|
GOT = 'Got'
|
||||||
GROUP_MAPS_TO_MULTIPLE_OUS = 'File: {0}, Group: {1} references multiple OUs: {2}'
|
GROUP_MAPS_TO_MULTIPLE_OUS = 'File: {0}, Group: {1} references multiple OUs: {2}'
|
||||||
@@ -294,13 +295,12 @@ GROUP_MAPS_TO_OU_INVALID_ROW = 'File: {0}, Invalid row, must contain non-blank <
|
|||||||
GUARDIAN_INVITATION_STATUS_NOT_PENDING = 'Guardian invitation status is not PENDING'
|
GUARDIAN_INVITATION_STATUS_NOT_PENDING = 'Guardian invitation status is not PENDING'
|
||||||
HAS_CHILD_ORGS = 'Has child {0}'
|
HAS_CHILD_ORGS = 'Has child {0}'
|
||||||
HAS_INVALID_FORMAT = '{0}: {1}, Has invalid format'
|
HAS_INVALID_FORMAT = '{0}: {1}, Has invalid format'
|
||||||
HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY = 'Giving account {0} rights to rotate {1} private key'
|
|
||||||
HEADER_NOT_FOUND_IN_CSV_HEADERS = 'Header "{0}" not found in CSV headers of "{1}".'
|
HEADER_NOT_FOUND_IN_CSV_HEADERS = 'Header "{0}" not found in CSV headers of "{1}".'
|
||||||
HELP_SYNTAX = 'Help: Syntax in file {0}\n'
|
HELP_SYNTAX = 'Help: Syntax in file {0}\n'
|
||||||
HELP_WIKI = 'Help: Documentation is at {0}\n'
|
HELP_WIKI = 'Help: Documentation is at {0}\n'
|
||||||
IGNORED = 'Ignored'
|
IGNORED = 'Ignored'
|
||||||
INSTRUCTIONS_CLIENT_SECRETS_JSON = 'Please run\n\ngam create|use project\ngam oauth create\n\nto create and authorize a Client account.\n'
|
INSTRUCTIONS_CLIENT_SECRETS_JSON = 'Please run\n\ngam create|use project\ngam oauth create\n\nto create and authorize a Client account.\n'
|
||||||
INSTRUCTIONS_OAUTH2SERVICE_JSON = 'Please run\n\ngam create|use project\ngam user <user> check serviceaccount\n\nto create and authorize a Service account.\n'
|
INSTRUCTIONS_OAUTH2SERVICE_JSON = 'Please run\n\ngam create|use project\ngam user <user> update serviceaccount\n\nto create and authorize a Service account.\n'
|
||||||
INSUFFICIENT_PERMISSIONS_TO_PERFORM_TASK = 'Insufficient permissions to perform this task'
|
INSUFFICIENT_PERMISSIONS_TO_PERFORM_TASK = 'Insufficient permissions to perform this task'
|
||||||
INTER_BATCH_WAIT_INCREASED = 'inter_batch_wait increased to {0:.2f}'
|
INTER_BATCH_WAIT_INCREASED = 'inter_batch_wait increased to {0:.2f}'
|
||||||
INVALID = 'Invalid'
|
INVALID = 'Invalid'
|
||||||
@@ -468,6 +468,10 @@ REFUSING_TO_DEPROVISION_DEVICES = 'Refusing to deprovision {0} devices because a
|
|||||||
REPLY_TO_CUSTOM_REQUIRES_EMAIL_ADDRESS = 'replyto REPLY_TO_CUSTOM requires customReplyTo <EmailAddress>'
|
REPLY_TO_CUSTOM_REQUIRES_EMAIL_ADDRESS = 'replyto REPLY_TO_CUSTOM requires customReplyTo <EmailAddress>'
|
||||||
REQUEST_COMPLETED_NO_FILES = 'Request completed but no results/files were returned, try requesting again'
|
REQUEST_COMPLETED_NO_FILES = 'Request completed but no results/files were returned, try requesting again'
|
||||||
REQUEST_NOT_COMPLETE = 'Request needs to be completed before downloading, current status is: {0}'
|
REQUEST_NOT_COMPLETE = 'Request needs to be completed before downloading, current status is: {0}'
|
||||||
|
RERUN_THE_COMMAND_AND_SPECIFY_A_NEW_SANAME = """
|
||||||
|
Re-run the command specify a new service account name with: saname <ServiceAccountName>
|
||||||
|
See: https://github.com/GAM-team/GAM/wiki/Authorization#advanced-use
|
||||||
|
"""
|
||||||
RESOURCE_CAPACITY_FLOOR_REQUIRED = 'Options "capacity <Number>" (<Number> > 0) and "floor <String>" required'
|
RESOURCE_CAPACITY_FLOOR_REQUIRED = 'Options "capacity <Number>" (<Number> > 0) and "floor <String>" required'
|
||||||
RESOURCE_FLOOR_REQUIRED = 'Option "floor <String>" required'
|
RESOURCE_FLOOR_REQUIRED = 'Option "floor <String>" required'
|
||||||
RESULTS_TOO_LARGE_FOR_GOOGLE_SPREADSHEET = 'Results are too large for Google Spreadsheets. Uploading as a regular CSV file.'
|
RESULTS_TOO_LARGE_FOR_GOOGLE_SPREADSHEET = 'Results are too large for Google Spreadsheets. Uploading as a regular CSV file.'
|
||||||
|
|||||||
@@ -144,6 +144,8 @@ _SKUS = {
|
|||||||
'product': 'Google-Apps', 'aliases': ['wsflw', 'workspacefrontline', 'workspacefrontlineworker'], 'displayName': 'Google Workspace Frontline Starter'},
|
'product': 'Google-Apps', 'aliases': ['wsflw', 'workspacefrontline', 'workspacefrontlineworker'], 'displayName': 'Google Workspace Frontline Starter'},
|
||||||
'1010020031': {
|
'1010020031': {
|
||||||
'product': 'Google-Apps', 'aliases': ['wsflwstan', 'workspacefrontlinestan', 'workspacefrontlineworkerstan'], 'displayName': 'Google Workspace Frontline Standard'},
|
'product': 'Google-Apps', 'aliases': ['wsflwstan', 'workspacefrontlinestan', 'workspacefrontlineworkerstan'], 'displayName': 'Google Workspace Frontline Standard'},
|
||||||
|
'1010020034': {
|
||||||
|
'product': 'Google-Apps', 'aliases': ['wsflwplus', 'workspacefrontlineplus', 'workspacefrontlineworkerplus'], 'displayName': 'Google Workspace Frontline Plus'},
|
||||||
'1010340001': {
|
'1010340001': {
|
||||||
'product': '101034', 'aliases': ['gseau', 'enterprisearchived', 'gsuiteenterprisearchived'], 'displayName': 'Google Workspace Enterprise Plus - Archived User'},
|
'product': '101034', 'aliases': ['gseau', 'enterprisearchived', 'gsuiteenterprisearchived'], 'displayName': 'Google Workspace Enterprise Plus - Archived User'},
|
||||||
'1010340002': {
|
'1010340002': {
|
||||||
|
|||||||
@@ -20,14 +20,19 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
GAM_VER_LIBS = ['cryptography',
|
GAM_VER_LIBS = [
|
||||||
'filelock',
|
'chardet',
|
||||||
'google-api-python-client',
|
'cryptography',
|
||||||
'google-auth-httplib2',
|
'filelock',
|
||||||
'google-auth-oauthlib',
|
'google-api-python-client',
|
||||||
'google-auth',
|
'google-auth-httplib2',
|
||||||
'httplib2',
|
'google-auth-oauthlib',
|
||||||
'passlib',
|
'google-auth',
|
||||||
'python-dateutil',
|
'lxml',
|
||||||
'yubikey-manager',
|
'httplib2',
|
||||||
]
|
'passlib',
|
||||||
|
'pathvalidate',
|
||||||
|
'pyscard',
|
||||||
|
'python-dateutil',
|
||||||
|
'yubikey-manager',
|
||||||
|
]
|
||||||
|
|||||||
BIN
src/license.rtf
BIN
src/license.rtf
Binary file not shown.
@@ -1,14 +1,15 @@
|
|||||||
chardet
|
chardet>=5.2.0
|
||||||
cryptography
|
cryptography>=44.0.2
|
||||||
distro; sys_platform=='linux'
|
distro; sys_platform=='linux'
|
||||||
filelock
|
filelock>=3.18.0
|
||||||
google-api-python-client>=2.166.0
|
google-api-python-client>=2.167.0
|
||||||
google-auth-httplib2>=0.2.0
|
google-auth-httplib2>=0.2.0
|
||||||
google-auth-oauthlib>=1.2.1
|
google-auth-oauthlib>=1.2.2
|
||||||
google-auth>=2.38.0
|
google-auth>=2.39.0
|
||||||
httplib2>=0.22.0
|
httplib2>=0.22.0
|
||||||
lxml
|
lxml>=5.4.0
|
||||||
passlib>=1.7.4
|
passlib>=1.7.4
|
||||||
pathvalidate
|
pathvalidate>=3.2.3
|
||||||
|
pyscard==2.2.1
|
||||||
python-dateutil
|
python-dateutil
|
||||||
yubikey-manager[yubikey]>=5.6.1
|
yubikey-manager>=5.6.1
|
||||||
|
|||||||
@@ -17,26 +17,29 @@ classifiers =
|
|||||||
Programming Language :: Python :: 3.10
|
Programming Language :: Python :: 3.10
|
||||||
Programming Language :: Python :: 3.11
|
Programming Language :: Python :: 3.11
|
||||||
Programming Language :: Python :: 3.12
|
Programming Language :: Python :: 3.12
|
||||||
|
Programming Language :: Python :: 3.13
|
||||||
License :: OSI Approved :: Apache License
|
License :: OSI Approved :: Apache License
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
packages = find:
|
packages = find:
|
||||||
python_requires = >= 3.8
|
python_requires = >= 3.9
|
||||||
|
# The following files should be edited to match: pyproject.toml, requirements.txt
|
||||||
install_requires =
|
install_requires =
|
||||||
chardet
|
chardet >= 5.2.0
|
||||||
cryptography
|
cryptography >= 44.0.2
|
||||||
distro; sys_platform == 'linux'
|
distro; sys_platform == 'linux'
|
||||||
filelock
|
filelock >= 3.18.0
|
||||||
google-api-python-client >= 2.36
|
google-api-python-client >= 2.167.0
|
||||||
google-auth-httplib2
|
google-auth-httplib2 >= 0.2.0
|
||||||
google-auth-oauthlib >= 0.4.6
|
google-auth-oauthlib >= 1.2.2
|
||||||
google-auth >= 2.3.3
|
google-auth >= 2.39.0
|
||||||
httplib2 >= 0.20.2
|
httplib2 >= 0.22.0
|
||||||
lxml
|
lxml >= 5.4.0
|
||||||
passlib >= 1.7.4
|
passlib >= 1.7.4
|
||||||
pathvalidate
|
pathvalidate >= 3.2.3
|
||||||
|
pyscard == 2.2.1
|
||||||
python-dateutil
|
python-dateutil
|
||||||
yubikey-manager >= 5.0
|
yubikey-manager >= 5.6.1
|
||||||
|
|
||||||
[options.package_data]
|
[options.package_data]
|
||||||
* = *.pem
|
* = *.pem
|
||||||
|
|||||||
@@ -24,18 +24,19 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
|||||||
- Start a terminal session.
|
- Start a terminal session.
|
||||||
|
|
||||||
* Executable Archive, Manual, Raspberry Pi/ChromeOS ARM devices
|
* Executable Archive, Manual, Raspberry Pi/ChromeOS ARM devices
|
||||||
- `gam-7.wx.yz-linux-aarch64-glibc2.35.tar.xz`
|
- `gam-7.wx.yz-linux-arm64-glibc2.35.tar.xz`
|
||||||
- `gam-7.wx.yz-linux-aarch64-legacy.tar.xz`
|
- `gam-7.wx.yz-linux-arm64-glibc2.39.tar.xz`
|
||||||
|
- `gam-7.wx.yz-linux-arm64-legacy.tar.xz`
|
||||||
- Download the archive, extract the contents into some directory.
|
- Download the archive, extract the contents into some directory.
|
||||||
- Start a terminal session.
|
- Start a terminal session.
|
||||||
|
|
||||||
* Executable Archive, Manual, Mac OS versions Sonoma, Sequoia - M1/M2
|
* Executable Archive, Manual, Mac OS versions Sonoma, Sequoia - M1/M2
|
||||||
- `gam-7.wx.yz-macos14.7-aarch64.tar.xz`
|
- `gam-7.wx.yz-macos14.7-arm64.tar.xz`
|
||||||
- Download the archive, extract the contents into some directory.
|
- Download the archive, extract the contents into some directory.
|
||||||
- Start a terminal session.
|
- Start a terminal session.
|
||||||
|
|
||||||
* Executable Archive, Manual, Mac OS versions Sequoia - M3
|
* Executable Archive, Manual, Mac OS versions Sequoia - M3
|
||||||
- `gam-7.wx.yz-macos15.2-aarch64.tar.xz`
|
- `gam-7.wx.yz-macos15.4-arm64.tar.xz`
|
||||||
- Download the archive, extract the contents into some directory.
|
- Download the archive, extract the contents into some directory.
|
||||||
- Start a terminal session.
|
- Start a terminal session.
|
||||||
|
|
||||||
@@ -54,6 +55,16 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
|||||||
- Download the installer and run it.
|
- Download the installer and run it.
|
||||||
- Start a Command Prompt/PowerShell session.
|
- Start a Command Prompt/PowerShell session.
|
||||||
|
|
||||||
|
* Executable Archive, Manual, Windows 11 ARM
|
||||||
|
- `gam-7.wx.yz-windows-arm64.zip`
|
||||||
|
- Download the archive, extract the contents into some directory.
|
||||||
|
- Start a Command Prompt/PowerShell session.
|
||||||
|
|
||||||
|
* Executable Installer, Manual, Windows 11 ARM
|
||||||
|
- `gam-7.wx.yz-windows-arm64.msi`
|
||||||
|
- Download the installer and run it.
|
||||||
|
- Start a Command Prompt/PowerShell session.
|
||||||
|
|
||||||
* Source, all platforms
|
* Source, all platforms
|
||||||
- `Source code(zip)`
|
- `Source code(zip)`
|
||||||
- `Source code(tar.gz)`
|
- `Source code(tar.gz)`
|
||||||
|
|||||||
@@ -10,6 +10,54 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
|||||||
|
|
||||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||||
|
|
||||||
|
### 7.06.12
|
||||||
|
|
||||||
|
Deleted commands to display Analytic UA properties; the API has been deprecated.
|
||||||
|
```
|
||||||
|
gam <UserTypeEntity> print|show analyticuaproperties
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.06.11
|
||||||
|
|
||||||
|
Improved `gam checkconn`.
|
||||||
|
|
||||||
|
Updated `gam print group-members` and `gam print cigroup-members` to recognize members
|
||||||
|
that are groups representing chat spaces. For now, these groups are not expanded when
|
||||||
|
`recursive` is specified.
|
||||||
|
|
||||||
|
### 7.06.10
|
||||||
|
|
||||||
|
Added the following license SKU.
|
||||||
|
```
|
||||||
|
1010020034 - Google Workspace Frontline Plus
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.06.09
|
||||||
|
|
||||||
|
Added `gemini` and `geminiforworkspace` to `<ActivityApplicationName>` for use in
|
||||||
|
`gam report <ActivityApplicationName>`.
|
||||||
|
|
||||||
|
### 7.06.08
|
||||||
|
|
||||||
|
Fixed problem where Yubikeys caused a trap.
|
||||||
|
|
||||||
|
### 7.06.07
|
||||||
|
|
||||||
|
Updated private key rotation progress messages in `gam create|use|update project`
|
||||||
|
and `gam upload sakey`.
|
||||||
|
|
||||||
|
Updated `gam use project` to display the following error message when the specifed project
|
||||||
|
already has a service account.
|
||||||
|
```
|
||||||
|
Re-run the command specify a new service account name with: saname <ServiceAccountName>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.06.06
|
||||||
|
|
||||||
|
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".
|
||||||
|
|
||||||
### 7.06.05
|
### 7.06.05
|
||||||
|
|
||||||
Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
|
Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt.
|
|||||||
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||||
admin@server:/Users/admin$ gam version
|
admin@server:/Users/admin$ gam version
|
||||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
GAM 7.06.12 - https://github.com/GAM-team/GAM - pyinstaller
|
||||||
GAM Team <google-apps-manager@googlegroups.com>
|
GAM Team <google-apps-manager@googlegroups.com>
|
||||||
Python 3.13.3 64-bit final
|
Python 3.13.3 64-bit final
|
||||||
MacOS Sequoia 15.4.1 x86_64
|
MacOS Sequoia 15.4.1 x86_64
|
||||||
@@ -989,7 +989,7 @@ writes the credentials into the file oauth2.txt.
|
|||||||
C:\>del C:\GAMConfig\oauth2.txt
|
C:\>del C:\GAMConfig\oauth2.txt
|
||||||
C:\>gam version
|
C:\>gam version
|
||||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pythonsource
|
GAM 7.06.12 - https://github.com/GAM-team/GAM - pythonsource
|
||||||
GAM Team <google-apps-manager@googlegroups.com>
|
GAM Team <google-apps-manager@googlegroups.com>
|
||||||
Python 3.13.3 64-bit final
|
Python 3.13.3 64-bit final
|
||||||
Windows-10-10.0.17134 AMD64
|
Windows-10-10.0.17134 AMD64
|
||||||
|
|||||||
@@ -110,6 +110,7 @@
|
|||||||
| Google Workspace for Education: Teaching and Learning Upgrade | 1010370001 | gwetlu |
|
| Google Workspace for Education: Teaching and Learning Upgrade | 1010370001 | gwetlu |
|
||||||
| Google Workspace Frontline Starter | 1010020030 | wsflw |
|
| Google Workspace Frontline Starter | 1010020030 | wsflw |
|
||||||
| Google Workspace Frontline Standard | 1010020031 | wsflwstan |
|
| Google Workspace Frontline Standard | 1010020031 | wsflwstan |
|
||||||
|
| Google Workspace Frontline Plus | 1010020034 | wsflwplus |
|
||||||
| Google Workspace Government | Google-Apps-For-Government | gsuitegov |
|
| Google Workspace Government | Google-Apps-For-Government | gsuitegov |
|
||||||
| Google Workspace Labs | 1010470002 | gwlabs | workspacelabs |
|
| Google Workspace Labs | 1010470002 | gwlabs | workspacelabs |
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ config csv_output_row_filter "'\"accounts:used_quota_in_mb\":count>15000'"
|
|||||||
domain|
|
domain|
|
||||||
drive|doc|docs|
|
drive|doc|docs|
|
||||||
gcp|
|
gcp|
|
||||||
|
gemini|geminiforworkspace|
|
||||||
groups|group|
|
groups|group|
|
||||||
groupsenterprise|enterprisegroups|
|
groupsenterprise|enterprisegroups|
|
||||||
jamboard|
|
jamboard|
|
||||||
|
|||||||
@@ -6,14 +6,13 @@
|
|||||||
- [Display Analytic Account Summaries](#display-analytic-account-summaries)
|
- [Display Analytic Account Summaries](#display-analytic-account-summaries)
|
||||||
- [Display Analytic Properties](#display-analytic-properties)
|
- [Display Analytic Properties](#display-analytic-properties)
|
||||||
- [Display Analytic Datastreams](#display-analytic-datastreams)
|
- [Display Analytic Datastreams](#display-analytic-datastreams)
|
||||||
- [Display Analytic UA Properties](#display-analytic-ua-properties)
|
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
|
|
||||||
## API documentation
|
## API documentation
|
||||||
* [Analytics Admin API](https://developers.google.com/analytics/devguides/config/admin/v1/rest)
|
* [Analytics Admin API](https://developers.google.com/analytics/devguides/config/admin/v1/rest)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
To use these commands you must add 'Analytics API' and 'Analytics Admin API' to your project and update your service account authorization.
|
To use these commands you must add 'Analytics Admin API' to your project and update your service account authorization.
|
||||||
```
|
```
|
||||||
gam update project
|
gam update project
|
||||||
gam user user@domain.com update serviceaccount
|
gam user user@domain.com update serviceaccount
|
||||||
@@ -142,37 +141,6 @@ When using the `formatjson` option, double quotes are used extensively in the da
|
|||||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||||
|
|
||||||
## Display Analytic UA Properties
|
|
||||||
```
|
|
||||||
gam <UserTypeEntity> show analyticuaproperties
|
|
||||||
accountid [accounts/]<String>
|
|
||||||
[maxresults <Integer>]
|
|
||||||
[formatjson]
|
|
||||||
```
|
|
||||||
The required `accountid <String>` can be in the format: 'accounts/123' or '123'.
|
|
||||||
|
|
||||||
By default, GAM asks the API for 50 properties per page of results,
|
|
||||||
* `maxresults` - Maximum number of results per page; range is 1-200; the default is 50.
|
|
||||||
|
|
||||||
By default, Gam displays the information as an indented list of keys and values.
|
|
||||||
* `formatjson` - Display the fields in JSON format.
|
|
||||||
```
|
|
||||||
gam <UserTypeEntity> print analyticuaproperties [todrive <ToDriveAttribute>*]
|
|
||||||
accountid [accounts/]<String>
|
|
||||||
[maxresults <Integer>]
|
|
||||||
[formatjson [quotechar <Character>]]
|
|
||||||
```
|
|
||||||
The required `accountid <String>` can be in the format: 'accounts/123' or '123'.
|
|
||||||
|
|
||||||
By default, GAM asks the API for 50 properties per page of results,
|
|
||||||
* `maxresults` - Maximum number of results per page; range is 1-200; the default is 50.
|
|
||||||
|
|
||||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
|
||||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
|
||||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
|
||||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
|
||||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
Get all analytic accounts
|
Get all analytic accounts
|
||||||
@@ -189,8 +157,3 @@ Get all analytic account properties (GA4)
|
|||||||
```
|
```
|
||||||
gam redirect stdout - multiprocess redirect stderr stdout redirect csv ./GA4AnalyticAccountProperties.csv multiprocess csv AnalyticAccounts.csv gam user "~User" print analyticproperties filter "parent:~~name~~"
|
gam redirect stdout - multiprocess redirect stderr stdout redirect csv ./GA4AnalyticAccountProperties.csv multiprocess csv AnalyticAccounts.csv gam user "~User" print analyticproperties filter "parent:~~name~~"
|
||||||
```
|
```
|
||||||
|
|
||||||
Get all analytic account properties (UA)
|
|
||||||
```
|
|
||||||
gam redirect stdout - multiprocess redirect stderr stdout redirect csv ./UAAnalyticAccountProperties.csv multiprocess csv AnalyticAccounts.csv gam user "~User" print analyticuaproperties accountid "~~name~~"
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
|||||||
|
|
||||||
## Set up a Chat Bot
|
## Set up a Chat Bot
|
||||||
|
|
||||||
* Run the command `gam setup chat`; it will point you to a URL to configure your Chat Bot; this is required to use the Chat API.
|
* Run the command `gam setup chat`; it will point you to a URL to configure your Chat Bot.
|
||||||
* Enter an App name and Description of your choosing.
|
* Enter an App name and Description of your choosing.
|
||||||
* For the Avatar URL you can use `https://dummyimage.com/384x256/4d4d4d/0011ff.png&text=+GAM` or a public URL to an image of your own choosing.
|
* For the Avatar URL you can use `https://dummyimage.com/384x256/4d4d4d/0011ff.png&text=+GAM` or a public URL to an image of your own choosing.
|
||||||
* In Functionality, uncheck both "Receive 1:1 messages" and "Join spaces and group conversations"
|
* In Functionality, uncheck both "Receive 1:1 messages" and "Join spaces and group conversations"
|
||||||
* In Connection settings, choose "Cloud Pub/Sub" and enter "no-topic" for the topic name. GAM doesn't yet listen to pub/sub so this option is not used.
|
* In Connection settings, choose "Cloud Pub/Sub" and enter `projects/<ProjectID>/topics/no-topic` for the topic name. Replace `<ProjectID>` with your GAM project ID. GAM doesn't yet listen to pub/sub so this option is not used.
|
||||||
* In Visibility, uncheck "Make this Chat app available to specific people and groups in Domain Workspace".
|
* In Visibility, uncheck "Make this Chat app available to specific people and groups in Domain Workspace".
|
||||||
* Click Save.
|
* Click Save.
|
||||||
|
|
||||||
## API documentation
|
## API documentation
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ k
|
|||||||
Print the current version of Gam with details
|
Print the current version of Gam with details
|
||||||
```
|
```
|
||||||
gam version
|
gam version
|
||||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
GAM 7.06.12 - https://github.com/GAM-team/GAM - pyinstaller
|
||||||
GAM Team <google-apps-manager@googlegroups.com>
|
GAM Team <google-apps-manager@googlegroups.com>
|
||||||
Python 3.13.3 64-bit final
|
Python 3.13.3 64-bit final
|
||||||
MacOS Sequoia 15.4.1 x86_64
|
MacOS Sequoia 15.4.1 x86_64
|
||||||
@@ -16,7 +16,7 @@ Time: 2023-06-02T21:10:00-07:00
|
|||||||
Print the current version of Gam with details and time offset information
|
Print the current version of Gam with details and time offset information
|
||||||
```
|
```
|
||||||
gam version timeoffset
|
gam version timeoffset
|
||||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
GAM 7.06.12 - https://github.com/GAM-team/GAM - pyinstaller
|
||||||
GAM Team <google-apps-manager@googlegroups.com>
|
GAM Team <google-apps-manager@googlegroups.com>
|
||||||
Python 3.13.3 64-bit final
|
Python 3.13.3 64-bit final
|
||||||
MacOS Sequoia 15.4.1 x86_64
|
MacOS Sequoia 15.4.1 x86_64
|
||||||
@@ -28,7 +28,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
|
Print the current version of Gam with extended details and SSL information
|
||||||
```
|
```
|
||||||
gam version extended
|
gam version extended
|
||||||
GAM 7.06.05 - https://github.com/GAM-team/GAM - pyinstaller
|
GAM 7.06.12 - https://github.com/GAM-team/GAM - pyinstaller
|
||||||
GAM Team <google-apps-manager@googlegroups.com>
|
GAM Team <google-apps-manager@googlegroups.com>
|
||||||
Python 3.13.3 64-bit final
|
Python 3.13.3 64-bit final
|
||||||
MacOS Sequoia 15.4.1 x86_64
|
MacOS Sequoia 15.4.1 x86_64
|
||||||
@@ -65,7 +65,7 @@ MacOS High Sierra 10.13.6 x86_64
|
|||||||
Path: /Users/Admin/bin/gam7
|
Path: /Users/Admin/bin/gam7
|
||||||
Version Check:
|
Version Check:
|
||||||
Current: 5.35.08
|
Current: 5.35.08
|
||||||
Latest: 7.06.05
|
Latest: 7.06.12
|
||||||
echo $?
|
echo $?
|
||||||
1
|
1
|
||||||
```
|
```
|
||||||
@@ -73,7 +73,7 @@ echo $?
|
|||||||
Print the current version number without details
|
Print the current version number without details
|
||||||
```
|
```
|
||||||
gam version simple
|
gam version simple
|
||||||
7.06.05
|
7.06.12
|
||||||
```
|
```
|
||||||
In Linux/MacOS you can do:
|
In Linux/MacOS you can do:
|
||||||
```
|
```
|
||||||
@@ -83,7 +83,7 @@ echo $VER
|
|||||||
Print the current version of Gam and address of this Wiki
|
Print the current version of Gam and address of this Wiki
|
||||||
```
|
```
|
||||||
gam help
|
gam help
|
||||||
GAM 7.06.05 - https://github.com/GAM-team/GAM
|
GAM 7.06.12 - https://github.com/GAM-team/GAM
|
||||||
GAM Team <google-apps-manager@googlegroups.com>
|
GAM Team <google-apps-manager@googlegroups.com>
|
||||||
Python 3.13.3 64-bit final
|
Python 3.13.3 64-bit final
|
||||||
MacOS Sequoia 15.4.1 x86_64
|
MacOS Sequoia 15.4.1 x86_64
|
||||||
|
|||||||
Reference in New Issue
Block a user