Added simple commands to get information about the last modified file on a drive.
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Push wiki / pushwiki (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled

This commit is contained in:
Ross Scroggs 2025-04-11 12:29:55 -07:00
parent 0a89e82f2d
commit 6da2b14111
No known key found for this signature in database
GPG Key ID: 54585EA0887857D5
8 changed files with 250 additions and 39 deletions

View File

@ -7163,7 +7163,8 @@ gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
[filenamematchpattern <REMatchPattern>] [filenamematchpattern <REMatchPattern>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
[excludetrashed] [excludetrashed]
[showsize] [showmimetypesize] [showlastmodification] [showsize] [showmimetypesize]
[showlastmodification] [pathdelimiter <Character>]
(addcsvdata <FieldName> <String>)* (addcsvdata <FieldName> <String>)*
[summary none|only|plus] [summaryuser <String>] [summary none|only|plus] [summaryuser <String>]
gam <UserTypeEntity> show filecounts gam <UserTypeEntity> show filecounts
@ -7178,7 +7179,8 @@ gam <UserTypeEntity> show filecounts
[filenamematchpattern <REMatchPattern>] [filenamematchpattern <REMatchPattern>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
[excludetrashed] [excludetrashed]
[showsize] [showmimetypesize] [showlastmodification] [showsize] [showmimetypesize]
[showlastmodification] [pathdelimiter <Character>]
[summary none|only|plus] [summaryuser <String>] [summary none|only|plus] [summaryuser <String>]
gam <UserTypeEntity> print filesharecounts [todrive <ToDriveAttribute>*] gam <UserTypeEntity> print filesharecounts [todrive <ToDriveAttribute>*]
@ -7308,6 +7310,14 @@ gam <UserTypeEntity> print driveactivity [todrive <ToDriveAttribute>*]
usageindrivetrash usageindrivetrash
<DriveSettingsFieldNameList> ::= "<DriveSettingsFieldName>(,<DriveSettingsFieldName>)*" <DriveSettingsFieldNameList> ::= "<DriveSettingsFieldName>(,<DriveSettingsFieldName>)*"
gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
(addcsvdata <FieldName> <String>)*
gam <UserTypeEntity> show drivelastmodification
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
gam <UserTypeEntity> print drivesettings [todrive <ToDriveAttribute>*] gam <UserTypeEntity> print drivesettings [todrive <ToDriveAttribute>*]
[allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)]
[delimiter <Character>] [showusagebytes] [delimiter <Character>] [showusagebytes]

View File

@ -1,8 +1,27 @@
7.06.02
Updated `gam <UserTypeEntity> print|show filecounts ... showlastmodification` to include
file mimetype and path information for the last modified file.
Added simple commands to get information about the last modified file on a drive.
By default, a user's My Drive is processed; optionally, a Shared Drive can be processed.
```
gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
(addcsvdata <FieldName> <String>)*
gam <UserTypeEntity> show drivelastmodification
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
```
7.06.01 7.06.01
Updated `gam <UserTypeEntity> create|update drivefileacl ... expiration <Time>` Updated `gam <UserTypeEntity> create|update drivefileacl ... expiration <Time>`
to handle additional API errors. to handle additional API errors.
Updated to Python 3.13.3.
7.06.00 7.06.00
Upgraded to OpenSSL 3.5.0. Upgraded to OpenSSL 3.5.0.

View File

@ -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.01' __version__ = '7.06.02'
__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
@ -56486,6 +56486,44 @@ def printFileParentTree(users):
kcount -= 1 kcount -= 1
csvPF.writeCSVfile('Drive File Parent Tree') csvPF.writeCSVfile('Drive File Parent Tree')
# Last file modification utilities
def _initLastModification():
return {'lastModifiedFileId': '', 'lastModifiedFileName': '',
'lastModifiedFileMimeType': '', 'lastModifiedFilaPath': '',
'lastModifyingUser': '', 'lastModifiedTime': NEVER_TIME,
'fileEntryInfo': {}}
def _checkUpdateLastModifiction(f_file, userLastModification):
if f_file.get('modifiedTime', NEVER_TIME) > userLastModification['lastModifiedTime'] and 'lastModifyingUser' in f_file:
userLastModification['lastModifiedFileId'] = f_file['id']
userLastModification['lastModifiedFileName'] = _stripControlCharsFromName(f_file['name'])
userLastModification['lastModifiedFileMimeType'] = f_file['mimeType']
userLastModification['lastModifiedTime'] = f_file['modifiedTime']
userLastModification['lastModifyingUser'] = f_file['lastModifyingUser'].get('emailAddress',
f_file['lastModifyingUser'].get('displayName', UNKNOWN))
userLastModification['fileEntryInfo'] = f_file.copy()
def _getLastModificationPath(drive, userLastModification, pathDelimiter):
filePathInfo = initFilePathInfo(pathDelimiter)
_, paths, _ = getFilePaths(drive, {}, userLastModification['fileEntryInfo'], filePathInfo)
userLastModification['lastModifiedFilePath'] = paths[0] if paths else UNKNOWN
def _showLastModification(lastModification):
printKeyValueList(['lastModifiedFileId', lastModification['lastModifiedFileId']])
printKeyValueList(['lastModifiedFileName', lastModification['lastModifiedFileName']])
printKeyValueList(['lastModifiedFileMimeType', lastModification['lastModifiedFileMimeType']])
printKeyValueList(['lastModifiedFilePath', lastModification['lastModifiedFilePath']])
printKeyValueList(['lastModifyingUser', lastModification['lastModifyingUser']])
printKeyValueList(['lastModifiedTime', formatLocalTime(lastModification['lastModifiedTime'])])
def _updateLastModificationRow(row, lastModification):
row.update({'lastModifiedFileId': lastModification['lastModifiedFileId'],
'lastModifiedFileName': lastModification['lastModifiedFileName'],
'lastModifiedFileMimeType': lastModification['lastModifiedFileMimeType'],
'lastModifiedFilePath': lastModification['lastModifiedFilePath'],
'lastModifyingUser': lastModification['lastModifyingUser'],
'lastModifiedTime': formatLocalTime(lastModification['lastModifiedTime'])})
# gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*] # gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
# [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*] # [((query <QueryDriveFile>) | (fullquery <QueryDriveFile>) | <DriveFileQueryShortcut>) (querytime<String> <Time>)*]
# [continueoninvalidquery [<Boolean>]] # [continueoninvalidquery [<Boolean>]]
@ -56497,7 +56535,8 @@ def printFileParentTree(users):
# [filenamematchpattern <REMatchPattern>] # [filenamematchpattern <REMatchPattern>]
# <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] # <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
# [excludetrashed] (addcsvdata <FieldName> <String>)* # [excludetrashed] (addcsvdata <FieldName> <String>)*
# [showsize] [showmimetypesize] [showlastmodification] # [showsize] [showmimetypesize]
# [showlastmodification] [pathdelimiter <Character>]
# (addcsvdata <FieldName> <String>)* # (addcsvdata <FieldName> <String>)*
# [summary none|only|plus] [summaryuser <String>] # [summary none|only|plus] [summaryuser <String>]
# gam <UserTypeEntity> show filecounts # gam <UserTypeEntity> show filecounts
@ -56511,7 +56550,8 @@ def printFileParentTree(users):
# [filenamematchpattern <REMatchPattern>] # [filenamematchpattern <REMatchPattern>]
# <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] # <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
# [excludetrashed] # [excludetrashed]
# [showsize] [showmimetypesize] [showlastmodification] # [showsize] [showmimetypesize]
# [showlastmodification] [pathdelimiter <Character>]
# [summary none|only|plus] [summaryuser <String>] # [summary none|only|plus] [summaryuser <String>]
def printShowFileCounts(users): def printShowFileCounts(users):
def _setSelectionFields(): def _setSelectionFields():
@ -56520,7 +56560,7 @@ def printShowFileCounts(users):
if showSize or (DLP.minimumFileSize is not None) or (DLP.maximumFileSize is not None): if showSize or (DLP.minimumFileSize is not None) or (DLP.maximumFileSize is not None):
fieldsList.append(sizeField) fieldsList.append(sizeField)
if showLastModification: if showLastModification:
fieldsList.extend(['id,name,modifiedTime,lastModifyingUser(me, displayName, emailAddress)']) fieldsList.extend(['id,name,modifiedTime,lastModifyingUser(me, displayName, emailAddress),parents'])
if DLP.filenameMatchPattern: if DLP.filenameMatchPattern:
fieldsList.append('name') fieldsList.append('name')
if DLP.excludeTrashed: if DLP.excludeTrashed:
@ -56556,9 +56596,7 @@ def printShowFileCounts(users):
printEntityKVList(kvList, dataList, i, count) printEntityKVList(kvList, dataList, i, count)
Ind.Increment() Ind.Increment()
if showLastModification: if showLastModification:
printKeyValueList(['lastModifiedFile', f"{lastModification['lastModifiedFileName']}({lastModification['lastModifiedFileId']})", _showLastModification(lastModification)
'lastModifyingUser', lastModification['lastModifyingUser'],
'lastModifiedTime', formatLocalTime(lastModification['lastModifiedTime'])])
for mimeType, mtinfo in sorted(iter(mimeTypeInfo.items())): for mimeType, mtinfo in sorted(iter(mimeTypeInfo.items())):
if not showMimeTypeSize: if not showMimeTypeSize:
printKeyValueList([mimeType, mtinfo['count']]) printKeyValueList([mimeType, mtinfo['count']])
@ -56573,10 +56611,7 @@ def printShowFileCounts(users):
if showSize: if showSize:
row['Size'] = sizeTotal row['Size'] = sizeTotal
if showLastModification: if showLastModification:
row.update({'lastModifiedFileId': lastModification['lastModifiedFileId'], _updateLastModificationRow(row, lastModification)
'lastModifiedFileName': lastModification['lastModifiedFileName'],
'lastModifyingUser': lastModification['lastModifyingUser'],
'lastModifiedTime': formatLocalTime(lastModification['lastModifiedTime'])})
if addCSVData: if addCSVData:
row.update(addCSVData) row.update(addCSVData)
for mimeType, mtinfo in sorted(iter(mimeTypeInfo.items())): for mimeType, mtinfo in sorted(iter(mimeTypeInfo.items())):
@ -56590,6 +56625,7 @@ def printShowFileCounts(users):
csvPF.SetZeroBlankMimeTypeCounts(True) csvPF.SetZeroBlankMimeTypeCounts(True)
fieldsList = ['mimeType'] fieldsList = ['mimeType']
DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': True, 'allowQuery': True, 'mimeTypeInQuery': True}) DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': True, 'allowQuery': True, 'mimeTypeInQuery': True})
pathDelimiter = '/'
sharedDriveId = sharedDriveName = '' sharedDriveId = sharedDriveName = ''
continueOnInvalidQuery = showSize = showLastModification = showMimeTypeSize = False continueOnInvalidQuery = showSize = showLastModification = showMimeTypeSize = False
sizeField = 'quotaBytesUsed' sizeField = 'quotaBytesUsed'
@ -56598,9 +56634,7 @@ def printShowFileCounts(users):
summaryMimeTypeInfo = {} summaryMimeTypeInfo = {}
fileIdEntity = {} fileIdEntity = {}
addCSVData = {} addCSVData = {}
summaryLastModification = { summaryLastModification = _initLastModification()
'lastModifiedFileId': '', 'lastModifiedFileName': '',
'lastModifyingUser': '', 'lastModifiedTime': NEVER_TIME}
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
if csvPF and myarg == 'todrive': if csvPF and myarg == 'todrive':
@ -56623,6 +56657,8 @@ def printShowFileCounts(users):
summary = getChoice(FILECOUNT_SUMMARY_CHOICE_MAP, mapChoice=True) summary = getChoice(FILECOUNT_SUMMARY_CHOICE_MAP, mapChoice=True)
elif myarg == 'summaryuser': elif myarg == 'summaryuser':
summaryUser = getString(Cmd.OB_STRING) summaryUser = getString(Cmd.OB_STRING)
elif myarg == 'pathdelimiter':
pathDelimiter = getCharacter()
elif csvPF and myarg == 'addcsvdata': elif csvPF and myarg == 'addcsvdata':
k = getString(Cmd.OB_STRING) k = getString(Cmd.OB_STRING)
addCSVData[k] = getString(Cmd.OB_STRING, minLen=0) addCSVData[k] = getString(Cmd.OB_STRING, minLen=0)
@ -56649,7 +56685,9 @@ def printShowFileCounts(users):
if showSize: if showSize:
sortTitles.insert(sortTitles.index('Total')+1, 'Size') sortTitles.insert(sortTitles.index('Total')+1, 'Size')
if showLastModification: if showLastModification:
sortTitles.extend(['lastModifiedFileId', 'lastModifiedFileName', 'lastModifyingUser', 'lastModifiedTime']) sortTitles.extend(['lastModifiedFileId', 'lastModifiedFileName',
'lastModifiedFileMimeType', 'lastModifiedFilePath',
'lastModifyingUser', 'lastModifiedTime'])
if addCSVData: if addCSVData:
sortTitles.extend(sorted(addCSVData.keys())) sortTitles.extend(sorted(addCSVData.keys()))
csvPF.SetTitles(sortTitles) csvPF.SetTitles(sortTitles)
@ -56664,9 +56702,7 @@ def printShowFileCounts(users):
sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '') sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '')
sharedDriveName = _getSharedDriveNameFromId(sharedDriveId) if sharedDriveId else '' sharedDriveName = _getSharedDriveNameFromId(sharedDriveId) if sharedDriveId else ''
mimeTypeInfo = {} mimeTypeInfo = {}
userLastModification = { userLastModification = _initLastModification()
'lastModifiedFileId': '', 'lastModifiedFileName': '',
'lastModifyingUser': '', 'lastModifiedTime': NEVER_TIME}
gettingEntity = _getGettingEntity(user, fileIdEntity) gettingEntity = _getGettingEntity(user, fileIdEntity)
printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count, query=DLP.fileIdEntity['query']) printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count, query=DLP.fileIdEntity['query'])
try: try:
@ -56678,7 +56714,7 @@ def printShowFileCounts(users):
retryReasons=[GAPI.UNKNOWN_ERROR], retryReasons=[GAPI.UNKNOWN_ERROR],
q=DLP.fileIdEntity['query'], q=DLP.fileIdEntity['query'],
fields=pagesFields, pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **btkwargs) fields=pagesFields, pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **btkwargs)
for files in feed: for files in feed:
for f_file in files: for f_file in files:
driveId = f_file.get('driveId') driveId = f_file.get('driveId')
checkSharedDrivePermissions = getPermissionsForSharedDrives and driveId and 'permissions' not in f_file checkSharedDrivePermissions = getPermissionsForSharedDrives and driveId and 'permissions' not in f_file
@ -56709,12 +56745,8 @@ def printShowFileCounts(users):
mimeTypeInfo[f_file['mimeType']]['count'] += 1 mimeTypeInfo[f_file['mimeType']]['count'] += 1
mimeTypeInfo[f_file['mimeType']]['size'] += int(f_file.get(sizeField, '0')) mimeTypeInfo[f_file['mimeType']]['size'] += int(f_file.get(sizeField, '0'))
if showLastModification: if showLastModification:
if f_file.get('modifiedTime', NEVER_TIME) > userLastModification['lastModifiedTime'] and 'lastModifyingUser' in f_file: _checkUpdateLastModifiction(f_file, userLastModification)
userLastModification['lastModifiedFileId'] = f_file['id'] _getLastModificationPath(drive, userLastModification, pathDelimiter)
userLastModification['lastModifiedFileName'] = _stripControlCharsFromName(f_file['name'])
userLastModification['lastModifiedTime'] = f_file['modifiedTime']
userLastModification['lastModifyingUser'] = f_file['lastModifyingUser'].get('emailAddress',
f_file['lastModifyingUser'].get('displayName', UNKNOWN))
showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, userLastModification, i, count) showMimeTypeInfo(user, mimeTypeInfo, sharedDriveId, sharedDriveName, userLastModification, i, count)
if showLastModification and userLastModification['lastModifiedTime'] > summaryLastModification['lastModifiedTime']: if showLastModification and userLastModification['lastModifiedTime'] > summaryLastModification['lastModifiedTime']:
summaryLastModification = userLastModification.copy() summaryLastModification = userLastModification.copy()
@ -56738,6 +56770,110 @@ def printShowFileCounts(users):
if csvPF: if csvPF:
csvPF.writeCSVfile('Drive File Counts') csvPF.writeCSVfile('Drive File Counts')
# gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
# [select <SharedDriveEntity>]
# [pathdelimiter <Character>]
# (addcsvdata <FieldName> <String>)*
# gam <UserTypeEntity> show drivelastmodification
# [select <SharedDriveEntity>]
# [pathdelimiter <Character>]
def printShowDrivelastModifications(users):
def showLastModificationInfo(user, sharedDriveId, sharedDriveName, lastModification, i, count):
if not csvPF:
if sharedDriveId:
kvList = [Ent.USER, user, Ent.SHAREDDRIVE, f'{sharedDriveName} ({sharedDriveId})']
else:
kvList = [Ent.USER, user]
printEntity(kvList, i, count)
Ind.Increment()
_showLastModification(lastModification)
Ind.Decrement()
else:
if sharedDriveId:
row = {'User': user, 'id': sharedDriveId, 'name': sharedDriveName}
else:
row = {'User': user}
_updateLastModificationRow(row, lastModification)
if addCSVData:
row.update(addCSVData)
csvPF.WriteRowTitles(row)
csvPF = CSVPrintFile() if Act.csvFormat() else None
fieldsList = ['id', 'driveId', 'name', 'mimeType', 'lastModifyingUser', 'modifiedTime', 'parents']
DLP = DriveListParameters({'allowChoose': False, 'allowCorpora': False, 'allowQuery': False, 'mimeTypeInQuery': True})
pathDelimiter = '/'
sharedDriveId = sharedDriveName = ''
fileIdEntity = {}
addCSVData = {}
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if csvPF and myarg == 'todrive':
csvPF.GetTodriveParameters()
elif myarg == 'select':
if fileIdEntity:
usageErrorExit(Msg.CAN_NOT_BE_SPECIFIED_MORE_THAN_ONCE.format('select'))
fileIdEntity = getSharedDriveEntity()
elif myarg == 'pathdelimiter':
pathDelimiter = getCharacter()
elif csvPF and myarg == 'addcsvdata':
k = getString(Cmd.OB_STRING)
addCSVData[k] = getString(Cmd.OB_STRING, minLen=0)
else:
unknownArgumentExit()
if not fileIdEntity:
fileIdEntity = DLP.GetFileIdEntity()
if not fileIdEntity.get('shareddrive'):
btkwargs = DLP.kwargs
else:
btkwargs = fileIdEntity['shareddrive']
fieldsList.append('driveId')
DLP.Finalize(fileIdEntity)
if csvPF:
sortTitles = ['User', 'id', 'name'] if fileIdEntity.get('shareddrive') else ['User']
sortTitles.extend(['lastModifiedFileId', 'lastModifiedFileName',
'lastModifiedFileMimeType', 'lastModifiedFilePath',
'lastModifyingUser', 'lastModifiedTime'])
if addCSVData:
sortTitles.extend(sorted(addCSVData.keys()))
csvPF.SetTitles(sortTitles)
csvPF.SetSortAllTitles()
pagesFields = getItemFieldsFromFieldsList('files', fieldsList)
i, count, users = getEntityArgument(users)
for user in users:
i += 1
user, drive = _validateUserSharedDrive(user, i, count, fileIdEntity)
if not drive:
continue
sharedDriveId = fileIdEntity.get('shareddrive', {}).get('driveId', '')
sharedDriveName = _getSharedDriveNameFromId(sharedDriveId) if sharedDriveId else ''
userLastModification = _initLastModification()
gettingEntity = _getGettingEntity(user, fileIdEntity)
printGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, gettingEntity, i, count)
try:
feed = yieldGAPIpages(drive.files(), 'list', 'files',
pageMessage=getPageMessageForWhom(),
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.INVALID, GAPI.BAD_REQUEST, GAPI.FILE_NOT_FOUND,
GAPI.NOT_FOUND, GAPI.TEAMDRIVE_MEMBERSHIP_REQUIRED],
retryReasons=[GAPI.UNKNOWN_ERROR],
fields=pagesFields, pageSize=GC.Values[GC.DRIVE_MAX_RESULTS], **btkwargs)
for files in feed:
for f_file in files:
_checkUpdateLastModifiction(f_file, userLastModification)
_getLastModificationPath(drive, userLastModification, pathDelimiter)
showLastModificationInfo(user, sharedDriveId, sharedDriveName, userLastModification, i, count)
except (GAPI.invalid, GAPI.badRequest) as e:
entityActionFailedWarning([Ent.USER, user, Ent.DRIVE_FILE_OR_FOLDER, None], str(e), i, count)
continue
except GAPI.fileNotFound:
printGotEntityItemsForWhom(0)
except (GAPI.notFound, GAPI.teamDriveMembershipRequired) as e:
entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, sharedDriveId], str(e), i, count)
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
userDriveServiceNotEnabledWarning(user, str(e), i, count)
continue
if csvPF:
csvPF.writeCSVfile('Drive File Last Modification')
DISKUSAGE_SHOW_CHOICES = {'all', 'summary', 'summaryandtrash'} DISKUSAGE_SHOW_CHOICES = {'all', 'summary', 'summaryandtrash'}
# gam <UserTypeEntity> print diskusage <DriveFileEntity> [todrive <ToDriveAttribute>*] # gam <UserTypeEntity> print diskusage <DriveFileEntity> [todrive <ToDriveAttribute>*]
@ -76555,6 +76691,7 @@ USER_COMMANDS_WITH_OBJECTS = {
Cmd.ARG_DRIVEFILEACL: printShowDriveFileACLs, Cmd.ARG_DRIVEFILEACL: printShowDriveFileACLs,
Cmd.ARG_DRIVELABEL: printShowDriveLabels, Cmd.ARG_DRIVELABEL: printShowDriveLabels,
Cmd.ARG_DRIVELABELPERMISSION: printShowDriveLabelPermissions, Cmd.ARG_DRIVELABELPERMISSION: printShowDriveLabelPermissions,
Cmd.ARG_DRIVELASTMODIFICATION: printShowDrivelastModifications,
Cmd.ARG_DRIVESETTINGS: printShowDriveSettings, Cmd.ARG_DRIVESETTINGS: printShowDriveSettings,
Cmd.ARG_EMPTYDRIVEFOLDERS: printEmptyDriveFolders, Cmd.ARG_EMPTYDRIVEFOLDERS: printEmptyDriveFolders,
Cmd.ARG_EVENT: printShowCalendarEvents, Cmd.ARG_EVENT: printShowCalendarEvents,
@ -76662,6 +76799,7 @@ USER_COMMANDS_WITH_OBJECTS = {
Cmd.ARG_DRIVEFILEACL: printShowDriveFileACLs, Cmd.ARG_DRIVEFILEACL: printShowDriveFileACLs,
Cmd.ARG_DRIVELABEL: printShowDriveLabels, Cmd.ARG_DRIVELABEL: printShowDriveLabels,
Cmd.ARG_DRIVELABELPERMISSION: printShowDriveLabelPermissions, Cmd.ARG_DRIVELABELPERMISSION: printShowDriveLabelPermissions,
Cmd.ARG_DRIVELASTMODIFICATION: printShowDrivelastModifications,
Cmd.ARG_DRIVESETTINGS: printShowDriveSettings, Cmd.ARG_DRIVESETTINGS: printShowDriveSettings,
Cmd.ARG_EVENT: printShowCalendarEvents, Cmd.ARG_EVENT: printShowCalendarEvents,
Cmd.ARG_FILECOMMENT: printShowFileComments, Cmd.ARG_FILECOMMENT: printShowFileComments,
@ -76886,13 +77024,14 @@ USER_COMMANDS_OBJ_ALIASES = {
Cmd.ARG_DOMAINCONTACT: Cmd.ARG_PEOPLECONTACT, Cmd.ARG_DOMAINCONTACT: Cmd.ARG_PEOPLECONTACT,
Cmd.ARG_DOMAINCONTACTS: Cmd.ARG_PEOPLECONTACT, Cmd.ARG_DOMAINCONTACTS: Cmd.ARG_PEOPLECONTACT,
Cmd.ARG_DRIVEFILEACLS: Cmd.ARG_DRIVEFILEACL, Cmd.ARG_DRIVEFILEACLS: Cmd.ARG_DRIVEFILEACL,
Cmd.ARG_FILEDRIVELABELS: Cmd.ARG_FILEDRIVELABEL,
Cmd.ARG_DRIVEFILESHORTCUTS: Cmd.ARG_DRIVEFILESHORTCUT, Cmd.ARG_DRIVEFILESHORTCUTS: Cmd.ARG_DRIVEFILESHORTCUT,
Cmd.ARG_DRIVELABELS: Cmd.ARG_DRIVELABEL, Cmd.ARG_DRIVELABELS: Cmd.ARG_DRIVELABEL,
Cmd.ARG_DRIVELABELPERMISSIONS: Cmd.ARG_DRIVELABELPERMISSION, Cmd.ARG_DRIVELABELPERMISSIONS: Cmd.ARG_DRIVELABELPERMISSION,
Cmd.ARG_DRIVELASTMODIFICATIONS: Cmd.ARG_DRIVELASTMODIFICATION,
Cmd.ARG_EVENTS: Cmd.ARG_EVENT, Cmd.ARG_EVENTS: Cmd.ARG_EVENT,
Cmd.ARG_FILECOMMENTS: Cmd.ARG_FILECOMMENT, Cmd.ARG_FILECOMMENTS: Cmd.ARG_FILECOMMENT,
Cmd.ARG_FILECOUNTS: Cmd.ARG_FILECOUNT, Cmd.ARG_FILECOUNTS: Cmd.ARG_FILECOUNT,
Cmd.ARG_FILEDRIVELABELS: Cmd.ARG_FILEDRIVELABEL,
Cmd.ARG_FILEPATHS: Cmd.ARG_FILEPATH, Cmd.ARG_FILEPATHS: Cmd.ARG_FILEPATH,
Cmd.ARG_FILEREVISIONS: Cmd.ARG_FILEREVISION, Cmd.ARG_FILEREVISIONS: Cmd.ARG_FILEREVISION,
Cmd.ARG_FILESHARECOUNTS: Cmd.ARG_FILESHARECOUNT, Cmd.ARG_FILESHARECOUNTS: Cmd.ARG_FILESHARECOUNT,

View File

@ -579,6 +579,8 @@ class GamCLArgs():
ARG_DRIVELABELS = 'drivelabels' ARG_DRIVELABELS = 'drivelabels'
ARG_DRIVELABELPERMISSION = 'drivelabelpermission' ARG_DRIVELABELPERMISSION = 'drivelabelpermission'
ARG_DRIVELABELPERMISSIONS = 'drivelabelpermissions' ARG_DRIVELABELPERMISSIONS = 'drivelabelpermissions'
ARG_DRIVELASTMODIFICATION = 'drivelastmodification'
ARG_DRIVELASTMODIFICATIONS = 'drivelastmodifications'
ARG_DRIVESETTINGS = 'drivesettings' ARG_DRIVESETTINGS = 'drivesettings'
ARG_DRIVETRASH = 'drivetrash' ARG_DRIVETRASH = 'drivetrash'
ARG_EMPTYDRIVEFOLDERS = 'emptydrivefolders' ARG_EMPTYDRIVEFOLDERS = 'emptydrivefolders'

View File

@ -10,6 +10,23 @@ 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.02
Updated `gam <UserTypeEntity> print|show filecounts ... showlastmodification` to include
file mimetype and path information for the last modified file.
Added simple commands to get information about the last modified file on a drive.
By default, a user's My Drive is processed; optionally, a Shared Drive can be processed.
```
gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
(addcsvdata <FieldName> <String>)*
gam <UserTypeEntity> show drivelastmodification
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
```
### 7.06.01 ### 7.06.01
Updated `gam <UserTypeEntity> create|update drivefileacl ... expiration <Time>` Updated `gam <UserTypeEntity> create|update drivefileacl ... expiration <Time>`

View File

@ -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.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.06.02 - 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 x86_64 MacOS Sequoia 15.4 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.01 - https://github.com/GAM-team/GAM - pythonsource GAM 7.06.02 - 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

View File

@ -32,6 +32,7 @@
- [Handle empty file lists](#handle-empty-file-lists) - [Handle empty file lists](#handle-empty-file-lists)
- [Display disk usage](#display-disk-usage) - [Display disk usage](#display-disk-usage)
- [Display files published to the web](#display-files-published-to-the-web) - [Display files published to the web](#display-files-published-to-the-web)
- [Display information about last modified file on a drive](#display-information-about-last-modified-file-on-a-drive)
## API documentation ## API documentation
* [Drive API - Files](https://developers.google.com/drive/api/v3/reference/files) * [Drive API - Files](https://developers.google.com/drive/api/v3/reference/files)
@ -704,7 +705,8 @@ gam <UserTypeEntity> print filecounts [todrive <ToDriveAttribute>*]
[filenamematchpattern <REMatchPattern>] [filenamematchpattern <REMatchPattern>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
[excludetrashed] [excludetrashed]
[showsize] [showmimetypesize] [showlastmodification] [showsize] [showmimetypesize]
[showlastmodification] [pathdelimiter <Character>]
(addcsvdata <FieldName> <String>)* (addcsvdata <FieldName> <String>)*
[summary none|only|plus] [summaryuser <String>] [summary none|only|plus] [summaryuser <String>]
gam <UserTypeEntity> show filecounts gam <UserTypeEntity> show filecounts
@ -719,7 +721,8 @@ gam <UserTypeEntity> show filecounts
[filenamematchpattern <REMatchPattern>] [filenamematchpattern <REMatchPattern>]
<PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>] <PermissionMatch>* [<PermissionMatchMode>] [<PermissionMatchAction>]
[excludetrashed] [excludetrashed]
[showsize] [showmimetypesize] [showlastmodification] [showsize] [showmimetypesize]
[showlastmodification] [pathdelimiter <Character>]
[summary none|only|plus] [summaryuser <String>] [summary none|only|plus] [summaryuser <String>]
``` ```
@ -736,7 +739,7 @@ The `showsize` option displays the total size (in bytes) of the files counted.
The `showmimetypesize` option displays the total size (in bytes) of each MIME type counted. The `showmimetypesize` option displays the total size (in bytes) of each MIME type counted.
The option `showlastmodification` displays the following fields: The option `showlastmodification` displays the following fields:
`lastModifiedFileId,lastModifiedFileName,lastModifyingUser,lastModifiedTime`; `lastModifiedFileId,lastModifiedFileName,lastModifiedFileMimeType,lastModifiedFilePath,lastModifyingUser,lastModifiedTime`;
these are for the most recently modified file. these are for the most recently modified file.
For print filecouts, add additional columns of data from the command line to the output: For print filecouts, add additional columns of data from the command line to the output:
@ -1748,3 +1751,24 @@ gam config csv_output_header_filter "Owner,id,revisions.0.published,revisions.0.
# Get the files name, MIMEtype and path # Get the files name, MIMEtype and path
gam redirect csv ./PublishedDocsWithName.csv multiprocess redirect stderr - multiprocess csv ./PublishedDocs.csv gam user "~Owner" print filelist select "~id" fields id,name,mimetype fullpath addcsvdata published "~revisions.0.published" addcsvdata publishedOutsideDomain "~revisions.0.publishedOutsideDomain" gam redirect csv ./PublishedDocsWithName.csv multiprocess redirect stderr - multiprocess csv ./PublishedDocs.csv gam user "~Owner" print filelist select "~id" fields id,name,mimetype fullpath addcsvdata published "~revisions.0.published" addcsvdata publishedOutsideDomain "~revisions.0.publishedOutsideDomain"
``` ```
## Display information about last modified file on a drive
Use these commands to display information about the most recently modified file on a drive.
By default, a user's My Drive is processed; optionally, a Shared Drive can be processed.
```
gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
(addcsvdata <FieldName> <String>)*
gam <UserTypeEntity> show drivelastmodification
[select <SharedDriveEntity>]
[pathdelimiter <Character>]
```
In addition to the user and optional Shared Drive information, The following fields are displayed
`lastModifiedFileId,lastModifiedFileName,lastModifiedFileMimeType,lastModifiedFilePath,lastModifyingUser,lastModifiedTime`
By default, file path components are separated by `/`; use `pathdelimiter <Character>` to use `<Character>` as the separator.
For print drivelastmodification, add additional columns of data from the command line to the output:
* `addcsvdata <FieldName> <String>` - Add additional columns of data from the command line to the output

View File

@ -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.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.06.02 - 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 x86_64 MacOS Sequoia 15.4 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.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.06.02 - 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 x86_64 MacOS Sequoia 15.4 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.01 - https://github.com/GAM-team/GAM - pyinstaller GAM 7.06.02 - 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 x86_64 MacOS Sequoia 15.4 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.01 Latest: 7.06.02
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.01 7.06.02
``` ```
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.01 - https://github.com/GAM-team/GAM GAM 7.06.02 - 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 x86_64 MacOS Sequoia 15.4 x86_64