Package platformids :: Package dist :: Module windows

Source Code for Module platformids.dist.windows

  1  # -*- coding: utf-8 -*- 
  2  """MS-Windows releases for the *WindowsNT* family based on the registry information. 
  3  This includes the IoT products, e.g. *Windows-NT-10.0-IoT-core* on the *RaspberryPi*. 
  4  """ 
  5  from __future__ import absolute_import 
  6  from __future__ import print_function 
  7   
  8  import os 
  9  import re 
 10   
 11  from platformids import _debug, _verbose 
 12  from platformids import RTE_NT, RTE_WIN, RTE_WINDOWS, \ 
 13      rte2num, num2rte, num2pretty, \ 
 14      decode_version_str_to_segments, \ 
 15      PlatformIDsError, PlatformIDsFileCheck 
 16   
 17  __author__ = 'Arno-Can Uestuensoez' 
 18  __license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints" 
 19  __copyright__ = "Copyright (C) 2010-2018 Arno-Can Uestuensoez" \ 
 20                  " @Ingenieurbuero Arno-Can Uestuensoez" 
 21  __version__ = '0.1.29' 
 22  __uuid__ = "7add5ded-c39b-4b6e-8c87-1b3a1c150ee9" 
 23   
 24  __docformat__ = "restructuredtext en" 
 25   
 26  if __debug__: 
 27   
 28      # this is for unittests only 
29 - class PlatformIDsUnittestTriggered(PlatformIDsError):
30 pass
31 32 # 33 # The handled versions are of the "nt' technology, historic pre-versions and others 34 # are not supported. 35 # 36 # set: win32 37 # currently no sub-categories, some are contained in 38 # the 'set: generic': drives, shares 39 # 40 # 41 # RTE_DOS = RTE_WIN32 + 1 #: MS-DOS - frozen 42 43 # 44 # dist - the base versions of major and minor numbers 45 # 46 RTE_NT35 = RTE_NT + 0x001d0000 # : Windows NT-3.5 47 RTE_NT40 = RTE_NT + 0x00200000 # : Windows NT-4.0 48 RTE_NT50 = RTE_NT + 0x00280000 # : Windows NT-5.0 - W2000 49 RTE_NT51 = RTE_NT + 0x00290000 # : Windows NT-5.1 - WXP - 32bit 50 RTE_NT52 = RTE_NT + 0x002a0000 # : Windows NT-5.2 - W2003 / 2003 / 2003R2 51 RTE_NT60 = RTE_NT + 0x00300000 # : Windows NT-6.0 - vista / 2008 52 RTE_NT61 = RTE_NT + 0x00310000 # : Windows NT-6.1 - win7 / 2008R2 53 RTE_NT62 = RTE_NT + 0x00320000 # : Windows NT-6.2 - win8 / 2012 54 RTE_NT63 = RTE_NT + 0x00330000 # : Windows NT-6.3 - win8.1 / 2012R2 55 RTE_NT100 = RTE_NT + 0x00500000 # : Windows NT-10.0 - win10 / 2016 56 57 # 58 # distrel - some predefined constant values of the complete versions 59 # 60 # the values could be easily calculated dynamically by 61 # old-scheme: adding the build number 62 # new-scheme: adding the date based product version 63 # 64 # frozen history 65 # 66 RTE_WINNT35 = RTE_NT35 + 807 # : WindowsNT-4.0 Workstation - 32bit 67 RTE_WINNT40 = RTE_NT40 + 1381 # : WindowsNT-4.0 Workstation - 32bit 68 RTE_WIN2000 = RTE_NT50 + 2195 # : Windows2000 69 70 RTE_WINXP = RTE_NT51 + 2600 # : WindowsXP - 32bit 71 72 RTE_WINXP64 = RTE_NT52 + 3790 # : WindowsXP - 64bit 73 RTE_WIN2003 = RTE_NT52 + 3790 # : Windows2003 74 RTE_WIN2003R2 = RTE_NT52 + 3790 # : Windows2003R2 - exception: same build as 2003 75 76 RTE_WIN2008 = RTE_NT60 + 6001 # : Windows2008 RTM 77 RTE_WIN2008SP2 = RTE_NT60 + 6002 # : Windows2008 SP1 78 79 RTE_WIN7 = RTE_NT61 + 7600 # : Windows7 80 RTE_WIN2008R2 = RTE_NT61 + 7600 # : Windows2008R2 81 82 RTE_WIN7SP1 = RTE_NT61 + 7601 # : Windows7 SP1 83 RTE_WIN2008R2SP1 = RTE_NT61 + 7601 # : Windows2008R2 SP1 84 85 RTE_WIN8 = RTE_NT62 + 9200 # : Windows8 86 RTE_WIN2012 = RTE_NT62 + 9200 # : Windows2012 87 88 RTE_WIN81 = RTE_NT63 + 9600 # : Windows81 89 RTE_WIN2012R2 = RTE_NT63 + 9600 # : Windows2012R2 90 91 # 92 # for generic NT-10.0 releases 93 # simply add the numeric version to the base value RTE_NT100 94 # 95 # RTE_WINNT100_1703 = RTE_NT100 + 1703 #: NT-10.0 - 2017.03 96 # RTE_WINNT100_1803 = RTE_NT100 + 1803 #: NT-10.0 - 2018.03 97 # RTE_WINNT100_1809 = RTE_NT100 + 1809 #: NT-10.0 - 2018.09 98 99 # : mapping of the rte string and numeric representation to the numeric value 100 rte2num.update( 101 { 102 '7 Server': RTE_WIN2008R2, 103 '7': RTE_WIN7, 104 '8 Server': RTE_WIN2012, 105 '8': RTE_WIN8, 106 'Blackcomb': RTE_WIN7, 107 'Blue Server': RTE_WIN2012R2, 108 'Blue': RTE_WIN81, 109 'Longhorn Server' : RTE_NT61 + 6002, # W2008 SP2 110 'Threshold 1': RTE_NT100 + 1507, 111 'Threshold 2': RTE_NT100 + 1511, 112 'Redstone 1': RTE_NT100 + 1607, 113 'Redstone 2': RTE_NT100 + 1703, 114 'Redstone 3': RTE_NT100 + 1709, 115 'Redstone 4': RTE_NT100 + 1803, 116 'Redstone 5': RTE_NT100 + 1809, 117 'Vienna': RTE_WIN7, 118 'winxp': RTE_WINXP, 119 'win2000': RTE_WIN2000, 120 'winnt40': RTE_WINNT40, 121 'win10': RTE_NT100, 122 'win7': RTE_WIN7, 123 'win8': RTE_WIN8, 124 'win81': RTE_WIN81, 125 'win2008': RTE_WIN2008, 126 'win2008r2': RTE_WIN2008R2, 127 'win2012': RTE_WIN2012, 128 'win2012r2': RTE_WIN2012R2, 129 'win2016': RTE_NT100, 130 'win2019': RTE_NT100, 131 'win2019se': RTE_NT100, 132 RTE_WIN2000: RTE_WIN2000, 133 RTE_WIN2008: RTE_WIN2008, 134 RTE_WIN2008R2: RTE_WIN2008R2, 135 RTE_WIN2012: RTE_WIN2012, 136 RTE_WIN2012R2: RTE_WIN2012R2, 137 RTE_WIN7: RTE_WIN7, 138 RTE_WIN81: RTE_WIN81, 139 RTE_WIN8: RTE_WIN8, 140 RTE_WINNT40: RTE_WINNT40, 141 RTE_WINXP: RTE_WINXP, 142 143 'nt40': RTE_NT40, 144 145 'nt50': RTE_NT50, 146 'nt51': RTE_NT51, 147 'nt52': RTE_NT52, 148 149 'nt60': RTE_NT60, 150 'nt61': RTE_NT61, 151 'nt62': RTE_NT62, 152 'nt63': RTE_NT63, 153 'nt100': RTE_NT100, 154 155 RTE_NT40: RTE_NT40, 156 157 RTE_NT50: RTE_NT50, 158 RTE_NT51: RTE_NT51, 159 RTE_NT52: RTE_NT52, 160 161 RTE_NT60: RTE_NT60, 162 RTE_NT61: RTE_NT61, 163 RTE_NT62: RTE_NT62, 164 RTE_NT63: RTE_NT63, 165 RTE_NT100: RTE_NT100, 166 167 } 168 ) 169 170 # : mapping of the rte numeric representation to the string value 171 num2rte.update( 172 { 173 # RTE_WINNT40: 'winnt40', 174 # RTE_WIN2000: 'win2000', 175 # RTE_WINXP: 'winxp', 176 # RTE_WIN7: 'win7', 177 # RTE_WIN81: 'win81', 178 # RTE_WIN8: 'win8', 179 # RTE_WIN2008: 'win2008', 180 # RTE_WIN2008R2: 'win2008r2', # the release is actually a different NT 181 # RTE_WIN2012: 'win2012', 182 # RTE_WIN2012R2: 'win2012r2', 183 184 RTE_WINNT40: 'nt401381', 185 RTE_WIN2000: 'nt502195', 186 RTE_WINXP: 'nt512600', 187 RTE_WIN7: 'nt617601', 188 RTE_WIN81: 'nt639600', 189 RTE_WIN8: 'nt629200', 190 RTE_WIN2008: 'nt606002', 191 RTE_WIN2008R2: 'nt617601', # the release is actually a different NT 192 RTE_WIN2012: 'nt629200', 193 RTE_WIN2012R2: 'nt639600', 194 195 RTE_NT40: 'nt40', 196 RTE_NT50: 'nt50', 197 RTE_NT51: 'nt51', 198 RTE_NT52: 'nt52', 199 RTE_NT60: 'nt60', 200 RTE_NT61: 'nt61', 201 RTE_NT62: 'nt62', 202 RTE_NT63: 'nt63', 203 RTE_NT100: 'nt100', 204 205 } 206 ) 207 208 # : mapping of the rte numeric representation to the pretty string value 209 num2pretty.update( 210 { 211 RTE_WIN: 'Windows', 212 RTE_WINDOWS: 'Windows', 213 214 RTE_WIN2000: 'Windows 2000', 215 RTE_WIN2008: 'Windows Server 2008', 216 RTE_WIN2008R2: 'Windows Server 2008R2', 217 RTE_WIN2012: 'Windows Server 2012', 218 RTE_WIN2012R2: 'Windows Server 2012R2', 219 RTE_WIN7: 'Windows 7', 220 RTE_WIN81: 'Windows 8.1', 221 RTE_WIN8: 'Windows 8', 222 RTE_WINNT40: 'WindowsNT-4.0', 223 RTE_WINXP: 'Windows XP', 224 225 RTE_NT40: 'NT-4.0', 226 227 RTE_NT50: 'NT-5.0', 228 RTE_NT51: 'NT-5.1', 229 RTE_NT52: 'NT-5.2', 230 231 RTE_NT60: 'NT-6.0', 232 RTE_NT61: 'NT-6.1', 233 RTE_NT62: 'NT-6.2', 234 RTE_NT63: 'NT-6.3', 235 RTE_NT100: 'NT-10.0', 236 237 } 238 ) 239 240 versions = { 241 RTE_WINNT40: '4.0.1381', 242 RTE_WIN2000: '5.0.2195', 243 RTE_WINXP: '5.1.2600', 244 RTE_WIN7: '6.1.7601', 245 RTE_WIN81: '6.3.9600', 246 RTE_WIN8: '6.2.9200', 247 248 RTE_WIN2008: '6.0.6002', 249 RTE_WIN2008R2: '6.1.7601', 250 RTE_WIN2012: '6.2.9200', 251 RTE_WIN2012R2: '6.3.9600', 252 253 RTE_NT40: '4.0', 254 255 RTE_NT50: '5.0', 256 RTE_NT51: '5.1', 257 RTE_NT52: '5.2', 258 259 RTE_NT60: '6.0', 260 RTE_NT61: '6.1', 261 RTE_NT62: '6.2', 262 RTE_NT63: '6.3', 263 RTE_NT100: '10.0', 264 265 } 266 267 # 268 # Microsoft: OSVERSIONINFOEXA.wProductType 269 # 270 VER_NT_GENERIC = 0x0000000 # : non standard enum 271 272 VER_NT_WORKSTATION = 0x0000001 # : see wProductType 273 VER_NT_DOMAIN_CONTROLLER = 0x0000002 # : see wProductType 274 VER_NT_SERVER = 0x0000003 # : see wProductType 275 276 VER_NT_IOT = 0x0000004 # : non standard enum 277 278
279 -class WinVersion(object):
280
281 - def __init__(self, *args, **kargs):
282 283 self.ntmajor = self.ntminor = self.release = self.build = 0 284 self.editionid = self.installationtype = self.sourcepath = self.productname = '' 285 self.productcategory = VER_NT_GENERIC # 0x0000000 #: non standard enum 286 self.sp = self.ubr = None 287 288 self.raw = {} 289 self.fetch_current_version_raw() 290 291 pass # 4debugging
292
293 - def fetch_current_version_raw(self, **kargs):
294 295 use_nt_native = kargs.get('usetest', 255) # : for unittests only 296 297 if os.name == 'java': 298 # it is Jython - use Java for access to native system data 299 300 try: 301 if __debug__: 302 # this is for unittests only 303 if (use_nt_native & 1) == 0: 304 raise PlatformIDsUnittestTriggered('use_nt_native_1(%d)' % (use_nt_native) ) 305 306 # 307 # 1. try JNA 308 if _verbose: 309 print("VERB:platformids:scan:try:JNA:jy.platformids.dist.nt.Kernel32GetProductInfo") 310 from jy.platformids.dist.nt import Kernel32GetProductInfo # @UnresolvedImport 311 312 if _verbose: 313 print("VERB:platformids:scan:try:JNA:jy.platformids.dist.nt.Advapi32GetCurrentVersion") 314 from jy.platformids.dist.nt import Advapi32GetCurrentVersion # @UnresolvedImport 315 316 if _verbose: 317 print("VERB:platformids:scan:JNA:LOADED") 318 319 currentversion = Advapi32GetCurrentVersion().getCurrentVersionValues() 320 for k, v in currentversion.items(): 321 self.raw[k] = v 322 323 except Exception as e: 324 if _debug: 325 print("VERB:platformids:scan:JNA:failed with:" + str(e)) 326 327 try: 328 if __debug__: 329 # this is for unittests only 330 if (use_nt_native & 2) == 0: 331 raise PlatformIDsUnittestTriggered('use_nt_native_2(%d)' % (use_nt_native) ) 332 333 # 334 # 2. try java.util.WindowsPreferences... 335 # 336 if _verbose: 337 print("VERB:platformids:scan:try:WindowsPreferences:jy.platformids.dist.nt.ReadCurrentVersionWinPrefs") 338 from jy.platformids.dist.nt import ReadCurrentVersionWinPrefs # @UnresolvedImport 339 340 if _verbose: 341 print("VERB:platformids:scan:WindowsPreferences:LOADED") 342 343 currentversion = ReadCurrentVersionWinPrefs() 344 for k, v in currentversion: 345 self.raw[k] = v 346 347 except Exception as e: 348 if _debug: 349 print("VERB:platformids:scan:WindowsPreferences:failed with:" + str(e)) 350 351 # 352 # 4. try JNI next... coming soon 353 # 354 355 try: 356 if __debug__: 357 # this is for unittests only 358 if (use_nt_native & 8) == 0: 359 raise PlatformIDsUnittestTriggered('use_nt_native_8(%d)' % (use_nt_native) ) 360 361 # 362 # 8. try REG.EXE next... 363 # 364 if _verbose: 365 print("VERB:platformids:scan:try:platformids.dist.nt.RegistryByExe") 366 from platformids.dist.nt.windows_subprocess_reg_exe import RegistryByExe # @UnresolvedImport 367 if _verbose: 368 print("VERB:platformids:scan:RegistryByExe:LOADED") 369 370 currentversion = RegistryByExe().read_CurrentVersion() 371 for k, v in currentversion.items(): 372 self.raw[k] = v 373 374 except: 375 if __debug__: 376 # this is for unittests only 377 if (use_nt_native & 16) == 0: 378 raise PlatformIDsUnittestTriggered('use_nt_native_16(%d)' % (use_nt_native) ) 379 380 # 381 # 16. try min-info 382 # 383 import platform 384 self.raw['ProductName'] = platform.System.getProperty('os.name').lower() # @UndefinedVariable # seems 2.0+ 385 self.raw['CurrentMajorVersionNumber'], self.raw['CurrentMajorVersionNumber'], self.raw['CurrentMajorVersionNumber'] = decode_version_str_to_segments( 386 platform.System.getProperty('os.version').lower()) # @UndefinedVariable 387 388 elif os.name == 'posix': 389 # for document generation by introspection on posix platform 390 # avoids exception with generator error for sphinx-apidoc 391 pass 392 393 else: 394 395 # 396 # read registry 397 # 398 399 # use standard libs _winreg / winreg 400 try: 401 import winreg # @UnresolvedImport @UnusedImport 402 validxError = WindowsError # @UndefinedVariable 403 except: 404 import _winreg as winreg # @UnresolvedImport @Reimport 405 validxError = OSError 406 407 hklm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) # @UndefinedVariable - win32 only 408 409 # rnumerate CurrentVersion attribute values 410 curvers_key = winreg.OpenKey(hklm, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion") # @UndefinedVariable - win32 only 411 for i in range(1024): 412 try: 413 n, v, t = winreg.EnumValue(curvers_key, i) # @UndefinedVariable - win32 only @UnusedVariable 414 self.raw[n] = v 415 except validxError: 416 break 417 418 winreg.CloseKey(curvers_key) # @UndefinedVariable - win32 only 419 420 # 421 # fetch product category 422 # 423 try: 424 # 425 # use API 426 # 427 428 # post winxp supports simple access to product type 429 from platformids.dist.nt.windows_kernel32dll import get_win32_OSProductInfo, get_win32_OSVersionInfoExa 430 from platformids.dist.nt.windows_products import prod_ext, prod_type_categories 431 432 osver = get_win32_OSVersionInfoExa() 433 pinfo = get_win32_OSProductInfo() 434 self.productcategory = pinfo.pdwReturnedProductType 435 436 # TODO: check it 437 if self.raw['InstallationType'].startswith('IoT'): 438 # superposes others if defined as IoT 439 self.productcategory = VER_NT_IOT 440 441 except: 442 # 443 # estimate by data - default is GENERIC 444 # 445 try: 446 if self.raw['InstallationType'].startswith('Client'): 447 self.productcategory = VER_NT_WORKSTATION 448 449 elif self.raw['InstallationType'].startswith('Server'): 450 self.productcategory = VER_NT_SERVER 451 452 elif self.raw['InstallationType'].startswith('IoT'): 453 self.productcategory = VER_NT_IOT 454 455 elif re.match(r'.*omain.*', self.raw['InstallationType'], flags=re.MULTILINE): # @UndefinedVariable 456 self.productcategory = VER_NT_DOMAIN_CONTROLLER 457 458 else: 459 # matches for almost all systems, which in nowadays 460 # could be used in multiple roles - without variation 461 self.productcategory = VER_NT_GENERIC 462 463 except: 464 self.productcategory = VER_NT_GENERIC # should already be from init 465 466 self.raw['productcategory'] = self.productcategory 467 468 return self.raw
469
470 - def readout_versioninfo_ext(self):
471 472 # 473 # Major-Minor-Version 474 # 475 try: 476 # >= Win10 477 self.ntmajor = int(self.raw['CurrentMajorVersionNumber']) # REG_SZ 17763 478 self.ntminor = int(self.raw['CurrentMinorVersionNumber']) # REG_DWORD 0xa 479 self.release = int(self.raw['ReleaseId']) # REG_SZ 1511 480 self.build = self.raw['CurrentBuildNumber'] # REG_DWORD 0x0 481 482 except KeyError: 483 # < Win10 484 try: 485 self.ntmajor, self.ntminor = self.raw['CurrentVersion'].split('.') # REG_SZ 6.3 486 self.ntmajor = int(self.ntmajor) 487 self.ntminor = int(self.ntminor) 488 except KeyError: 489 # ooops... 490 pass 491 492 try: 493 self.release = self.build = int(self.raw['CurrentBuildNumber']) # REG_DWORD 0x0 494 except: 495 pass 496 497 try: 498 # WinXP < x < Win10 499 self.sp = re.sub(r'^[^0-9]*', '', self.raw['CSDVersion']) # REG_SZ 500 self.sp = int(self.sp) 501 except KeyError: 502 pass 503 504 try: 505 self.ubr = int(self.raw['UBR']) # REG_DWORD 0x6b 506 except KeyError: 507 pass 508 509 try: 510 self.editionid = self.raw['EditionID'] # REG_SZ IoTUAP 511 except KeyError: 512 self.editionid = '' 513 514 try: 515 self.installationtype = self.raw['InstallationType'] # REG_SZ IoTUAP 516 except KeyError: 517 self.installationtype = '' 518 519 try: 520 # 521 # a weak criteria as the last resort, 522 # the installation source path with some encoding 523 # into the path name, e.g.: 524 # 525 # D:\GERMAN\WIN2000\SERVER\I386 526 # D:\GERMAN\WINXP\PRO\I386 527 # 528 self.sourcepath = self.raw['SourcePath'] # REG_SZ D:\GERMAN\WINXP\PRO\I386 529 self.sourcepath = re.sub(r'', r'', self.sourcepath) 530 except KeyError: 531 self.sourcepath = '' 532 533 try: 534 self.productname = self.raw['ProductName'] # REG_SZ IoTUAP 535 except: 536 pass 537 538 ret = { 539 "ntmajor": self.ntmajor, 540 "ntminor": self.ntminor, 541 "release": self.release, 542 543 "build": self.build, 544 545 "productcategory": self.productcategory, 546 547 "InstallationType": self.installationtype, 548 "ProductName": self.productname, 549 "EditionID": self.editionid 550 } 551 552 if self.sp != None: 553 ret["sp"] = self.sp 554 555 if self.ubr != None: 556 ret["ubr"] = self.ubr 557 558 return ret
559
560 - def readout_distribution(self):
561 562 self.readout_versioninfo_ext() 563 return [ 564 'nt%d%d%d' % (self.ntmajor, self.ntminor, self.release), 565 '%d.%d.%d' % (self.ntmajor, self.ntminor, self.release), 566 'NT-%d.%d.%d' % (self.ntmajor, self.ntminor, self.release), 567 'NT', 568 (self.ntmajor, self.ntminor, self.release), 569 'nt' 570 ]
571
572 - def __str__(self):
573 try: 574 res = '' 575 res += "ntmajor = %s\n" % (str(self.ntmajor)) 576 res += "ntminor = %s\n" % (str(self.ntminor)) 577 res += "release = %s\n" % (str(self.release)) 578 res += "build = %s\n" % (str(self.build)) 579 580 res += "productcategory = %s\n" % (str(self.productcategory)) 581 582 try: 583 res += "sp = %s\n" % (str(self.sp)) 584 except AttributeError: 585 res += "ubr = %s\n" % (str(self.ubr)) 586 587 res += "InstallationType = %s\n" % (str(self.installationtype)) 588 res += "EditionID = %s\n" % (str(self.editionid)) 589 res += "ProductName = %s\n" % (str(self.productname)) 590 591 return res 592 except: 593 594 return
595
596 - def __repr__(self):
597 try: 598 res = "{" 599 res += "ntmajor: %s, " % (str(self.ntmajor)) 600 res += "ntminor: %s, " % (str(self.ntminor)) 601 res += "release: %s, " % (str(self.release)) 602 res += "build: %s, " % (str(self.build)) 603 604 res += "productcategory: %s, " % (str(self.productcategory)) 605 606 try: 607 res += "sp: %s, " % (str(self.sp)) 608 except AttributeError: 609 res += "ubr: %s, " % (str(self.ubr)) 610 611 res += "InstallationType: %s, " % (str(self.installationtype)) 612 res += "EditionID: %s, " % (str(self.editionid)) 613 res += "ProductName: %s, " % (str(self.productname)) 614 res += "}" 615 616 return res 617 618 except: 619 return
620 621 dist = ['', '', '', 'NT', '', ''] 622 623 try: 624 WINVERSION = WinVersion() 625 WINVERSION.fetch_current_version_raw() 626 dist = WINVERSION.readout_distribution() 627 628 except PlatformIDsFileCheck: 629 # not on MS-Windows platform, so scan will fail 630 pass 631 632 633 if dist[5] != 'nt': 634 # does not actually match MS-Windows 635 dist = ['nt', '0.0.0', 'NT-0.0.0', 'NT', (0, 0, 0,), 'nt'] 636 637 638 if __name__ == "__main__": 639 winv = WinVersion() 640 vinfo = winv.readout_versioninfo_ext() 641 print(vinfo) 642