def __collect_software_info(self, sid, key_software, use_32bit):
        '''
        Update data with the next software found
        '''

        reg_soft_info = RegSoftwareInfo(key_software, sid, use_32bit)

        # Check if the registry entry is a valid.
        # a) Cannot manage software without at least a display name
        display_name = reg_soft_info.get_install_value('DisplayName', wanted_type='str')
        if display_name is None or self.__whitespace_pattern.match(display_name):
            return

        # b) make sure its not an 'Hotfix', 'Update Rollup', 'Security Update', 'ServicePack'
        # General this is software which pre dates Windows 10
        default_value = reg_soft_info.get_install_value('', wanted_type='str')
        release_type = reg_soft_info.get_install_value('ReleaseType', wanted_type='str')

        if (re.match(r'^{.*\}\.KB\d{6,}$', key_software, flags=re.IGNORECASE + re.UNICODE) is not None or
                (default_value and default_value.startswith(('KB', 'kb', 'Kb'))) or
                (release_type and release_type in ('Hotfix', 'Update Rollup', 'Security Update', 'ServicePack'))):
            log.debug('skipping hotfix/update/service pack %s', key_software)
            return

        # if NoRemove exists we would expect their to be no UninstallString
        uninstall_no_remove = reg_soft_info.is_install_true('NoRemove')
        uninstall_string = reg_soft_info.get_install_value('UninstallString')
        uninstall_quiet_string = reg_soft_info.get_install_value('QuietUninstallString')
        uninstall_modify_path = reg_soft_info.get_install_value('ModifyPath')
        windows_installer = reg_soft_info.is_install_true('WindowsInstaller')
        system_component = reg_soft_info.is_install_true('SystemComponent')
        publisher = reg_soft_info.get_install_value('Publisher', wanted_type='str')

        # UninstallString is optional if the installer is "windows installer"/MSI
        # However for it to appear in Control-Panel -> Program and Features -> Uninstall or change a program
        # the UninstallString needs to be set or ModifyPath set
        if (uninstall_string is None and
                uninstall_quiet_string is None and
                uninstall_modify_path is None and
                (not windows_installer)):
            return

        # Question: If uninstall string is not set and windows_installer should we set it
        # Question: if uninstall_quiet is not set .......

        if sid:
            username = self.__sid_to_username(sid)
        else:
            username = None

        # We now have a valid software install or a system component
        pkg_id = self.__software_to_pkg_id(publisher, display_name, system_component, use_32bit)
        version_binary, version_src = reg_soft_info.version_binary
        version_display = reg_soft_info.get_install_value('DisplayVersion', wanted_type='str')
        # version_capture is what the slp defines, the result overrides. Question: maybe it should error if it fails?
        (version_text, version_src, user_version) = \
            self.__version_capture_slp(pkg_id, version_binary, version_display, display_name)
        if not user_version:
            user_version = version_text

        # log.trace('%s\\%s ver:%s src:%s', username or 'SYSTEM', pkg_id, version_text, version_src)

        if username:
            dict_key = '{};{}'.format(username, pkg_id)  # Use ; as its not a valid hostnmae char
        else:
            dict_key = pkg_id

        # Guessing the architecture http://helpnet.flexerasoftware.com/isxhelp21/helplibrary/IHelp64BitSupport.htm
        # A 32 bit installed.exe can install a 64 bit app, but for it to write to 64bit reg it will
        # need to use WOW. So the following is a bit of a guess

        if self.__version_only:
            # package name and package version list, are the only info being return
            if dict_key in self.__reg_software:
                if version_text not in self.__reg_software[dict_key]:
                    # Not expecting the list to be big, simple search and insert
                    insert_point = 0
                    for ver_item in self.__reg_software[dict_key]:
                        if LooseVersion(version_text) <= LooseVersion(ver_item):
                            break
                        insert_point += 1
                    self.__reg_software[dict_key].insert(insert_point, version_text)
                else:
                    # This code is here as it can happen, especially if the
                    # package id provided by pkg_obj is simple.
                    log.debug(
                        'Found extra entries for \'%s\' with same version '
                        '\'%s\', skipping entry \'%s\'',
                        dict_key, version_text, key_software
                    )
            else:
                self.__reg_software[dict_key] = [version_text]

            return

        if dict_key in self.__reg_software:
            data = self.__reg_software[dict_key]
        else:
            data = self.__reg_software[dict_key] = OrderedDict()

        if sid:
            # HKEY_USERS has no 32bit and 64bit view like HKEY_LOCAL_MACHINE
            data.update({'arch': 'unknown'})
        else:
            arch_str = 'x86' if use_32bit else 'x64'
            if 'arch' in data:
                if data['arch'] != arch_str:
                    data['arch'] = 'many'
            else:
                data.update({'arch': arch_str})

        if publisher:
            if 'vendor' in data:
                if data['vendor'].lower() != publisher.lower():
                    data['vendor'] = 'many'
            else:
                data['vendor'] = publisher

        if 'win_system_component' in data:
            if data['win_system_component'] != system_component:
                data['win_system_component'] = None
        else:
            data['win_system_component'] = system_component

        data.update({'win_version_src': version_src})

        data.setdefault('version', {})
        if version_text in data['version']:
            if 'win_install_count' in data['version'][version_text]:
                data['version'][version_text]['win_install_count'] += 1
            else:
                # This is only defined when we have the same item already
                data['version'][version_text]['win_install_count'] = 2
        else:
            data['version'][version_text] = OrderedDict()

        version_data = data['version'][version_text]
        version_data.update({'win_display_name': display_name})
        if uninstall_string:
            version_data.update({'win_uninstall_cmd': uninstall_string})
        if uninstall_quiet_string:
            version_data.update({'win_uninstall_quiet_cmd': uninstall_quiet_string})
        if uninstall_no_remove:
            version_data.update({'win_uninstall_no_remove': uninstall_no_remove})

        version_data.update({'win_product_code': key_software})
        if version_display:
            version_data.update({'win_version_display': version_display})
        if version_binary:
            version_data.update({'win_version_binary': version_binary})
        if user_version:
            version_data.update({'win_version_user': user_version})

        # Determine Installer Product
        #   'NSIS:Language'
        #   'Inno Setup: Setup Version'
        if (windows_installer or
                (uninstall_string and
                    re.search(r'MsiExec.exe\s|MsiExec\s', uninstall_string, flags=re.IGNORECASE + re.UNICODE))):
            version_data.update({'win_installer_type': 'winmsi'})
        elif (re.match(r'InstallShield_', key_software, re.IGNORECASE) is not None or
                (uninstall_string and (
                 re.search(r'InstallShield', uninstall_string, flags=re.IGNORECASE + re.UNICODE) is not None or
                 re.search(r'isuninst\.exe.*\.isu', uninstall_string, flags=re.IGNORECASE + re.UNICODE) is not None)
                 )
              ):
            version_data.update({'win_installer_type': 'installshield'})
        elif (key_software.endswith('_is1') and
              reg_soft_info.get_install_value('Inno Setup: Setup Version', wanted_type='str')):
            version_data.update({'win_installer_type': 'inno'})
        elif (uninstall_string and
              re.search(r'.*\\uninstall.exe|.*\\uninst.exe', uninstall_string, flags=re.IGNORECASE + re.UNICODE)):
            version_data.update({'win_installer_type': 'nsis'})
        else:
            version_data.update({'win_installer_type': 'unknown'})

        # Update dict with information retrieved so far for detail results to be return
        # Do not add fields which are blank.
        language_number = reg_soft_info.get_install_value('Language')
        if isinstance(language_number, six.integer_types) and language_number in locale.windows_locale:
            version_data.update({'win_language': locale.windows_locale[language_number]})

        package_code = reg_soft_info.package_code
        if package_code:
            version_data.update({'win_package_code': package_code})

        upgrade_code = reg_soft_info.upgrade_code
        if upgrade_code:
            version_data.update({'win_upgrade_code': upgrade_code})

        is_minor_upgrade = reg_soft_info.is_install_true('IsMinorUpgrade')
        if is_minor_upgrade:
            version_data.update({'win_is_minor_upgrade': is_minor_upgrade})

        install_time = reg_soft_info.install_time
        if install_time:
            version_data.update({'install_date': datetime.datetime.fromtimestamp(install_time).isoformat()})
            version_data.update({'install_date_time_t': int(install_time)})

        for infokey, infotype, regfield_list in self.__uninstall_search_list:
            for regfield in regfield_list:
                strvalue = reg_soft_info.get_install_value(regfield, wanted_type=infotype)
                if strvalue:
                    version_data.update({infokey: strvalue})
                    break

        for infokey, infotype, regfield_list in self.__products_search_list:
            for regfield in regfield_list:
                data = reg_soft_info.get_product_value(regfield, wanted_type=infotype)
                if data is not None:
                    version_data.update({infokey: data})
                    break
        patch_list = reg_soft_info.list_patches
        if patch_list:
            version_data.update({'win_patches': patch_list})
def __collect_software_info ( self , sid , key_software , use_32bit ) : reg_soft_info = RegSoftwareInfo ( key_software , sid , use_32bit ) display_name = reg_soft_info . get_install_value ( 'DisplayName' , wanted_type = 'str' ) if display_name is None or self . __whitespace_pattern . match ( display_name ) : return default_value = reg_soft_info . get_install_value ( '' , wanted_type = 'str' ) release_type = reg_soft_info . get_install_value ( 'ReleaseType' , wanted_type = 'str' ) if ( re . match ( r'^{.*\}\.KB\d{6,}$' , key_software , flags = re . IGNORECASE + re . UNICODE ) is not None or ( default_value and default_value . startswith ( ( 'KB' , 'kb' , 'Kb' ) ) ) or ( release_type and release_type in ( 'Hotfix' , 'Update Rollup' , 'Security Update' , 'ServicePack' ) ) ) : log . debug ( 'skipping hotfix/update/service pack %s' , key_software ) return uninstall_no_remove = reg_soft_info . is_install_true ( 'NoRemove' ) uninstall_string = reg_soft_info . get_install_value ( 'UninstallString' ) uninstall_quiet_string = reg_soft_info . get_install_value ( 'QuietUninstallString' ) uninstall_modify_path = reg_soft_info . get_install_value ( 'ModifyPath' ) windows_installer = reg_soft_info . is_install_true ( 'WindowsInstaller' ) system_component = reg_soft_info . is_install_true ( 'SystemComponent' ) publisher = reg_soft_info . get_install_value ( 'Publisher' , wanted_type = 'str' ) if ( uninstall_string is None and uninstall_quiet_string is None and uninstall_modify_path is None and ( not windows_installer ) ) : return if sid : username = self . __sid_to_username ( sid ) else : username = None pkg_id = self . __software_to_pkg_id ( publisher , display_name , system_component , use_32bit ) version_binary , version_src = reg_soft_info . version_binary version_display = reg_soft_info . get_install_value ( 'DisplayVersion' , wanted_type = 'str' ) ( version_text , version_src , user_version ) = self . __version_capture_slp ( pkg_id , version_binary , version_display , display_name ) if not user_version : user_version = version_text if username : dict_key = '{};{}' . format ( username , pkg_id ) else : dict_key = pkg_id if self . __version_only : if dict_key in self . __reg_software : if version_text not in self . __reg_software [ dict_key ] : insert_point = 0 for ver_item in self . __reg_software [ dict_key ] : if LooseVersion ( version_text ) <= LooseVersion ( ver_item ) : break insert_point += 1 self . __reg_software [ dict_key ] . insert ( insert_point , version_text ) else : log . debug ( 'Found extra entries for \'%s\' with same version ' '\'%s\', skipping entry \'%s\'' , dict_key , version_text , key_software ) else : self . __reg_software [ dict_key ] = [ version_text ] return if dict_key in self . __reg_software : data = self . __reg_software [ dict_key ] else : data = self . __reg_software [ dict_key ] = OrderedDict ( ) if sid : data . update ( { 'arch' : 'unknown' } ) else : arch_str = 'x86' if use_32bit else 'x64' if 'arch' in data : if data [ 'arch' ] != arch_str : data [ 'arch' ] = 'many' else : data . update ( { 'arch' : arch_str } ) if publisher : if 'vendor' in data : if data [ 'vendor' ] . lower ( ) != publisher . lower ( ) : data [ 'vendor' ] = 'many' else : data [ 'vendor' ] = publisher if 'win_system_component' in data : if data [ 'win_system_component' ] != system_component : data [ 'win_system_component' ] = None else : data [ 'win_system_component' ] = system_component data . update ( { 'win_version_src' : version_src } ) data . setdefault ( 'version' , { } ) if version_text in data [ 'version' ] : if 'win_install_count' in data [ 'version' ] [ version_text ] : data [ 'version' ] [ version_text ] [ 'win_install_count' ] += 1 else : data [ 'version' ] [ version_text ] [ 'win_install_count' ] = 2 else : data [ 'version' ] [ version_text ] = OrderedDict ( ) version_data = data [ 'version' ] [ version_text ] version_data . update ( { 'win_display_name' : display_name } ) if uninstall_string : version_data . update ( { 'win_uninstall_cmd' : uninstall_string } ) if uninstall_quiet_string : version_data . update ( { 'win_uninstall_quiet_cmd' : uninstall_quiet_string } ) if uninstall_no_remove : version_data . update ( { 'win_uninstall_no_remove' : uninstall_no_remove } ) version_data . update ( { 'win_product_code' : key_software } ) if version_display : version_data . update ( { 'win_version_display' : version_display } ) if version_binary : version_data . update ( { 'win_version_binary' : version_binary } ) if user_version : version_data . update ( { 'win_version_user' : user_version } ) if ( windows_installer or ( uninstall_string and re . search ( r'MsiExec.exe\s|MsiExec\s' , uninstall_string , flags = re . IGNORECASE + re . UNICODE ) ) ) : version_data . update ( { 'win_installer_type' : 'winmsi' } ) elif ( re . match ( r'InstallShield_' , key_software , re . IGNORECASE ) is not None or ( uninstall_string and ( re . search ( r'InstallShield' , uninstall_string , flags = re . IGNORECASE + re . UNICODE ) is not None or re . search ( r'isuninst\.exe.*\.isu' , uninstall_string , flags = re . IGNORECASE + re . UNICODE ) is not None ) ) ) : version_data . update ( { 'win_installer_type' : 'installshield' } ) elif ( key_software . endswith ( '_is1' ) and reg_soft_info . get_install_value ( 'Inno Setup: Setup Version' , wanted_type = 'str' ) ) : version_data . update ( { 'win_installer_type' : 'inno' } ) elif ( uninstall_string and re . search ( r'.*\\uninstall.exe|.*\\uninst.exe' , uninstall_string , flags = re . IGNORECASE + re . UNICODE ) ) : version_data . update ( { 'win_installer_type' : 'nsis' } ) else : version_data . update ( { 'win_installer_type' : 'unknown' } ) language_number = reg_soft_info . get_install_value ( 'Language' ) if isinstance ( language_number , six . integer_types ) and language_number in locale . windows_locale : version_data . update ( { 'win_language' : locale . windows_locale [ language_number ] } ) package_code = reg_soft_info . package_code if package_code : version_data . update ( { 'win_package_code' : package_code } ) upgrade_code = reg_soft_info . upgrade_code if upgrade_code : version_data . update ( { 'win_upgrade_code' : upgrade_code } ) is_minor_upgrade = reg_soft_info . is_install_true ( 'IsMinorUpgrade' ) if is_minor_upgrade : version_data . update ( { 'win_is_minor_upgrade' : is_minor_upgrade } ) install_time = reg_soft_info . install_time if install_time : version_data . update ( { 'install_date' : datetime . datetime . fromtimestamp ( install_time ) . isoformat ( ) } ) version_data . update ( { 'install_date_time_t' : int ( install_time ) } ) for infokey , infotype , regfield_list in self . __uninstall_search_list : for regfield in regfield_list : strvalue = reg_soft_info . get_install_value ( regfield , wanted_type = infotype ) if strvalue : version_data . update ( { infokey : strvalue } ) break for infokey , infotype , regfield_list in self . __products_search_list : for regfield in regfield_list : data = reg_soft_info . get_product_value ( regfield , wanted_type = infotype ) if data is not None : version_data . update ( { infokey : data } ) break patch_list = reg_soft_info . list_patches if patch_list : version_data . update ( { 'win_patches' : patch_list } )
Update data with the next software found