VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testboxscript/win/fix_stale_refs.py@ 93718

Last change on this file since 93718 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.9 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: fix_stale_refs.py 93115 2022-01-01 11:31:46Z vboxsync $
3
4"""
5This module must be used interactively!
6Use with caution as it will delete some values from the regisry!
7
8It tries to locate client references to products that no longer exist.
9"""
10
11__copyright__ = \
12"""
13Copyright (C) 2012-2022 Oracle Corporation
14
15This file is part of VirtualBox Open Source Edition (OSE), as
16available from http://www.virtualbox.org. This file is free software;
17you can redistribute it and/or modify it under the terms of the GNU
18General Public License (GPL) as published by the Free Software
19Foundation, in version 2 as it comes in the "COPYING" file of the
20VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22
23The contents of this file may alternatively be used under the terms
24of the Common Development and Distribution License Version 1.0
25(CDDL) only, as it comes in the "COPYING.CDDL" file of the
26VirtualBox OSE distribution, in which case the provisions of the
27CDDL are applicable instead of those of the GPL.
28
29You may elect to license modified versions of this file under the
30terms and conditions of either the GPL or the CDDL or both.
31"""
32__version__ = "$Revision: 93115 $"
33
34
35from _winreg import HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS
36from _winreg import OpenKey, CloseKey, EnumKey, QueryInfoKey, EnumValue, DeleteValue, QueryValueEx
37from distutils.util import strtobool
38
39def reverse_bytes(hex_string):
40 """
41 This function reverses the order of bytes in the provided string.
42 Each byte is represented by two characters which are reversed as well.
43 """
44 #print 'reverse_bytes(' + hex_string + ')'
45 chars = len(hex_string)
46 if chars > 2:
47 return reverse_bytes(hex_string[chars/2:]) + reverse_bytes(hex_string[:chars/2])
48 else:
49 return hex_string[1] + hex_string[0]
50
51def transpose_guid(guid):
52 """
53 Windows Installer uses different way to present GUID string. This function converts GUID
54 from installer's presentation to more conventional form.
55 """
56 return '{' + reverse_bytes(guid[0:8]) + '-' + reverse_bytes(guid[8:12]) + \
57 '-' + reverse_bytes(guid[12:16]) + \
58 '-' + reverse_bytes(guid[16:18]) + reverse_bytes(guid[18:20]) + \
59 '-' + ''.join([reverse_bytes(guid[i:i+2]) for i in range(20, 32, 2)]) + '}'
60
61PRODUCTS_KEY = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products'
62COMPONENTS_KEY = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components'
63
64def get_installed_products():
65 """
66 Enumerate all installed products.
67 """
68 products = {}
69 hkey_products = OpenKey(HKEY_LOCAL_MACHINE, PRODUCTS_KEY, 0, KEY_ALL_ACCESS)
70
71 try:
72 product_index = 0
73 while True:
74 product_guid = EnumKey(hkey_products, product_index)
75 hkey_product_properties = OpenKey(hkey_products, product_guid + r'\InstallProperties', 0, KEY_ALL_ACCESS)
76 try:
77 value = QueryValueEx(hkey_product_properties, 'DisplayName')[0]
78 except WindowsError as oXcpt:
79 if oXcpt.winerror != 2:
80 raise
81 value = '<unknown>'
82 CloseKey(hkey_product_properties)
83 products[product_guid] = value
84 product_index += 1
85 except WindowsError as oXcpt:
86 if oXcpt.winerror != 259:
87 print(oXcpt.strerror + '.', 'error', oXcpt.winerror)
88 CloseKey(hkey_products)
89
90 print('Installed products:')
91 for product_key in sorted(products.keys()):
92 print(transpose_guid(product_key), '=', products[product_key])
93
94 print()
95 return products
96
97def get_missing_products(hkey_components):
98 """
99 Detect references to missing products.
100 """
101 products = get_installed_products()
102
103 missing_products = {}
104
105 for component_index in xrange(0, QueryInfoKey(hkey_components)[0]):
106 component_guid = EnumKey(hkey_components, component_index)
107 hkey_component = OpenKey(hkey_components, component_guid, 0, KEY_ALL_ACCESS)
108 clients = []
109 for value_index in xrange(0, QueryInfoKey(hkey_component)[1]):
110 client_guid, client_path = EnumValue(hkey_component, value_index)[:2]
111 clients.append((client_guid, client_path))
112 if not client_guid in products:
113 if client_guid in missing_products:
114 missing_products[client_guid].append((component_guid, client_path))
115 else:
116 missing_products[client_guid] = [(component_guid, client_path)]
117 CloseKey(hkey_component)
118 return missing_products
119
120def main():
121 """
122 Enumerate all installed products, go through all components and check if client refences
123 point to valid products. Remove references to non-existing products if the user allowed it.
124 """
125 hkey_components = OpenKey(HKEY_LOCAL_MACHINE, COMPONENTS_KEY, 0, KEY_ALL_ACCESS)
126
127 missing_products = get_missing_products(hkey_components)
128
129 print('Missing products refer the following components:')
130 for product_guid in sorted(missing_products.keys()):
131 if product_guid[1:] == '0'*31:
132 continue
133 print('Product', transpose_guid(product_guid) + ':')
134 for component_guid, component_file in missing_products[product_guid]:
135 print(' ' + transpose_guid(component_guid), '=', component_file)
136
137 print('Remove all references to product', transpose_guid(product_guid) + '? [y/n]')
138 if strtobool(raw_input().lower()):
139 for component_guid, component_file in missing_products[product_guid]:
140 hkey_component = OpenKey(hkey_components, component_guid, 0, KEY_ALL_ACCESS)
141 print('Removing reference in ' + transpose_guid(component_guid), '=', component_file)
142 DeleteValue(hkey_component, product_guid)
143 CloseKey(hkey_component)
144 else:
145 print('Cancelled removal of product', transpose_guid(product_guid))
146
147 CloseKey(hkey_components)
148
149if __name__ == "__main__":
150 main()
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette