diff --git a/src/GamCommands.txt b/src/GamCommands.txt index b3ed8007..e21d463a 100644 --- a/src/GamCommands.txt +++ b/src/GamCommands.txt @@ -1435,6 +1435,50 @@ gam print browsertokens [todrive *] [allfields] * [fields ] [sortheaders] [formatjson [quotechar ]] +# Chrome Installed Apps Counts + +gam show chromeapps + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [filter ] + [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] + [formatjson] +gam print chromeapps [todrive *] + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [filter ] + [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] + [formatjson [quotechar ]] [delimiter ] + +gam show chromeappdevices + appid apptype extension|app|theme|hostedapp|androidapp + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [start ] [end ] + [orderby deviceid|machine] + [formatjson] +gam print chromeappdevices [todrive *] + appid apptype extension|app|theme|hostedapp|androidapp + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [start ] [end ] + [orderby deviceid|machine] + [formatjson [quotechar ]] + +# Chrome Versions Counts + +gam show chromeversions + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [start ] [end ] [recentfirst []] + [formatjson] +gam print chromeversions [todrive *] + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [start ] [end ] + [recentfirst []] + [formatjson [quotechar ]] + # ChromeOS Devices ::= @@ -1649,6 +1693,47 @@ gam show chromepolicies gam show chromeschemas [filter ] +# Chrome Apps/Versions + +gam show chromeapps + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [filter ] + [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] + [formatjson] +gam print chromeapps [todrive *] + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [filter ] + [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] + [formatjson [quotechar ]] + +gam show chromeappdevices + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [appid ] [apptype extension|app|theme|hostedapp|androidapp] + [filter ] + [orderby deviceid|machine] + [formatjson] +gam print chromeappdevices [todrive *] + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [appid ] [apptype extension|app|theme|hostedapp|androidapp] + [filter ] + [orderby deviceid|machine] + [formatjson [quotechar ]] + +gam show chromeversions + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [start ] [end ] + [formatjson] +gam print chromeversions [todrive *] + [(ou )|(ou_and_children )| + (ous )|(ous_and_children )] + [start ] [end ] + [formatjson [quotechar ]] + # Contacts ::= diff --git a/src/GamUpdate.txt b/src/GamUpdate.txt index 22df4c15..8afc9da4 100644 --- a/src/GamUpdate.txt +++ b/src/GamUpdate.txt @@ -1,3 +1,16 @@ +6.01.00 + +Added the capability to access two new areas. + +* Chrome Installed Apps Counts - https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Installed-Apps-Counts +* Chrome Versions Counts - https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Versions-Counts + +You'll have to do `gam update project` and `gam oauth create` to enable these commands. + +As with any initial release, report any problems. + +Improved error reporting when trying to add/remove licenses with an administrator that is not authorized to do so. + 6.00.08 Fixed bug in `gam print course-materials fields ` that caused the following error: diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 8ff804ea..ffb56b89 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -23,7 +23,7 @@ """ __author__ = 'Ross Scroggs ' -__version__ = '6.00.08' +__version__ = '6.01.00' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' import base64 @@ -19520,7 +19520,7 @@ def doInfoPrinter(): except (GAPI.invalid, GAPI.permissionDenied) as e: entityActionFailedWarning([Ent.DEVICE, f'{printerId}'], str(e)) -PRINTERS_ENTITIES_MAP = { +ORGUNIT_ENTITIES_MAP = { 'org': Cmd.ENTITY_OU, 'organdchildren': Cmd.ENTITY_OU_AND_CHILDREN, 'orgs': Cmd.ENTITY_OUS, @@ -19528,7 +19528,11 @@ def doInfoPrinter(): 'ou': Cmd.ENTITY_OU, 'ouandchildren': Cmd.ENTITY_OU_AND_CHILDREN, 'ous': Cmd.ENTITY_OUS, - 'ousandchildren': Cmd.ENTITY_OUS_AND_CHILDREN + 'ousandchildren': Cmd.ENTITY_OUS_AND_CHILDREN, + 'orgunit': Cmd.ENTITY_OU, + 'orgunitandchildren': Cmd.ENTITY_OU_AND_CHILDREN, + 'orgunits': Cmd.ENTITY_OUS, + 'orgunitsandchildren': Cmd.ENTITY_OUS_AND_CHILDREN, } # gam show printers @@ -19567,8 +19571,8 @@ def _printPrinter(printer): myarg = getArgument() if myarg == 'todrive': csvPF.GetTodriveParameters() - elif myarg in PRINTERS_ENTITIES_MAP: - myarg = PRINTERS_ENTITIES_MAP[myarg] + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} elif getFieldsList(myarg, PRINTER_FIELDS_CHOICE_MAP, fieldsList, initialField='id'): @@ -19631,12 +19635,12 @@ def _printPrinter(printer): if csvPF: csvPF.writeCSVfile('Printers') -# gam show printermodels -# [filter ] -# [formatjson] # gam print printermodels [todrive *] # [filter ] # [[formatjson [quotechar ]] +# gam show printermodels +# [filter ] +# [formatjson] def doPrintShowPrinterModels(): def _showPrinterModel(model, FJQC, i, count): if FJQC is not None and FJQC.formatJSON: @@ -19698,6 +19702,422 @@ def _printPrinterModel(model): if csvPF: csvPF.writeCSVfile('Printer Models') +CHROME_APPS_ORDERBY_CHOICE_MAP = { + 'appname': 'app_name', + 'apptype': 'appType', + 'installtype': 'install_type', + 'numberofpermissions': 'number_of_permissions', + 'totalinstallcount': 'total_install_count', + } +CHROME_APPS_TITLES = [ + 'displayName', + 'browserDeviceCount', 'osUserCount', + 'appType', 'description', + 'appInstallType', 'appSource', + 'disabled', 'homepageUri', 'permissions' + ] + +# gam print chromeapps [todrive *] +# [(ou )|(ou_and_children )| +# (ous )|(ous_and_children )] +# [filter ] +# [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] +# [formatjson [quotechar ]] [delimiter ] +# gam show chromeapps +# [(ou )|(ou_and_children )| +# (ous )|(ous_and_children )] +# [filter ] +# [orderby appname|apptype|installtype|numberofpermissions|totalinstallcount] +# [formatjson] +def doPrintShowChromeApps(): + def _printApp(app): + if showOrgUnit: + app['orgUnitPath'] = orgUnitPath + if FJQC.formatJSON: + if (not csvPF.rowFilter and not csvPF.rowDropFilter) or csvPF.CheckRowTitles(flattenJSON(app)): + csvPF.WriteRowNoFilter({'appId': app['appId'], + 'JSON': json.dumps(cleanJSON(app), + ensure_ascii=False, sort_keys=True)}) + else: + csvPF.WriteRow(flattenJSON(app, simpleLists=['permissions'], delimiter=delimiter)) + + def _showApp(app, i=0, count=0): + if showOrgUnit: + app['orgUnitPath'] = orgUnitPath + if FJQC is not None and FJQC.formatJSON: + printLine(json.dumps(cleanJSON(app), ensure_ascii=False, sort_keys=True)) + else: + printEntity([Ent.CHROME_APP, app['appId']], i, count) + Ind.Increment() + showJSON(None, app) + Ind.Decrement() + + cd = buildGAPIObject(API.DIRECTORY) + cm = buildGAPIObject(API.CHROMEMANAGEMENT) + customerId = _getCustomersCustomerIdWithC() + csvPF = CSVPrintFile(['appId']) if Act.csvFormat() else None + FJQC = FormatJSONQuoteChar(csvPF) + delimiter = GC.Values[GC.CSV_OUTPUT_FIELD_DELIMITER] + ous = [None] + directlyInOU = True + showOrgUnit = False + orderBy = pfilter = None + while Cmd.ArgumentsRemaining(): + myarg = getArgument() + if myarg == 'todrive': + csvPF.GetTodriveParameters() + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] + ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) + directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} + elif myarg == 'filter': + pfilter = getString(Cmd.OB_STRING) + elif myarg == 'orderby': + orderBy = getChoice(CHROME_APPS_ORDERBY_CHOICE_MAP, mapChoice=True) + elif myarg == 'delimiter': + delimiter = getCharacter() + else: + FJQC.GetFormatJSONQuoteChar(myarg, True) + if ous[0] is not None: + showOrgUnit = True + if csvPF and not FJQC.formatJSON: + csvPF.AddTitles(CHROME_APPS_TITLES) + if showOrgUnit: + csvPF.AddTitle('orgUnitPath') + for ou in ous: + if ou is not None: + ou = makeOrgUnitPathAbsolute(ou) + _, orgUnitId = getOrgUnitId(cd, ou) + ouList = [(ou, orgUnitId[3:])] + else: + ouList = [('/', None)] + if not directlyInOU: + try: + orgs = callGAPI(cd.orgunits(), 'list', + throwReasons=GAPI.ORGUNIT_GET_THROW_REASONS, + customerId=GC.Values[GC.CUSTOMER_ID], orgUnitPath=makeOrgUnitPathRelative(ou), + type='all', fields='organizationUnits(orgUnitPath,orgUnitId)') + except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.backendError, GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired): + checkEntityDNEorAccessErrorExit(cd, Ent.ORGANIZATIONAL_UNIT, ou) + return + ouList.extend([(subou['orgUnitPath'], subou['orgUnitId'][3:]) for subou in sorted(orgs.get('organizationUnits', []), key=lambda k: k['orgUnitPath'])]) + for subou in ouList: + orgUnitPath = subou[0] + orgUnitId = subou[1] + if orgUnitId is not None: + oneQualifier = Msg.DIRECTLY_IN_THE.format(Ent.Singular(Ent.ORGANIZATIONAL_UNIT)) + printGettingAllEntityItemsForWhom(Ent.CHROME_APP, orgUnitPath, qualifier=oneQualifier, entityType=Ent.ORGANIZATIONAL_UNIT) + else: + printGettingAllAccountEntities(Ent.CHROME_APP, pfilter) + pageMessage = getPageMessage() + try: + apps = callGAPIpages(cm.customers().reports(), 'countInstalledApps', 'installedApps', + throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], + pageMessage=pageMessage, + customer=customerId, orgUnitId=orgUnitId, filter=pfilter, orderBy=orderBy) + except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e: + entityActionFailedWarning([Ent.CHROME_APP, None], str(e)) + return + jcount = len(apps) + if not csvPF: + entityPerformActionNumItems([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], jcount, Ent.CHROME_APP) + Ind.Increment() + j = 0 + for app in apps: + j += 1 + _showApp(app, j, jcount) + Ind.Decrement() + else: + for app in apps: + _printApp(app) + if csvPF: + csvPF.writeCSVfile('Chrome Installed Applications') + +CHROME_APP_DEVICES_APPTYPE_CHOICE_MAP = { + 'extension': 'EXTENSION', + 'app': 'APP', + 'theme': 'THEME', + 'hostedapp': 'HOSTED_APP', + 'androidapp': 'ANDROID_APP', + } +CHROME_APP_DEVICES_ORDERBY_CHOICE_MAP = { + 'deviceid': 'deviceId', + 'machine': 'machine', + } +CHROME_APP_DEVICES_TITLES = [ + 'appType', 'deviceId', 'machine' + ] + +# gam print chromeappdevices [todrive *] +# appid apptype extension|app|theme|hostedapp|androidapp +# [(ou )|(ou_and_children )| +# (ous )|(ous_and_children )] +# [start ] [end ] +# [orderby deviceid|machine] +# [formatjson [quotechar ]] +# gam show chromeappdevices +# appid apptype extension|app|theme|hostedapp|androidapp +# [(ou )|(ou_and_children )| +# (ous )|(ous_and_children )] +# [start ] [end ] +# [orderby deviceid|machine] +# [formatjson] +def doPrintShowChromeAppDevices(): + def _printDevice(device): + device['appId'] = appId + device['appType'] = appType + if showOrgUnit: + device['orgUnitPath'] = orgUnitPath + if FJQC.formatJSON: + if (not csvPF.rowFilter and not csvPF.rowDropFilter) or csvPF.CheckRowTitles(flattenJSON(device)): + csvPF.WriteRowNoFilter({'appId': device['appId'], + 'JSON': json.dumps(cleanJSON(device), + ensure_ascii=False, sort_keys=True)}) + else: + csvPF.WriteRow(flattenJSON(device)) + + def _showDevice(device, i=0, count=0): + device['appId'] = appId + device['appType'] = appType + if showOrgUnit: + device['orgUnitPath'] = orgUnitPath + if FJQC is not None and FJQC.formatJSON: + printLine(json.dumps(cleanJSON(device), ensure_ascii=False, sort_keys=True)) + else: + printEntity([Ent.CHROME_APP, device['appId']], i, count) + Ind.Increment() + showJSON(None, device) + Ind.Decrement() + + cd = buildGAPIObject(API.DIRECTORY) + cm = buildGAPIObject(API.CHROMEMANAGEMENT) + customerId = _getCustomersCustomerIdWithC() + csvPF = CSVPrintFile(['appId']) if Act.csvFormat() else None + FJQC = FormatJSONQuoteChar(csvPF) + ous = [None] + directlyInOU = True + showOrgUnit = False + appId = appType = orderBy = None + startDate = endDate = pfilter = None + while Cmd.ArgumentsRemaining(): + myarg = getArgument() + if myarg == 'todrive': + csvPF.GetTodriveParameters() + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] + ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) + directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} + elif myarg == 'appid': + appId = getString(Cmd.OB_APP_ID) + elif myarg == 'apptype': + appType = getChoice(CHROME_APP_DEVICES_APPTYPE_CHOICE_MAP, mapChoice=True) + elif myarg in CROS_START_ARGUMENTS: + startDate, _ = _getFilterDateTime() + startDate = startDate.strftime(YYYYMMDD_FORMAT) + elif myarg in CROS_END_ARGUMENTS: + endDate, _ = _getFilterDateTime() + endDate = endDate.strftime(YYYYMMDD_FORMAT) + elif myarg == 'orderby': + orderBy = getChoice(CHROME_APP_DEVICES_ORDERBY_CHOICE_MAP, mapChoice=True) + else: + FJQC.GetFormatJSONQuoteChar(myarg, True) + if appId is None: + missingArgumentExit('appid') + if appType is None: + missingArgumentExit('apptype') + if endDate: + pfilter = f'last_active_date<={endDate}' + if startDate: + if pfilter: + pfilter += ' AND ' + else: + pfilter = '' + pfilter += f'last_active_date>={startDate}' + if ous[0] is not None: + showOrgUnit = True + if csvPF and not FJQC.formatJSON: + csvPF.AddTitles(CHROME_APP_DEVICES_TITLES) + if showOrgUnit: + csvPF.AddTitle('orgUnitPath') + for ou in ous: + if ou is not None: + ou = makeOrgUnitPathAbsolute(ou) + _, orgUnitId = getOrgUnitId(cd, ou) + ouList = [(ou, orgUnitId[3:])] + else: + ouList = [('/', None)] + if not directlyInOU: + try: + orgs = callGAPI(cd.orgunits(), 'list', + throwReasons=GAPI.ORGUNIT_GET_THROW_REASONS, + customerId=GC.Values[GC.CUSTOMER_ID], orgUnitPath=makeOrgUnitPathRelative(ou), + type='all', fields='organizationUnits(orgUnitPath,orgUnitId)') + except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.backendError, GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired): + checkEntityDNEorAccessErrorExit(cd, Ent.ORGANIZATIONAL_UNIT, ou) + return + ouList.extend([(subou['orgUnitPath'], subou['orgUnitId'][3:]) for subou in sorted(orgs.get('organizationUnits', []), key=lambda k: k['orgUnitPath'])]) + for subou in ouList: + orgUnitPath = subou[0] + orgUnitId = subou[1] + if orgUnitId is not None: + oneQualifier = Msg.DIRECTLY_IN_THE.format(Ent.Singular(Ent.ORGANIZATIONAL_UNIT)) + printGettingAllEntityItemsForWhom(Ent.CHROME_APP_DEVICE, orgUnitPath, qualifier=oneQualifier, entityType=Ent.ORGANIZATIONAL_UNIT) + else: + printGettingAllAccountEntities(Ent.CHROME_APP_DEVICE, pfilter) + pageMessage = getPageMessage() + try: + devices = callGAPIpages(cm.customers().reports(), 'findInstalledAppDevices', 'devices', + throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], + pageMessage=pageMessage, + appId=appId, appType=appType, + customer=customerId, orgUnitId=orgUnitId, filter=pfilter, orderBy=orderBy) + except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e: + entityActionFailedWarning([Ent.CHROME_APP_DEVICE, None], str(e)) + return + jcount = len(devices) + if not csvPF: + entityPerformActionNumItems([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], jcount, Ent.CHROME_APP_DEVICE) + Ind.Increment() + j = 0 + for device in devices: + j += 1 + _showDevice(device, j, jcount) + Ind.Decrement() + else: + for device in devices: + _printDevice(device) + if csvPF: + csvPF.writeCSVfile('Chrome Installed Application Devices') + +CHROME_VERSIONS_TITLES = [ + 'channel', 'system', 'deviceOsVersion' + ] + +# gam print chromeversions [todrive *] +# [(ou )|(ou_and_children )| +# (ous )|(ous_and_children )] +# [start ] [end ] +# [recentfirst []] +# [formatjson [quotechar ]] +# gam show chromeversions +# [(ou )|(ou_and_children )| +# (ous )|(ous_and_children )] +# [start ] [end ] +# [recentfirst []] +# [formatjson] +def doPrintShowChromeVersions(): + def _printVersion(version): + if showOrgUnit: + version['orgUnitPath'] = orgUnitPath + if FJQC.formatJSON: + if (not csvPF.rowFilter and not csvPF.rowDropFilter) or csvPF.CheckRowTitles(flattenJSON(version)): + csvPF.WriteRowNoFilter({'version': version['version'], 'count': version['count'], + 'JSON': json.dumps(cleanJSON(version), + ensure_ascii=False, sort_keys=True)}) + else: + csvPF.WriteRow(flattenJSON(version)) + + def _showVersion(version, i=0, count=0): + if showOrgUnit: + version['orgUnitPath'] = orgUnitPath + if FJQC is not None and FJQC.formatJSON: + printLine(json.dumps(cleanJSON(version), ensure_ascii=False, sort_keys=True)) + else: + printEntity([Ent.CHROME_VERSION, version['version']], i, count) + Ind.Increment() + showJSON(None, version) + Ind.Decrement() + + cd = buildGAPIObject(API.DIRECTORY) + cm = buildGAPIObject(API.CHROMEMANAGEMENT) + customerId = _getCustomersCustomerIdWithC() + csvPF = CSVPrintFile(['version', 'count']) if Act.csvFormat() else None + FJQC = FormatJSONQuoteChar(csvPF) + ous = [None] + directlyInOU = True + reverse = showOrgUnit = False + startDate = endDate = pfilter = None + while Cmd.ArgumentsRemaining(): + myarg = getArgument() + if myarg == 'todrive': + csvPF.GetTodriveParameters() + elif myarg in ORGUNIT_ENTITIES_MAP: + myarg = ORGUNIT_ENTITIES_MAP[myarg] + ous = convertEntityToList(getString(Cmd.OB_ENTITY, minLen=0), shlexSplit=True, nonListEntityType=myarg in [Cmd.ENTITY_OU, Cmd.ENTITY_OU_AND_CHILDREN]) + directlyInOU = myarg in {Cmd.ENTITY_OU, Cmd.ENTITY_OUS} + elif myarg in CROS_START_ARGUMENTS: + startDate, _ = _getFilterDateTime() + startDate = startDate.strftime(YYYYMMDD_FORMAT) + elif myarg in CROS_END_ARGUMENTS: + endDate, _ = _getFilterDateTime() + endDate = endDate.strftime(YYYYMMDD_FORMAT) + elif myarg == 'recentfirst': + reverse = getBoolean() + else: + FJQC.GetFormatJSONQuoteChar(myarg, True) + if endDate: + pfilter = f'last_active_date<={endDate}' + if startDate: + if pfilter: + pfilter += ' AND ' + else: + pfilter = '' + pfilter += f'last_active_date>={startDate}' + if ous[0] is not None: + showOrgUnit = True + if csvPF and not FJQC.formatJSON: + csvPF.AddTitles(CHROME_VERSIONS_TITLES) + if showOrgUnit: + csvPF.AddTitle('orgUnitPath') + for ou in ous: + if ou is not None: + ou = makeOrgUnitPathAbsolute(ou) + _, orgUnitId = getOrgUnitId(cd, ou) + ouList = [(ou, orgUnitId[3:])] + else: + ouList = [('/', None)] + if not directlyInOU: + try: + orgs = callGAPI(cd.orgunits(), 'list', + throwReasons=GAPI.ORGUNIT_GET_THROW_REASONS, + customerId=GC.Values[GC.CUSTOMER_ID], orgUnitPath=makeOrgUnitPathRelative(ou), + type='all', fields='organizationUnits(orgUnitPath,orgUnitId)') + except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.backendError, GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired): + checkEntityDNEorAccessErrorExit(cd, Ent.ORGANIZATIONAL_UNIT, ou) + return + ouList.extend([(subou['orgUnitPath'], subou['orgUnitId'][3:]) for subou in sorted(orgs.get('organizationUnits', []), key=lambda k: k['orgUnitPath'])]) + for subou in ouList: + orgUnitPath = subou[0] + orgUnitId = subou[1] + if orgUnitId is not None: + oneQualifier = Msg.DIRECTLY_IN_THE.format(Ent.Singular(Ent.ORGANIZATIONAL_UNIT)) + printGettingAllEntityItemsForWhom(Ent.CHROME_VERSION, orgUnitPath, qualifier=oneQualifier, entityType=Ent.ORGANIZATIONAL_UNIT) + else: + printGettingAllAccountEntities(Ent.CHROME_VERSION, pfilter) + pageMessage = getPageMessage() + try: + versions = callGAPIpages(cm.customers().reports(), 'countChromeVersions', 'browserVersions', + throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], + pageMessage=pageMessage, + customer=customerId, orgUnitId=orgUnitId, filter=pfilter) + except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e: + entityActionFailedWarning([Ent.CHROME_VERSION, None], str(e)) + return + jcount = len(versions) + if not csvPF: + entityPerformActionNumItems([Ent.ORGANIZATIONAL_UNIT, orgUnitPath], jcount, Ent.CHROME_VERSION) + Ind.Increment() + j = 0 + for version in sorted(versions, key=lambda k: k['version'], reverse=reverse): + j += 1 + _showVersion(version, j, jcount) + Ind.Decrement() + else: + for version in sorted(versions, key=lambda k: k['version'], reverse=reverse): + _printVersion(version) + if csvPF: + csvPF.writeCSVfile('Chrome Versions') + # Mobile command utilities MOBILE_ACTION_CHOICE_MAP = { 'accountwipe': 'admin_account_wipe', @@ -35952,7 +36372,7 @@ def removeCalendars(users): # gam print calendars [todrive *] [permissions] # [primary] * [noprimary] [nogroups] [noresources] [nosystem] [nousers] -# [formatjson] [delimiter ] [quotechar } +# [formatjson [quotechar ]] [delimiter ] # gam show calendars [permissions] # [primary] * [noprimary] [nogroups] [noresources] [nosystem] [nousers] # [formatjson] @@ -46587,10 +47007,10 @@ def _createLicenses(lic, parameters, count, users): productId=parameters[LICENSE_PRODUCTID], skuId=parameters[LICENSE_SKUID], body={'userId': user}, fields='') message = Act.SUCCESS entityActionPerformed([Ent.USER, user, Ent.LICENSE, SKU.formatSKUIdDisplayName(parameters[LICENSE_SKUID])], i, count) - except (GAPI.duplicate, GAPI.conditionNotMet, GAPI.invalid) as e: + except (GAPI.duplicate, GAPI.forbidden, GAPI.conditionNotMet, GAPI.invalid) as e: message = str(e) entityActionFailedWarning([Ent.USER, user, Ent.LICENSE, SKU.formatSKUIdDisplayName(parameters[LICENSE_SKUID])], message, i, count) - except (GAPI.userNotFound, GAPI.forbidden, GAPI.backendError) as e: + except (GAPI.userNotFound, GAPI.backendError) as e: message = str(e) entityUnknownWarning(Ent.USER, user, i, count) if parameters['csvPF']: @@ -46625,10 +47045,10 @@ def updateLicense(users): message = Act.SUCCESS entityModifierNewValueActionPerformed([Ent.USER, user, Ent.LICENSE, SKU.skuIdToDisplayName(parameters[LICENSE_SKUID])], Act.MODIFIER_FROM, SKU.skuIdToDisplayName(parameters[LICENSE_OLDSKUID]), i, count) - except (GAPI.internalError, GAPI.notFound, GAPI.conditionNotMet, GAPI.invalid) as e: + except (GAPI.internalError, GAPI.notFound, GAPI.forbidden, GAPI.conditionNotMet, GAPI.invalid) as e: message = str(e) entityActionFailedWarning([Ent.USER, user, Ent.LICENSE, SKU.formatSKUIdDisplayName(parameters[LICENSE_OLDSKUID])], message, i, count) - except (GAPI.userNotFound, GAPI.forbidden, GAPI.backendError) as e: + except (GAPI.userNotFound, GAPI.backendError) as e: message = str(e) entityUnknownWarning(Ent.USER, user, i, count) if parameters['csvPF']: @@ -46651,10 +47071,10 @@ def _deleteLicenses(lic, parameters, count, users): productId=parameters[LICENSE_PRODUCTID], skuId=parameters[LICENSE_SKUID], userId=user) message = Act.SUCCESS entityActionPerformed([Ent.USER, user, Ent.LICENSE, SKU.formatSKUIdDisplayName(parameters[LICENSE_SKUID])], i, count) - except (GAPI.notFound, GAPI.conditionNotMet, GAPI.invalid) as e: + except (GAPI.notFound, GAPI.forbidden, GAPI.conditionNotMet, GAPI.invalid) as e: message = str(e) entityActionFailedWarning([Ent.USER, user, Ent.LICENSE, SKU.formatSKUIdDisplayName(parameters[LICENSE_SKUID])], message, i, count) - except (GAPI.userNotFound, GAPI.forbidden, GAPI.backendError) as e: + except (GAPI.userNotFound, GAPI.backendError) as e: message = str(e) entityUnknownWarning(Ent.USER, user, i, count) if parameters['csvPF']: @@ -51426,6 +51846,9 @@ def _printVacation(user, result, showDisabled): Cmd.ARG_BROWSER: doPrintShowBrowsers, Cmd.ARG_BROWSERTOKEN: doPrintShowBrowserTokens, Cmd.ARG_BUILDING: doPrintShowBuildings, + Cmd.ARG_CHROMEAPPS: doPrintShowChromeApps, + Cmd.ARG_CHROMEAPPDEVICES: doPrintShowChromeAppDevices, + Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions, Cmd.ARG_CIGROUP: doPrintCIGroups, Cmd.ARG_CIGROUPMEMBERS: doPrintCIGroupMembers, Cmd.ARG_CLASSROOMINVITATION: doPrintShowClassroomInvitations, @@ -51516,6 +51939,9 @@ def _printVacation(user, result, showDisabled): Cmd.ARG_BROWSER: doPrintShowBrowsers, Cmd.ARG_BROWSERTOKEN: doPrintShowBrowserTokens, Cmd.ARG_BUILDING: doPrintShowBuildings, + Cmd.ARG_CHROMEAPPS: doPrintShowChromeApps, + Cmd.ARG_CHROMEAPPDEVICES: doPrintShowChromeAppDevices, + Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions, Cmd.ARG_CHROMEPOLICY: doPrintShowChromePolicies, Cmd.ARG_CHROMESCHEMA: doPrintShowChromeSchemas, Cmd.ARG_CIGROUPMEMBERS: doShowCIGroupMembers, diff --git a/src/gam/gamlib/glapi.py b/src/gam/gamlib/glapi.py index ea414468..18082eab 100644 --- a/src/gam/gamlib/glapi.py +++ b/src/gam/gamlib/glapi.py @@ -24,6 +24,7 @@ CALENDAR = 'calendar' CBCM = 'cbcm' CHAT = 'chat' +CHROMEMANAGEMENT = 'chromemanagement' CHROMEPOLICY = 'chromepolicy' CLASSROOM = 'classroom' CLOUDIDENTITY_DEVICES = 'cloudidentitydevices' @@ -104,6 +105,7 @@ 'alertcenter.googleapis.com', 'calendar-json.googleapis.com', 'chat.googleapis.com', + 'chromemanagement.googleapis.com', 'chromepolicy.googleapis.com', 'classroom.googleapis.com', 'cloudidentity.googleapis.com', @@ -132,6 +134,7 @@ CALENDAR: {'name': 'Calendar API', 'version': 'v3', 'v2discovery': False}, CBCM: {'name': 'Chrome Browser Cloud Management API', 'version': 'v1.1beta1', 'v2discovery': True, 'localjson': True}, CLASSROOM: {'name': 'Classroom API', 'version': 'v1', 'v2discovery': True}, + CHROMEMANAGEMENT: {'name': 'Chrome Management API', 'version': 'v1', 'v2discovery': True}, CHROMEPOLICY: {'name': 'Chrome Policy API', 'version': 'v1', 'v2discovery': True}, CLOUDIDENTITY_DEVICES: {'name': 'Cloud Identity Devices API', 'version': 'v1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, CLOUDIDENTITY_GROUPS: {'name': 'Cloud Identity Groups API', 'version': 'v1beta1', 'v2discovery': True, 'mappedAPI': 'cloudidentity'}, @@ -182,6 +185,12 @@ 'subscopes': READONLY, 'scope': 'https://www.googleapis.com/auth/admin.directory.device.chromebrowsers', }, + { + 'name': 'Chrome Management API - read only', + 'api': CHROMEPOLICY, + 'subscopes': [], + 'scope': 'https://www.googleapis.com/auth/chrome.management.reports.readonly', + }, { 'name': 'Chrome Policy API', 'api': CHROMEPOLICY, diff --git a/src/gam/gamlib/glclargs.py b/src/gam/gamlib/glclargs.py index 8059663e..674a0fed 100644 --- a/src/gam/gamlib/glclargs.py +++ b/src/gam/gamlib/glclargs.py @@ -369,6 +369,9 @@ class GamCLArgs(): ARG_CALENDARACLS = 'calendaracls' ARG_CALENDARTRASH = 'calendartrash' ARG_CALSETTINGS = 'calsettings' + ARG_CHROMEAPPS = 'chromeapps' + ARG_CHROMEAPPDEVICES = 'chromeappdevices' + ARG_CHROMEVERSIONS = 'chromeversions' ARG_CHROMEPOLICY = 'chromepolicy' ARG_CHROMEPOLICIES = 'chromepolicies' ARG_CHROMESCHEMA = 'chromeschema' diff --git a/src/gam/gamlib/glentity.py b/src/gam/gamlib/glentity.py index f0d1699f..2306006a 100644 --- a/src/gam/gamlib/glentity.py +++ b/src/gam/gamlib/glentity.py @@ -68,10 +68,13 @@ class GamEntity(): CALENDAR = 'cale' CALENDAR_ACL = 'cacl' CALENDAR_SETTINGS = 'cset' + CHROME_APP = 'capp' + CHROME_APP_DEVICE = 'capd' CHROME_BROWSER = 'chbr' CHROME_BROWSER_ENROLLMENT_TOKEN = 'cbet' CHROME_POLICY = 'cpol' CHROME_POLICY_SCHEMA = 'cpsc' + CHROME_VERSION = 'cver' CLASSROOM_INVITATION = 'clai' CLASSROOM_INVITATION_OWNER = 'clio' CLASSROOM_INVITATION_STUDENT = 'clis' @@ -305,10 +308,13 @@ class GamEntity(): CALENDAR: ['Calendars', 'Calendar'], CALENDAR_ACL: ['Calendar ACLs', 'Calendar ACL'], CALENDAR_SETTINGS: ['Calendar Settings', 'Calendar Settings'], + CHROME_APP: ['Chrome Applications', 'Chrome Application'], + CHROME_APP_DEVICE: ['Chrome Application Devices', 'Chrome Application Device'], CHROME_BROWSER: ['Chrome Browsers', 'Chrome Browser'], CHROME_BROWSER_ENROLLMENT_TOKEN: ['Chrome Browser Enrollment Tokens', 'Chrome Browser Enrollment Token'], CHROME_POLICY: ['Chrome Policies', 'Chrome Policy'], CHROME_POLICY_SCHEMA: ['Chrome Policy Schemas', 'Chrome Policy Schema'], + CHROME_VERSION: ['Chrome Versions', 'Chrome Version'], CLASSROOM_INVITATION: ['Classroom Invitations', 'Classroom Invitation'], CLASSROOM_INVITATION_OWNER: ['Classroom Owner Invitations', 'Classroom Owner Invitation'], CLASSROOM_INVITATION_STUDENT: ['Classroom Student Invitations', 'Classroom Student Invitation'],