mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-05 14:51:39 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55e5b86ec4 | ||
|
|
bf29a56aeb | ||
|
|
07c57d4197 | ||
|
|
146db31cb5 | ||
|
|
14239fcd47 | ||
|
|
8dc6a17295 | ||
|
|
76f9a6c746 | ||
|
|
eb155a5690 | ||
|
|
b78575aa8f | ||
|
|
91a5cd5c69 |
12
.travis.yml
12
.travis.yml
@@ -5,8 +5,8 @@ dist: focal
|
||||
|
||||
env:
|
||||
global:
|
||||
- BUILD_PYTHON_VERSION=3.8.6
|
||||
- MIN_PYTHON_VERSION=3.8.6
|
||||
- BUILD_PYTHON_VERSION=3.9.0
|
||||
- MIN_PYTHON_VERSION=3.9.0
|
||||
- BUILD_OPENSSL_VERSION=1.1.1h
|
||||
- MIN_OPENSSL_VERSION=1.1.1h
|
||||
- PATCHELF_VERSION=0.11
|
||||
@@ -61,9 +61,13 @@ jobs:
|
||||
language: python
|
||||
python: 3.7
|
||||
- os: linux
|
||||
name: "Python 3.9 dev Source Testing"
|
||||
name: "Python 3.8 Source Testing"
|
||||
language: python
|
||||
python: 3.9-dev
|
||||
python: 3.8
|
||||
- os: linux
|
||||
name: "Python 3.10 dev Source Testing"
|
||||
language: python
|
||||
python: 3.10-dev
|
||||
# - os: linux
|
||||
# name: "Python trunk nightly Source Testing"
|
||||
# language: python
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
GAM is a command line tool for Google G Suite Administrators to manage domain and user settings quickly and easily. [](https://travis-ci.org/jay0lee/GAM)
|
||||
GAM is a command line tool for Google Workspace (fka G Suite) Administrators to manage domain and user settings quickly and easily. [](https://travis-ci.org/jay0lee/GAM)
|
||||
# Quick Start
|
||||
## Linux / MacOS
|
||||
Open a terminal and run:
|
||||
|
||||
@@ -288,7 +288,7 @@ while true; do
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
if [ "$adminuser" == "" ]; then
|
||||
read -p "Please enter your G Suite admin email address: " adminuser
|
||||
read -p "Please enter your Google Workspace admin email address: " adminuser
|
||||
fi
|
||||
"$target_dir/gam/gam" create project $adminuser
|
||||
rc=$?
|
||||
@@ -312,7 +312,7 @@ done
|
||||
|
||||
admin_authorized=false
|
||||
while $project_created; do
|
||||
read -p "Are you ready to authorize GAM to perform G Suite management operations as your admin account? (yes or no) " yn
|
||||
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_dir/gam/gam" oauth create $adminuser
|
||||
@@ -337,11 +337,11 @@ done
|
||||
|
||||
service_account_authorized=false
|
||||
while $project_created; do
|
||||
read -p "Are you ready to authorize GAM to manage G Suite user data and settings? (yes or no) " yn
|
||||
read -p "Are you ready to authorize GAM to manage Google Workspace user data and settings? (yes or no) " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
if [ "$regularuser" == "" ]; then
|
||||
read -p "Please enter the email address of a regular G Suite user: " regularuser
|
||||
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_dir/gam/gam" user $adminuser check serviceaccount
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
@ goto createproject
|
||||
)
|
||||
@echo(
|
||||
@set /p adminemail= "Please enter your G Suite admin email address: "
|
||||
@set /p adminemail= "Please enter your Google Workspace admin email address: "
|
||||
@gam create project %adminemail%
|
||||
@if not ERRORLEVEL 1 goto projectdone
|
||||
@echo(
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
:adminauth
|
||||
@echo(
|
||||
@set /p yn= "Are you ready to authorize GAM to perform G Suite management operations as your admin account? [y or n] "
|
||||
@set /p yn= "Are you ready to authorize GAM to perform Google Workspace management operations as your admin account? [y or n] "
|
||||
@if /I "%yn%"=="n" (
|
||||
@ echo(
|
||||
@ echo You can authorize an admin later by running:
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
:saauth
|
||||
@echo(
|
||||
@set /p yn= "Are you ready to authorize GAM to manage G Suite user data and settings? [y or n] "
|
||||
@set /p yn= "Are you ready to authorize GAM to manage Google Workspace user data and settings? [y or n] "
|
||||
@if /I "%yn%"=="n" (
|
||||
@ echo(
|
||||
@ echo You can authorize a service account later by running:
|
||||
@@ -73,7 +73,7 @@
|
||||
@ goto saauth
|
||||
)
|
||||
@echo(
|
||||
@set /p regularuser= "Please enter the email address of a regular G Suite user: "
|
||||
@set /p regularuser= "Please enter the email address of a regular Google Workspace user: "
|
||||
@echo 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.
|
||||
@gam user %regularuser% check serviceaccount
|
||||
@if not ERRORLEVEL 1 goto sadone
|
||||
|
||||
@@ -3454,6 +3454,7 @@ def initializeDriveFileAttributes():
|
||||
|
||||
|
||||
def getDriveFileAttribute(i, body, parameters, myarg, update=False):
|
||||
operation = 'update' if update else 'add'
|
||||
if myarg == 'localfile':
|
||||
parameters[DFA_LOCALFILEPATH] = sys.argv[i + 1]
|
||||
parameters[DFA_LOCALFILENAME] = os.path.basename(
|
||||
@@ -3529,9 +3530,26 @@ def getDriveFileAttribute(i, body, parameters, myarg, update=False):
|
||||
elif myarg == 'writerscantshare':
|
||||
body['writersCanShare'] = False
|
||||
i += 1
|
||||
elif myarg == 'contentrestrictions':
|
||||
body['contentRestrictions'] = [{}]
|
||||
restriction = sys.argv[i+1].lower().replace('_', '')
|
||||
if restriction == 'readonly':
|
||||
body['contentRestrictions'][0]['readOnly'] = getBoolean(
|
||||
sys.argv[i+2], f'gam <users> {operation} drivefile')
|
||||
i += 3
|
||||
if len(sys.argv) > i and sys.argv[i].lower() == 'reason':
|
||||
body['contentRestrictions'][0]['reason'] = sys.argv[i+1]
|
||||
i += 2
|
||||
else:
|
||||
controlflow.invalid_argument_exit(
|
||||
restriction, f'gam <users> {operation} drivefile')
|
||||
elif myarg == 'shortcut':
|
||||
body['mimeType'] = MIMETYPE_GA_SHORTCUT
|
||||
body['shortcutDetails'] = {'targetId': sys.argv[i+1]}
|
||||
i += 2
|
||||
else:
|
||||
controlflow.invalid_argument_exit(
|
||||
myarg, f"gam <users> {['add', 'update'][update]} drivefile")
|
||||
myarg, f"gam <users> {operation} drivefile")
|
||||
return i
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""GAM is a command line tool which allows Administrators to control their G Suite domain and accounts.
|
||||
"""GAM is a command line tool which allows Administrators to control their Google Workspace domain and accounts.
|
||||
|
||||
With GAM you can programmatically create users, turn on/off services for users like POP and Forwarding and much more.
|
||||
For more information, see https://git.io/gam
|
||||
|
||||
@@ -326,6 +326,6 @@ def sync():
|
||||
kwargs = {'customer': customer}
|
||||
else:
|
||||
kwargs = {'body': {'customer': customer}}
|
||||
gapi.call(ci.devices(), unassigned_missing_action,
|
||||
gapi.call(ci.devices(), action,
|
||||
name=name, **kwargs)
|
||||
print(f'{action}d {sn}')
|
||||
|
||||
@@ -237,6 +237,11 @@ def print_():
|
||||
for groupEntity in entityList:
|
||||
i += 1
|
||||
groupEmail = groupEntity['groupKey']['id']
|
||||
for k, v in iter(groupEntity.pop('labels', {}).items()):
|
||||
if v == '':
|
||||
groupEntity[f'labels.{k}'] = True
|
||||
else:
|
||||
groupEntity[f'labels.{k}'] = v
|
||||
group = utils.flatten_json(groupEntity)
|
||||
for a_key in group:
|
||||
if a_key not in titles:
|
||||
@@ -304,7 +309,7 @@ def print_():
|
||||
csvRows.append(group)
|
||||
if sortHeaders:
|
||||
display.sort_csv_titles([
|
||||
'Email',
|
||||
'name', 'groupKey.id'
|
||||
], titles)
|
||||
display.write_csv_file(csvRows, titles, 'Groups', todrive)
|
||||
|
||||
@@ -407,6 +412,7 @@ def update():
|
||||
def _getRoleAndUsers():
|
||||
checkSuspended = None
|
||||
role = None
|
||||
expireTime = None
|
||||
i = 5
|
||||
if sys.argv[i].lower() in GROUP_ROLES_MAP:
|
||||
role = GROUP_ROLES_MAP[sys.argv[i].lower()]
|
||||
@@ -414,6 +420,9 @@ def update():
|
||||
if sys.argv[i].lower() in ['suspended', 'notsuspended']:
|
||||
checkSuspended = sys.argv[i].lower() == 'suspended'
|
||||
i += 1
|
||||
if sys.argv[i].lower() in ['expire', 'expires']:
|
||||
expireTime = sys.argv[i+1]
|
||||
i += 2
|
||||
if sys.argv[i].lower() in usergroup_types:
|
||||
users_email = gam.getUsersToModify(entity_type=sys.argv[i].lower(),
|
||||
entity=sys.argv[i + 1],
|
||||
@@ -424,7 +433,7 @@ def update():
|
||||
gam.normalizeEmailAddressOrUID(sys.argv[i],
|
||||
checkForCustomerId=True)
|
||||
]
|
||||
return (role, users_email)
|
||||
return (role, expireTime, users_email)
|
||||
|
||||
ci = gapi_cloudidentity.build('cloudidentity_beta')
|
||||
group = sys.argv[3]
|
||||
@@ -439,7 +448,7 @@ def update():
|
||||
if not parent:
|
||||
return
|
||||
if myarg == 'add':
|
||||
role, users_email = _getRoleAndUsers()
|
||||
role, expireTime, users_email = _getRoleAndUsers()
|
||||
if not role:
|
||||
role = ROLE_MEMBER
|
||||
if len(users_email) > 1:
|
||||
@@ -448,8 +457,10 @@ def update():
|
||||
for user_email in users_email:
|
||||
item = [
|
||||
'gam', 'update', 'cigroup', f'id:{parent}', 'add', role,
|
||||
user_email
|
||||
]
|
||||
if expireTime:
|
||||
item.extend(['expires', expireTime])
|
||||
item.append(user_email)
|
||||
items.append(item)
|
||||
elif len(users_email) > 0:
|
||||
body = {
|
||||
@@ -462,6 +473,10 @@ def update():
|
||||
}
|
||||
if role != ROLE_MEMBER:
|
||||
body['roles'].append({'name': role})
|
||||
if expireTime:
|
||||
for role in body['roles']:
|
||||
if role['name'] == ROLE_MEMBER:
|
||||
role['expiryDetail'] = {'expireTime': expireTime}
|
||||
add_text = [f'as {role}']
|
||||
for i in range(2):
|
||||
try:
|
||||
@@ -494,7 +509,7 @@ def update():
|
||||
elif myarg == 'sync':
|
||||
syncMembersSet = set()
|
||||
syncMembersMap = {}
|
||||
role, users_email = _getRoleAndUsers()
|
||||
role, expireTime, users_email = _getRoleAndUsers()
|
||||
for user_email in users_email:
|
||||
if user_email in ('*', GC_Values[GC_CUSTOMER_ID]):
|
||||
syncMembersSet.add(GC_Values[GC_CUSTOMER_ID])
|
||||
@@ -527,17 +542,18 @@ def update():
|
||||
f'Group: {group}, Will add {len(to_add)} and remove {len(to_remove)} {role}s.\n'
|
||||
)
|
||||
for user in to_add:
|
||||
item = [
|
||||
'gam', 'update', 'cigroup', f'id:{parent}', 'add', role,
|
||||
user
|
||||
]
|
||||
item = ['gam', 'update', 'cigroup', f'id:{parent}', 'add',
|
||||
role,]
|
||||
if expireTime:
|
||||
item.extend(['expires', expireTime])
|
||||
item.append(user)
|
||||
items.append(item)
|
||||
for user in to_remove:
|
||||
items.append([
|
||||
'gam', 'update', 'cigroup', f'id:{parent}', 'remove', user
|
||||
])
|
||||
elif myarg in ['delete', 'remove']:
|
||||
_, users_email = _getRoleAndUsers()
|
||||
_, _, users_email = _getRoleAndUsers()
|
||||
if len(users_email) > 1:
|
||||
sys.stderr.write(
|
||||
f'Group: {group}, Will remove {len(users_email)} emails.\n')
|
||||
@@ -563,7 +579,7 @@ def update():
|
||||
f' Group: {group}, {users_email[0]} Remove Failed: {str(e)}'
|
||||
)
|
||||
elif myarg == 'update':
|
||||
role, users_email = _getRoleAndUsers()
|
||||
role, expireTime, users_email = _getRoleAndUsers()
|
||||
if not role:
|
||||
role = ROLE_MEMBER
|
||||
if len(users_email) > 1:
|
||||
@@ -573,8 +589,10 @@ def update():
|
||||
for user_email in users_email:
|
||||
item = [
|
||||
'gam', 'update', 'cigroup', f'id:{parent}', 'update',
|
||||
role, user_email
|
||||
]
|
||||
role,]
|
||||
if expireTime:
|
||||
item.extend(['expires', expireTime])
|
||||
item.append(user_email)
|
||||
items.append(item)
|
||||
elif len(users_email) > 0:
|
||||
name = membership_email_to_id(ci, parent, users_email[0])
|
||||
@@ -589,12 +607,25 @@ def update():
|
||||
if crole not in {ROLE_MEMBER, role}:
|
||||
removeRoles.append(crole)
|
||||
if role not in current_roles:
|
||||
addRoles.append({'name': role})
|
||||
new_role = {'name': role}
|
||||
if role == ROLE_MEMBER and expireTime:
|
||||
new_role['expiryDetail'] = {'expireTime': expireTime}
|
||||
expireTime = None
|
||||
addRoles.append(new_role)
|
||||
bodys = []
|
||||
if addRoles:
|
||||
bodys.append({'addRoles': addRoles})
|
||||
if removeRoles:
|
||||
bodys.append({'removeRoles': removeRoles})
|
||||
if expireTime:
|
||||
bodys.append({
|
||||
'name': ROLE_MEMBER,
|
||||
# Note this doesn't actually work for some reason. Only known method to change
|
||||
# expire time right now is to remove/re-add member.
|
||||
'expiryDetail': {
|
||||
'expireTime': expireTime
|
||||
}
|
||||
})
|
||||
for body in bodys:
|
||||
try:
|
||||
gapi.call(ci.groups().memberships(),
|
||||
|
||||
@@ -184,5 +184,5 @@ def update():
|
||||
pass
|
||||
print()
|
||||
print(
|
||||
f'You can now add {a_domain} or it\'s subdomains as secondary or domain aliases of the {GC_Values[GC_DOMAIN]} G Suite Account.'
|
||||
f'You can now add {a_domain} or it\'s subdomains as secondary or domain aliases of the {GC_Values[GC_DOMAIN]} Google Workspace Account.'
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import platform
|
||||
import re
|
||||
|
||||
GAM_AUTHOR = 'Jay Lee <jay0lee@gmail.com>'
|
||||
GAM_VERSION = '5.22'
|
||||
GAM_VERSION = '5.23'
|
||||
GAM_LICENSE = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
GAM_URL = 'https://git.io/gam'
|
||||
@@ -117,7 +117,7 @@ SKUS = {
|
||||
'1010020020': {
|
||||
'product': 'Google-Apps',
|
||||
'aliases': ['gae', 'gse', 'enterprise', 'gsuiteenterprise'],
|
||||
'displayName': 'G Suite Enterprise'
|
||||
'displayName': 'Google Workspace Enterprise Plus (fka G Suite Enterprise)'
|
||||
},
|
||||
'1010340002': {
|
||||
'product': '101034',
|
||||
@@ -127,7 +127,7 @@ SKUS = {
|
||||
'1010340001': {
|
||||
'product': '101034',
|
||||
'aliases': ['gseau', 'enterprisearchived', 'gsuiteenterprisearchived'],
|
||||
'displayName': 'G Suite Enterprise Archived'
|
||||
'displayName': 'Google Workspace Enterprise Plus Archived'
|
||||
},
|
||||
'1010060001': {
|
||||
'product': '101006',
|
||||
@@ -135,7 +135,7 @@ SKUS = {
|
||||
'gsuiteessentials', 'essentials', 'd4e', 'driveenterprise',
|
||||
'drive4enterprise'
|
||||
],
|
||||
'displayName': 'G Suite Essentials'
|
||||
'displayName': 'Google Workspace Essentials'
|
||||
},
|
||||
'Google-Drive-storage-20GB': {
|
||||
'product': 'Google-Drive-storage',
|
||||
@@ -210,7 +210,7 @@ PRODUCTID_NAME_MAPPINGS = {
|
||||
'101031': 'G Suite Enterprise for Education',
|
||||
'101033': 'Google Voice',
|
||||
'101034': 'G Suite Archived',
|
||||
'Google-Apps': 'G Suite',
|
||||
'Google-Apps': 'Google Workspace',
|
||||
'Google-Chrome-Device-Management': 'Google Chrome Device Management',
|
||||
'Google-Coordinate': 'Google Coordinate',
|
||||
'Google-Drive-storage': 'Google Drive Storage',
|
||||
@@ -223,7 +223,6 @@ V1_DISCOVERY_APIS = {
|
||||
'appsactivity',
|
||||
'calendar',
|
||||
'drive',
|
||||
'licensing',
|
||||
'oauth2',
|
||||
'reseller',
|
||||
'siteVerification',
|
||||
@@ -489,16 +488,17 @@ DRIVEFILE_LABEL_CHOICES_MAP = {
|
||||
}
|
||||
|
||||
APPLICATION_VND_GOOGLE_APPS = 'application/vnd.google-apps.'
|
||||
MIMETYPE_GA_DOCUMENT = APPLICATION_VND_GOOGLE_APPS + 'document'
|
||||
MIMETYPE_GA_DRAWING = APPLICATION_VND_GOOGLE_APPS + 'drawing'
|
||||
MIMETYPE_GA_FOLDER = APPLICATION_VND_GOOGLE_APPS + 'folder'
|
||||
MIMETYPE_GA_FORM = APPLICATION_VND_GOOGLE_APPS + 'form'
|
||||
MIMETYPE_GA_FUSIONTABLE = APPLICATION_VND_GOOGLE_APPS + 'fusiontable'
|
||||
MIMETYPE_GA_MAP = APPLICATION_VND_GOOGLE_APPS + 'map'
|
||||
MIMETYPE_GA_PRESENTATION = APPLICATION_VND_GOOGLE_APPS + 'presentation'
|
||||
MIMETYPE_GA_SCRIPT = APPLICATION_VND_GOOGLE_APPS + 'script'
|
||||
MIMETYPE_GA_SITES = APPLICATION_VND_GOOGLE_APPS + 'sites'
|
||||
MIMETYPE_GA_SPREADSHEET = APPLICATION_VND_GOOGLE_APPS + 'spreadsheet'
|
||||
MIMETYPE_GA_DOCUMENT = f'{APPLICATION_VND_GOOGLE_APPS}document'
|
||||
MIMETYPE_GA_DRAWING = f'{APPLICATION_VND_GOOGLE_APPS}drawing'
|
||||
MIMETYPE_GA_FOLDER = f'{APPLICATION_VND_GOOGLE_APPS}folder'
|
||||
MIMETYPE_GA_FORM = f'{APPLICATION_VND_GOOGLE_APPS}form'
|
||||
MIMETYPE_GA_FUSIONTABLE = f'{APPLICATION_VND_GOOGLE_APPS}fusiontable'
|
||||
MIMETYPE_GA_MAP = f'{APPLICATION_VND_GOOGLE_APPS}map'
|
||||
MIMETYPE_GA_PRESENTATION = f'{APPLICATION_VND_GOOGLE_APPS}presentation'
|
||||
MIMETYPE_GA_SCRIPT = f'{APPLICATION_VND_GOOGLE_APPS}script'
|
||||
MIMETYPE_GA_SITES = f'{APPLICATION_VND_GOOGLE_APPS}sites'
|
||||
MIMETYPE_GA_SPREADSHEET = f'{APPLICATION_VND_GOOGLE_APPS}spreadsheet'
|
||||
MIMETYPE_GA_SHORTCUT = f'{APPLICATION_VND_GOOGLE_APPS}shortcut'
|
||||
|
||||
MIMETYPE_CHOICES_MAP = {
|
||||
'gdoc': MIMETYPE_GA_DOCUMENT,
|
||||
@@ -513,6 +513,7 @@ MIMETYPE_CHOICES_MAP = {
|
||||
'gsite': MIMETYPE_GA_SITES,
|
||||
'gsheet': MIMETYPE_GA_SPREADSHEET,
|
||||
'gspreadsheet': MIMETYPE_GA_SPREADSHEET,
|
||||
'shortcut': MIMETYPE_GA_SHORTCUT,
|
||||
}
|
||||
|
||||
DFA_CONVERT = 'convert'
|
||||
|
||||
Reference in New Issue
Block a user