mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-08 16:21:38 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67a6d3f4de | ||
|
|
7987a94aab | ||
|
|
e6494b6747 | ||
|
|
401f5095e1 | ||
|
|
93323d12d3 | ||
|
|
c3e23fabf1 | ||
|
|
95eb36c5c2 | ||
|
|
17105d51f1 | ||
|
|
8dbc455407 | ||
|
|
7e7b8416a4 | ||
|
|
ed81501bf2 | ||
|
|
428f8f5987 | ||
|
|
b9a489251b | ||
|
|
3b9a9ba224 | ||
|
|
0d63a85a45 | ||
|
|
a8ea30e19e | ||
|
|
660e9deb70 | ||
|
|
ad5ba656ee |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -153,7 +153,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20260213
|
||||
key: gam-${{ matrix.jid }}-20260224
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
|
||||
@@ -11,7 +11,7 @@ authors = [
|
||||
#significant compile dependencies.
|
||||
dependencies = [
|
||||
"arrow>=1.3.0",
|
||||
"chardet>=5.2.0",
|
||||
"chardet==5.2.0",
|
||||
"cryptography>=46.0.5",
|
||||
"distro; sys_platform=='linux'",
|
||||
"filelock>=3.18.0",
|
||||
|
||||
@@ -4662,6 +4662,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
|
||||
[event|events <EventNameList>] [ip <String>]
|
||||
[gmaileventtypes <NumberRangeList>]
|
||||
[groupidfilter <String>] [resourcedetailsfilter <String>]
|
||||
[notimesort]
|
||||
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
[countsonly [bydate|summary] [eventrowfilter]]
|
||||
(addcsvdata <FieldName> <String>)* [shownoactivities]
|
||||
@@ -5692,6 +5693,7 @@ gam download storagefile <StorageBucketObjectName>
|
||||
fullname|
|
||||
gender|
|
||||
givenname|firstname|
|
||||
guestaccountinfo|
|
||||
id|
|
||||
ims|im|
|
||||
includeinglobaladdresslist|gal|
|
||||
@@ -5699,6 +5701,7 @@ gam download storagefile <StorageBucketObjectName>
|
||||
isdelegatedadmin|admin|isadmin|
|
||||
isenforcedin2sv|is2svenforced|
|
||||
isenrolledin2sv|is2svenrolled|
|
||||
isguestuser|
|
||||
ismailboxsetup|
|
||||
keyword|keywords|
|
||||
language|languages|
|
||||
@@ -6906,6 +6909,7 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
[copyfilepermissions [<Boolean>]]
|
||||
[copyfileinheritedpermissions [<Boolean>]
|
||||
[copyfilenoninheritedpermissions [<Boolean>]
|
||||
[copyfolderpermissions [<Boolean>]]
|
||||
[copymergewithparentfolderpermissions [<Boolean>]]
|
||||
[copymergedtopfolderpermissions [<Boolean>]]
|
||||
[copytopfolderpermissions [<Boolean>]]
|
||||
@@ -6935,6 +6939,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
|
||||
[createshortcutsfornonmovablefiles [<Boolean>]]
|
||||
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
|
||||
[duplicatefolders merge|duplicatename|uniquename|skip]
|
||||
[copyfolderpermissions [<Boolean>]]
|
||||
[copymergewithparentfolderpermissions [<Boolean>]]
|
||||
[copymergedtopfolderpermissions [<Boolean>]]
|
||||
[copytopfolderpermissions [<Boolean>]]
|
||||
|
||||
@@ -1,3 +1,53 @@
|
||||
7.34.09
|
||||
|
||||
Updated `gam <UserTypeEntity> update photo` to delete the user's existing photo
|
||||
before performing the update as the API update will succeed but not replace a user's existing self-set photo.
|
||||
|
||||
7.34.08
|
||||
|
||||
Rebuild to avoid the following error:
|
||||
```
|
||||
requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
|
||||
```
|
||||
|
||||
7.34.07
|
||||
|
||||
Added the following command to create a guest user.
|
||||
* See: https://support.google.com/a/answer/16558545
|
||||
```
|
||||
gam create guestuser <EmailAddress>
|
||||
```
|
||||
|
||||
Added the following items to `<UserFieldName>`:
|
||||
* `guestaccountinfo` - Additional guest-related metadata fields
|
||||
* `isguestuser` - Indicates if the inserted user is a guest
|
||||
|
||||
7.34.06
|
||||
|
||||
Added option `copyfolderpermissions [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`.
|
||||
|
||||
When `copyfolderpermissions false` is specified, no folder permissions are copied; this simplifies
|
||||
disabling all folder permission copying.
|
||||
|
||||
When not specified or `copyfolderpermissions [true]` is specified, folder permissions are copied based on the following options:
|
||||
```
|
||||
copymergewithparentfolderpermissions [<Boolean>]
|
||||
copymergedtopfolderpermissions [<Boolean>]
|
||||
copytopfolderpermissions [<Boolean>]
|
||||
copytopfolderiheritedpermissions [<Boolean>]
|
||||
copytopfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
|
||||
copymergedsubfolderpermissions [<Boolean>]
|
||||
copysubfolderpermissions [<Boolean>]
|
||||
copysubfolderinheritedpermissions [<Boolean>]
|
||||
copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
|
||||
```
|
||||
|
||||
7.34.05
|
||||
|
||||
Updated `gam report <ActivityApplictionName>` to perform a reverse chronological sort
|
||||
on all rows across multiple users and/or event names; this is consistent with the behavior
|
||||
in the Admin console. Use option `notimesort` to suppress this sort.
|
||||
|
||||
7.34.04
|
||||
|
||||
Updated `gam <UserTypeEntity> create drivefileacl <DriveFileEntity> user <UserItem> role owner` to better
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.34.04'
|
||||
__version__ = '7.34.09'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
@@ -13829,7 +13829,9 @@ REPORT_ACTIVITIES_TIME_OBJECTS = {'time'}
|
||||
# yesterday|today|thismonth|(previousmonths <Integer>)]
|
||||
# [filter <String> (filtertime<String> <Time>)*]
|
||||
# [event|events <EventNameList>] [ip <String>]
|
||||
# [groupidfilter <String>]
|
||||
# [gmaileventtypes <NumberRangeList>]
|
||||
# [groupidfilter <String>] [resourcedetailsfilter <String>]
|
||||
# [notimesort]
|
||||
# [maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
# [countsonly [bydate|summary] [eventrowfilter]]
|
||||
# (addcsvdata <FieldName> <String>)* [shownoactivities]
|
||||
@@ -14144,6 +14146,7 @@ def doReport():
|
||||
maxResults = 1000
|
||||
aggregateByDate = aggregateByUser = convertMbToGb = countsOnly = countsByDate = countsSummary = \
|
||||
eventRowFilter = exitUserLoop = noAuthorizedApps = normalizeUsers = select = userCustomerRange = False
|
||||
sortAllTimes = True
|
||||
limitDateChanges = -1
|
||||
allVerifyUser = userKey = 'all'
|
||||
cd = orgUnit = orgUnitId = None
|
||||
@@ -14241,6 +14244,8 @@ def doReport():
|
||||
eventNames.append(event)
|
||||
elif activityReports and myarg == 'ip':
|
||||
actorIpAddress = getString(Cmd.OB_STRING)
|
||||
elif activityReports and myarg == 'notimesort':
|
||||
sortAllTimes = False
|
||||
elif activityReports and myarg == 'countsonly':
|
||||
countsOnly = True
|
||||
elif activityReports and myarg == 'bydate':
|
||||
@@ -14706,6 +14711,8 @@ def doReport():
|
||||
if addCSVData:
|
||||
row.update(addCSVData)
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif sortAllTimes:
|
||||
csvPF.SortRows('id.time', True)
|
||||
else:
|
||||
if eventRowFilter:
|
||||
csvPF.SetRowFilter([], GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE])
|
||||
@@ -37824,7 +37831,7 @@ def doCreateUpdateCIPolicy():
|
||||
updateCmd = Act.Get() == Act.UPDATE
|
||||
groupEmail = orgUnit = None
|
||||
checkArgumentPresent('json', True)
|
||||
jsonData = getJSON(['type'])
|
||||
jsonData = getJSON(['customer', 'type'])
|
||||
if updateCmd:
|
||||
pname = jsonData.pop('name', None)
|
||||
else:
|
||||
@@ -46002,10 +46009,13 @@ def doCreateGuestUser():
|
||||
checkForExtraneousArguments()
|
||||
try:
|
||||
result = callGAPI(cd.users(), 'createGuest',
|
||||
throwReasons=[GAPI.FAILED_PRECONDITION],
|
||||
throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.INVALID_ARGUMENT],
|
||||
body=body)
|
||||
entityActionPerformed([Ent.GUEST_USER, result['primaryGuestEmail']])
|
||||
except (GAPI.failedPrecondition) as e:
|
||||
entityActionPerformed([Ent.GUEST_USER, body['primaryGuestEmail']])
|
||||
Ind.Increment()
|
||||
showJSON(None, result)
|
||||
Ind.Decrement()
|
||||
except (GAPI.failedPrecondition, GAPI.invalidArgument) as e:
|
||||
entityActionFailedExit([Ent.GUEST_USER, body['primaryGuestEmail']], str(e))
|
||||
|
||||
# gam <UserTypeEntity> update user <UserAttribute>*
|
||||
@@ -46617,8 +46627,9 @@ USER_FIELDS_CHOICE_MAP = {
|
||||
'firstname': 'name.givenName',
|
||||
'fullname': 'name.fullName',
|
||||
'gal': 'includeInGlobalAddressList',
|
||||
'givenname': 'name.givenName',
|
||||
'gender': ['gender.type', 'gender.customGender', 'gender.addressMeAs'],
|
||||
'givenname': 'name.givenName',
|
||||
'guestaccountinfo': 'guestAccountInfo',
|
||||
'id': 'id',
|
||||
'im': 'ims',
|
||||
'ims': 'ims',
|
||||
@@ -46628,6 +46639,7 @@ USER_FIELDS_CHOICE_MAP = {
|
||||
'isdelegatedadmin': ['isAdmin', 'isDelegatedAdmin'],
|
||||
'isenforcedin2sv': 'isEnforcedIn2Sv',
|
||||
'isenrolledin2sv': 'isEnrolledIn2Sv',
|
||||
'isguestuser': 'isGuestUser',
|
||||
'is2svenforced': 'isEnforcedIn2Sv',
|
||||
'is2svenrolled': 'isEnrolledIn2Sv',
|
||||
'ismailboxsetup': 'isMailboxSetup',
|
||||
@@ -62058,6 +62070,7 @@ def initCopyMoveOptions(copyCmd):
|
||||
'copyFilePermissions': False,
|
||||
'copyFileInheritedPermissions': True,
|
||||
'copyFileNonInheritedPermissions': COPY_NONINHERITED_PERMISSIONS_ALWAYS,
|
||||
'copyFolderPermissions': True,
|
||||
'copyMergeWithParentFolderPermissions': False,
|
||||
'copyMergedTopFolderPermissions': copyCmd,
|
||||
'copyMergedSubFolderPermissions': copyCmd,
|
||||
@@ -62135,6 +62148,8 @@ def getCopyMoveOptions(myarg, copyMoveOptions):
|
||||
copyMoveOptions['duplicateFiles'] = getChoice(DUPLICATE_FILE_CHOICES, mapChoice=True)
|
||||
elif myarg == 'duplicatefolders':
|
||||
copyMoveOptions['duplicateFolders'] = getChoice(DUPLICATE_FOLDER_CHOICES, mapChoice=True)
|
||||
elif myarg == 'copyfolderpermissions':
|
||||
copyMoveOptions['copyFolderPermissions'] = getBoolean()
|
||||
elif myarg == 'copymergewithparentfolderpermissions':
|
||||
copyMoveOptions['copyMergeWithParentFolderPermissions'] = getBoolean()
|
||||
elif myarg == 'copymergedtopfolderpermissions':
|
||||
@@ -62813,6 +62828,7 @@ copyReturnItemMap = {
|
||||
# [copyfilepermissions [<Boolean>]]
|
||||
# [copyfileinheritedpermissions [<Boolean>]
|
||||
# [copyfilenoninheritedpermissions [<Boolean>]
|
||||
# [copyfolderpermissions [<Boolean>]]
|
||||
# [copymergewithparentfolderpermissions [<Boolean>]]
|
||||
# [copymergedtopfolderpermissions [<Boolean>]]
|
||||
# [copytopfolderpermissions [<Boolean>]]
|
||||
@@ -62860,7 +62876,8 @@ def copyDriveFile(users):
|
||||
_writeCSVData(user, folderName, folderId, newParentName, newParentId, MIMETYPE_GA_FOLDER)
|
||||
Act.Set(action)
|
||||
_incrStatistic(statistics, STAT_FOLDER_MERGED)
|
||||
if (copyMoveOptions['copyMergeWithParentFolderPermissions'] and
|
||||
if (copyMoveOptions['copyFolderPermissions'] and
|
||||
copyMoveOptions['copyMergeWithParentFolderPermissions'] and
|
||||
copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT):
|
||||
copyFolderNonInheritedPermissions =\
|
||||
_getCopyFolderNonInheritedPermissions(copyMoveOptions,
|
||||
@@ -62890,7 +62907,8 @@ def copyDriveFile(users):
|
||||
_writeCSVData(user, folderName, folderId, newFolderName, newFolderId, MIMETYPE_GA_FOLDER)
|
||||
Act.Set(action)
|
||||
_incrStatistic(statistics, STAT_FOLDER_MERGED)
|
||||
if (copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and
|
||||
if (copyMoveOptions['copyFolderPermissions'] and
|
||||
copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and
|
||||
(not atTop or copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT)):
|
||||
copyFolderNonInheritedPermissions =\
|
||||
_getCopyFolderNonInheritedPermissions(copyMoveOptions,
|
||||
@@ -62942,7 +62960,8 @@ def copyDriveFile(users):
|
||||
else:
|
||||
_writeCSVData(user, folderName, folderId, newFolderName, newFolderId, body['mimeType'])
|
||||
_incrStatistic(statistics, STAT_FOLDER_COPIED_MOVED)
|
||||
if copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]:
|
||||
if (copyMoveOptions['copyFolderPermissions'] and
|
||||
copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]):
|
||||
_copyPermissions(drive, user, i, count, j, jcount,
|
||||
Ent.DRIVE_FOLDER, folderId, folderName, newFolderId, newFolderName,
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
@@ -63697,6 +63716,7 @@ def _recursiveUpdateMovePermissions(drive, user, i, count,
|
||||
# [createshortcutsfornonmovablefiles [<Boolean>]]
|
||||
# [duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
|
||||
# [duplicatefolders merge|duplicatename|uniquename|skip]
|
||||
# [copyfolderpermissions [<Boolean>]]
|
||||
# [copymergewithparentfolderpermissions [<Boolean>]]
|
||||
# [copymergedtopfolderpermissions [<Boolean>]]
|
||||
# [copytopfolderpermissions [<Boolean>]]
|
||||
@@ -63733,7 +63753,8 @@ def moveDriveFile(users):
|
||||
entityPerformActionModifierItemValueList(kvList, Act.MODIFIER_CONTENTS_WITH, [Ent.DRIVE_FOLDER, newParentNameId], j, jcount)
|
||||
Act.Set(action)
|
||||
_incrStatistic(statistics, STAT_FOLDER_MERGED)
|
||||
if (copyMoveOptions['copyMergeWithParentFolderPermissions'] and
|
||||
if (copyMoveOptions['copyFolderPermissions'] and
|
||||
copyMoveOptions['copyMergeWithParentFolderPermissions'] and
|
||||
copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT):
|
||||
copyFolderNonInheritedPermissions =\
|
||||
_getCopyFolderNonInheritedPermissions(copyMoveOptions,
|
||||
@@ -63763,7 +63784,8 @@ def moveDriveFile(users):
|
||||
entityModifierItemValueListActionPerformed(kvList, Act.MODIFIER_CONTENTS_WITH, [Ent.DRIVE_FOLDER, f'{newFolderName}({newFolderId})'], j, jcount)
|
||||
Act.Set(action)
|
||||
_incrStatistic(statistics, STAT_FOLDER_MERGED)
|
||||
if (copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and
|
||||
if (copyMoveOptions['copyFolderPermissions'] and
|
||||
copyMoveOptions[['copyMergedSubFolderPermissions', 'copyMergedTopFolderPermissions'][atTop]] and
|
||||
(not atTop or copyMoveOptions['destParentType'] != DEST_PARENT_MYDRIVE_ROOT)):
|
||||
copyFolderNonInheritedPermissions =\
|
||||
_getCopyFolderNonInheritedPermissions(copyMoveOptions,
|
||||
@@ -63857,7 +63879,8 @@ def moveDriveFile(users):
|
||||
j, jcount)
|
||||
Act.Set(action)
|
||||
_incrStatistic(statistics, STAT_FOLDER_COPIED_MOVED)
|
||||
if copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]:
|
||||
if (copyMoveOptions['copyFolderPermissions'] and
|
||||
copyMoveOptions[['copySubFolderPermissions', 'copyTopFolderPermissions'][atTop]]):
|
||||
_copyPermissions(drive, user, i, count, j, jcount,
|
||||
Ent.DRIVE_FOLDER, folderId, folderName, newFolderId, newFolderName,
|
||||
statistics, STAT_FOLDER_PERMISSIONS_FAILED,
|
||||
@@ -71317,6 +71340,13 @@ def updatePhoto(users):
|
||||
continue
|
||||
body = {'photoData': base64.urlsafe_b64encode(image_data).decode(UTF8)}
|
||||
try:
|
||||
try:
|
||||
callGAPI(cd.users().photos(), 'delete',
|
||||
bailOnInternalError=True,
|
||||
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.PHOTO_NOT_FOUND, GAPI.INTERNAL_ERROR],
|
||||
userKey=user)
|
||||
except (GAPI.photoNotFound, GAPI.internalError) as e:
|
||||
pass
|
||||
callGAPI(cd.users().photos(), 'update',
|
||||
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID_INPUT, GAPI.CONDITION_NOT_MET],
|
||||
userKey=user, body=body, fields='')
|
||||
|
||||
@@ -649,6 +649,16 @@ _SVCACCT_SCOPES = [
|
||||
'api': CLOUDIDENTITY_DEVICES,
|
||||
'subscopes': READONLY,
|
||||
'scope': 'https://www.googleapis.com/auth/cloud-identity.devices'},
|
||||
# {'name': 'Cloud Identity API - Policy',
|
||||
# 'api': CLOUDIDENTITY_POLICY,
|
||||
# 'subscopes': READONLY,
|
||||
# 'roByDefault': True,
|
||||
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
|
||||
# {'name': 'Cloud Identity API - Policy Beta',
|
||||
# 'api': CLOUDIDENTITY_POLICY_BETA,
|
||||
# 'subscopes': [],
|
||||
# 'offByDefault': True,
|
||||
# 'scope': 'https://www.googleapis.com/auth/cloud-identity.policies'},
|
||||
# {'name': 'Cloud Identity User Invitations API',
|
||||
# 'api': CLOUDIDENTITY_USERINVITATIONS,
|
||||
# 'subscopes': READONLY,
|
||||
|
||||
@@ -10,6 +10,85 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.34.08
|
||||
|
||||
Rebuild to avoid the following error:
|
||||
```
|
||||
requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
|
||||
```
|
||||
|
||||
### 7.34.07
|
||||
|
||||
Added the following command to create a guest user.
|
||||
* See: https://support.google.com/a/answer/16558545
|
||||
```
|
||||
gam create guestuser <EmailAddress>
|
||||
```
|
||||
|
||||
Added the following items to `<UserFieldName>`:
|
||||
* `guestaccountinfo` - Additional guest-related metadata fields
|
||||
* `isguestuser` - Indicates if the inserted user is a guest
|
||||
|
||||
### 7.34.06
|
||||
|
||||
Added option `copyfolderpermissions [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`.
|
||||
|
||||
When `copyfolderpermissions false` is specified, no folder permissions are copied; this simplifies
|
||||
disabling all folder permission copying.
|
||||
|
||||
When not specified or `copyfolderpermissions [true]` is specified, folder permissions are copied based on the following options:
|
||||
```
|
||||
copymergewithparentfolderpermissions [<Boolean>]
|
||||
copymergedtopfolderpermissions [<Boolean>]
|
||||
copytopfolderpermissions [<Boolean>]
|
||||
copytopfolderiheritedpermissions [<Boolean>]
|
||||
copytopfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
|
||||
copymergedsubfolderpermissions [<Boolean>]
|
||||
copysubfolderpermissions [<Boolean>]
|
||||
copysubfolderinheritedpermissions [<Boolean>]
|
||||
copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
|
||||
```
|
||||
|
||||
### 7.34.05
|
||||
|
||||
Updated `gam report <ActivityApplictionName>` to perform a reverse chronological sort
|
||||
on all rows across multiple users and/or event names; this is consistent with the behavior
|
||||
in the Admin console. Use option `notimesort` to suppress this sort.
|
||||
|
||||
### 7.34.04
|
||||
|
||||
Updated `gam <UserTypeEntity> create drivefileacl <DriveFileEntity> user <UserItem> role owner` to better
|
||||
handle the case where the current owner of a file is suspended. Previously, the command was displayed as an error
|
||||
even though the ownership was changed.
|
||||
```
|
||||
gam user currentowner@domain.com add drivefileacl <DriveFileID> user newowner@domain.com role owner
|
||||
User: currentowner@domain.com, Add 1 Drive File/Folder ACL
|
||||
User: currentowner@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: newowner@domain.com, Add Failed: Sorry, the items were successfully shared but emails could not be sent to newowner@domain.com.
|
||||
```
|
||||
|
||||
Now the command is displayed as a success with a note indicating that the ownership change email was not sent.
|
||||
```
|
||||
gam user currentowner@domain.com add drivefileacl <DriveFileID> user newowner@domain.com role owner
|
||||
User: currentowner@domain.com, Add 1 Drive File/Folder ACL
|
||||
User: currentowner@domain.com, Drive File/Folder ID: <DriveFileID>, Permission ID: newowner@domain.com, Added: Sorry, the items were successfully shared but emails could not be sent to newowner@domain.com.
|
||||
New Owner
|
||||
id: 10834698115409747890
|
||||
type: user
|
||||
emailAddress: newowner@domain.com
|
||||
domain: domain.com
|
||||
role: owner
|
||||
permissionDetails:
|
||||
role: writer
|
||||
type: file
|
||||
inherited: True
|
||||
inheritedFrom: Unknown
|
||||
role: owner
|
||||
type: file
|
||||
inherited: False
|
||||
deleted: False
|
||||
pendingOwner: False
|
||||
```
|
||||
|
||||
### 7.34.03
|
||||
|
||||
Updated to Python 3.14.3
|
||||
|
||||
@@ -252,7 +252,7 @@ writes the credentials into the file oauth2.txt.
|
||||
gamteam@server:/Users/gamteam$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
|
||||
gamteam@server:/Users/gamteam$ gam version
|
||||
WARNING: Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/gamteam/GAMConfig/oauth2.txt, Not Found
|
||||
GAM 7.34.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.08 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -1036,7 +1036,7 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAM 7.34.03 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.34.08 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
Windows 11 10.0.26200 AMD64
|
||||
|
||||
@@ -99,6 +99,7 @@ gam report <ActivityApplicationName> [todrive <ToDriveAttribute>*]
|
||||
[event|events <EventNameList>] [ip <String>]
|
||||
[gmaileventtypes <NumberRangeList>]
|
||||
[groupidfilter <String>] [resourcedetailsfilter <String>]
|
||||
[notimesort]
|
||||
[maxactivities <Number>] [maxevents <Number>] [maxresults <Number>]
|
||||
[countsonly [bydate|summary] [eventrowfilter]]
|
||||
(addcsvdata <FieldName> <String>)* [shownoactivities]
|
||||
@@ -176,6 +177,9 @@ show the most recent activity/event; this can be useful when reporting drive act
|
||||
Add additional columns of data from the command line to the output.
|
||||
* `addcsvdata <FieldName> <String>`
|
||||
|
||||
By default, a reverse chronological sort is performed on all rows across multiple users and/or event names;
|
||||
this is consistent with the behavior in the Admin console. Use option `notimesort` to suppress this sort.
|
||||
|
||||
Display a row with a key value of `NoActivities` when there are no activities to report.
|
||||
* `shownoactivities`
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
|
||||
[copyfilepermissions [<Boolean>]]
|
||||
[copyfileinheritedpermissions [<Boolean>]
|
||||
[copyfilenoninheritedpermissions [<Boolean>]
|
||||
[copyfolderpermissions [<Boolean>]]
|
||||
[copymergewithparentfolderpermissions [<Boolean>]]
|
||||
[copymergedtopfolderpermissions [<Boolean>]]
|
||||
[copytopfolderpermissions [<Boolean>]]
|
||||
@@ -294,6 +295,8 @@ When a folder is copied, its permissions are not copied; these options control c
|
||||
of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When copied, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions.
|
||||
* `copyfolderpermissions false` - The permissions of the source folders are not copied to the target folder.
|
||||
* `copyfolderpermissions true` - The permissions of the source folders are copied to the target folder based on the following options; this is the default action.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
@@ -571,6 +574,7 @@ gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileNam
|
||||
[createshortcutsfornonmovablefiles [<Boolean>]]
|
||||
[duplicatefiles overwriteolder|overwriteall|duplicatename|uniquename|skip]
|
||||
[duplicatefolders merge|duplicatename|uniquename|skip]
|
||||
[copyfolderpermissions [<Boolean>]]
|
||||
[copymergewithparentfolderpermissions [<Boolean>]]
|
||||
[copymergedtopfolderpermissions [<Boolean>]]
|
||||
[copytopfolderpermissions [<Boolean>]]
|
||||
@@ -660,6 +664,8 @@ When a folder is moved by recreating it, its permissions are not copied by the D
|
||||
For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions;
|
||||
* `copyfolderpermissions false` - The permissions of the source folders are not copied to the target folder.
|
||||
* `copyfolderpermissions true` - The permissions of the source folders are copied to the target folder based on the following options; this is the default action.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
|
||||
@@ -619,8 +619,10 @@ This option is not available for `print|show filetree`.
|
||||
```
|
||||
((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*
|
||||
```
|
||||
GAM initializes the query to `'me' in owners`.
|
||||
|
||||
* `query "xxx"` - ` and xxx` is appended to the current query; you can repeat the query argument to build up a longer query.
|
||||
* `fullquery "xxx"` - The query is set to `xxx` eliminating the initial `'me' in owners`.
|
||||
* `fullquery "xxx"` - The query is set to `xxx` eliminating the initial `'me' in owners`. You must also use `showownedby any|others` as desired.
|
||||
* `<DriveFileQueryShortcut>` - Predefined queries
|
||||
|
||||
Use the `querytime<String> <Time>` option to allow times, usually relative, to be substituted into the `query <QueryDriveFile>` option.
|
||||
|
||||
@@ -404,7 +404,7 @@ Messages are archived to the group specified by `<GroupItem>`.
|
||||
### Archive a selected set of messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
|
||||
* `max_to_archive <Number>` - Limit the number of messages that will be archived; use a value of 0 for no limit
|
||||
* `max_to_archive <Number>` - Limit the number of messages that will be archived; use a value of 0 for no limit
|
||||
* `doit` - No messages are archived unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations.
|
||||
|
||||
When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query.
|
||||
@@ -430,8 +430,6 @@ user@domain.com,18e9fc6581b9acab,Archived,
|
||||
user@domain.com,18e9fc58c5491f4c,Archived,
|
||||
```
|
||||
|
||||
See below for message selection.
|
||||
|
||||
## Export messages/threads
|
||||
Export messages in EML format.
|
||||
```
|
||||
@@ -464,7 +462,18 @@ By default, when exporting a message, an existing local file will not be overwri
|
||||
* `overwrite true` - Overwite an existing file
|
||||
* `overwrite false` - Do not overwite an existing file; add a numeric prefix and create a new file
|
||||
|
||||
See below for message selection.
|
||||
### Export a specific set of messages
|
||||
* `ids <MessageIDEntity>` - A list of message ids
|
||||
|
||||
### Export a selected set of messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
|
||||
* `max_to_export <Number>` - Limit the number of messages that will be exported; use a value of 0 for no limit
|
||||
|
||||
When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query.
|
||||
```
|
||||
&()"|{}/
|
||||
```
|
||||
|
||||
## Forward messages/threads
|
||||
```
|
||||
@@ -492,7 +501,19 @@ If `addorigfieldstosubject` is specified, GAM appends the original `from`, `to`
|
||||
Fwd: Ross to TestUser (Original From: Ross Scroggs <ross.scroggs@gmail.com> To: testuser@domain.com Date: Thu, 23 Nov 2023 07:01:59 -0800)
|
||||
```
|
||||
|
||||
See below for message selection.
|
||||
### Forward a specific set of messages
|
||||
* `ids <MessageIDEntity>` - A list of message ids
|
||||
|
||||
### Forward a selected set of messages
|
||||
* `((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+` - Criteria to select messages
|
||||
* `labelids <LabelIDList>` - Select messages with labels that match all of the specified label IDs.
|
||||
* `max_to_forward <Number>` - Limit the number of messages that will be forwarded; use a value of 0 for no limit
|
||||
* `doit` - No messages are processed unless you specify `doit`. By not specifying `doit`, you can preview the messages selected to verify that the results match your expectations.
|
||||
|
||||
When `matchlabel <LabelName>` is specified, the following characters are replaced with a `-` in the generated query.
|
||||
```
|
||||
&()"|{}/
|
||||
```
|
||||
|
||||
## Manage messages/threads
|
||||
```
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- [Upload a user's photo specifying a Google Drive owner and file name](#upload-a-users-photo-specifying-a-google-drive-owner-and-file-name)
|
||||
- [Download a user's photo](#download-a-users-photo)
|
||||
- [Delete a user's photo](#delete-a-users-photo)
|
||||
- [Update photo fails to change user's photo](#update-photo-fails-to-change-users-photo)
|
||||
- [Download a user's profile photo](Users-Profile-Photo)
|
||||
|
||||
## API documentation
|
||||
@@ -81,3 +82,7 @@ By default, the Base64 encoded data is dumped to stdout.
|
||||
```
|
||||
gam <UserTypeEntity> delete|del photo
|
||||
```
|
||||
|
||||
## Update photo fails to change user's photo
|
||||
If you use `gam <UserTypeEntity> update photo ...` to change a user's photo and the command succeeds
|
||||
but the photo doesn't change, use `gam <UserTypeEntity> delete photo` first and then do the update.
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
- [Print user list](#print-user-list)
|
||||
- [Display user counts](#display-user-counts)
|
||||
- [Verify domain membership](#verify-domain-membership)
|
||||
- [Guest Users](#guest-users)
|
||||
|
||||
## API documentation
|
||||
* [Directory API - Users](https://developers.google.com/admin-sdk/directory/reference/rest/v1/users)
|
||||
@@ -169,6 +170,7 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
|
||||
fullname|
|
||||
gender|
|
||||
givenname|firstname|
|
||||
guestaccountinfo|
|
||||
id|
|
||||
ims|im|
|
||||
includeinglobaladdresslist|gal|
|
||||
@@ -176,6 +178,7 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
|
||||
isdelegatedadmin|admin|isadmin|
|
||||
isenforcedin2sv|is2svenforced|
|
||||
isenrolledin2sv|is2svenrolled|
|
||||
isguestuser|
|
||||
ismailboxsetup|
|
||||
keyword|keywords|
|
||||
language|languages|
|
||||
@@ -1384,3 +1387,11 @@ testuser1@domain.com,118080758787650801331,True,Test User 1
|
||||
testuserxxx@domain.com,,False,Test User XXX
|
||||
testuser2@domain.com,107344800159717682514,True,Test User 2
|
||||
```
|
||||
|
||||
## Guest Users
|
||||
* See: https://support.google.com/a/answer/16558545
|
||||
```
|
||||
gam create guestuser <EmailAddress>
|
||||
```
|
||||
|
||||
Guest users are in the OU "/Workspace guests".
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.34.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.08 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -15,7 +15,7 @@ Time: 2026-02-15T07:51:00-08:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.34.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.08 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
|
||||
Print the current version of Gam with extended details and SSL information
|
||||
```
|
||||
gam version extended
|
||||
GAM 7.34.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.34.08 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
@@ -68,7 +68,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.34.03
|
||||
Latest: 7.34.08
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -76,7 +76,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.34.03
|
||||
7.34.08
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -86,7 +86,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.34.03 - https://github.com/GAM-team/GAM
|
||||
GAM 7.34.08 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.3 64-bit final
|
||||
macOS Tahoe 26.3 arm64
|
||||
|
||||
Reference in New Issue
Block a user