Buscar actualizaciones de Windows instaladas y disponibles -- python campo con performance campo con python-3.x campo con windows campo con com camp codereview Relacionados El problema

Find installed and available Windows Updates


10
vote

problema

Español

Tengo una función que usa Agente de Windows Update ( Wua) api a través de com usando el módulo win32com.client , parte de Paquete PYWIN32 para recuperar las actualizaciones de Windows instaladas y disponibles (aún no instaladas). Para cada actualización, el nombre, se muestra la URL de la documentación y categoría relativa de Microsoft. Finalmente, la función devuelve 2 diccionarios que contienen un nombre y categoría de las actualizaciones instaladas y las actualizaciones disponibles (aún no están instaladas).

Este es el código que escribí, compila y produce el resultado esperado:

  import win32com.client import win32con import win32api import pywintypes import re  def enum_winupdates():     wua = win32com.client.Dispatch("Microsoft.Update.Session")     update_seeker = wua.CreateUpdateSearcher()     # Search installed Software Windows Updates     search_installed = update_seeker.Search("IsInstalled=1 and Type='Software'")     updates_installed = win32com.client.Dispatch("Microsoft.Update.UpdateColl")     print(" [+] Enumerating installed Windows or Drivers' Updates...(if any) ")     installed_updates = []     installed_categories = []     available_updates = []     available_categories = []     installed_dict = {}     available_dict = {}     # compiles the regex pattern for finding Windows Update codes     updates_pattern = re.compile(r'KB+d+')     for i in range(0, (len(search_installed.Updates))):         # saves installed update name in a variable         update_installed = search_installed.Updates.Item(i)         for j in range(0, len(update_installed.Categories)):             # extracts Windows Update code using regex             update_code = updates_pattern.findall(str(update_installed))             # saves installed update category in a variable             category = update_installed.Categories.Item(j).Name             print("[*] Name: " + str(update_installed) + " - " +                   "url: " + "https://support.microsoft.com/en-us/kb/{}".format(                 "".join(update_code).strip("KB")) + " - " +                   "Category: " + category)             installed_updates.append(str(update_installed))             installed_categories.append(category)     # converts lists to tuples in order to be used as a dictionary key     installed_hashable = tuple(installed_updates)     installed_hashable_category = tuple(installed_categories)     # creates category:update dictionary     for update in installed_hashable:         for category_update in installed_hashable_category:             installed_dict[category_update] = str(update)      # Searches available Software Windows updates not installed     search_available = update_seeker.Search("IsInstalled=0 and Type='Software'")     updates_available = win32com.client.Dispatch("Microsoft.Update.UpdateColl")     print(" [+] Enumerating available Windows or Drivers' Updates not installed...(if any) ")     for i in range(0, (len(search_available.Updates))):         update_available = search_available.Updates.Item(i)         for j in range(0, len(updates_available.Categories)):             # extracts Windows Update code using regex             update_code = updates_pattern.findall(str(update_available))             # saves installed update category in a variable             category = updates_available.Categories.Item(j).Name             print("[*] Name: " + str(update_available) + " - " +                   "url: " + "https://support.microsoft.com/en-us/kb/{}".format(                 "".join(update_code).strip("KB")) + " - " +                   "Category: " + category)             available_updates.append(str(update_available))             available_categories.append(category)     # converts lists to tuples in order to be used as a dictionary key     available_hashable = tuple(available_updates)     available_hashable_category = tuple(available_categories)     # creates category:update dictionary     for update in available_hashable:         for category_update in available_hashable_category:             available_dict[category_update] = str(update)     return installed_dict, available_dict   

Solicitaría una revisión de código centrada en el rendimiento y se seca. La mayor parte del código que utilicé para encontrar las actualizaciones instaladas es el mismo utilizado para encontrar las actualizaciones que aún no están instaladas. Me pregunto si el código podría refactorarse de alguna manera para evitar la repetición y quizás tenga una ganancia de rendimiento.

Original en ingles

I have a function that uses Windows Update Agent (WUA) API through COM using the win32com.client module, part of pywin32 package for retrieving the installed and the available (not yet installed) Windows Updates. For each update, name, url of the relative Microsoft documentation and category is displayed. Finally the function returns 2 dictionaries containing a name and category of the installed updates and the available updates (not yet installed).

This is the code I wrote, it compiles and produces the expected result:

import win32com.client import win32con import win32api import pywintypes import re  def enum_winupdates():     wua = win32com.client.Dispatch("Microsoft.Update.Session")     update_seeker = wua.CreateUpdateSearcher()     # Search installed Software Windows Updates     search_installed = update_seeker.Search("IsInstalled=1 and Type='Software'")     updates_installed = win32com.client.Dispatch("Microsoft.Update.UpdateColl")     print("\n[+] Enumerating installed Windows or Drivers' Updates...(if any)\n")     installed_updates = []     installed_categories = []     available_updates = []     available_categories = []     installed_dict = {}     available_dict = {}     # compiles the regex pattern for finding Windows Update codes     updates_pattern = re.compile(r'KB+\d+')     for i in range(0, (len(search_installed.Updates))):         # saves installed update name in a variable         update_installed = search_installed.Updates.Item(i)         for j in range(0, len(update_installed.Categories)):             # extracts Windows Update code using regex             update_code = updates_pattern.findall(str(update_installed))             # saves installed update category in a variable             category = update_installed.Categories.Item(j).Name             print("[*] Name: " + str(update_installed) + " - " +                   "url: " + "https://support.microsoft.com/en-us/kb/{}".format(                 "".join(update_code).strip("KB")) + " - " +                   "Category: " + category)             installed_updates.append(str(update_installed))             installed_categories.append(category)     # converts lists to tuples in order to be used as a dictionary key     installed_hashable = tuple(installed_updates)     installed_hashable_category = tuple(installed_categories)     # creates category:update dictionary     for update in installed_hashable:         for category_update in installed_hashable_category:             installed_dict[category_update] = str(update)      # Searches available Software Windows updates not installed     search_available = update_seeker.Search("IsInstalled=0 and Type='Software'")     updates_available = win32com.client.Dispatch("Microsoft.Update.UpdateColl")     print("\n[+] Enumerating available Windows or Drivers' Updates not installed...(if any)\n")     for i in range(0, (len(search_available.Updates))):         update_available = search_available.Updates.Item(i)         for j in range(0, len(updates_available.Categories)):             # extracts Windows Update code using regex             update_code = updates_pattern.findall(str(update_available))             # saves installed update category in a variable             category = updates_available.Categories.Item(j).Name             print("[*] Name: " + str(update_available) + " - " +                   "url: " + "https://support.microsoft.com/en-us/kb/{}".format(                 "".join(update_code).strip("KB")) + " - " +                   "Category: " + category)             available_updates.append(str(update_available))             available_categories.append(category)     # converts lists to tuples in order to be used as a dictionary key     available_hashable = tuple(available_updates)     available_hashable_category = tuple(available_categories)     # creates category:update dictionary     for update in available_hashable:         for category_update in available_hashable_category:             available_dict[category_update] = str(update)     return installed_dict, available_dict 

I would kindly ask for a code review focusing on performance and DRY. Most of the code I used for finding the installed updates is the same used for finding the updates that aren't installed yet. I wonder if the code could be refactored in some way in order to avoid repetition and perhaps have a performance gain.

              

Lista de respuestas

8
 
vote
vote
La mejor respuesta
 

bucle como un nativo

Le sugiero que tenga un vistazo / leído en Ned Batchelder's Excelente presentación "Loop como un nativo" .

En su caso, en cualquier momento que escriba:

  T3  

Probablemente deberías escribir:

  T4  

Si está utilizando objetos que no admiten esto de forma nativa, puede valer la pena escribir un adaptador como se sugiere en Talk "Beyond Pep 8" de Raymond Hettinger .

(En cualquier caso, tenga en cuenta que T5 como primer argumento de T6 es inútil, puede escribir T7 en lugar de T8 )

Hacer menos, con menos frecuencia

Usted realiza esta operación T9 Para cada categoría, aunque el resultado será (por lo que puedo decir) no cambiar de una categoría a otra. Probablemente tendría sentido hacer esto fuera del bucle.

también, llame temp0 muchas veces para el mismo temp1 . Una vez más, puede valer la pena hacerlo solo una vez.

no se repita

Parece que estás haciendo lo mismo dos veces. Sólo unos pocos parámetros son diferentes. Usted podría definir una función para manejar esto.

En esta etapa, el código se ve (y está altamente no probado, los nombres de las variables pueden ser bastante malos y puedo haber introducido errores, pero obtendrás la idea de lo que estaba tratando de lograr):

  temp2  

haz menos (otra vez)

Del código anterior, está claro que los elementos de temp3 ya son cadenas, pero aún hemos llamado temp4 en ellos. Espero que esto sea inútil.

Además, espero el temp5 temp6655443326 tuples no es útil.

Simplemente podría escribir:

  temp7  

Formato de cadena adecuado

en:

  temp8  

Usted utiliza una mezcla de CUERDA Concatenación de formato de cadena. Esto es muy confuso. En su lugar, simplemente podría escribir:

  temp9  

hacer las cosas con menos frecuencia (nuevamente)

Lo extrañé en primer lugar, pero podría hacer la parte de unión y tira fuera del bucle:

  operator++0  

estructura de datos

Tengo problemas para comprender cuál se supone que la estructura de datos de devoluciones es. Un diccionario de diccionario de cada categoría a una sola actualización es un poco rara. ¿No tendría más sentido para mapear cada categoría en una lista de actualizaciones?

He intentado emular una jerarquía de artículo / categoría para ver lo que estaba sucediendo, pero podría tener suposiciones equivocadas sobre lo que se supone que su código se supone.

Para el registro, aquí está la función falsa correspondiente y el valor devuelto:

  operator++1  

Regresando:

  operator++2  

(Lo que me parece raro es el hecho de que todas las categorías están de alguna manera vinculadas a la misma actualización).

 

Loop like a native

I suggest you have a look/read at Ned Batchelder's excellent presentation "Loop like a native".

In your case, any time you write:

for i in range(0, (len(search_installed.Updates))):     # saves installed update name in a variable     update_installed = search_installed.Updates.Item(i) 

You should most probably write:

for update_installed in search_installed.Updates:     # saves installed update name in a variable 

If you are using objects that do not support this natively, it may be worth writting an adapter as suggested in Raymond Hettinger's "Beyond PEP 8" talk.

(In any case, please note that 0 as a first argument of range is useless, you can write range(foo) instead of range(0, foo))

Do less, less often

You perform this operation update_code = updates_pattern.findall(str(update_installed)) for each category even though the result will (as far as I can tell) not change from one category to another. It would probably make sense to do this out of the loop.

Also, you call str(update_installed) many times for the same update_installed. Again, it may be worth doing only once.

Do not repeat yourself

It seems that you are doing the same thing twice. Only a few parameters are different. You could define a function to handle this.

At this stage, the code looks like (and is highly untested, the variable names might be pretty bad and I may have introduced errors but you'll get the idea of what I was trying to achieve):

import win32com.client import win32con import win32api import pywintypes import re  def get_software_updates(update_seeker, installed):     # Search installed/not installed Software Windows Updates     search_string = "IsInstalled=%d and Type='Software'" % installed     search_update = update_seeker.Search(search_string)     _ = win32com.client.Dispatch("Microsoft.Update.UpdateColl")     updates = []     categories = []     update_dict = {}     # compiles the regex pattern for finding Windows Update codes     updates_pattern = re.compile(r'KB+\d+')     for update in search_update.Updates:         update_str = str(update)         # extracts Windows Update code using regex         update_code = updates_pattern.findall(update_str)         for category in update.Categories:             category_name = category.Name             print("[*] Name: " + update_str + " - " +                   "url: " + "https://support.microsoft.com/en-us/kb/{}".format(                 "".join(update_code).strip("KB")) + " - " +                   "Category: " + category_name)             updates.append(update_str)             categories.append(category_name)     # converts lists to tuples in order to be used as a dictionary key     hashable = tuple(updates)     hashable_category = tuple(categories)     # creates category:update dictionary     for update in hashable:         for category_update in hashable_category:             update_dict[category_update] = str(update)     return update_dict  def enum_winupdates():     wua = win32com.client.Dispatch("Microsoft.Update.Session")     update_seeker = wua.CreateUpdateSearcher()     print("\n[+] Enumerating installed Windows or Drivers' Updates...(if any)\n")     installed = get_software_updates(update_seeker, installed=True)     print("\n[+] Enumerating available Windows or Drivers' Updates not installed...(if any)\n")     available = get_software_updates(update_seeker, installed=False)     return installed, available 

Do less (again)

From the code above, it is clear that elements from updates are already string but we have still calling str on them. I expect this to be useless.

Also, I expect the hashable and hashable_categories tuples not to be useful.

You could simply write:

    # creates category:update dictionary     for update in updates:         for category_update in categories:             update_dict[category_update] = update     return update_dict 

Proper string format

In :

            print("[*] Name: " + update_str + " - " +                   "url: " + "https://support.microsoft.com/en-us/kb/{}".format(                 "".join(update_code).strip("KB")) + " - " +                   "Category: " + category_name) 

You use a mix of string concatenation of string formatting. This is highly confusing. Instead, you could simply write:

            print("[*] Name: {} - url: https://support.microsoft.com/en-us/kb/{} - Category: {}".format(                 update_str,                 "".join(update_code).strip("KB"),                 category_name)) 

Do things less often (again)

I missed it in the first place but you could do the join-and-strip part out of the loop:

        # extracts Windows Update code using regex         update_codes = updates_pattern.findall(update_str)         update_codes_stripped = "".join(update_code).strip("KB") 

Data structure

I have troubles understanding what the returns data structure is supposed to be. A dictionnary mapping each category to a single update is a bit weird. Wouldn't it make more sense to map each category to a list of updates ?

I've tried to emulate some item/category hierarchy to see what was happening but I might have wrong assumptions about what your code is suppose to retrieve.

For the record, here is the corresponding fake function and the value returned:

def get_software_updates(update_seeker, installed):     hardcoded_updates = {         'update1': ['cat1a', 'cat1b', 'cat1c'],         'update2': [],         'update3': ['cat3a', 'cat3b', 'cat3c', 'cat4c']     }     updates = []     categories = []     update_dict = {}     for update, hardcoded_categories in hardcoded_updates.iteritems():         for category in hardcoded_categories:             updates.append(update)             categories.append(category)     for update in updates:         for category_update in categories:             update_dict[category_update] = update     print(update_dict)     return update_dict 

returning:

{'cat3a': 'update1', 'cat3b': 'update1', 'cat3c': 'update1', 'cat4c': 'update1', 'cat1b': 'update1', 'cat1c': 'update1', 'cat1a': 'update1'} 

(What I find weird is the fact that all categories are somehow linked to the same update).

 
 
   
   

Relacionados problema

2  Organización de código de deserialización de estructura variante  ( Variant structure deserialization code organization ) 
En mi proyecto, trabajo con objeto COM a través de Questions8 . Com Objeto Devoluciones Puntero en Estructura Questions9 , que eché como Sections0 y luego...

2  Actualizando la hoja de Excel con información de un DataTable  ( Updating excel sheet with information from a datatable ) 
Básicamente, estoy tratando de actualizar una hoja de Excel usando un A8 La estructura de las columnas entre los dos son no lo mismo ) Con respecto a las ...

2  Usando objetos COM en llanda C  ( Using com objects in plain c ) 
En este código, estoy creando un objeto COM para acceder programáticamente a Internet Explorer. Para acceder a las propiedades y métodos de este objeto, estoy...

7  Tuning Excel Motor de cálculo que utiliza MS Excel Interop  ( Tuning excel calculation engine which uses ms excel interop ) 
Actualmente estoy construyendo un motor de cálculo de Excel. Su propósito es básicamente envolver la lógica de cálculo de un libro de Excel para usar la lógic...

12  No tan excelente del caballero de la gira  ( Not so excellent knights tour ) 
Nota: Esto es parte de un conjunto de aplicaciones de demostración que estoy escribiendo para que los colegas muestren que no estamos limitados a VBA cuando s...

4  ¿Es la fuerza bruta la mejor práctica aceptada para manejar excepciones de excel "ocupado"?  ( Is brute force the accepted best practice for handling excel com busy exceptio ) 
Siguiendo a partir de una pregunta sobre manejo-com-excepciones: códigos ocupados-ocupados Me gustaría saber si el siguiente modelo es la mejor práctica ace...

2  (COM, COMPLETABLE) Clase Python para descompilar * .CHM Archivo con Microsoft HTML Ayuda Ayuda Ejecutable  ( Com callable python class to decompile chm file with microsoft html help exe ) 
Windows solamente. Por lo tanto, estoy escribiendo código para descompilar un archivo de ayuda HTML compilado de Windows (* .CHM) y luego ordenar los archivos...

3  C # Diccionario Wrapper para VBA  ( C dictionary wrapper for vba ) 
Soy un revisor / escritor técnico y yo uso VBA por palabra mucho para administrar problemas en los documentos de Word que recibo. Con frecuencia, he encontrad...

4  Manera correcta de usar ixmldomdocument  ( Proper way of using ixmldomdocument ) 
Estoy tratando de usar ixmldomdocument para lectura / escritura XML. No soy bueno com, y no soy consciente de que estoy haciendo las cosas bien o mal. Estoy m...

2  D3D COM Object Pooling  ( D3d com object pooling ) 
Estoy usando el siguiente patrón para agrupar objetos D3D globalmente en mi solicitud. ¿Es una buena idea (alternativas)? ¿Es seguro? CComPtr<ID3D11Texture...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos