Compare commits

..

10 Commits
v5.22 ... v5.23

Author SHA1 Message Date
Ross Scroggs
55e5b86ec4 Make labels display useful (#1260)
With the existing code you get these columns:

labels.cloudidentity.googleapis.com/groups.discussion_forum,labels.cloudidentity.googleapis.com/groups.security

but there is no data in the columns so you can't tell whcih groups have which values; by translating '' to True you can.
2020-10-09 10:33:03 -04:00
Max Mathieu
bf29a56aeb Updated branding (#1261)
* Update branding

* Update branding

* Update branding

* Update branding

* Update branding

* Update var.py
2020-10-09 10:32:37 -04:00
Jay Lee
07c57d4197 add support for Drive shortcut creation 2020-10-09 10:31:21 -04:00
Jay Lee
146db31cb5 Merge branch 'master' of https://github.com/jay0lee/GAM 2020-10-09 09:11:28 -04:00
Jay Lee
14239fcd47 Support Drive content restrictions 2020-10-09 09:11:14 -04:00
Jay Lee
8dc6a17295 Update .travis.yml 2020-10-07 13:51:25 -04:00
Jay Lee
76f9a6c746 Update .travis.yml 2020-10-06 08:42:05 -04:00
Jay Lee
eb155a5690 Merge branch 'master' of https://github.com/jay0lee/GAM 2020-10-05 09:46:39 -04:00
Jay Lee
b78575aa8f Initial support for group membership expiration 2020-10-05 09:46:24 -04:00
Ross Scroggs
91a5cd5c69 Fix bug in sync devices (#1259) 2020-10-03 19:52:22 -04:00
10 changed files with 101 additions and 47 deletions

View File

@@ -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

View File

@@ -1,4 +1,4 @@
GAM is a command line tool for Google G Suite Administrators to manage domain and user settings quickly and easily. [![Build Status](https://travis-ci.org/jay0lee/GAM.svg?branch=master)](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. [![Build Status](https://travis-ci.org/jay0lee/GAM.svg?branch=master)](https://travis-ci.org/jay0lee/GAM)
# Quick Start
## Linux / MacOS
Open a terminal and run:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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}')

View File

@@ -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(),

View File

@@ -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.'
)

View File

@@ -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'