Added option onelicenseperrow|onelicenceperrow to gam print users ... licenses

This commit is contained in:
Ross Scroggs
2024-01-17 20:14:18 -08:00
parent 647da9f980
commit 432ef09129
7 changed files with 103 additions and 25 deletions

View File

@@ -5348,6 +5348,7 @@ gam print users [todrive <ToDriveAttribute>*]
[orderby <UserOrderByFieldName> [ascending|descending]]
[groups|groupsincolumns]
[license|licenses|licence|licences|licensebyuser|licensesbyuser|licencebyuser|licencesbyuser]
[onelicenseperrow|onelicenceperrow]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
@@ -5363,6 +5364,7 @@ gam print users [todrive <ToDriveAttribute>*] select <UserTypeEntity>
[orderby <UserOrderByFieldName> [ascending|descending]]
[groups|groupsincolumns]
[license|licenses|licence|licences|licensebyuser|licensesbyuser|licencebyuser|licencesbyuser]
[onelicenseperrow|onelicenceperrow]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
@@ -5376,6 +5378,7 @@ gam <UserTypeEntity> print users [todrive <ToDriveAttribute>*]
[orderby <UserOrderByFieldName> [ascending|descending]]
[groups|groupsincolumns]
[license|licenses|licence|licences|licensebyuser|licensesbyuser|licencebyuser|licencesbyuser]
[onelicenseperrow|onelicenceperrow]
[(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]
[schemas|custom|customschemas all|<SchemaNameList>]
[emailpart|emailparts|username]
@@ -5778,7 +5781,7 @@ gam <UserTypeEntity> create workinglocation
(home|
(custom <String>)|
(office <String> [building|buildingid <String>] [floor|floorname <String>]
[section|floorsection <String>] [desk|deskcode <String>]))
[section|floorsection <String>] [desk|deskcode <String>]))
((date yyyy-mm-dd)|
(range yyyy-mm-dd yyyy-mm-dd)|
(daily yyyy-mm-dd N)|

View File

@@ -2,6 +2,24 @@
Merged GAM-Team version
6.67.20
Added option `onelicenseperrow|onelicenceperrow` to `gam print users ... licenses` that causes GAM to print
a seperate user information row for each license a user is assigned. This makes processing
the licenses in a script possible and allows better sorting in a CSV File.
By default, all licenses for a user are displayed in a list on one row:
```
primaryEmail,LicensesCount,Licenses,LicensesDisplay
user@domain.com,2,1010020020 1010330004,Google Workspace Enterprise Plus Google Voice Standard
```
With `onelicenseperrow|onelicenceperrow`, each license is on a separate row:
```
primaryEmail,License,LicenseDisplay
user@domain.com,1010020020,Google Workspace Enterprise Plus
user@domain.com 1010330004,Google Voice Standard
```
6.67.19
Updated `gam create|update user ... notify` to encode the characters `<>&` in the password

View File

@@ -42598,6 +42598,15 @@ USERS_INDEXED_TITLES = ['addresses', 'aliases', 'nonEditableAliases', 'emails',
# [issuspended <Boolean>]
# [showitemcountonly]
def doPrintUsers(entityList=None):
def _writeUserEntity(userEntity):
row = flattenJSON(userEntity, skipObjects=USER_SKIP_OBJECTS, timeObjects=USER_TIME_OBJECTS)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
csvPF.WriteRowNoFilter({'primaryEmail': userEntity['primaryEmail'],
'JSON': json.dumps(cleanJSON(userEntity, skipObjects=USER_SKIP_OBJECTS, timeObjects=USER_TIME_OBJECTS),
ensure_ascii=False, sort_keys=True)})
def _printUser(userEntity, i, count):
if isSuspended is None or isSuspended == userEntity.get('suspended', isSuspended):
userEmail = userEntity['primaryEmail']
@@ -42635,24 +42644,31 @@ def doPrintUsers(entityList=None):
badRequestWarning(Ent.GROUP, Ent.MEMBER, userEmail)
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
accessErrorExit(cd)
if aliasMatchPattern and 'aliases' in userEntity:
userEntity['aliases'] = [alias for alias in userEntity['aliases'] if aliasMatchPattern.match(alias)]
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
if printOptions['getLicenseFeed']:
u_licenses = licenses.get(userEmail.lower(), [])
else:
u_licenses = getUserLicenses(lic, userEntity, skus)
userEntity['LicensesCount'] = len(u_licenses)
if not oneLicensePerRow:
userEntity['LicensesCount'] = len(u_licenses)
if u_licenses:
userEntity['Licenses'] = delimiter.join(u_licenses)
userEntity['LicensesDisplay'] = delimiter.join([SKU.skuIdToDisplayName(skuId) for skuId in u_licenses])
else:
u_licenses = []
if not oneLicensePerRow:
_writeUserEntity(userEntity)
else:
if u_licenses:
userEntity['Licenses'] = delimiter.join(u_licenses)
userEntity['LicensesDisplay'] = delimiter.join([SKU.skuIdToDisplayName(skuId) for skuId in u_licenses])
if aliasMatchPattern and 'aliases' in userEntity:
userEntity['aliases'] = [alias for alias in userEntity['aliases'] if aliasMatchPattern.match(alias)]
row = flattenJSON(userEntity, skipObjects=USER_SKIP_OBJECTS, timeObjects=USER_TIME_OBJECTS)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
csvPF.WriteRowNoFilter({'primaryEmail': userEmail,
'JSON': json.dumps(cleanJSON(userEntity, skipObjects=USER_SKIP_OBJECTS, timeObjects=USER_TIME_OBJECTS),
ensure_ascii=False, sort_keys=True)})
for skuId in u_licenses:
userEntity['License'] = skuId
userEntity['LicenseDisplay'] = SKU.skuIdToDisplayName(skuId)
_writeUserEntity(userEntity)
else:
userEntity['License'] = userEntity['LicenseDisplay'] = ''
_writeUserEntity(userEntity)
def _updateDomainCounts(emailAddress):
atLoc = emailAddress.find('@')
@@ -42718,7 +42734,7 @@ def doPrintUsers(entityList=None):
projection = 'basic'
projectionSet = False
customFieldMask = None
quotePlusPhoneNumbers = showDeleted = False
oneLicensePerRow = quotePlusPhoneNumbers = showDeleted = False
aliasMatchPattern = isSuspended = orgUnitPath = orgUnitPathLower = orderBy = sortOrder = None
viewType = 'admin_view'
delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER]
@@ -42781,6 +42797,8 @@ def doPrintUsers(entityList=None):
elif myarg in {'licensebyuser', 'licensesbyuser', 'licencebyuser', 'licencesbyuser'}:
printOptions['getLicenseFeedByUser'] = True
printOptions['getLicenseFeed'] = False
elif myarg in {'onelicenseperrow', 'onelicenceperrow'}:
oneLicensePerRow = True
elif myarg in {'products', 'product'}:
skus = SKU.convertProductListToSKUList(getGoogleProductList())
elif myarg in {'sku', 'skus'}:
@@ -42818,7 +42836,10 @@ def doPrintUsers(entityList=None):
else:
csvPF.AddTitles(['Groups'])
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
csvPF.AddTitles(['LicensesCount', 'Licenses', 'LicensesDisplay'])
if not oneLicensePerRow:
csvPF.AddTitles(['LicensesCount', 'Licenses', 'LicensesDisplay'])
else:
csvPF.AddTitles(['License', 'LicenseDisplay'])
if printOptions['getLicenseFeed']:
if skus is None and GM.Globals[GM.LICENSE_SKUS]:
skus = GM.Globals[GM.LICENSE_SKUS]
@@ -42958,7 +42979,10 @@ def doPrintUsers(entityList=None):
else:
csvPF.MoveTitlesToEnd(['Groups']+[f'Groups{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{j}' for j in range(printOptions['maxGroups'])])
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
csvPF.MoveTitlesToEnd(['LicensesCount', 'Licenses', 'LicensesDisplay'])
if not oneLicensePerRow:
csvPF.MoveTitlesToEnd(['LicensesCount', 'Licenses', 'LicensesDisplay'])
else:
csvPF.MoveTitlesToEnd(['License', 'LicenseDisplay'])
elif not FJQC.formatJSON:
for domain, count in sorted(iter(domainCounts.items())):
csvPF.WriteRowNoFilter({'domain': domain, 'count': count})