def main():
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    if len(args) < 2:
        logger.error("pancontentpack: Wrong number of arguments: %s, expected 2.\n" % len(args))
        usage()

    if args[1] == "apps":
        logger.info("Getting apps from content pack on Palo Alto Networks device at %s..." % args[0])
    elif args[1] == "threats":
        logger.info("Getting threats from content pack on Palo Alto Networks device at %s..." % args[0])
    else:
        usage()

    # Results contains the data from the search results and settings
    # contains the sessionKey that we can use to talk to Splunk
    # Ignore the results
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()
    # Get the sessionKey
    sessionKey = settings['sessionKey']

    log(debug, "Begin get API key")
    # Get the API key from the Splunk store or from the device at hostname if no apikey is stored
    apikey = common.apikey(sessionKey, args[0], debug)

    device = pandevice.base.PanDevice(args[0], api_key=apikey)
    device.refresh_system_info()

    try:
        if args[1] == "apps":
            device.xapi.get("/config/predefined/application")
            app_xml = device.xapi.xml_document
            csv = parse_apps(app_xml)
        else:
            if device._version_info >= (8, 0, 0):
                threat_xml = device.op(
                    'show predefined xpath "/predefined/threats"',
                    xml=True, cmd_xml=True,
                )
            else:
                device.xapi.get("/config/predefined/threats")
                threat_xml = device.xapi.xml_document
            csv = parse_threats(threat_xml)

    except pan.xapi.PanXapiError as e:
        common.exit_with_error(str(e))


    # output results
    splunk.Intersplunk.outputResults(csv)
Example #2
0
def main_splunk():
    # Get arguments passed to command on Splunk searchbar
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    debug = common.check_debug(kwargs)

    # Setup the logger. $SPLUNK_HOME/var/log/splunk/python.log
    logger = common.logging.getLogger()
    if debug:
        logger.setLevel(common.logging.DEBUG)

    # Results contains the data from the search results and settings contains
    # the sessionKey that we can use to talk to splunk
    logger.debug("Getting search results and settings from Splunk")
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()

    # Get the sessionKey
    sessionKey = settings['sessionKey']
    # If there are logs to act on, get the Panorama user and password from Splunk using the sessionKey
    if len(results) == 0:
        logger.debug(
            "WildFire Report Retrieval: No search results.  Nothing to do.")
        splunk.Intersplunk.outputResults(results)
        sys.exit(0)

    logger.debug("Getting WildFire APIKey from encrypted store")
    wf_apikey = common.get_wildfire_apikey(sessionKey)

    # Get a wildfire report for each row
    logger.debug("Getting WildFire reports for %s search results" %
                 len(results))
    for idx, result in enumerate(results):
        # Check to see if the result has the necessary fields
        if 'file_digest' in result:
            logger.debug(
                "Getting WildFire report for result # %s with file_digest: %s"
                % (idx, result['file_digest']))
            try:
                # Get the report
                wfReportXml = retrieveWildFireData(
                    wf_apikey, result['file_digest']).strip()
                result['wildfire_report'] = wfReportXml
            except:
                logger.warn(
                    "Error retrieving WildFire report for file_digest: %s" %
                    result['file_digest'])
                # Log the result row in case of an exception
                logger.info("Log with error: %s" % result)
                stack = traceback.format_exc()
                # log the stack information
                logger.warn(stack)
        else:
            logger.debug("Required fields missing from result # %s."
                         "Expected the following fields: file_digest" % idx)
    # output the complete results sent back to splunk
    splunk.Intersplunk.outputResults(results)
Example #3
0
def main():
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    if len(args) < 2:
        logger.error(
            "pancontentpack: Wrong number of arguments: %s, expected 2.\n" %
            len(args))
        usage()

    if args[1] == "apps":
        logger.info(
            "Getting apps from content pack on Palo Alto Networks device at %s..."
            % args[0])
    elif args[1] == "threats":
        logger.info(
            "Getting threats from content pack on Palo Alto Networks device at %s..."
            % args[0])
    else:
        usage()

    # Results contains the data from the search results and settings
    # contains the sessionKey that we can use to talk to Splunk
    # Ignore the results
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()
    # Get the sessionKey
    sessionKey = settings['sessionKey']

    log(debug, "Begin get API key")
    # Get the API key from the Splunk store or from the device at hostname if no apikey is stored
    apikey = common.apikey(sessionKey, args[0], debug)

    device = pandevice.base.PanDevice(args[0], api_key=apikey)

    try:
        if args[1] == "apps":
            device.xapi.get("/config/predefined/application")
            app_xml = device.xapi.xml_document
            csv = parse_apps(app_xml)
        else:
            device.xapi.get("/config/predefined/threats")
            threat_xml = device.xapi.xml_document
            csv = parse_threats(threat_xml)

    except pan.xapi.PanXapiError as e:
        common.exit_with_error(str(e))

    # output results
    splunk.Intersplunk.outputResults(csv)
def main_splunk():
    # Get arguments passed to command on Splunk searchbar
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    debug = common.check_debug(kwargs)

    # Setup the logger. $SPLUNK_HOME/var/log/splunk/python.log
    logger = common.logging.getLogger()
    if debug:
        logger.setLevel(common.logging.DEBUG)

    # Results contains the data from the search results and settings contains
    # the sessionKey that we can use to talk to splunk
    logger.debug("Getting search results and settings from Splunk")
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()

    # Get the sessionKey
    sessionKey = settings['sessionKey']
    # If there are logs to act on, get the Panorama user and password from Splunk using the sessionKey
    if len(results) < 0:
        logger.debug("No search results.  Nothing to do.")
        splunk.Intersplunk.outputResults(results)
        sys.exit(0)

    logger.debug("Getting Wildfire APIKey from encrypted store")
    wf_apikey = common.get_wildfire_apikey(sessionKey)

    # Get a wildfire report for each row
    logger.debug("Getting Wildfire reports for %s search results" % len(results))
    for idx, result in enumerate(results):
        # Check to see if the result has the necessary fields
        if 'serial_number' in result and 'report_id' in result:
            logger.debug("Getting Wildfire report for result # %s with report_id: %s" % (idx, result['report_id']))
            try:
                # Get the report
                wfReportXml = retrieveWildFireData(wf_apikey, result['serial_number'],
                                                   result['report_id']).read().strip()
                # Add the report id to the XML for correlation to the original WildFire log from the firewall
                wfReportXml = wfReportXml.replace("</version>", "</version>\n<id>" + result['report_id'] + "</id>", 1)
                result['wildfire_report'] = wfReportXml
            except:
                logger.warn("Error retrieving WildFire report for report id: %s" % result['report_id'])
                # Log the result row in case of an exception
                logger.info("Log with error: %s" % result)
                stack = traceback.format_exc()
                # Log the stack information
                logger.warn(stack)
        else:
            logger.debug("Required fields missing from result # %s."
                         "Expected the following fields: serial_number, report_id" % idx)
    # output the complete results sent back to splunk
    splunk.Intersplunk.outputResults(results)
Example #5
0
def main_splunk():
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    # kwargs contains important parameters.
    # parameters from splunk searchbar include:
    #   action
    #   device
    #   panorama
    #   serial
    #   vsys
    #   tag
    #   tag_field
    #   ip_field
    #   debug

    # Verify required args were passed to command
    log(debug, "Determining if required arguments are present")
    if 'device' not in kwargs and 'panorama' not in kwargs:
        common.exit_with_error("Missing required command argument: device or panorama", 3)
    if 'tag' not in kwargs and 'tag_field' not in kwargs:
        common.exit_with_error("Missing required command argument: tag or tag_field", 3)

    # Assign defaults to fields that aren't specified
    action = kwargs['action'] if 'action' in kwargs else "addip"
    vsys = kwargs['vsys'] if 'vsys' in kwargs else None
    ip_field = kwargs['ip_field'] if 'ip_field' in kwargs else "src_ip"
    user_field = kwargs['user_field'] if 'user_field' in kwargs else "src_user"
    # Support 'field' argument (legacy syntax)
    if 'field' in kwargs and not 'ip_field' in kwargs:
        ip_field = kwargs['field']
    tag = kwargs['tag'] if 'tag' in kwargs else None
    tag_field = kwargs['tag_field'] if 'tag_field' in kwargs else None

    # Determine if device hostname or serial was provided as argument or should be pulled from entries
    log(debug, "Determining how firewalls should be contacted based on arguments")
    use_panorama = False
    hostname = None
    serial = None
    if "device" in kwargs:
        hostname = kwargs['device']
        if vsys is None:
            vsys = "vsys1"
    elif "panorama" in kwargs:
        use_panorama = True
        hostname = kwargs['panorama']
        if "serial" in kwargs:
            serial = kwargs['serial']
            if vsys is None:
                vsys = "vsys1"
    else:
        common.exit_with_error("Missing required command argument: device or panorama", 3)
    log(debug, "Use Panorama: %s" % use_panorama)
    log(debug, "VSys: %s" % vsys)
    log(debug, "Hostname: %s" % hostname)
    if use_panorama and serial is not None:
        log(debug, "Device Serial: %s" % serial)
    else:
        log(debug, "Using serials from logs")


    # Results contains the data from the search results and settings
    # contains the sessionKey that we can use to talk to Splunk
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()
    # Get the sessionKey
    sessionKey = settings['sessionKey']

    log(debug, "Begin get API key")
    # Get the API key from the Splunk store or from the device at hostname if no apikey is stored
    apikey = common.apikey(sessionKey, hostname, debug)

    # Create the connection to the firewall or Panorama
    panorama = None
    if use_panorama:
        # For Panorama, create the Panorama object, and the firewall if only one serial
        panorama = Panorama(hostname, api_key=apikey)
        if serial is not None:
            firewall = {'firewall': Firewall(serial=serial, vsys=vsys)}
            panorama.add(firewall['firewall'])
            firewall['firewall'].userid.batch_start()
        else:
            firewall = {}
    else:
        firewall = {'firewall': Firewall(hostname, api_key=apikey, vsys=vsys)}
        firewall['firewall'].userid.batch_start()

    # Collect all the ip addresses and tags into firewall batch requests
    for result in results:

        ## Find the serial (if not a single firewall)

        if use_panorama and serial is None:
            try:
                this_serial = result['serial_number']
                this_vsys = result['vsys']
            except KeyError as e:
                result['status'] = "ERROR: Unable to determine serial number or vsys of device"
                continue
            else:
                ## Create the firewall object if using multiple serials
                if this_serial in firewall:
                    this_firewall = firewall[(this_serial, this_vsys)]
                else:
                    # Create the firewall object for this serial
                    firewall[(this_serial, this_vsys)] = Firewall(serial=this_serial, vsys=this_vsys)
                    this_firewall = firewall[(this_serial, this_vsys)]
                    panorama.add(this_firewall)
                    this_firewall.userid.batch_start()
        else:
            this_firewall = firewall['firewall']

        ## Find the tag (if a tag_field was specified)

        this_tag = []
        if tag_field is not None:
            try:
                this_tag.append(result[tag_field])
            except KeyError as e:
                result['status'] = "ERROR: Unable to determine tag from field: %s" % tag_field
                continue
        if tag is not None:
            this_tag.append(tag)

        ## Find the field

        try:
            if action in ("adduser", "removeuser"):
                this_field = result[user_field]
            else: 
                this_field = result[ip_field]
        except KeyError as e:
            result['status'] = "ERROR: Unable to determine value from field: %s" % this_field

        ## Create a request in the batch user-id update for the firewall
        ## No API call to the firewall happens until all batch requests are created.

        if action in ("add", "addip"):
            log(debug, "Registering tags on firewall %s: %s - %s" % (this_firewall, this_field, this_tag))
            this_firewall.userid.register(this_field, this_tag)
        elif action in ("remove", "removeip"):
            log(debug, "Unregistering tags on firewall %s: %s - %s" % (this_firewall, this_field, this_tag))
            this_firewall.userid.unregister(this_field, this_tag)
        elif action == "adduser":
            log(debug, "Registering tags on firewall %s: %s - %s" % (this_firewall, this_field, this_tag))
            this_firewall.userid.tag_user(this_field, this_tag)
        elif action == "removeuser":
            log(debug, "Unregistering tags on firewall %s: %s - %s" % (this_firewall, this_field, this_tag))
            this_firewall.userid.untag_user(this_field, this_tag)

        result['status'] = "Submitted successfully"

    ## Make the API calls to the User-ID API of each firewall

    try:
        for fw in list(firewall.values()):
            fw.userid.batch_end()

    except pan.xapi.PanXapiError as e:
        common.exit_with_error(str(e))

    except Exception as e:
        common.exit_with_error(str(e))

    # output results
    splunk.Intersplunk.outputResults(results)
def main_splunk():
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    # kwargs contains important parameters.
    # parameters from splunk searchbar include:
    #   action
    #   device
    #   panorama
    #   serial
    #   vsys
    #   user_field
    #   ip_field
    #   debug

    # Verify required args were passed to command
    log(debug, "Determining if required arguments are present")
    if "device" not in kwargs and "panorama" not in kwargs:
        common.exit_with_error("Missing required command argument: device or panorama", 3)
    if "panorama" in kwargs and "serial" not in kwargs:
        common.exit_with_error("Found 'panorama' arguments, but missing 'serial' argument", 3)

    # Assign defaults to fields that aren't specified
    action = kwargs["action"] if "action" in kwargs else "login"
    vsys = kwargs["vsys"] if "vsys" in kwargs else "vsys1"
    ip_field = kwargs["ip_field"] if "ip_field" in kwargs else "src_ip"
    user_field = kwargs["tag_field"] if "tag_field" in kwargs else "user"

    # Determine if device hostname or serial was provided as argument or should be pulled from entries
    log(debug, "Determining how firewalls should be contacted based on arguments")
    use_panorama = False
    hostname = None
    serial = None
    if "device" in kwargs:
        hostname = kwargs["device"]
    elif "panorama" in kwargs:
        use_panorama = True
        hostname = kwargs["panorama"]
        serial = kwargs["serial"]
    else:
        common.exit_with_error("Missing required command argument: device or panorama", 3)
    log(debug, "Use Panorama: %s" % use_panorama)
    log(debug, "VSys: %s" % vsys)
    log(debug, "Hostname: %s" % hostname)
    if use_panorama and serial is not None:
        log(debug, "Device Serial: %s" % serial)

    # Results contains the data from the search results and settings
    # contains the sessionKey that we can use to talk to Splunk
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()
    # Get the sessionKey
    sessionKey = settings["sessionKey"]

    log(debug, "Begin get API key")
    # Get the API key from the Splunk store or from the device at hostname if no apikey is stored
    apikey = common.apikey(sessionKey, hostname, debug)

    # Create the connection to the firewall or Panorama
    panorama = None
    if use_panorama:
        # For Panorama, create the Panorama object, and the firewall object
        panorama = Panorama(hostname, api_key=apikey)
        firewall = Firewall(panorama=panorama, serial=serial, vsys=vsys)
        firewall.userid.batch_start()
    else:
        # No Panorama, so just create the firewall object
        firewall = Firewall(hostname, api_key=apikey, vsys=vsys)
        firewall.userid.batch_start()

    # Collect all the ip addresses and tags into firewall batch requests
    for result in results:

        ## Find the tag (if a tag_field was specified)

        try:
            this_user = result[user_field]
        except KeyError as e:
            result["status"] = "ERROR: Unable to determine user from field: %s" % user_field
            continue

        ## Find the IP

        try:
            this_ip = result[ip_field]
        except KeyError as e:
            result["status"] = "ERROR: Unable to determine ip from field: %s" % ip_field

        ## Create a request in the batch user-id update for the firewall
        ## No API call to the firewall happens until all batch requests are created.

        if action == "login":
            log(debug, "Login event on firewall %s: %s - %s" % (firewall, this_ip, this_user))
            firewall.userid.login(this_user, this_ip)
        else:
            log(debug, "Logout event on firewall %s: %s - %s" % (firewall, this_ip, this_user))
            firewall.userid.logout(this_user, this_ip)

        result["status"] = "Submitted successfully"

    ## Make the API calls to the User-ID API of each firewall

    try:
        firewall.userid.batch_end()

    except pan.xapi.PanXapiError as e:
        common.exit_with_error(str(e))

    except Exception as e:
        common.exit_with_error(str(e))

    # output results
    splunk.Intersplunk.outputResults(results)
Example #7
0
    newAppUrl = 'https://ww2.paloaltonetworks.com/iphone/NewApps.aspx'
    # Create a request object
    newAppReq = urllib2.Request(newAppUrl)
    # Make the request
    result = opener.open(newAppReq)
    return result


try:
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    # Results contains the data from the search results
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()

    existing_apps = []
    for app in results:
        existing_apps.append(str(app['app{@name}']))

    results = []
    log(
        debug, "Existing apps already known and considered: %s" %
        (len(existing_apps), ))
    log(debug, existing_apps)

    log(debug, "Getting new Apps from Palo Alto Networks")
def main_splunk():
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    # kwargs contains important parameters.
    # parameters from splunk searchbar include:
    #   action
    #   device
    #   panorama
    #   serial
    #   vsys
    #   tag
    #   tag_field
    #   ip_field
    #   debug

    # Verify required args were passed to command
    log(debug, "Determining if required arguments are present")
    if 'device' not in kwargs and 'panorama' not in kwargs:
        common.exit_with_error("Missing required command argument: device or panorama", 3)
    if 'tag' not in kwargs and 'tag_field' not in kwargs:
        common.exit_with_error("Missing required command argument: tag or tag_field", 3)

    # Assign defaults to fields that aren't specified
    action = kwargs['action'] if 'action' in kwargs else "add"
    vsys = kwargs['vsys'] if 'vsys' in kwargs else None
    ip_field = kwargs['ip_field'] if 'ip_field' in kwargs else "src_ip"
    # Support 'field' argument (legacy syntax)
    if 'field' in kwargs and not 'ip_field' in kwargs:
        ip_field = kwargs['field']
    tag = kwargs['tag'] if 'tag' in kwargs else None
    tag_field = kwargs['tag_field'] if 'tag_field' in kwargs else None

    # Determine if device hostname or serial was provided as argument or should be pulled from entries
    log(debug, "Determining how firewalls should be contacted based on arguments")
    use_panorama = False
    hostname = None
    serial = None
    if "device" in kwargs:
        hostname = kwargs['device']
        if vsys is None:
            vsys = "vsys1"
    elif "panorama" in kwargs:
        use_panorama = True
        hostname = kwargs['panorama']
        if "serial" in kwargs:
            serial = kwargs['serial']
            if vsys is None:
                vsys = "vsys1"
    else:
        common.exit_with_error("Missing required command argument: device or panorama", 3)
    log(debug, "Use Panorama: %s" % use_panorama)
    log(debug, "VSys: %s" % vsys)
    log(debug, "Hostname: %s" % hostname)
    if use_panorama and serial is not None:
        log(debug, "Device Serial: %s" % serial)
    else:
        log(debug, "Using serials from logs")


    # Results contains the data from the search results and settings
    # contains the sessionKey that we can use to talk to Splunk
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()
    # Get the sessionKey
    sessionKey = settings['sessionKey']

    log(debug, "Begin get API key")
    # Get the API key from the Splunk store or from the device at hostname if no apikey is stored
    apikey = common.apikey(sessionKey, hostname, debug)

    # Create the connection to the firewall or Panorama
    panorama = None
    if use_panorama:
        # For Panorama, create the Panorama object, and the firewall if only one serial
        panorama = Panorama(hostname, api_key=apikey)
        if serial is not None:
            firewall = {'firewall': Firewall(panorama=panorama, serial=serial, vsys=vsys)}
            firewall['firewall'].userid.batch_start()
        else:
            firewall = {}
    else:
        firewall = {'firewall': Firewall(hostname, api_key=apikey, vsys=vsys)}
        firewall['firewall'].userid.batch_start()

    # Collect all the ip addresses and tags into firewall batch requests
    for result in results:

        ## Find the serial (if not a single firewall)

        if use_panorama and serial is None:
            try:
                this_serial = result['serial_number']
                this_vsys = result['vsys']
            except KeyError as e:
                result['status'] = "ERROR: Unable to determine serial number or vsys of device"
                continue
            else:
                ## Create the firewall object if using multiple serials
                if this_serial in firewall:
                    this_firewall = firewall[(this_serial, this_vsys)]
                else:
                    # Create the firewall object for this serial
                    firewall[(this_serial, this_vsys)] = Firewall(panorama=panorama, serial=this_serial, vsys=this_vsys)
                    this_firewall = firewall[(this_serial, this_vsys)]
                    this_firewall.userid.batch_start()
        else:
            this_firewall = firewall['firewall']

        ## Find the tag (if a tag_field was specified)

        this_tag = []
        if tag_field is not None:
            try:
                this_tag.append(result[tag_field])
            except KeyError as e:
                result['status'] = "ERROR: Unable to determine tag from field: %s" % tag_field
                continue
        if tag is not None:
            this_tag.append(tag)

        ## Find the IP

        try:
            this_ip = result[ip_field]
        except KeyError as e:
            result['status'] = "ERROR: Unable to determine ip from field: %s" % ip_field

        ## Create a request in the batch user-id update for the firewall
        ## No API call to the firewall happens until all batch requests are created.

        if action == "add":
            log(debug, "Registering tags on firewall %s: %s - %s" % (this_firewall, this_ip, this_tag))
            this_firewall.userid.register(this_ip, this_tag)
        else:
            log(debug, "Unregistering tags on firewall %s: %s - %s" % (this_firewall, this_ip, this_tag))
            this_firewall.userid.unregister(this_ip, this_tag)

        result['status'] = "Submitted successfully"

    ## Make the API calls to the User-ID API of each firewall

    try:
        for fw in firewall.values():
            fw.userid.batch_end()

    except pan.xapi.PanXapiError as e:
        common.exit_with_error(str(e))

    except Exception as e:
        common.exit_with_error(str(e))

    # output results
    splunk.Intersplunk.outputResults(results)
    # Create a request object
    newAppReq = urllib2.Request(newAppUrl)
    # Make the request
    result = opener.open(newAppReq)
    return result



try:
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    # Results contains the data from the search results
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()

    existing_apps = []
    for app in results:
        existing_apps.append(str(app['app{@name}']))

    results = []
    log(debug, "Existing apps already known and considered: %s" % (len(existing_apps),))
    log(debug, existing_apps)

    log(debug, "Getting new Apps from Palo Alto Networks")
    resp = retrieveNewApps()
    log(debug, "Apps retrieved")
Example #10
0
def main_splunk():
    # Get arguments
    args, kwargs = splunk.Intersplunk.getKeywordsAndOptions()

    # Enable debugging by passing 'debug=yes' as an argument of
    # the command on the Splunk searchbar.

    debug = common.check_debug(kwargs)

    # kwargs contains important parameters.
    # parameters from splunk searchbar include:
    #   action
    #   device
    #   panorama
    #   serial
    #   vsys
    #   user_field
    #   ip_field
    #   debug

    # Verify required args were passed to command
    log(debug, "Determining if required arguments are present")
    if 'device' not in kwargs and 'panorama' not in kwargs:
        common.exit_with_error(
            "Missing required command argument: device or panorama", 3)
    if 'panorama' in kwargs and 'serial' not in kwargs:
        common.exit_with_error(
            "Found 'panorama' arguments, but missing 'serial' argument", 3)

    # Assign defaults to fields that aren't specified
    action = kwargs['action'] if 'action' in kwargs else "login"
    vsys = kwargs['vsys'] if 'vsys' in kwargs else "vsys1"
    ip_field = kwargs['ip_field'] if 'ip_field' in kwargs else "src_ip"
    user_field = kwargs['user_field'] if 'user_field' in kwargs else "user"

    # Determine if device hostname or serial was provided as argument or should be pulled from entries
    log(debug,
        "Determining how firewalls should be contacted based on arguments")
    use_panorama = False
    hostname = None
    serial = None
    if "device" in kwargs:
        hostname = kwargs['device']
    elif "panorama" in kwargs:
        use_panorama = True
        hostname = kwargs['panorama']
        serial = kwargs['serial']
    else:
        common.exit_with_error(
            "Missing required command argument: device or panorama", 3)
    log(debug, "Use Panorama: %s" % use_panorama)
    log(debug, "VSys: %s" % vsys)
    log(debug, "Hostname: %s" % hostname)
    if use_panorama and serial is not None:
        log(debug, "Device Serial: %s" % serial)

    # Results contains the data from the search results and settings
    # contains the sessionKey that we can use to talk to Splunk
    results, unused1, settings = splunk.Intersplunk.getOrganizedResults()
    # Get the sessionKey
    sessionKey = settings['sessionKey']

    log(debug, "Begin get API key")
    # Get the API key from the Splunk store or from the device at hostname if no apikey is stored
    apikey = common.apikey(sessionKey, hostname, debug)

    # Create the connection to the firewall or Panorama
    panorama = None
    if use_panorama:
        # For Panorama, create the Panorama object, and the firewall object
        panorama = Panorama(hostname, api_key=apikey)
        firewall = Firewall(panorama=panorama, serial=serial, vsys=vsys)
        firewall.userid.batch_start()
    else:
        # No Panorama, so just create the firewall object
        firewall = Firewall(hostname, api_key=apikey, vsys=vsys)
        firewall.userid.batch_start()

    # Collect all the ip addresses and users into firewall batch requests
    for result in results:

        ## Find the user (if a user_field was specified)

        try:
            this_user = result[user_field]
        except KeyError as e:
            result[
                'status'] = "ERROR: Unable to determine user from field: %s" % user_field
            continue

        ## Find the IP

        try:
            this_ip = result[ip_field]
        except KeyError as e:
            result[
                'status'] = "ERROR: Unable to determine ip from field: %s" % ip_field

        ## Create a request in the batch user-id update for the firewall
        ## No API call to the firewall happens until all batch requests are created.

        if action == "login":
            log(
                debug, "Login event on firewall %s: %s - %s" %
                (firewall, this_ip, this_user))
            firewall.userid.login(this_user, this_ip)
        else:
            log(
                debug, "Logout event on firewall %s: %s - %s" %
                (firewall, this_ip, this_user))
            firewall.userid.logout(this_user, this_ip)

        result['status'] = "Submitted successfully"

    ## Make the API calls to the User-ID API of each firewall

    try:
        firewall.userid.batch_end()

    except pan.xapi.PanXapiError as e:
        common.exit_with_error(str(e))

    except Exception as e:
        common.exit_with_error(str(e))

    # output results
    splunk.Intersplunk.outputResults(results)