Beispiel #1
0
def bulk_is_invitable(emails):
    '''gam <users> check isinvitable'''
    def _invitation_result(request_id, response, _):
        if response.get('isInvitableUser'):
            rows.append({'invitableUsers': request_id})

    svc = gapi_cloudidentity.build_dwd('cloudidentity_beta')
    customer = _get_customerid()
    todrive = False
    #batch_size = 1000
    #ebatch = svc.new_batch_http_request(callback=_invitation_result)
    rows = []
    throw_reasons = [gapi_errors.ErrorReason.FOUR_O_THREE]
    for email in emails:
        encoded_email = quote_plus(email)
        name = f'{customer}/userinvitations/{encoded_email}'
        endpoint = svc.customers().userinvitations()
        #if len(ebatch._order) == batch_size:
        #    ebatch.execute()
        #    ebatch = svc.new_batch_http_request(callback=_invitation_result)
        #req = endpoint.isInvitableUser(name=name)
        #ebatch.add(req, request_id=email)
        try:
            result = gapi.call(endpoint,
                               'isInvitableUser',
                               throw_reasons=throw_reasons,
                               name=name)
        except googleapiclient.errors.HttpError:
            continue
        if result.get('isInvitableUser'):
            rows.append({'invitableUsers': email})
    #ebatch.execute()
    titles = ['invitableUsers']
    display.write_csv_file(rows, titles, 'Invitable Users', todrive)
Beispiel #2
0
def create():
    ci = gapi_cloudidentity.build_dwd()
    customer = _get_device_customerid()
    device_types = gapi.get_enum_values_minus_unspecified(
        ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device']
        ['properties']['deviceType']['enum'])
    body = {'deviceType': '', 'serialNumber': ''}
    i = 3
    while i < len(sys.argv):
        myarg = sys.argv[i].lower().replace('_', '')
        if myarg == 'serialnumber':
            body['serialNumber'] = sys.argv[i + 1]
            i += 2
        elif myarg == 'devicetype':
            body['deviceType'] = sys.argv[i + 1].upper()
            if body['deviceType'] not in device_types:
                controlflow.expected_argument_exit('device_type',
                                                   ', '.join(device_types),
                                                   sys.argv[i + 1])
            i += 2
        elif myarg in {'assettag', 'assetid'}:
            body['assetTag'] = sys.argv[i + 1]
            i += 2
        else:
            controlflow.invalid_argument_exit(sys.argv[i], 'gam create device')
    if not body['serialNumber'] or not body['deviceType']:
        controlflow.system_error_exit(
            3,
            'serial_number and device_type are required arguments for "gam create device".'
        )
    result = gapi.call(ci.devices(), 'create', customer=customer, body=body)
    print(f'Created device {result["response"]["name"]}')
Beispiel #3
0
def _generic_action(action, device_user=False):
    ci = gapi_cloudidentity.build_dwd()
    customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
    
    # bah, inconsistencies in API
    if action == 'delete':
        kwargs = {'customer': customer}
    else:
        kwargs = {'body': {'customer': customer}}

    if device_user:
        endpoint = ci.devices().deviceUsers()
    else:
        endpoint = ci.devices()
    name = None
    i = 3
    while i < len(sys.argv):
        myarg = sys.argv[i].lower().replace('_', '')
        # The API calls it "name" but GAM will expose as "id" to avoid admin confusion.
        if myarg == 'id':
            name = sys.argv[i+1]
            if not name.startswith('devices/'):
                name = f'devices/{name}'
            i += 2
        else:
            controlflow.invalid_argument_exit(sys.argv[i], f'gam {action} device')
    if not name:
        controlflow.system_error_exit(3, f'id is a required argument for "gam {action} device".')
    op = gapi.call(endpoint, action, name=name, **kwargs)
    print(op) 
Beispiel #4
0
def is_invitable_user(email):
    '''return email isInvitableUser'''
    svc = gapi_cloudidentity.build_dwd('cloudidentity_beta')
    customer = _get_customerid()
    encoded_email = quote_plus(email)
    name = f'{customer}/userinvitations/{encoded_email}'
    return gapi.call(svc.customers().userinvitations(),
                     'isInvitableUser',
                     name=name)['isInvitableUser']
Beispiel #5
0
def _generic_action(action, device_user=False):
    ci = gapi_cloudidentity.build_dwd()
    customer = _get_device_customerid()
    name, kwargs = _parse_action(action)
    if device_user:
        endpoint = ci.devices().deviceUsers()
    else:
        endpoint = ci.devices()
    op = gapi.call(endpoint, action, name=name, **kwargs)
    print(op)
Beispiel #6
0
def _generic_get(get_type):
    '''generic function to call read data APIs'''
    svc = gapi_cloudidentity.build_dwd('cloudidentity_beta')
    customer = _get_customerid()
    email = sys.argv[3].lower()
    encoded_email = quote_plus(email)
    name = f'{customer}/userinvitations/{encoded_email}'
    result = gapi.call(svc.customers().userinvitations(), get_type, name=name)
    if 'name' in result:
        result['name'] = _reduce_name(result['name'])
    display.print_json(result)
Beispiel #7
0
def info():
    ci = gapi_cloudidentity.build_dwd()
    customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
    name = sys.argv[3]
    if not name.startswith('devices/'):
        name = f'devices/{name}'
    device = gapi.call(ci.devices(), 'get', name=name, customer=customer)
    device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list',
        'deviceUsers', parent=name, customer=customer)
    display.print_json(device)
    print('Device Users:')
    display.print_json(device_users)
Beispiel #8
0
def info():
    ci = gapi_cloudidentity.build_dwd()
    customer = _get_device_customerid()
    name = _get_device_name()
    device = gapi.call(ci.devices(), 'get', name=name, customer=customer)
    device_users = gapi.get_all_pages(ci.devices().deviceUsers(),
                                      'list',
                                      'deviceUsers',
                                      parent=name,
                                      customer=customer)
    display.print_json(device)
    print('Device Users:')
    display.print_json(device_users)
Beispiel #9
0
def _generic_action(action):
    '''generic function to call actionable APIs'''
    svc = gapi_cloudidentity.build_dwd('cloudidentity_beta')
    customer = _get_customerid()
    email = sys.argv[3].lower()
    encoded_email = quote_plus(email)
    name = f'{customer}/userinvitations/{encoded_email}'
    action_map = {'cancel': 'Cancelling', 'send': 'Sending'}
    print_action = action_map[action]
    print(f'{print_action} user invitation...')
    result = gapi.call(svc.customers().userinvitations(), action, name=name)
    name = result.get('response', {}).get('name')
    if name:
        result['response']['name'] = _reduce_name(name)
    display.print_json(result)
Beispiel #10
0
def _generic_action(action, device_user=False):
    ci = gapi_cloudidentity.build_dwd()
    customer = _get_device_customerid()
    name = _get_device_name()

    # bah, inconsistencies in API
    if action == 'delete':
        kwargs = {'customer': customer}
    else:
        kwargs = {'body': {'customer': customer}}

    if device_user:
        endpoint = ci.devices().deviceUsers()
    else:
        endpoint = ci.devices()
    op = gapi.call(endpoint, action, name=name, **kwargs)
    print(op)
Beispiel #11
0
def info_state():
    ci = gapi_cloudidentity.build_dwd()
    gapi_directory_customer.setTrueCustomerId()
    customer = _get_device_customerid()
    customer_id = customer[10:]
    client_id = f'{customer_id}-gam'
    i, deviceuser = _get_deviceuser_name()
    while i < len(sys.argv):
        myarg = sys.argv[i].lower().replace('_', '')
        if myarg == 'clientid':
            client_id = f'{customer_id}-{sys.argv[i+1]}'
            i += 2
        else:
            controlflow.invalid_argument_exit(sys.argv[i], 'gam info deviceuserstate')
    name = f'{deviceuser}/clientStates/{client_id}'
    result = gapi.call(ci.devices().deviceUsers().clientStates(), 'get',
                       name=name, customer=customer)
    display.print_json(result)
Beispiel #12
0
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}')
Beispiel #13
0
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)
Beispiel #14
0
def update_state():
    ci = gapi_cloudidentity.build_dwd()
    gapi_directory_customer.setTrueCustomerId()
    customer = _get_device_customerid()
    customer_id = customer[10:]
    client_id = f'{customer_id}-gam'
    body = {}
    i, deviceuser = _get_deviceuser_name()
    while i < len(sys.argv):
        myarg = sys.argv[i].lower().replace('_', '')
        if myarg == 'clientid':
            client_id = f'{customer_id}-{sys.argv[i+1]}'
            i += 2
        elif myarg in ['assettag', 'assettags']:
            body['assetTags'] = gam.shlexSplitList(sys.argv[i + 1])
            if body['assetTags'] == ['clear']:
                # TODO: this doesn't work to clear
                # existing values. Figure out why.
                body['assetTags'] = [None]
            i += 2
        elif myarg in ['compliantstate', 'compliancestate']:
            comp_states = gapi.get_enum_values_minus_unspecified(
                ci._rootDesc['schemas']
                ['GoogleAppsCloudidentityDevicesV1ClientState']['properties']
                ['complianceState']['enum'])
            body['complianceState'] = sys.argv[i + 1].upper()
            if body['complianceState'] not in comp_states:
                controlflow.expected_argument_exit('compliant_state',
                                                   ', '.join(comp_states),
                                                   sys.argv[i + 1])
            i += 2
        elif myarg == 'customid':
            body['customId'] = sys.argv[i + 1]
            i += 2
        elif myarg == 'healthscore':
            health_scores = gapi.get_enum_values_minus_unspecified(
                ci._rootDesc['schemas']
                ['GoogleAppsCloudidentityDevicesV1ClientState']['properties']
                ['healthScore']['enum'])
            body['healthScore'] = sys.argv[i + 1].upper()
            if body['healthScore'] == 'CLEAR':
                body['healthScore'] = None
            if body['healthScore'] and body['healthScore'] not in health_scores:
                controlflow.expected_argument_exit('health_score',
                                                   ', '.join(health_scores),
                                                   sys.argv[i + 1])
            i += 2
        elif myarg == 'customvalue':
            allowed_types = ['bool', 'number', 'string']
            value_type = sys.argv[i + 1].lower()
            if value_type not in allowed_types:
                controlflow.expected_argument_exit('custom_value',
                                                   ', '.join(allowed_types),
                                                   sys.argv[i + 1])
            key = sys.argv[i + 2]
            value = sys.argv[i + 3]
            if value_type == 'bool':
                value = gam.getBoolean(value, key)
            elif value_type == 'number':
                value = int(value)
            body.setdefault('keyValuePairs', {})
            body['keyValuePairs'][key] = {f'{value_type}Value': value}
            i += 4
        elif myarg in ['managedstate']:
            managed_states = gapi.get_enum_values_minus_unspecified(
                ci._rootDesc['schemas']
                ['GoogleAppsCloudidentityDevicesV1ClientState']['properties']
                ['managed']['enum'])
            body['managed'] = sys.argv[i + 1].upper()
            if body['managed'] == 'CLEAR':
                body['managed'] = None
            if body['managed'] and body['managed'] not in managed_states:
                controlflow.expected_argument_exit('managed_state',
                                                   ', '.join(managed_states),
                                                   sys.argv[i + 1])
            i += 2
        elif myarg in ['scorereason']:
            body['scoreReason'] = sys.argv[i + 1]
            if body['scoreReason'] == 'clear':
                body['scoreReason'] = None
            i += 2
        else:
            controlflow.invalid_argument_exit(sys.argv[i],
                                              'gam update deviceuserstate')
    name = f'{deviceuser}/clientStates/{client_id}'
    updateMask = ','.join(body.keys())
    result = gapi.call(ci.devices().deviceUsers().clientStates(),
                       'patch',
                       name=name,
                       customer=customer,
                       updateMask=updateMask,
                       body=body)
    display.print_json(result)
Beispiel #15
0
def print_():
    '''gam print userinvitations'''
    svc = gapi_cloudidentity.build_dwd('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)
Beispiel #16
0
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)