def print_(): cbcm = build() customer_id = _get_customerid() projection = 'BASIC' orgUnitPath = query = None fields = None titles = [] csv_rows = [] todrive = False sort_headers = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'query': query = sys.argv[i + 1] i += 2 elif myarg in ['ou', 'org', 'orgunit']: orgUnitPath = gapi_directory_orgunits.getOrgUnitItem( sys.argv[i + 1], pathOnly=True, absolutePath=True) i += 2 elif myarg == 'projection': projection = sys.argv[i + 1].upper() i += 2 elif myarg == 'todrive': todrive = True i += 1 elif myarg == 'sortheaders': sort_headers = True i += 1 elif myarg == 'fields': fields = sys.argv[i + 1].replace(',', ' ').split() i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print browsers') if fields: fields.append('deviceId') fields = f'browsers({",".join(set(fields))}),nextPageToken' page_message = gapi.got_total_items_msg('Browsers', '...\n') browsers = gapi.get_all_pages(cbcm.chromebrowsers(), 'list', 'browsers', page_message=page_message, customer=customer_id, orgUnitPath=orgUnitPath, query=query, projection=projection, fields=fields) for browser in browsers: browser = utils.flatten_json(browser) for a_key in browser: if a_key not in titles: titles.append(a_key) csv_rows.append(browser) if sort_headers: display.sort_csv_titles([ 'deviceId', ], titles) display.write_csv_file(csv_rows, titles, 'Browsers', todrive)
def printEvents(): calendarId, cal = buildCalendarDataGAPIObject(sys.argv[2]) if not cal: return q = showDeleted = showHiddenInvitations = timeMin = \ timeMax = timeZone = updatedMin = None toDrive = False titles = [] csvRows = [] i = 4 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'query': q = sys.argv[i + 1] i += 2 elif myarg == 'includedeleted': showDeleted = True i += 1 elif myarg == 'includehidden': showHiddenInvitations = True i += 1 elif myarg == 'after': timeMin = utils.get_time_or_delta_from_now(sys.argv[i + 1]) i += 2 elif myarg == 'before': timeMax = utils.get_time_or_delta_from_now(sys.argv[i + 1]) i += 2 elif myarg == 'timezone': timeZone = sys.argv[i + 1] i += 2 elif myarg == 'updated': updatedMin = utils.get_time_or_delta_from_now(sys.argv[i + 1]) i += 2 elif myarg == 'todrive': toDrive = True i += 1 else: controlflow.invalid_argument_exit( sys.argv[i], 'gam calendar <email> printevents') page_message = gapi.got_total_items_msg(f'Events for {calendarId}', '') results = gapi.get_all_pages(cal.events(), 'list', 'items', page_message=page_message, calendarId=calendarId, q=q, showDeleted=showDeleted, showHiddenInvitations=showHiddenInvitations, timeMin=timeMin, timeMax=timeMax, timeZone=timeZone, updatedMin=updatedMin) for result in results: row = {'calendarId': calendarId} display.add_row_titles_to_csv_file( utils.flatten_json(result, flattened=row), csvRows, titles) display.sort_csv_titles(['calendarId', 'id', 'summary', 'status'], titles) display.write_csv_file(csvRows, titles, 'Calendar Events', toDrive)
def printApps(): cm = build() customer = _get_customerid() todrive = False titles = CHROME_APPS_TITLES csvRows = [] orgunit = None pfilter = None orderBy = None i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 elif myarg in ['ou', 'org', 'orgunit']: orgunit = _get_orgunit(sys.argv[i + 1]) i += 2 elif myarg == 'filter': pfilter = sys.argv[i + 1] i += 2 elif myarg == 'orderby': orderBy = sys.argv[i + 1].lower().replace('_', '') if orderBy not in CHROME_APPS_ORDERBY_CHOICE_MAP: controlflow.expected_argument_exit( 'orderby', ', '.join(CHROME_APPS_ORDERBY_CHOICE_MAP), orderBy) orderBy = CHROME_APPS_ORDERBY_CHOICE_MAP[orderBy] i += 2 else: msg = f'{myarg} is not a valid argument to "gam print chromeapps"' controlflow.system_error_exit(3, msg) if orgunit: orgUnitPath = gapi_directory_orgunits.orgunit_from_orgunitid( orgunit, None) titles.append('orgUnitPath') else: orgUnitPath = '/' gam.printGettingAllItems('Chrome Installed Applications', pfilter) page_message = gapi.got_total_items_msg('Chrome Installed Applications', '...\n') apps = gapi.get_all_pages(cm.customers().reports(), 'countInstalledApps', 'installedApps', page_message=page_message, customer=customer, orgUnitId=orgunit, filter=pfilter, orderBy=orderBy) for app in apps: if orgunit: app['orgUnitPath'] = orgUnitPath if 'permissions' in app: app['permissions'] = ' '.join(app['permissions']) csvRows.append(app) display.write_csv_file(csvRows, titles, 'Chrome Installed Applications', todrive)
def print_(): cbcm = build() projection = 'BASIC' query = None fields = None titles = [] csv_rows = [] todrive = False sort_headers = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'query': query = sys.argv[i+1] i += 2 elif myarg == 'projection': projection = sys.argv[i + 1].upper() i += 2 elif myarg == 'todrive': todrive = True i += 1 elif myarg == 'sortheaders': sort_headers = True i += 1 elif myarg == 'fields': fields = sys.argv[i + 1] i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print browsers') if fields: fields = f'browsers({fields}),nextPageToken' page_message = gapi.got_total_items_msg('Browsers', '...\n') browsers = gapi.get_all_pages(cbcm.chromebrowsers(), 'list', 'browsers', page_message=page_message, customer=GC_Values[GC_CUSTOMER_ID], query=query, projection=projection, fields=fields) for browser in browsers: browser = utils.flatten_json(browser) for a_key in browser: if a_key not in titles: titles.append(a_key) csv_rows.append(browser) if sort_headers: display.sort_csv_titles(['name',], titles) display.write_csv_file(csv_rows, titles, 'Browsers', todrive)
def printMatters(): v = buildGAPIObject() todrive = False csvRows = [] initialTitles = ['matterId', 'name', 'description', 'state'] titles = initialTitles[:] view = 'FULL' state = None i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 elif myarg in PROJECTION_CHOICES_MAP: view = PROJECTION_CHOICES_MAP[myarg] i += 1 elif myarg == 'matterstate': valid_states = gapi.get_enum_values_minus_unspecified( v._rootDesc['schemas']['Matter']['properties']['state'] ['enum']) state = sys.argv[i + 1].upper() if state not in valid_states: controlflow.expected_argument_exit('state', ', '.join(valid_states), state) i += 2 else: controlflow.invalid_argument_exit(myarg, 'gam print matters') gam.printGettingAllItems('Vault Matters', None) page_message = gapi.got_total_items_msg('Vault Matters', '...\n') matters = gapi.get_all_pages(v.matters(), 'list', 'matters', page_message=page_message, view=view, state=state) for matter in matters: display.add_row_titles_to_csv_file(utils.flatten_json(matter), csvRows, titles) display.sort_csv_titles(initialTitles, titles) display.write_csv_file(csvRows, titles, 'Vault Matters', todrive)
def print_(users, csvFormat): condel = build() if csvFormat: todrive = False csv_rows = [] titles = ['User', 'delegateAddress'] else: csvStyle = False i = 5 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if not csvFormat and myarg == 'csv': csvStyle = True i += 1 elif csvFormat and myarg == 'todrive': todrive = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print contactdelegation') page_message = gapi.got_total_items_msg('Contact Delegates', '...\n') for user in users: delegates = gapi.get_all_pages(condel.delegates(), 'list', 'delegates', page_message=page_message, user=user) for delegate in delegates: if csvFormat: csv_rows.append({ 'User': user, 'delegateAddress': delegate['email'] }) else: if csvStyle: print(f'{user},{delegate["email"]}') else: print( f'Delegator: {user}\n Delegate Email: {delegate["email"]}\n' ) if csvFormat: display.write_csv_file(csv_rows, titles, 'Contact Delegates', todrive)
def download_bucket(): bucket = sys.argv[3] s = build_gapi() page_message = gapi.got_total_items_msg('Files', '...') fields = 'nextPageToken,items(name,id,md5Hash)' objects = gapi.get_all_pages(s.objects(), 'list', 'items', page_message=page_message, bucket=bucket, projection='noAcl', fields=fields) i = 1 for object_ in objects: print(f'{i}/{len(objects)}') expectedMd5 = base64.b64decode(object_['md5Hash']).hex() get_cloud_storage_object(s, bucket, object_['name'], expectedMd5=expectedMd5) i += 1
def print_(): cd = gapi_directory.build() todrive = False titles = [] csvRows = [] fields = None projection = orderBy = sortOrder = None queries = [None] delimiter = ' ' listLimit = 1 appsLimit = -1 i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 elif myarg in ['query', 'queries']: queries = gam.getQueries(myarg, sys.argv[i + 1]) i += 2 elif myarg == 'delimiter': delimiter = sys.argv[i + 1] i += 2 elif myarg == 'listlimit': listLimit = gam.getInteger(sys.argv[i + 1], myarg, minVal=-1) i += 2 elif myarg == 'appslimit': appsLimit = gam.getInteger(sys.argv[i + 1], myarg, minVal=-1) i += 2 elif myarg == 'fields': fields = f'nextPageToken,mobiledevices({sys.argv[i+1]})' i += 2 elif myarg == 'orderby': orderBy = sys.argv[i + 1].lower() validOrderBy = [ 'deviceid', 'email', 'lastsync', 'model', 'name', 'os', 'status', 'type' ] if orderBy not in validOrderBy: controlflow.expected_argument_exit('orderby', ', '.join(validOrderBy), orderBy) if orderBy == 'lastsync': orderBy = 'lastSync' elif orderBy == 'deviceid': orderBy = 'deviceId' i += 2 elif myarg in SORTORDER_CHOICES_MAP: sortOrder = SORTORDER_CHOICES_MAP[myarg] i += 1 elif myarg in PROJECTION_CHOICES_MAP: projection = PROJECTION_CHOICES_MAP[myarg] i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print mobile') for query in queries: gam.printGettingAllItems('Mobile Devices', query) page_message = gapi.got_total_items_msg('Mobile Devices', '...\n') all_mobile = gapi.get_all_pages(cd.mobiledevices(), 'list', 'mobiledevices', page_message=page_message, customerId=GC_Values[GC_CUSTOMER_ID], query=query, projection=projection, fields=fields, orderBy=orderBy, sortOrder=sortOrder) for mobile in all_mobile: row = {} for attrib in mobile: if attrib in ['kind', 'etag']: continue if attrib in ['name', 'email', 'otherAccountsInfo']: if attrib not in titles: titles.append(attrib) if listLimit > 0: row[attrib] = delimiter.join( mobile[attrib][0:listLimit]) elif listLimit == 0: row[attrib] = delimiter.join(mobile[attrib]) elif attrib == 'applications': if appsLimit >= 0: if attrib not in titles: titles.append(attrib) applications = [] j = 0 for app in mobile[attrib]: j += 1 if appsLimit and (j > appsLimit): break appDetails = [] for field in [ 'displayName', 'packageName', 'versionName' ]: appDetails.append(app.get(field, '<None>')) appDetails.append( str(app.get('versionCode', '<None>'))) permissions = app.get('permission', []) if permissions: appDetails.append('/'.join(permissions)) else: appDetails.append('<None>') applications.append('-'.join(appDetails)) row[attrib] = delimiter.join(applications) else: if attrib not in titles: titles.append(attrib) if attrib == 'deviceId': row[attrib] = mobile[attrib].encode( 'unicode-escape').decode(UTF8) elif attrib == 'securityPatchLevel' and int( mobile[attrib]): row[attrib] = utils.formatTimestampYMDHMS( mobile[attrib]) else: row[attrib] = mobile[attrib] csvRows.append(row) display.sort_csv_titles( ['resourceId', 'deviceId', 'serialNumber', 'name', 'email', 'status'], titles) display.write_csv_file(csvRows, titles, 'Mobile', todrive)
def doPrintCrosDevices(): def _getSelectedLists(myarg): if myarg in CROS_ACTIVE_TIME_RANGES_ARGUMENTS: selectedLists['activeTimeRanges'] = True elif myarg in CROS_RECENT_USERS_ARGUMENTS: selectedLists['recentUsers'] = True elif myarg in CROS_DEVICE_FILES_ARGUMENTS: selectedLists['deviceFiles'] = True elif myarg in CROS_CPU_STATUS_REPORTS_ARGUMENTS: selectedLists['cpuStatusReports'] = True elif myarg in CROS_DISK_VOLUME_REPORTS_ARGUMENTS: selectedLists['diskVolumeReports'] = True elif myarg in CROS_SYSTEM_RAM_FREE_REPORTS_ARGUMENTS: selectedLists['systemRamFreeReports'] = True cd = gapi_directory.build() todrive = False fieldsList = [] fieldsTitles = {} titles = [] csvRows = [] display.add_field_to_csv_file('deviceid', CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList, fieldsTitles, titles) projection = orderBy = sortOrder = orgUnitPath = None queries = [None] noLists = sortHeaders = False selectedLists = {} startDate = endDate = None listLimit = 0 i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg in ['query', 'queries']: queries = gam.getQueries(myarg, sys.argv[i + 1]) i += 2 elif myarg == 'limittoou': orgUnitPath = gapi_directory_orgunits.getOrgUnitItem(sys.argv[i + 1]) i += 2 elif myarg == 'todrive': todrive = True i += 1 elif myarg == 'nolists': noLists = True selectedLists = {} i += 1 elif myarg == 'listlimit': listLimit = gam.getInteger(sys.argv[i + 1], myarg, minVal=0) i += 2 elif myarg in CROS_START_ARGUMENTS: startDate = _getFilterDate(sys.argv[i + 1]) i += 2 elif myarg in CROS_END_ARGUMENTS: endDate = _getFilterDate(sys.argv[i + 1]) i += 2 elif myarg == 'orderby': orderBy = sys.argv[i + 1].lower().replace('_', '') validOrderBy = [ 'location', 'user', 'lastsync', 'notes', 'serialnumber', 'status', 'supportenddate' ] if orderBy not in validOrderBy: controlflow.expected_argument_exit('orderby', ', '.join(validOrderBy), orderBy) if orderBy == 'location': orderBy = 'annotatedLocation' elif orderBy == 'user': orderBy = 'annotatedUser' elif orderBy == 'lastsync': orderBy = 'lastSync' elif orderBy == 'serialnumber': orderBy = 'serialNumber' elif orderBy == 'supportenddate': orderBy = 'supportEndDate' i += 2 elif myarg in SORTORDER_CHOICES_MAP: sortOrder = SORTORDER_CHOICES_MAP[myarg] i += 1 elif myarg in PROJECTION_CHOICES_MAP: projection = PROJECTION_CHOICES_MAP[myarg] sortHeaders = True if projection == 'FULL': fieldsList = [] else: fieldsList = CROS_BASIC_FIELDS_LIST[:] i += 1 elif myarg == 'allfields': projection = 'FULL' sortHeaders = True fieldsList = [] i += 1 elif myarg == 'sortheaders': sortHeaders = True i += 1 elif myarg in CROS_LISTS_ARGUMENTS: _getSelectedLists(myarg) i += 1 elif myarg in CROS_ARGUMENT_TO_PROPERTY_MAP: display.add_field_to_fields_list(myarg, CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList) i += 1 elif myarg == 'fields': fieldNameList = sys.argv[i + 1] for field in fieldNameList.lower().replace(',', ' ').split(): if field in CROS_LISTS_ARGUMENTS: _getSelectedLists(field) elif field in CROS_ARGUMENT_TO_PROPERTY_MAP: display.add_field_to_fields_list( field, CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList) else: controlflow.invalid_argument_exit(field, 'gam print cros fields') i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print cros') if selectedLists: noLists = False projection = 'FULL' for selectList in selectedLists: display.add_field_to_fields_list(selectList, CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList) if fieldsList: fieldsList.append('deviceId') fields = f'nextPageToken,chromeosdevices({",".join(set(fieldsList))})'.replace( '.', '/') else: fields = None for query in queries: gam.printGettingAllItems('CrOS Devices', query) page_message = gapi.got_total_items_msg('CrOS Devices', '...\n') all_cros = gapi.get_all_pages(cd.chromeosdevices(), 'list', 'chromeosdevices', page_message=page_message, query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection=projection, orgUnitPath=orgUnitPath, orderBy=orderBy, sortOrder=sortOrder, fields=fields) for cros in all_cros: _checkTPMVulnerability(cros) if not noLists and not selectedLists: for cros in all_cros: if 'notes' in cros: cros['notes'] = cros['notes'].replace('\n', '\\n') if 'autoUpdateExpiration' in cros: cros['autoUpdateExpiration'] = utils.formatTimestampYMD( cros['autoUpdateExpiration']) for cpuStatusReport in cros.get('cpuStatusReports', []): tempInfos = cpuStatusReport.get('cpuTemperatureInfo', []) for tempInfo in tempInfos: tempInfo['label'] = tempInfo['label'].strip() display.add_row_titles_to_csv_file( utils.flatten_json(cros, listLimit=listLimit), csvRows, titles) continue for cros in all_cros: if 'notes' in cros: cros['notes'] = cros['notes'].replace('\n', '\\n') if 'autoUpdateExpiration' in cros: cros['autoUpdateExpiration'] = utils.formatTimestampYMD( cros['autoUpdateExpiration']) row = {} for attrib in cros: if attrib not in { 'kind', 'etag', 'tpmVersionInfo', 'recentUsers', 'activeTimeRanges', 'deviceFiles', 'cpuStatusReports', 'diskVolumeReports', 'systemRamFreeReports' }: row[attrib] = cros[attrib] if selectedLists.get('activeTimeRanges'): timergs = cros.get('activeTimeRanges', []) else: timergs = [] activeTimeRanges = _filterTimeRanges(timergs, startDate, endDate) if selectedLists.get('recentUsers'): recentUsers = cros.get('recentUsers', []) else: recentUsers = [] if selectedLists.get('deviceFiles'): device_files = cros.get('deviceFiles', []) else: device_files = [] deviceFiles = _filterCreateReportTime(device_files, 'createTime', startDate, endDate) if selectedLists.get('cpuStatusReports'): cpu_reports = cros.get('cpuStatusReports', []) else: cpu_reports = [] cpuStatusReports = _filterCreateReportTime(cpu_reports, 'reportTime', startDate, endDate) if selectedLists.get('diskVolumeReports'): diskVolumeReports = cros.get('diskVolumeReports', []) else: diskVolumeReports = [] if selectedLists.get('systemRamFreeReports'): ram_reports = cros.get('systemRamFreeReports', []) else: ram_reports = [] systemRamFreeReports = _filterCreateReportTime( ram_reports, 'reportTime', startDate, endDate) if noLists or (not activeTimeRanges and \ not recentUsers and \ not deviceFiles and \ not cpuStatusReports and \ not diskVolumeReports and \ not systemRamFreeReports): display.add_row_titles_to_csv_file(row, csvRows, titles) continue lenATR = len(activeTimeRanges) lenRU = len(recentUsers) lenDF = len(deviceFiles) lenCSR = len(cpuStatusReports) lenDVR = len(diskVolumeReports) lenSRFR = len(systemRamFreeReports) max_len = max(lenATR, lenRU, lenDF, lenCSR, lenDVR, lenSRFR) for i in range(min(max_len, listLimit or max_len)): nrow = row.copy() if i < lenATR: nrow['activeTimeRanges.date'] = \ activeTimeRanges[i]['date'] nrow['activeTimeRanges.activeTime'] = \ str(activeTimeRanges[i]['activeTime']) active_time = activeTimeRanges[i]['activeTime'] nrow['activeTimeRanges.duration'] = \ utils.formatMilliSeconds(active_time) nrow['activeTimeRanges.minutes'] = active_time // 60000 if i < lenRU: nrow['recentUsers.type'] = recentUsers[i]['type'] nrow['recentUsers.email'] = recentUsers[i].get('email') if not nrow['recentUsers.email']: if nrow['recentUsers.type'] == 'USER_TYPE_UNMANAGED': nrow['recentUsers.email'] = 'UnmanagedUser' else: nrow['recentUsers.email'] = 'Unknown' if i < lenDF: nrow['deviceFiles.type'] = deviceFiles[i]['type'] nrow['deviceFiles.createTime'] = \ deviceFiles[i]['createTime'] if i < lenCSR: nrow['cpuStatusReports.reportTime'] = \ cpuStatusReports[i]['reportTime'] tempInfos = cpuStatusReports[i].get( 'cpuTemperatureInfo', []) for tempInfo in tempInfos: label = tempInfo['label'].strip() base = 'cpuStatusReports.cpuTemperatureInfo.' nrow[f'{base}{label}'] = tempInfo['temperature'] cpu_field = 'cpuUtilizationPercentageInfo' if cpu_field in cpuStatusReports[i]: cpu_reports = cpuStatusReports[i][cpu_field] cpu_pcts = [str(x) for x in cpu_reports] nrow[f'cpuStatusReports.{cpu_field}'] = ','.join( cpu_pcts) if i < lenDVR: volumeInfo = diskVolumeReports[i]['volumeInfo'] j = 0 vfield = 'diskVolumeReports.volumeInfo.' for volume in volumeInfo: nrow[f'{vfield}{j}.volumeId'] = \ volume['volumeId'] nrow[f'{vfield}{j}.storageFree'] = \ volume['storageFree'] nrow[f'{vfield}{j}.storageTotal'] = \ volume['storageTotal'] j += 1 if i < lenSRFR: nrow['systemRamFreeReports.reportTime'] = \ systemRamFreeReports[i]['reportTime'] ram_reports = systemRamFreeReports[i]['systemRamFreeInfo'] ram_info = [str(x) for x in ram_reports] nrow['systenRamFreeReports.systemRamFreeInfo'] = \ ','.join(ram_info) display.add_row_titles_to_csv_file(nrow, csvRows, titles) if sortHeaders: display.sort_csv_titles([ 'deviceId', ], titles) display.write_csv_file(csvRows, titles, 'CrOS', todrive)
def doPrintCrosActivity(): cd = gapi_directory.build() todrive = False titles = [ 'deviceId', 'annotatedAssetId', 'annotatedLocation', 'serialNumber', 'orgUnitPath' ] csvRows = [] fieldsList = [ 'deviceId', 'annotatedAssetId', 'annotatedLocation', 'serialNumber', 'orgUnitPath' ] startDate = endDate = None selectActiveTimeRanges = selectDeviceFiles = selectRecentUsers = False listLimit = 0 delimiter = ',' orgUnitPath = None queries = [None] i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg in ['query', 'queries']: queries = gam.getQueries(myarg, sys.argv[i + 1]) i += 2 elif myarg == 'limittoou': orgUnitPath = gapi_directory_orgunits.getOrgUnitItem(sys.argv[i + 1]) i += 2 elif myarg == 'todrive': todrive = True i += 1 elif myarg in CROS_ACTIVE_TIME_RANGES_ARGUMENTS: selectActiveTimeRanges = True i += 1 elif myarg in CROS_DEVICE_FILES_ARGUMENTS: selectDeviceFiles = True i += 1 elif myarg in CROS_RECENT_USERS_ARGUMENTS: selectRecentUsers = True i += 1 elif myarg == 'both': selectActiveTimeRanges = selectRecentUsers = True i += 1 elif myarg == 'all': selectActiveTimeRanges = selectDeviceFiles = True selectRecentUsers = True i += 1 elif myarg in CROS_START_ARGUMENTS: startDate = _getFilterDate(sys.argv[i + 1]) i += 2 elif myarg in CROS_END_ARGUMENTS: endDate = _getFilterDate(sys.argv[i + 1]) i += 2 elif myarg == 'listlimit': listLimit = gam.getInteger(sys.argv[i + 1], myarg, minVal=0) i += 2 elif myarg == 'delimiter': delimiter = sys.argv[i + 1] i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print crosactivity') if not selectActiveTimeRanges and \ not selectDeviceFiles and \ not selectRecentUsers: selectActiveTimeRanges = selectRecentUsers = True if selectRecentUsers: fieldsList.append('recentUsers') display.add_titles_to_csv_file([ 'recentUsers.email', ], titles) if selectActiveTimeRanges: fieldsList.append('activeTimeRanges') titles_to_add = [ 'activeTimeRanges.date', 'activeTimeRanges.duration', 'activeTimeRanges.minutes' ] display.add_titles_to_csv_file(titles_to_add, titles) if selectDeviceFiles: fieldsList.append('deviceFiles') titles_to_add = ['deviceFiles.type', 'deviceFiles.createTime'] display.add_titles_to_csv_file(titles_to_add, titles) fields = f'nextPageToken,chromeosdevices({",".join(fieldsList)})' for query in queries: gam.printGettingAllItems('CrOS Devices', query) page_message = gapi.got_total_items_msg('CrOS Devices', '...\n') all_cros = gapi.get_all_pages(cd.chromeosdevices(), 'list', 'chromeosdevices', page_message=page_message, query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection='FULL', fields=fields, orgUnitPath=orgUnitPath) for cros in all_cros: row = {} skip_attribs = ['recentUsers', 'activeTimeRanges', 'deviceFiles'] for attrib in cros: if attrib not in skip_attribs: row[attrib] = cros[attrib] if selectActiveTimeRanges: activeTimeRanges = _filterTimeRanges( cros.get('activeTimeRanges', []), startDate, endDate) lenATR = len(activeTimeRanges) num_ranges = min(lenATR, listLimit or lenATR) for activeTimeRange in activeTimeRanges[:num_ranges]: newrow = row.copy() newrow['activeTimeRanges.date'] = activeTimeRange['date'] active_time = activeTimeRange['activeTime'] newrow['activeTimeRanges.duration'] = \ utils.formatMilliSeconds(active_time) newrow['activeTimeRanges.minutes'] = \ activeTimeRange['activeTime']//60000 csvRows.append(newrow) if selectRecentUsers: recentUsers = cros.get('recentUsers', []) lenRU = len(recentUsers) num_ranges = min(lenRU, listLimit or lenRU) recent_users = [] for recentUser in recentUsers[:num_ranges]: useremail = recentUser.get('email') if not useremail: if recentUser['type'] == 'USER_TYPE_UNMANAGED': useremail = 'UnmanagedUser' else: useremail = 'Unknown' recent_users.append(useremail) row['recentUsers.email'] = delimiter.join(recent_users) csvRows.append(row) if selectDeviceFiles: deviceFiles = _filterCreateReportTime( cros.get('deviceFiles', []), 'createTime', startDate, endDate) lenDF = len(deviceFiles) num_ranges = min(lenDF, listLimit or lenDF) for deviceFile in deviceFiles[:num_ranges]: newrow = row.copy() newrow['deviceFiles.type'] = deviceFile['type'] create_time = deviceFile['createTime'] newrow['deviceFiles.createTime'] = create_time csvRows.append(newrow) display.write_csv_file(csvRows, titles, 'CrOS Activity', todrive)
def printHistory(): cv = build() entityType = sys.argv[3].lower().replace('_', '') if entityType not in CHROME_HISTORY_ENTITY_CHOICES: msg = f'{entityType} is not a valid argument to "gam print chromehistory"' controlflow.system_error_exit(3, msg) todrive = False csvRows = [] cplatform = 'all' channel = 'all' version = 'all' kwargs = {} orderByList = [] i = 4 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 elif entityType != 'platforms' and myarg == 'platform': cplatform = sys.argv[i + 1].lower().replace('_', '') platform_map = get_platform_map(cv) if cplatform not in platform_map: controlflow.expected_argument_exit('platform', ', '.join(platform_map), cplatform) cplatform = platform_map[cplatform] i += 2 elif entityType in {'versions', 'releases'} and myarg == 'channel': channel = sys.argv[i + 1].lower().replace('_', '') channel_map = get_channel_map(cv) if channel not in channel_map: controlflow.expected_argument_exit('channel', ', '.join(channel_map), channel) channel = channel_map[channel] i += 2 elif entityType == 'releases' and myarg == 'version': version = sys.argv[i + 1] i += 2 elif entityType in {'versions', 'releases'} and myarg == 'orderby': fieldName = sys.argv[i + 1].lower().replace('_', '') i += 2 if fieldName in CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP[entityType]: fieldName = CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP[entityType][fieldName] orderBy = '' if i < len(sys.argv): orderBy = sys.argv[i].lower() if orderBy in SORTORDER_CHOICES_MAP: orderBy = SORTORDER_CHOICES_MAP[orderBy] i += 1 if orderBy != 'DESCENDING': orderByList.append(fieldName) else: orderByList.append(f'{fieldName} desc') else: controlflow.expected_argument_exit('orderby', ', '.join(CHROME_VERSIONHISTORY_ORDERBY_CHOICE_MAP[entityType]), fieldName) elif entityType in {'versions', 'releases'} and myarg == 'filter': kwargs['filter'] = sys.argv[i + 1] i += 2 else: msg = f'{myarg} is not a valid argument to "gam print chromehistory {entityType}"' controlflow.system_error_exit(3, msg) if orderByList: kwargs['orderBy'] = ','.join(orderByList) if entityType == 'platforms': svc = cv.platforms() parent = 'chrome' elif entityType == 'channels': svc = cv.platforms().channels() parent = f'chrome/platforms/{cplatform}' elif entityType == 'versions': svc = cv.platforms().channels().versions() parent = f'chrome/platforms/{cplatform}/channels/{channel}' else: #elif entityType == 'releases' svc = cv.platforms().channels().versions().releases() parent = f'chrome/platforms/{cplatform}/channels/{channel}/versions/{version}' reportTitle = f'Chrome Version History {entityType.capitalize()}' page_message = gapi.got_total_items_msg(reportTitle, '...\n') gam.printGettingAllItems(reportTitle, None) citems = gapi.get_all_pages(svc, 'list', entityType, page_message=page_message, parent=parent, fields=f'nextPageToken,{entityType}', **kwargs) for citem in citems: for key in list(citem): if key.endswith('Type'): newkey = key[:-4] citem[newkey] = citem.pop(key) if 'channel' in citem: citem['channel'] = citem['channel'].lower() else: channel_match = re.search(r"\/channels\/([^/]*)", citem['name']) if channel_match: try: citem['channel'] = channel_match.group(1) except IndexError: pass if 'platform' in citem: citem['platform'] = citem['platform'].lower() else: platform_match = re.search(r"\/platforms\/([^/]*)", citem['name']) if platform_match: try: citem['platform'] = platform_match.group(1) except IndexError: pass if citem.get('version', '').count('.') == 3: citem['major_version'], \ citem['minor_version'], \ citem['build'], \ citem['patch'] = citem['version'].split('.') citem.pop('name') csvRows.append(utils.flatten_json(citem)) display.write_csv_file(csvRows, CHROME_VERSIONHISTORY_TITLES[entityType], reportTitle, todrive)
def print_(): '''gam print userinvitations''' svc = gapi_cloudidentity.build('cloudidentity_beta') customer = _get_customerid() todrive = False titles = ['name', 'state', 'updateTime'] rows = [] filter_ = None orderByList = [] i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'state': state = sys.argv[i + 1].lower().replace('_', '') if state in USERINVITATION_STATE_CHOICES_MAP: filter_ = f"state=='{USERINVITATION_STATE_CHOICES_MAP[state]}'" else: controlflow.expected_argument_exit( 'state', ', '.join(USERINVITATION_STATE_CHOICES_MAP), state) i += 2 elif myarg == 'orderby': fieldName = sys.argv[i + 1].lower() i += 2 if fieldName in USERINVITATION_ORDERBY_CHOICES_MAP: fieldName = USERINVITATION_ORDERBY_CHOICES_MAP[fieldName] orderBy = '' if i < len(sys.argv): orderBy = sys.argv[i].lower() if orderBy in SORTORDER_CHOICES_MAP: orderBy = SORTORDER_CHOICES_MAP[orderBy] i += 1 if orderBy != 'DESCENDING': orderByList.append(fieldName) else: orderByList.append(f'{fieldName} desc') else: controlflow.expected_argument_exit( 'orderby', ', '.join(sorted(USERINVITATION_ORDERBY_CHOICES_MAP)), fieldName) elif myarg == 'todrive': todrive = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print userinvitations') if orderByList: orderBy = ' '.join(orderByList) else: orderBy = None gam.printGettingAllItems('User Invitations', filter_) page_message = gapi.got_total_items_msg('User Invitations', '...\n') invitations = gapi.get_all_pages(svc.customers().userinvitations(), 'list', 'userInvitations', page_message=page_message, parent=customer, filter=filter_, orderBy=orderBy) for invitation in invitations: invitation['name'] = _reduce_name(invitation['name']) row = {} for key, val in invitation.items(): if key not in titles: titles.append(key) row[key] = val rows.append(row) display.write_csv_file(rows, titles, 'User Invitations', todrive)
def print_(returnFields=None, skus=None, countsOnly=False, returnCounts=False): lic = build() products = [] licenses = [] licenseCounts = [] if not returnFields: csvRows = [] todrive = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower() if not returnCounts and myarg == 'todrive': todrive = True i += 1 elif myarg in ['products', 'product']: products = sys.argv[i + 1].split(',') i += 2 elif myarg in ['sku', 'skus']: skus = sys.argv[i + 1].split(',') i += 2 elif myarg == 'allskus': skus = sorted(SKUS) products = [] i += 1 elif myarg == 'gsuite': skus = [ skuId for skuId in SKUS if SKUS[skuId]['product'] in ['Google-Apps', '101031'] ] products = [] i += 1 elif myarg == 'countsonly': countsOnly = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print licenses') if not countsOnly: fields = 'nextPageToken,items(productId,skuId,userId)' titles = ['userId', 'productId', 'skuId'] else: fields = 'nextPageToken,items(userId)' if not returnCounts: if skus: titles = ['productId', 'skuId', 'licenses'] else: titles = ['productId', 'licenses'] else: fields = f'nextPageToken,items({returnFields})' if skus: for sku in skus: if not products: product, sku = getProductAndSKU(sku) else: product = products[0] page_message = gapi.got_total_items_msg( f'Licenses for {SKUS.get(sku, {"displayName": sku})["displayName"]}', '...\n') try: licenses += gapi.get_all_pages( lic.licenseAssignments(), 'listForProductAndSku', 'items', throw_reasons=[ gapi_errors.ErrorReason.INVALID, gapi_errors.ErrorReason.FORBIDDEN ], page_message=page_message, customerId=GC_Values[GC_DOMAIN], productId=product, skuId=sku, fields=fields) if countsOnly: licenseCounts.append([ 'Product', product, 'SKU', sku, 'Licenses', len(licenses) ]) licenses = [] except (gapi_errors.GapiInvalidError, gapi_errors.GapiForbiddenError): pass else: if not products: products = sorted(PRODUCTID_NAME_MAPPINGS) for productId in products: page_message = gapi.got_total_items_msg( f'Licenses for {PRODUCTID_NAME_MAPPINGS.get(productId, productId)}', '...\n') try: licenses += gapi.get_all_pages( lic.licenseAssignments(), 'listForProduct', 'items', throw_reasons=[ gapi_errors.ErrorReason.INVALID, gapi_errors.ErrorReason.FORBIDDEN ], page_message=page_message, customerId=GC_Values[GC_DOMAIN], productId=productId, fields=fields) if countsOnly: licenseCounts.append( ['Product', productId, 'Licenses', len(licenses)]) licenses = [] except (gapi_errors.GapiInvalidError, gapi_errors.GapiForbiddenError): pass if countsOnly: if returnCounts: return licenseCounts if skus: for u_license in licenseCounts: csvRows.append({ 'productId': u_license[1], 'skuId': u_license[3], 'licenses': u_license[5] }) else: for u_license in licenseCounts: csvRows.append({ 'productId': u_license[1], 'licenses': u_license[3] }) display.write_csv_file(csvRows, titles, 'Licenses', todrive) return if returnFields: if returnFields == 'userId': userIds = [] for u_license in licenses: userId = u_license.get('userId', '').lower() if userId: userIds.append(userId) return userIds userSkuIds = {} for u_license in licenses: userId = u_license.get('userId', '').lower() skuId = u_license.get('skuId') if userId and skuId: userSkuIds.setdefault(userId, []) userSkuIds[userId].append(skuId) return userSkuIds for u_license in licenses: userId = u_license.get('userId', '').lower() skuId = u_license.get('skuId', '') csvRows.append({ 'userId': userId, 'productId': u_license.get('productId', ''), 'skuId': _skuIdToDisplayName(skuId) }) display.write_csv_file(csvRows, titles, 'Licenses', todrive)
def printShowCrosTelemetry(mode): cm = build() cd = None parent = _get_customerid() todrive = False filter_ = None readMask = [] orgUnitIdPathMap = {} diskpercentonly = False showOrgUnitPath = False supported_readmask_values = list( cm._rootDesc['schemas']['GoogleChromeManagementV1TelemetryDevice'] ['properties'].keys()) supported_readmask_values.sort() supported_readmask_map = { item.lower(): item for item in supported_readmask_values } i = 3 if mode == 'info': if i >= len(sys.argv): controlflow.system_error_exit( 3, f'<SerialNumber> required for "gam info crostelemetry"') filter_ = f'serialNumber={sys.argv[i]}' i += 1 mode = 'show' while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'fields': field_list = sys.argv[i + 1].lower().split(',') for field_item in field_list: if field_item not in supported_readmask_map: controlflow.expected_argument_exit( 'fields', ', '.join(supported_readmask_values), field_item) else: readMask.append(supported_readmask_map[field_item]) i += 2 elif myarg in supported_readmask_map: readMask.append(supported_readmask_map[myarg]) i += 1 elif myarg == 'filter': filter_ = sys.argv[i + 1] i += 2 elif myarg in ['ou', 'org', 'orgunit']: _, orgUnitId = gapi_directory_orgunits.getOrgUnitId( sys.argv[i + 1], None) filter_ = f'orgUnitId={orgUnitId[3:]}' i += 2 elif myarg == 'crossn': filter_ = f'serialNumber={sys.argv[i + 1]}' i += 2 elif myarg == 'todrive': todrive = True i += 1 elif myarg == 'showorgunitpath': showOrgUnitPath = True cd = gapi_directory.build() i += 1 elif myarg == 'storagepercentonly': diskpercentonly = True i += 1 else: msg = f'{myarg} is not a valid argument to "gam print crostelemetry"' controlflow.system_error_exit(3, msg) if not readMask: readMask = ','.join(supported_readmask_values) else: if 'deviceId' not in readMask: readMask.append('deviceId') readMask = ','.join(readMask) gam.printGettingAllItems('Chrome Device Telemetry...', filter_) page_message = gapi.got_total_items_msg('Chrome Device Telemetry', '...\n') devices = gapi.get_all_pages(cm.customers().telemetry().devices(), 'list', 'devices', page_message=page_message, parent=parent, filter=filter_, readMask=readMask) for device in devices: if 'totalDiskBytes' in device.get( 'storageInfo', {}) and 'availableDiskBytes' in device.get( 'storageInfo', {}): disk_avail = int(device['storageInfo']['availableDiskBytes']) disk_size = int(device['storageInfo']['totalDiskBytes']) if diskpercentonly: device['storageInfo'] = {} device['storageInfo']['percentDiskFree'] = int( (disk_avail / disk_size) * 100) device['storageInfo']['percentDiskUsed'] = 100 - device[ 'storageInfo']['percentDiskFree'] for cpuStatusReport in device.get('cpuStatusReport', []): for tempInfo in cpuStatusReport.pop('cpuTemperatureInfo', []): cpuStatusReport[ f"cpuTemperatureInfo.{tempInfo['label'].strip()}"] = tempInfo[ 'temperatureCelsius'] if showOrgUnitPath: orgUnitId = device.get('orgUnitId') if orgUnitId not in orgUnitIdPathMap: orgUnitIdPathMap[ orgUnitId] = gapi_directory_orgunits.orgunit_from_orgunitid( orgUnitId, cd) device['orgUnitPath'] = orgUnitIdPathMap[orgUnitId] if mode == 'show': for device in devices: display.print_json(device) print() print() else: csvRows = [] titles = [] for device in devices: display.add_row_titles_to_csv_file(utils.flatten_json(device), csvRows, titles) display.write_csv_file(csvRows, titles, 'Telemetry Devices', todrive)
def update(): cd = gapi_directory.build resourceIds = sys.argv[3] match_users = None doit = False if resourceIds[:6] == 'query:': query = resourceIds[6:] fields = 'nextPageToken,mobiledevices(resourceId,email)' page_message = gapi.got_total_items_msg('Mobile Devices', '...\n') devices = gapi.get_all_pages(cd.mobiledevices(), 'list', page_message=page_message, customerId=GC_Values[GC_CUSTOMER_ID], items='mobiledevices', query=query, fields=fields) else: devices = [{'resourceId': resourceIds, 'email': ['not set']}] doit = True i = 4 body = {} while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'action': body['action'] = sys.argv[i + 1].lower() validActions = [ 'wipe', 'wipeaccount', 'accountwipe', 'wipe_account', 'account_wipe', 'approve', 'block', 'cancel_remote_wipe_then_activate', 'cancel_remote_wipe_then_block' ] if body['action'] not in validActions: controlflow.expected_argument_exit('action', ', '.join(validActions), body['action']) if body['action'] == 'wipe': body['action'] = 'admin_remote_wipe' elif body['action'].replace('_', '') in ['accountwipe', 'wipeaccount']: body['action'] = 'admin_account_wipe' i += 2 elif myarg in ['ifusers', 'matchusers']: match_users = gam.getUsersToModify(entity_type=sys.argv[i + 1].lower(), entity=sys.argv[i + 2]) i += 3 elif myarg == 'doit': doit = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam update mobile') if body: if doit: print(f'Updating {len(devices)} devices') describe_as = 'Performing' else: print( f'Showing {len(devices)} changes that would be made, not actually making changes because doit argument not specified' ) describe_as = 'Would perform' for device in devices: device_user = device.get('email', [''])[0] if match_users and device_user not in match_users: print( f'Skipping device for user {device_user} that did not match match_users argument' ) else: print( f'{describe_as} {body["action"]} on user {device_user} device {device["resourceId"]}' ) if doit: gapi.call(cd.mobiledevices(), 'action', resourceId=device['resourceId'], body=body, customerId=GC_Values[GC_CUSTOMER_ID])
def sync(): ci = gapi_cloudidentity.build_dwd() device_types = gapi.get_enum_values_minus_unspecified( ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device'] ['properties']['deviceType']['enum']) customer = _get_device_customerid() device_filter = None csv_file = None serialnumber_column = 'serialNumber' devicetype_column = 'deviceType' static_devicetype = None assettag_column = None unassigned_missing_action = 'delete' assigned_missing_action = 'donothing' missing_actions = ['delete', 'wipe', 'donothing'] i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg in ['filter', 'query']: device_filter = sys.argv[i + 1] i += 2 elif myarg == 'csvfile': csv_file = sys.argv[i + 1] i += 2 elif myarg == 'serialnumbercolumn': serialnumber_column = sys.argv[i + 1] i += 2 elif myarg == 'devicetypecolumn': devicetype_column = sys.argv[i + 1] i += 2 elif myarg == 'staticdevicetype': static_devicetype = sys.argv[i + 1].upper() if static_devicetype not in device_types: controlflow.expected_argument_exit('device_type', ', '.join(device_types), sys.argv[i + 1]) i += 2 elif myarg in {'assettagcolumn', 'assetidcolumn'}: assettag_column = sys.argv[i + 1] i += 2 elif myarg == 'unassignedmissingaction': unassigned_missing_action = sys.argv[i + 1].lower().replace( '_', '') if unassigned_missing_action not in missing_actions: controlflow.expected_argument_exit('unassigned_missing_action', ', '.join(missing_actions), sys.argv[i + 1]) i += 2 elif myarg == 'assignedmissingaction': assigned_missing_action = sys.argv[i + 1].lower().replace('_', '') if assigned_missing_action not in missing_actions: controlflow.expected_argument_exit('assigned_missing_action', ', '.join(missing_actions), sys.argv[i + 1]) i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam sync devices') if not csv_file: controlflow.system_error_exit( 3, 'csvfile is a required argument for "gam sync devices".') f = fileutils.open_file(csv_file) input_file = csv.DictReader(f, restval='') if serialnumber_column not in input_file.fieldnames: controlflow.csv_field_error_exit(serialnumber_column, input_file.fieldnames) if not static_devicetype and devicetype_column not in input_file.fieldnames: controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames) if assettag_column and assettag_column not in input_file.fieldnames: controlflow.csv_field_error_exit(assettag_column, input_file.fieldnames) local_devices = {} for row in input_file: # upper() is very important to comparison since Google # always return uppercase serials local_device = { 'serialNumber': row[serialnumber_column].strip().upper() } if static_devicetype: local_device['deviceType'] = static_devicetype else: local_device['deviceType'] = row[devicetype_column].strip() sndt = f"{local_device['serialNumber']}-{local_device['deviceType']}" if assettag_column: local_device['assetTag'] = row[assettag_column].strip() sndt += f"-{local_device['assetTag']}" local_devices[sndt] = local_device fileutils.close_file(f) page_message = gapi.got_total_items_msg('Company Devices', '...\n') device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name'] if assettag_column: device_fields.append('assetTag') fields = f'nextPageToken,devices({",".join(device_fields)})' remote_devices = {} remote_device_map = {} result = gapi.get_all_pages(ci.devices(), 'list', 'devices', customer=customer, page_message=page_message, pageSize=100, filter=device_filter, view='COMPANY_INVENTORY', fields=fields) for remote_device in result: sn = remote_device['serialNumber'] last_sync = remote_device.pop('lastSyncTime', NEVER_TIME_NOMS) name = remote_device.pop('name') sndt = f"{remote_device['serialNumber']}-{remote_device['deviceType']}" if assettag_column: if 'assetTag' not in remote_device: remote_device['assetTag'] = '' sndt += f"-{remote_device['assetTag']}" remote_devices[sndt] = remote_device remote_device_map[sndt] = {'name': name} if last_sync == NEVER_TIME_NOMS: remote_device_map[sndt]['unassigned'] = True devices_to_add = [] for sndt, device in iter(local_devices.items()): if sndt not in remote_devices: devices_to_add.append(device) missing_devices = [] for sndt, device in iter(remote_devices.items()): if sndt not in local_devices: missing_devices.append(device) print( f'Need to add {len(devices_to_add)} and remove {len(missing_devices)} devices...' ) for add_device in devices_to_add: print(f'Creating {add_device["serialNumber"]}') try: result = gapi.call( ci.devices(), 'create', customer=customer, throw_reasons=[gapi_errors.ErrorReason.FOUR_O_NINE], body=add_device) print( f' created {result["response"]["deviceType"]} device {result["response"]["name"]} with serial {result["response"]["serialNumber"]}' ) except googleapiclient.errors.HttpError: print(f' {add_device["serialNumber"]} already exists') for missing_device in missing_devices: sn = missing_device['serialNumber'] sndt = f"{sn}-{missing_device['deviceType']}" if assettag_column: sndt += f"-{missing_device['assetTag']}" name = remote_device_map[sndt]['name'] unassigned = remote_device_map[sndt].get('unassigned') action = unassigned_missing_action if unassigned else assigned_missing_action if action == 'donothing': pass else: if action == 'delete': kwargs = {'customer': customer} else: kwargs = {'body': {'customer': customer}} gapi.call(ci.devices(), action, name=name, **kwargs) print(f'{action}d {sn}')
def print_(): ci = gapi_cloudidentity.build_dwd() customer = _get_device_customerid() parent = 'devices/-' device_filter = None get_device_users = True view = None orderByList = [] titles = [] csvRows = [] todrive = False sortHeaders = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg in ['filter', 'query']: device_filter = sys.argv[i + 1] i += 2 elif myarg == 'company': view = 'COMPANY_INVENTORY' i += 1 elif myarg == 'personal': view = 'USER_ASSIGNED_DEVICES' i += 1 elif myarg == 'nocompanydevices': view = 'USER_ASSIGNED_DEVICES' i += 1 elif myarg == 'nopersonaldevices': view = 'COMPANY_INVENTORY' i += 1 elif myarg == 'nodeviceusers': get_device_users = False i += 1 elif myarg == 'todrive': todrive = True i += 1 elif myarg == 'orderby': fieldName = sys.argv[i + 1].lower() i += 2 if fieldName in DEVICE_ORDERBY_CHOICES_MAP: fieldName = DEVICE_ORDERBY_CHOICES_MAP[fieldName] orderBy = '' if i < len(sys.argv): orderBy = sys.argv[i].lower() if orderBy in SORTORDER_CHOICES_MAP: orderBy = SORTORDER_CHOICES_MAP[orderBy] i += 1 if orderBy != 'DESCENDING': orderByList.append(fieldName) else: orderByList.append(f'{fieldName} desc') else: controlflow.expected_argument_exit( 'orderby', ', '.join(sorted(DEVICE_ORDERBY_CHOICES_MAP)), fieldName) elif myarg == 'sortheaders': sortHeaders = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print devices') view_name_map = { None: 'Devices', 'COMPANY_INVENTORY': 'Company Devices', 'USER_ASSIGNED_DEVICES': 'Personal Devices', } if orderByList: orderBy = ','.join(orderByList) else: orderBy = None devices = [] page_message = gapi.got_total_items_msg(view_name_map[view], '...\n') devices += gapi.get_all_pages(ci.devices(), 'list', 'devices', customer=customer, page_message=page_message, pageSize=100, filter=device_filter, view=view, orderBy=orderBy) if get_device_users: page_message = gapi.got_total_items_msg('Device Users', '...\n') device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list', 'deviceUsers', customer=customer, parent=parent, page_message=page_message, pageSize=20, filter=device_filter) for device_user in device_users: for device in devices: if device_user.get('name').startswith(device.get('name')): if 'users' not in device: device['users'] = [] device['users'].append(device_user) break for device in devices: device = utils.flatten_json(device) for a_key in device: if a_key not in titles: titles.append(a_key) csvRows.append(device) if sortHeaders: display.sort_csv_titles([ 'name', ], titles) display.write_csv_file(csvRows, titles, 'Devices', todrive)
def printshowtokens(csvFormat): cbcm = build() query = None fields = [] if csvFormat: titles = ['token'] csv_rows = [] todrive = False sort_headers = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'query': query = sys.argv[i + 1] i += 2 elif csvFormat and myarg == 'todrive': todrive = True i += 1 elif csvFormat and myarg == 'sortheaders': sort_headers = True i += 1 elif myarg == 'fields': fields = sys.argv[i + 1].replace(',', ' ').split() i += 2 else: controlflow.invalid_argument_exit( sys.argv[i], f"gam {['show', 'print'][csvFormat]} browsertokens") if fields: fields.append('token') fields = f'chromeEnrollmentTokens({",".join(set(fields))}),nextPageToken' page_message = gapi.got_total_items_msg('Chrome Browser Enrollment Tokens', '...\n') browsers = gapi.get_all_pages(cbcm.enrollmentTokens(), 'list', 'chromeEnrollmentTokens', page_message=page_message, customer=GC_Values[GC_CUSTOMER_ID], query=query, fields=fields) if not csvFormat: count = len(browsers) print(f'Show {count} Chrome Browser Enrollment Tokens') i = 0 for browser in browsers: i += 1 print( f' Chrome Browser Enrollment Token: {browser["token"]}{gam.currentCount(i, count)}' ) browser.pop('kind', None) for field in browser: print(f' {field}: {browser[field]}') else: for browser in browsers: browser = utils.flatten_json(browser) for a_key in browser: if a_key not in titles: titles.append(a_key) csv_rows.append(browser) if sort_headers: display.sort_csv_titles([ 'token', ], titles) display.write_csv_file(csv_rows, titles, 'Chrome Browser Enrollment Tokens', todrive)
def update(): # Convert [email protected] to [email protected]; eliminate periods in name for [email protected] def _cleanConsumerAddress(emailAddress, mapCleanToOriginal): atLoc = emailAddress.find('@') if atLoc > 0: if emailAddress[atLoc + 1:] in ['gmail.com', 'googlemail.com']: cleanEmailAddress = emailAddress[:atLoc].replace( '.', '') + '@gmail.com' if cleanEmailAddress != emailAddress: mapCleanToOriginal[cleanEmailAddress] = emailAddress return cleanEmailAddress return emailAddress def _getRoleAndUsers(): checkSuspended = None role = ROLE_MEMBER expireTime = None i = 5 if sys.argv[i].lower() in GROUP_ROLES_MAP: role = GROUP_ROLES_MAP[sys.argv[i].lower()] i += 1 if sys.argv[i].lower() in ['suspended', 'notsuspended']: checkSuspended = sys.argv[i].lower() == 'suspended' i += 1 if sys.argv[i].lower() in ['expire', 'expires']: if role != ROLE_MEMBER: controlflow.invalid_argument_exit( sys.argv[i], f'role {role}') expireTime = utils.get_time_or_delta_from_now(sys.argv[i+1]) i += 2 if sys.argv[i].lower() in usergroup_types: users_email = gam.getUsersToModify(entity_type=sys.argv[i].lower(), entity=sys.argv[i + 1], checkSuspended=checkSuspended, groupUserMembersOnly=False) else: users_email = [ gam.normalizeEmailAddressOrUID(sys.argv[i], checkForCustomerId=True) ] return (role, expireTime, users_email) ci = gapi_cloudidentity.build('cloudidentity_beta') group = sys.argv[3] myarg = sys.argv[4].lower() items = [] if myarg in UPDATE_GROUP_SUBCMDS: group = gam.normalizeEmailAddressOrUID(group) if group.startswith('groups/'): parent = group else: parent = group_email_to_id(ci, group) if not parent: return if myarg == 'add': role, expireTime, users_email = _getRoleAndUsers() if len(users_email) > 1: sys.stderr.write( f'Group: {group}, Will add {len(users_email)} {role}s.\n') for user_email in users_email: item = [ 'gam', 'update', 'cigroup', f'id:{parent}', 'add', role, ] if expireTime: item.extend(['expires', expireTime]) item.append(user_email) items.append(item) elif len(users_email) > 0: body = { 'preferredMemberKey': { 'id': users_email[0] }, 'roles': [{ 'name': ROLE_MEMBER }] } if role != ROLE_MEMBER: body['roles'].append({'name': role}) elif expireTime not in {None, NEVER_TIME}: for role in body['roles']: if role['name'] == ROLE_MEMBER: role['expiryDetail'] = {'expireTime': expireTime} add_text = [f'as {role}'] for i in range(2): try: gapi.call( ci.groups().memberships(), 'create', throw_reasons=[ gapi_errors.ErrorReason.FOUR_O_NINE, gapi_errors.ErrorReason.MEMBER_NOT_FOUND, gapi_errors.ErrorReason.RESOURCE_NOT_FOUND, gapi_errors.ErrorReason.INVALID_MEMBER, gapi_errors.ErrorReason. CYCLIC_MEMBERSHIPS_NOT_ALLOWED ], parent=parent, body=body) print( f' Group: {group}, {users_email[0]} Added {" ".join(add_text)}' ) break except (gapi_errors.GapiMemberNotFoundError, gapi_errors.GapiResourceNotFoundError, gapi_errors.GapiInvalidMemberError, gapi_errors.GapiCyclicMembershipsNotAllowedError ) as e: print( f' Group: {group}, {users_email[0]} Add {" ".join(add_text)} Failed: {str(e)}' ) break elif myarg == 'sync': syncMembersSet = set() syncMembersMap = {} role, expireTime, users_email = _getRoleAndUsers() for user_email in users_email: if user_email in ('*', GC_Values[GC_CUSTOMER_ID]): syncMembersSet.add(GC_Values[GC_CUSTOMER_ID]) else: syncMembersSet.add( _cleanConsumerAddress(user_email.lower(), syncMembersMap)) currentMembersSet = set() currentMembersMap = {} for current_email in gam.getUsersToModify( entity_type='cigroup', entity=group, member_type=role, groupUserMembersOnly=False): if current_email == GC_Values[GC_CUSTOMER_ID]: currentMembersSet.add(current_email) else: currentMembersSet.add( _cleanConsumerAddress(current_email.lower(), currentMembersMap)) to_add = [ syncMembersMap.get(emailAddress, emailAddress) for emailAddress in syncMembersSet - currentMembersSet ] to_remove = [ currentMembersMap.get(emailAddress, emailAddress) for emailAddress in currentMembersSet - syncMembersSet ] sys.stderr.write( f'Group: {group}, Will add {len(to_add)} and remove {len(to_remove)} {role}s.\n' ) for user in to_add: item = ['gam', 'update', 'cigroup', f'id:{parent}', 'add', role,] if role == ROLE_MEMBER and expireTime not in {None, NEVER_TIME}: item.extend(['expires', expireTime]) item.append(user) items.append(item) for user in to_remove: items.append([ 'gam', 'update', 'cigroup', f'id:{parent}', 'remove', user ]) elif myarg in ['delete', 'remove']: _, _, users_email = _getRoleAndUsers() if len(users_email) > 1: sys.stderr.write( f'Group: {group}, Will remove {len(users_email)} emails.\n') for user_email in users_email: items.append([ 'gam', 'update', 'cigroup', f'id:{parent}', 'remove', user_email ]) elif len(users_email) == 1: name = membership_email_to_id(ci, parent, users_email[0]) try: gapi.call(ci.groups().memberships(), 'delete', throw_reasons=[ gapi_errors.ErrorReason.MEMBER_NOT_FOUND, gapi_errors.ErrorReason.INVALID_MEMBER ], name=name) print(f' Group: {group}, {users_email[0]} Removed') except (gapi_errors.GapiMemberNotFoundError, gapi_errors.GapiInvalidMemberError) as e: print( f' Group: {group}, {users_email[0]} Remove Failed: {str(e)}' ) elif myarg == 'update': role, expireTime, users_email = _getRoleAndUsers() if len(users_email) > 1: sys.stderr.write( f'Group: {group}, Will update {len(users_email)} {role}s.\n' ) for user_email in users_email: item = [ 'gam', 'update', 'cigroup', f'id:{parent}', 'update', role,] if expireTime: item.extend(['expires', expireTime]) item.append(user_email) items.append(item) elif len(users_email) > 0: name = membership_email_to_id(ci, parent, users_email[0]) preUpdateRoles = [] addRoles = [] removeRoles = [] postUpdateRoles = [] member_roles = gapi.call(ci.groups().memberships(), 'get', name=name, fields='roles').get('roles', [{'name': ROLE_MEMBER}]) current_roles = [crole['name'] for crole in member_roles] # When upgrading role, strip any expiryDetail from member before role changes if role != ROLE_MEMBER: for crole in member_roles: if 'expiryDetail' in crole: preUpdateRoles.append( {'fieldMask': 'expiryDetail.expireTime', 'membershipRole': {'name': ROLE_MEMBER, 'expiryDetail': {'expireTime': None}}}) break # When downgrading role or simply updating member expireTime, update expiryDetail after role changes elif expireTime: postUpdateRoles.append( {'fieldMask': 'expiryDetail.expireTime', 'membershipRole': {'name': role, 'expiryDetail': {'expireTime': expireTime if expireTime != NEVER_TIME else None}}}) for crole in current_roles: if crole not in {ROLE_MEMBER, role}: removeRoles.append(crole) if role not in current_roles: new_role = {'name': role} if role == ROLE_MEMBER and expireTime not in {None, NEVER_TIME}: new_role['expiryDetail'] = {'expireTime': expireTime} postUpdateRoles = [] addRoles.append(new_role) bodys = [] if preUpdateRoles: bodys.append({'updateRolesParams': preUpdateRoles}) if addRoles: bodys.append({'addRoles': addRoles}) if removeRoles: bodys.append({'removeRoles': removeRoles}) if postUpdateRoles: bodys.append({'updateRolesParams': postUpdateRoles}) for body in bodys: try: gapi.call(ci.groups().memberships(), 'modifyMembershipRoles', throw_reasons=[ gapi_errors.ErrorReason.MEMBER_NOT_FOUND, gapi_errors.ErrorReason.INVALID_MEMBER ], name=name, body=body) except (gapi_errors.GapiMemberNotFoundError, gapi_errors.GapiInvalidMemberError) as e: print( f' Group: {group}, {users_email[0]} Update to {role} Failed: {str(e)}' ) break print( f' Group: {group}, {users_email[0]} Updated to {role}' ) else: # clear roles = [] i = 5 while i < len(sys.argv): myarg = sys.argv[i].lower() if myarg.upper() in [ROLE_OWNER, ROLE_MANAGER, ROLE_MEMBER]: roles.append(myarg.upper()) i += 1 else: controlflow.invalid_argument_exit( sys.argv[i], 'gam update cigroup clear') if not roles: roles = [ROLE_MEMBER] group = gam.normalizeEmailAddressOrUID(group) member_type_message = f'{",".join(roles).lower()}s' sys.stderr.write( f'Getting {member_type_message} of {group} (may take some time for large groups)...\n' ) page_message = gapi.got_total_items_msg(f'{member_type_message}', '...') try: result = gapi.get_all_pages( ci.groups().memberships(), 'list', 'memberships', page_message=page_message, throw_reasons=gapi_errors.MEMBERS_THROW_REASONS, parent=parent, fields='nextPageToken,memberships(preferredMemberKey,roles)') result = filter_members_to_roles(result, roles) if not result: print('Group already has 0 members') return users_email = [member['preferredMemberKey']['id'] for member in result] sys.stderr.write( f'Group: {group}, Will remove {len(users_email)} {", ".join(roles).lower()}s.\n' ) for user_email in users_email: items.append([ 'gam', 'update', 'cigroup', group, 'remove', user_email ]) except (gapi_errors.GapiGroupNotFoundError, gapi_errors.GapiDomainNotFoundError, gapi_errors.GapiInvalidError, gapi_errors.GapiForbiddenError): gam.entityUnknownWarning('Group', group, 0, 0) if items: gam.run_batch(items) else: i = 4 body = {} sec_body = {} while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'name': body['displayName'] = sys.argv[i + 1] i += 2 elif myarg == 'description': body['description'] = sys.argv[i + 1] i += 2 elif myarg == 'security': body['labels'] = { 'cloudidentity.googleapis.com/groups.security': '', 'cloudidentity.googleapis.com/groups.discussion_forum': '' } i += 1 elif myarg in ['dynamic']: body['dynamicGroupMetadata'] = { 'queries': [{ 'query': sys.argv[i + 1], 'resourceType': 'USER' }] } i += 2 elif myarg in ['memberrestriction', 'memberrestrictions']: query = sys.argv[i + 1] member_types = { 'USER': '******', 'SERVICE_ACCOUNT': '2', 'GROUP': '3', } for key, val in member_types.items(): query = query.replace(key, val) sec_body['memberRestriction'] = {'query': query} i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam update cigroup') if body: updateMask = ','.join(body.keys()) name = group_email_to_id(ci, group) print(f'Updating group {group}') gapi.call(ci.groups(), 'patch', updateMask=updateMask, name=name, body=body) if sec_body: updateMask = 'member_restriction.query' # it seems like a bug that API requires /securitySettings # appended to name. We'll see if Google servers change this # at some point. name = f'{group_email_to_id(ci, group)}/securitySettings' print(f'Updating group {group} security settings') gapi.call(ci.groups(), 'updateSecuritySettings', name=name, updateMask=updateMask, body=sec_body)
def printAppDevices(): cm = build() customer = _get_customerid() todrive = False titles = CHROME_APP_DEVICES_TITLES csvRows = [] orgunit = None appId = None appType = None startDate = None endDate = None pfilter = None orderBy = None i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 elif myarg in ['ou', 'org', 'orgunit']: orgunit = _get_orgunit(sys.argv[i + 1]) i += 2 elif myarg == 'appid': appId = sys.argv[i + 1] i += 2 elif myarg == 'apptype': appType = sys.argv[i + 1].lower().replace('_', '') if appType not in CHROME_APP_DEVICES_APPTYPE_CHOICE_MAP: controlflow.expected_argument_exit( 'orderby', ', '.join(CHROME_APP_DEVICES_APPTYPE_CHOICE_MAP), appType) appType = CHROME_APP_DEVICES_APPTYPE_CHOICE_MAP[appType] i += 2 elif myarg in CROS_START_ARGUMENTS: startDate = _getFilterDate(sys.argv[i + 1]).strftime(YYYYMMDD_FORMAT) i += 2 elif myarg in CROS_END_ARGUMENTS: endDate = _getFilterDate(sys.argv[i + 1]).strftime(YYYYMMDD_FORMAT) i += 2 elif myarg == 'orderby': orderBy = sys.argv[i + 1].lower().replace('_', '') if orderBy not in CHROME_APP_DEVICES_ORDERBY_CHOICE_MAP: controlflow.expected_argument_exit( 'orderby', ', '.join(CHROME_APP_DEVICES_ORDERBY_CHOICE_MAP), orderBy) orderBy = CHROME_APP_DEVICES_ORDERBY_CHOICE_MAP[orderBy] i += 2 else: msg = f'{myarg} is not a valid argument to "gam print chromeappdevices"' controlflow.system_error_exit(3, msg) if not appId: controlflow.system_error_exit(3, 'You must specify an appid') if not appType: controlflow.system_error_exit(3, 'You must specify an apptype') if endDate: pfilter = f'last_active_date<={endDate}' if startDate: if pfilter: pfilter += ' AND ' else: pfilter = '' pfilter += f'last_active_date>={startDate}' if orgunit: orgUnitPath = gapi_directory_orgunits.orgunit_from_orgunitid( orgunit, None) titles.append('orgUnitPath') else: orgUnitPath = '/' gam.printGettingAllItems('Chrome Installed Application Devices', pfilter) page_message = gapi.got_total_items_msg( 'Chrome Installed Application Devices', '...\n') devices = gapi.get_all_pages(cm.customers().reports(), 'findInstalledAppDevices', 'devices', page_message=page_message, appId=appId, appType=appType, customer=customer, orgUnitId=orgunit, filter=pfilter, orderBy=orderBy) for device in devices: if orgunit: device['orgUnitPath'] = orgUnitPath device['appId'] = appId device['appType'] = appType csvRows.append(device) display.write_csv_file(csvRows, titles, 'Chrome Installed Application Devices', todrive)
def showReport(): rep = buildGAPIObject() throw_reasons = [gapi.errors.ErrorReason.INVALID] report = sys.argv[2].lower() report = REPORT_CHOICE_MAP.get(report.replace('_', ''), report) if report == 'usage': showUsage() return if report == 'usageparameters': showUsageParameters() return valid_apps = gapi.get_enum_values_minus_unspecified( rep._rootDesc['resources']['activities']['methods']['list'] ['parameters']['applicationName']['enum']) + ['customer', 'user'] if report not in valid_apps: controlflow.expected_argument_exit('report', ', '.join(sorted(valid_apps)), report) customerId = GC_Values[GC_CUSTOMER_ID] if customerId == MY_CUSTOMER: customerId = None filters = parameters = actorIpAddress = startTime = endTime = eventName = orgUnitId = None tryDate = datetime.date.today().strftime(YYYYMMDD_FORMAT) to_drive = False userKey = 'all' fullDataRequired = None i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower() if myarg == 'date': tryDate = utils.get_yyyymmdd(sys.argv[i + 1]) i += 2 elif myarg in ['orgunit', 'org', 'ou']: _, orgUnitId = gam.getOrgUnitId(sys.argv[i + 1]) i += 2 elif myarg == 'fulldatarequired': fullDataRequired = [] fdr = sys.argv[i + 1].lower() if fdr and fdr == 'all': fullDataRequired = 'all' else: fullDataRequired = fdr.replace(',', ' ').split() i += 2 elif myarg == 'start': startTime = utils.get_time_or_delta_from_now(sys.argv[i + 1]) i += 2 elif myarg == 'end': endTime = utils.get_time_or_delta_from_now(sys.argv[i + 1]) i += 2 elif myarg == 'event': eventName = sys.argv[i + 1] i += 2 elif myarg == 'user': userKey = sys.argv[i + 1].lower() if userKey != 'all': userKey = gam.normalizeEmailAddressOrUID(sys.argv[i + 1]) i += 2 elif myarg in ['filter', 'filters']: filters = sys.argv[i + 1] i += 2 elif myarg in ['fields', 'parameters']: parameters = sys.argv[i + 1] i += 2 elif myarg == 'ip': actorIpAddress = sys.argv[i + 1] i += 2 elif myarg == 'todrive': to_drive = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam report') if report == 'user': while True: try: one_page = gapi.call(rep.userUsageReport(), 'get', throw_reasons=throw_reasons, date=tryDate, userKey=userKey, customerId=customerId, orgUnitID=orgUnitId, fields='warnings,usageReports', maxResults=1) warnings = one_page.get('warnings', []) has_reports = bool(one_page.get('usageReports')) fullData, tryDate = _check_full_data_available( warnings, tryDate, fullDataRequired, has_reports) if fullData < 0: print('No user report available.') sys.exit(1) if fullData == 0: continue page_message = gapi.got_total_items_msg('Users', '...\n') usage = gapi.get_all_pages(rep.userUsageReport(), 'get', 'usageReports', page_message=page_message, throw_reasons=throw_reasons, date=tryDate, userKey=userKey, customerId=customerId, orgUnitID=orgUnitId, filters=filters, parameters=parameters) break except gapi.errors.GapiInvalidError as e: tryDate = _adjust_date(str(e)) if not usage: print('No user report available.') sys.exit(1) titles = ['email', 'date'] csvRows = [] for user_report in usage: if 'entity' not in user_report: continue row = {'email': user_report['entity']['userEmail'], 'date': tryDate} for item in user_report.get('parameters', []): if 'name' not in item: continue name = item['name'] if not name in titles: titles.append(name) for ptype in REPORTS_PARAMETERS_SIMPLE_TYPES: if ptype in item: row[name] = item[ptype] break else: row[name] = '' csvRows.append(row) display.write_csv_file(csvRows, titles, f'User Reports - {tryDate}', to_drive) elif report == 'customer': while True: try: first_page = gapi.call(rep.customerUsageReports(), 'get', throw_reasons=throw_reasons, customerId=customerId, date=tryDate, fields='warnings,usageReports') warnings = first_page.get('warnings', []) has_reports = bool(first_page.get('usageReports')) fullData, tryDate = _check_full_data_available( warnings, tryDate, fullDataRequired, has_reports) if fullData < 0: print('No customer report available.') sys.exit(1) if fullData == 0: continue usage = gapi.get_all_pages(rep.customerUsageReports(), 'get', 'usageReports', throw_reasons=throw_reasons, customerId=customerId, date=tryDate, parameters=parameters) break except gapi.errors.GapiInvalidError as e: tryDate = _adjust_date(str(e)) if not usage: print('No customer report available.') sys.exit(1) titles = ['name', 'value', 'client_id'] csvRows = [] auth_apps = list() for item in usage[0]['parameters']: if 'name' not in item: continue name = item['name'] if 'intValue' in item: value = item['intValue'] elif 'msgValue' in item: if name == 'accounts:authorized_apps': for subitem in item['msgValue']: app = {} for an_item in subitem: if an_item == 'client_name': app['name'] = 'App: ' + \ subitem[an_item].replace('\n', '\\n') elif an_item == 'num_users': app['value'] = f'{subitem[an_item]} users' elif an_item == 'client_id': app['client_id'] = subitem[an_item] auth_apps.append(app) continue values = [] for subitem in item['msgValue']: if 'count' in subitem: mycount = myvalue = None for key, value in list(subitem.items()): if key == 'count': mycount = value else: myvalue = value if mycount and myvalue: values.append(f'{myvalue}:{mycount}') value = ' '.join(values) elif 'version_number' in subitem \ and 'num_devices' in subitem: values.append(f'{subitem["version_number"]}:' f'{subitem["num_devices"]}') else: continue value = ' '.join(sorted(values, reverse=True)) csvRows.append({'name': name, 'value': value}) for app in auth_apps: # put apps at bottom csvRows.append(app) display.write_csv_file(csvRows, titles, f'Customer Report - {tryDate}', todrive=to_drive) else: page_message = gapi.got_total_items_msg('Activities', '...\n') activities = gapi.get_all_pages(rep.activities(), 'list', 'items', page_message=page_message, applicationName=report, userKey=userKey, customerId=customerId, actorIpAddress=actorIpAddress, startTime=startTime, endTime=endTime, eventName=eventName, filters=filters, orgUnitID=orgUnitId) if activities: titles = ['name'] csvRows = [] for activity in activities: events = activity['events'] del activity['events'] activity_row = utils.flatten_json(activity) purge_parameters = True for event in events: for item in event.get('parameters', []): if set(item) == set(['value', 'name']): event[item['name']] = item['value'] elif set(item) == set(['intValue', 'name']): if item['name'] in ['start_time', 'end_time']: val = item.get('intValue') if val is not None: val = int(val) if val >= 62135683200: event[item['name']] = \ datetime.datetime.fromtimestamp( val-62135683200).isoformat() else: event[item['name']] = item['intValue'] elif set(item) == set(['boolValue', 'name']): event[item['name']] = item['boolValue'] elif set(item) == set(['multiValue', 'name']): event[item['name']] = ' '.join(item['multiValue']) elif item['name'] == 'scope_data': parts = {} for message in item['multiMessageValue']: for mess in message['parameter']: value = mess.get( 'value', ' '.join(mess.get('multiValue', []))) parts[mess['name']] = parts.get( mess['name'], []) + [value] for part, v in parts.items(): if part == 'scope_name': part = 'scope' event[part] = ' '.join(v) else: purge_parameters = False if purge_parameters: event.pop('parameters', None) row = utils.flatten_json(event) row.update(activity_row) for item in row: if item not in titles: titles.append(item) csvRows.append(row) display.sort_csv_titles([ 'name', ], titles) display.write_csv_file(csvRows, titles, f'{report.capitalize()} Activity Report', to_drive)
def printVersions(): cm = build() customer = _get_customerid() todrive = False titles = CHROME_VERSIONS_TITLES csvRows = [] orgunit = None startDate = None endDate = None pfilter = None reverse = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'todrive': todrive = True i += 1 elif myarg in ['ou', 'org', 'orgunit']: orgunit = _get_orgunit(sys.argv[i + 1]) i += 2 elif myarg in CROS_START_ARGUMENTS: startDate = _getFilterDate(sys.argv[i + 1]).strftime(YYYYMMDD_FORMAT) i += 2 elif myarg in CROS_END_ARGUMENTS: endDate = _getFilterDate(sys.argv[i + 1]).strftime(YYYYMMDD_FORMAT) i += 2 elif myarg == 'recentfirst': reverse = True i += 1 else: msg = f'{myarg} is not a valid argument to "gam print chromeversions"' controlflow.system_error_exit(3, msg) if endDate: pfilter = f'last_active_date<={endDate}' if startDate: if pfilter: pfilter += ' AND ' else: pfilter = '' pfilter += f'last_active_date>={startDate}' if orgunit: orgUnitPath = gapi_directory_orgunits.orgunit_from_orgunitid( orgunit, None) titles.append('orgUnitPath') else: orgUnitPath = '/' gam.printGettingAllItems('Chrome Versions', pfilter) page_message = gapi.got_total_items_msg('Chrome Versions', '...\n') versions = gapi.get_all_pages(cm.customers().reports(), 'countChromeVersions', 'browserVersions', page_message=page_message, customer=customer, orgUnitId=orgunit, filter=pfilter) for version in sorted(versions, key=lambda k: k.get('version', 'Unknown'), reverse=reverse): if orgunit: version['orgUnitPath'] = orgUnitPath if 'version' not in version: version['version'] = 'Unknown' csvRows.append(version) display.write_csv_file(csvRows, titles, 'Chrome Versions', todrive)
def move(): cbcm = build() body = {'resource_ids': []} i = 3 resource_ids = [] batch_size = 600 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'ids': resource_ids.extend(sys.argv[i + 1].split(',')) i += 2 elif myarg == 'query': query = sys.argv[i + 1] page_message = gapi.got_total_items_msg('Browsers', '...\n') browsers = gapi.get_all_pages(cbcm.chromebrowsers(), 'list', 'browsers', page_message=page_message, customer=GC_Values[GC_CUSTOMER_ID], query=query, projection='BASIC', fields='browsers(deviceId),nextPageToken') ids = [browser['deviceId'] for browser in browsers] resource_ids.extend(ids) i += 2 elif myarg == 'file': with fileutils.open_file(sys.argv[i+1], strip_utf_bom=True) as filed: for row in filed: rid = row.strip() if rid: resource_ids.append(rid) i += 2 elif myarg == 'csvfile': drive, fname_column = os.path.splitdrive(sys.argv[i+1]) if fname_column.find(':') == -1: controlflow.system_error_exit( 2, 'Expected csvfile FileName:FieldName') (filename, column) = fname_column.split(':') with fileutils.open_file(drive + filename) as filed: input_file = csv.DictReader(filed, restval='') if column not in input_file.fieldnames: controlflow.csv_field_error_exit(column, input_file.fieldnames) for row in input_file: rid = row[column].strip() if rid: resource_ids.append(rid) i += 2 elif myarg in ['ou', 'orgunit', 'org']: org_unit = gapi_directory_orgunits.getOrgUnitItem(sys.argv[i + 1]) body['org_unit_path'] = org_unit i += 2 elif myarg == 'batchsize': batch_size = int(sys.argv[i+1]) i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam move browsers') if 'org_unit_path' not in body: controlflow.missing_argument_exit('ou', 'gam move browsers') elif not resource_ids: controlflow.missing_argument_exit('query or ids', 'gam move browsers') # split moves into max 600 devices per batch for chunk in range(0, len(resource_ids), batch_size): body['resource_ids'] = resource_ids[chunk:chunk + batch_size] print(f' moving {len(body["resource_ids"])} browsers to ' \ f'{body["org_unit_path"]}') gapi.call(cbcm.chromebrowsers(), 'moveChromeBrowsersToOu', customer=GC_Values[GC_CUSTOMER_ID], body=body)
def update(): # Convert [email protected] to [email protected]; eliminate periods in name for [email protected] def _cleanConsumerAddress(emailAddress, mapCleanToOriginal): atLoc = emailAddress.find('@') if atLoc > 0: if emailAddress[atLoc + 1:] in ['gmail.com', 'googlemail.com']: cleanEmailAddress = emailAddress[:atLoc].replace( '.', '') + '@gmail.com' if cleanEmailAddress != emailAddress: mapCleanToOriginal[cleanEmailAddress] = emailAddress return cleanEmailAddress return emailAddress def _getRoleAndUsers(): checkSuspended = None role = None i = 5 if sys.argv[i].lower() in GROUP_ROLES_MAP: role = GROUP_ROLES_MAP[sys.argv[i].lower()] i += 1 if sys.argv[i].lower() in ['suspended', 'notsuspended']: checkSuspended = sys.argv[i].lower() == 'suspended' i += 1 if sys.argv[i].lower() in usergroup_types: users_email = gam.getUsersToModify(entity_type=sys.argv[i].lower(), entity=sys.argv[i + 1], checkSuspended=checkSuspended, groupUserMembersOnly=False) else: users_email = [ gam.normalizeEmailAddressOrUID(sys.argv[i], checkForCustomerId=True) ] return (role, users_email) ci = gapi_cloudidentity.build() group = sys.argv[3] myarg = sys.argv[4].lower() items = [] if myarg in UPDATE_GROUP_SUBCMDS: group = gam.normalizeEmailAddressOrUID(group) if group.startswith('groups/'): parent = group else: parent = group_email_to_id(ci, group) if not parent: return if myarg == 'add': role, users_email = _getRoleAndUsers() if not role: role = ROLE_MEMBER if len(users_email) > 1: sys.stderr.write( f'Group: {group}, Will add {len(users_email)} {role}s.\n') for user_email in users_email: item = [ 'gam', 'update', 'cigroup', f'id:{parent}', 'add', role, user_email ] items.append(item) elif len(users_email) > 0: body = { 'memberKey': { 'id': users_email[0] }, 'roles': [{ 'name': ROLE_MEMBER }] } if role != ROLE_MEMBER: body['roles'].append({'name': role}) add_text = [f'as {role}'] for i in range(2): try: gapi.call( ci.groups().memberships(), 'create', throw_reasons=[ gapi_errors.ErrorReason.FOUR_O_NINE, gapi_errors.ErrorReason.MEMBER_NOT_FOUND, gapi_errors.ErrorReason.RESOURCE_NOT_FOUND, gapi_errors.ErrorReason.INVALID_MEMBER, gapi_errors.ErrorReason. CYCLIC_MEMBERSHIPS_NOT_ALLOWED ], parent=parent, body=body) print( f' Group: {group}, {users_email[0]} Added {" ".join(add_text)}' ) break except (gapi_errors.GapiMemberNotFoundError, gapi_errors.GapiResourceNotFoundError, gapi_errors.GapiInvalidMemberError, gapi_errors.GapiCyclicMembershipsNotAllowedError ) as e: print( f' Group: {group}, {users_email[0]} Add {" ".join(add_text)} Failed: {str(e)}' ) break elif myarg == 'sync': syncMembersSet = set() syncMembersMap = {} role, users_email = _getRoleAndUsers() for user_email in users_email: if user_email in ('*', GC_Values[GC_CUSTOMER_ID]): syncMembersSet.add(GC_Values[GC_CUSTOMER_ID]) else: syncMembersSet.add( _cleanConsumerAddress(user_email.lower(), syncMembersMap)) currentMembersSet = set() currentMembersMap = {} for current_email in gam.getUsersToModify( entity_type='cigroup', entity=group, member_type=role, groupUserMembersOnly=False): if current_email == GC_Values[GC_CUSTOMER_ID]: currentMembersSet.add(current_email) else: currentMembersSet.add( _cleanConsumerAddress(current_email.lower(), currentMembersMap)) to_add = [ syncMembersMap.get(emailAddress, emailAddress) for emailAddress in syncMembersSet - currentMembersSet ] to_remove = [ currentMembersMap.get(emailAddress, emailAddress) for emailAddress in currentMembersSet - syncMembersSet ] sys.stderr.write( f'Group: {group}, Will add {len(to_add)} and remove {len(to_remove)} {role}s.\n' ) for user in to_add: item = [ 'gam', 'update', 'cigroup', f'id:{parent}', 'add', role, user ] items.append(item) for user in to_remove: items.append([ 'gam', 'update', 'cigroup', f'id:{parent}', 'remove', user ]) elif myarg in ['delete', 'remove']: _, users_email = _getRoleAndUsers() if len(users_email) > 1: sys.stderr.write( f'Group: {group}, Will remove {len(users_email)} emails.\n' ) for user_email in users_email: items.append([ 'gam', 'update', 'cigroup', f'id:{parent}', 'remove', user_email ]) elif len(users_email) == 1: name = membership_email_to_id(ci, parent, users_email[0]) try: gapi.call(ci.groups().memberships(), 'delete', throw_reasons=[ gapi_errors.ErrorReason.MEMBER_NOT_FOUND, gapi_errors.ErrorReason.INVALID_MEMBER ], name=name) print(f' Group: {group}, {users_email[0]} Removed') except (gapi_errors.GapiMemberNotFoundError, gapi_errors.GapiInvalidMemberError) as e: print( f' Group: {group}, {users_email[0]} Remove Failed: {str(e)}' ) elif myarg == 'update': role, users_email = _getRoleAndUsers() if not role: role = ROLE_MEMBER if len(users_email) > 1: sys.stderr.write( f'Group: {group}, Will update {len(users_email)} {role}s.\n' ) for user_email in users_email: item = [ 'gam', 'update', 'cigroup', f'id:{parent}', 'update', role, user_email ] items.append(item) elif len(users_email) > 0: name = membership_email_to_id(ci, parent, users_email[0]) addRoles = [] removeRoles = [] new_role = {'role': role} current_roles = gapi.call(ci.groups().memberships(), 'get', name=name, fields='roles').get('roles', []) current_roles = [role['name'] for role in current_roles] for crole in current_roles: if crole != ROLE_MEMBER and crole != role: removeRoles.append(crole) if role not in current_roles: addRoles.append({'name': role}) bodys = [] if addRoles: bodys.append({'addRoles': addRoles}) if removeRoles: bodys.append({'removeRoles': removeRoles}) for body in bodys: try: gapi.call(ci.groups().memberships(), 'modifyMembershipRoles', throw_reasons=[ gapi_errors.ErrorReason.MEMBER_NOT_FOUND, gapi_errors.ErrorReason.INVALID_MEMBER ], name=name, body=body) except (gapi_errors.GapiMemberNotFoundError, gapi_errors.GapiInvalidMemberError) as e: print( f' Group: {group}, {users_email[0]} Update to {role} Failed: {str(e)}' ) break print(f' Group: {group}, {users_email[0]} Updated to {role}') else: # clear roles = [] i = 5 while i < len(sys.argv): myarg = sys.argv[i].lower() if myarg.upper() in [ROLE_OWNER, ROLE_MANAGER, ROLE_MEMBER]: roles.append(myarg.upper()) i += 1 else: controlflow.invalid_argument_exit( sys.argv[i], 'gam update cigroup clear') if not roles: roles = [ROLE_MEMBER] group = gam.normalizeEmailAddressOrUID(group) member_type_message = f'{",".join(roles).lower()}s' sys.stderr.write( f'Getting {member_type_message} of {group} (may take some time for large groups)...\n' ) page_message = gapi.got_total_items_msg(f'{member_type_message}', '...') try: result = gapi.get_all_pages( ci.groups().memberships(), 'list', 'memberships', page_message=page_message, throw_reasons=gapi_errors.MEMBERS_THROW_REASONS, parent=parent, fields='nextPageToken,memberships(memberKey,roles)') result = filter_members_to_roles(result, roles) if not result: print('Group already has 0 members') return users_email = [member['memberKey']['id'] for member in result] sys.stderr.write( f'Group: {group}, Will remove {len(users_email)} {", ".join(roles).lower()}s.\n' ) for user_email in users_email: items.append([ 'gam', 'update', 'cigroup', group, 'remove', user_email ]) except (gapi_errors.GapiGroupNotFoundError, gapi_errors.GapiDomainNotFoundError, gapi_errors.GapiInvalidError, gapi_errors.GapiForbiddenError): gam.entityUnknownWarning('Group', group, 0, 0) if items: gam.run_batch(items) else: i = 4 body = {} while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'name': body['displayName'] = sys.argv[i + 1] i += 2 elif myarg == 'description': body['description'] = sys.argv[i + 1] i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam update cigroup') updateMask = ','.join(body.keys()) name = group_email_to_id(ci, group) print(f'Updating group {group}') gapi.call(ci.groups(), 'patch', updateMask=updateMask, name=name, body=body)
def print_(): ci = gapi_cloudidentity.build_dwd() customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}' parent = 'devices/-' device_filter = None get_device_users = True get_device_views = ['COMPANY_INVENTORY', 'USER_ASSIGNED_DEVICES'] titles = [] csvRows = [] todrive = False sortHeaders = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg in ['filter', 'query']: device_filter = sys.argv[i+1] i += 2 elif myarg == 'nocompanydevices': get_device_views.remove('COMPANY_INVENTORY') i += 1 elif myarg == 'nopersonaldevices': get_device_views.remove('USER_ASSIGNED_DEVICES') i += 1 elif myarg == 'todrive': todrive = True i += 1 elif myarg == 'sortheaders': sortHeaders = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print devices') view_name_map = { 'COMPANY_INVENTORY': 'Company Devices', 'USER_ASSIGNED_DEVICES': 'Personal Devices', } devices = [] for view in get_device_views: view_name = view_name_map.get(view, 'Devices') page_message = gapi.got_total_items_msg(view_name, '...\n') devices += gapi.get_all_pages(ci.devices(), 'list', 'devices', customer=customer, page_message=page_message, pageSize=100, filter=device_filter, view=view) if get_device_users: page_message = gapi.got_total_items_msg('Device Users', '...\n') device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list', 'deviceUsers', customer=customer, parent=parent, page_message=page_message, pageSize=20, filter=device_filter) for device_user in device_users: for device in devices: if device_user.get('name').startswith(device.get('name')): if 'users' not in device: device['users'] = [] device['users'].append(device_user) break for device in devices: device = utils.flatten_json(device) for a_key in device: if a_key not in titles: titles.append(a_key) csvRows.append(device) if sortHeaders: display.sort_csv_titles(['name',], titles) display.write_csv_file(csvRows, titles, 'Devices', todrive)