@python -x %~f0 %* & goto :EOF

#
# regtime.py
#
# get last modified time of a registry key
#
#

import sys
import re
import time
import string
import winerror
import win32api
import win32con
import pywintypes

from win32api import *
from win32con import *

EXIT_SUCCESS = 0
EXIT_FAILURE = 1


HELP_MESSAGE = \
'''\
Registry scan tool - check for registry corruption.
       

Usage: Regscan <key>

       <key>                   \tRegistry key path.
                               \t To specify the hive, use:
                               \t      HKLM or HKEY_LOCAL_MACHINE
                               \t      HKCU or HKEY_CURRENT_USER
                               \t      HKU  or HKEY_USERS
                               \t      HKCR or HKEY_CLASSES_ROOT
                               \t Example:
                               \t      Regscan HKLM\System\CurrentControlSet
       -? -h -help             \tHelp screen.
'''


def main():
    
    # command line arg is fully qualified key
    keypath = GetArgs()

    # strip leading backslash if present
    if keypath[0] == '\\':
	keypath = keypath[1:]

    # check for standard root keys
    if (string.find( string.upper(keypath), 'HKEY_LOCAL_MACHINE' ) == 0) or (string.find( string.upper(keypath), 'HKLM' ) == 0):
        rootkey = HKEY_LOCAL_MACHINE
    elif (string.find( string.upper(keypath), 'HKEY_CLASSES_ROOT' ) == 0) or (string.find( string.upper(keypath), 'HKCR' ) == 0):
        rootkey = HKEY_CLASSES_ROOT
    elif (string.find( string.upper(keypath), 'HKEY_USERS' ) == 0) or (string.find( string.upper(keypath), 'HKU' ) == 0):
        rootkey = HKEY_USERS
    elif (string.find( string.upper(keypath), 'HKEY_CURRENT_USER' ) == 0) or (string.find( string.upper(keypath), 'HKCU' ) == 0):
        rootkey = HKEY_CURRENT_USER
    elif (string.find( string.upper(keypath), 'HKEY_CURRENT_CONFIG' ) == 0): # who ever uses this???
        rootkey = HKEY_CURRENT_CONFIG

    pos = string.find( keypath, '\\' )
    if (pos>0):
        subkey = keypath[pos+1:]
    else:
        subkey = ''
    countFailures = EnumerateKeys( rootkey, subkey )
    print 'There were %s error(s).' % str(countFailures)


def GetArgs():

    argc = len( sys.argv )
    i = 1
    while i < argc:
        arg = sys.argv[i]
        argUC = string.upper( arg )
        if argUC in [ '-?', '-H', '-HELP' ]:
            PrintUsageAndExit()
        else:
            return arg
        i = i + 1
    PrintUsageAndExit()


def EnumerateKeys( rootKey, subKey ):
    if ( string.find (subKey,'\\',1,1)):
        subKey = re.sub('^\\\\','',subKey)

    countFailures = 0
    reg = Registry( )
    hKey = reg.OpenKeyForRead( rootKey, subKey )

    if (hKey):
        countFailures = countFailures + reg.EnumerateValues ( hKey, subKey )
        numKeys, numVals, modTime = reg.QueryInfoKey (hKey)
        if (numKeys):
            lastKey = ''
            for i in range( numKeys ):
                thisKey = reg.EnumKey( hKey, i )
                if (thisKey):
                    x = reg.OpenKeyForRead( hKey, thisKey )
                    if (x):
                        a, b, t = reg.QueryInfoKey( x )
                        countFailures = countFailures + EnumerateKeys( rootKey, subKey + '\\' + thisKey ) 
                        RegCloseKey(x)
                    else:
                        countFailures = countFailures + 1
                        print 'Failed to open subkey: ' + subKey + '\\' + thisKey
                        print
                else:
                    countFailures = countFailures + 1
                    print 'Failed to enumerate key: ' + subKey + ' at offset: ' + str(i) 
                    print
    else:
        countFailures = countFailures + 1
        print 'Failed to open key: '+ subKey
        print
    return countFailures


class Registry:
    def __init__( self ):
      None

    def OpenKeyForRead( self, hKey, thisKey ):
      try:
        x = win32api.RegOpenKey( hKey, thisKey, 0, KEY_READ )
        return x
      except:
        errorType, errorValue = sys.exc_info()[:2]
        print 'Error: %s %s'  % ( str(errorType), str(errorValue) )

    def EnumerateValues( self, hKey, subKey ):
        numKeys, numVals, modTime = self.QueryInfoKey ( hKey )
        lastK = ''
        countFailures = 0
        for j in range ( numVals ):
            ( k, l, m ) = self.EnumValue( hKey, j, subKey )
            if k == l == m == '':
                print 'Failed to enumerate values in: %s at offset: %s' % ( subKey, str(j) )
                print 'Previous value was: %s' % lastK
                print
                countFailures = countFailures + 1
            else:
                lastK = k
        return countFailures

    def EnumKey ( self, hKey, i ):
      try:
        thisKey = win32api.RegEnumKey( hKey, i )
        return thisKey
      except:
        errorType, errorValue = sys.exc_info()[:2]
        print 'Error: %s %s'  % ( str(errorType), str(errorValue) )
        return

    def QueryInfoKey( self, hKey ):
      try:
        a, b, t = win32api.RegQueryInfoKey( hKey )
        return a, b, t
      except:
        errorType, errorValue = sys.exc_info()[:2]
        print 'Error: %s %s'  % ( str(errorType), str(errorValue) )
        return '', '', ''

    def EnumValue( self, hKey, j, subKey ):
      try:
        ( k, l, m ) = win32api.RegEnumValue( hKey, j)
        return k, l, m
      except:
        errorType, errorValue = sys.exc_info()[:2]
        print 'Error: %s %s'  % ( str(errorType), str(errorValue) )
        return '','',''
    
    def QueryValue( self, hKey, j, subKey ):
      try:
        (k, l, m ) = win32api.RegQueryValue( hKey, j )
        return k, l, m
      except:
        errorType, errorValue = sys.exc_info()[:2]
        print 'Error: %s %s'  % ( str(errorType), str(errorValue) )
        return '','',''


def PrintUsageAndExit( errmsg='', exitcode=EXIT_SUCCESS ):
    if errmsg:
        print errmsg
        print
    print HELP_MESSAGE
    sys.exit( exitcode )


if __name__ == '__main__':
    main()
