Perl code to read and print the folder permissions on regkeys


Can someone please help to write Perl code that fetches values from registry keys and also prints what permissions different users of system have on those keys?


Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

See the python docs on  _winreg  ( for accessing the registry.

I couldn't find any examples of reading the security settings so went ahead and wrote one up.  Basically, boils down to using the win32api module to make a windows api call to RegGetKeySecurity, using the winsecurity module to get the DACL, and finally enumerating over the access control entries.  Both win32api and win32security are part of the pywin32  extensions (

Anyway... here's an example of both reading from the registry and listing the permissions on a key:

import win32api
import win32security
import _winreg

class Ace(object):
    ace_flags = {win32security.CONTAINER_INHERIT_ACE: 'Container Inherit',
                 win32security.FAILED_ACCESS_ACE_FLAG: 'Failed Access',
                 win32security.INHERIT_ONLY_ACE: 'Inherit only',
                 win32security.INHERITED_ACE: 'Inherited ACE',
                 win32security.NO_PROPAGATE_INHERIT_ACE: 'No propagate',
                 win32security.OBJECT_INHERIT_ACE: 'Object inherit',
                 win32security.SUCCESSFUL_ACCESS_ACE_FLAG: 'Successful access'}
    def __init__(self, ace):
        self.ace = ace
        ( (self.access_type, self.flags), self.mask, self.pysid) = ace

    def getType(self):
        if self.access_type == win32security.ACCESS_ALLOWED_ACE_TYPE:
            return "Allow"
        if self.access_type == win32security.ACCESS_DENIED_ACE_TYPE:
            return "Deny"

    def getFlags(self):
        readable_flags = list()
        for (f, v) in self.ace_flags.items():
            if f & self.flags == f:
        return readable_flags
class RegKey(object):

    registry_rights = {_winreg.KEY_ALL_ACCESS: 'All Access',
                      _winreg.KEY_WRITE: 'Write',
                      _winreg.KEY_READ: 'Read',
                      _winreg.KEY_EXECUTE: 'Read',
                      _winreg.KEY_QUERY_VALUE: 'Query value',
                      _winreg.KEY_SET_VALUE: 'Set value',
                      _winreg.KEY_CREATE_SUB_KEY: 'Create subkey',
                      _winreg.KEY_ENUMERATE_SUB_KEYS: 'Enum subkeys',
                      _winreg.KEY_NOTIFY: 'Request notification',
                      _winreg.KEY_CREATE_LINK: 'Link (reserved)' }
    def __init__(self, key_path, machine=None, root=winreg.HKEY_LOCAL_MACHINE):
        self.registry = _winreg.ConnectRegistry(None, root)
        self.key_path = key_path
        self.key = _winreg.OpenKey(self.registry, key_path) = win32api.RegGetKeySecurity(self.key.handle, win32security.DACL_SECURITY_INFORMATION)
        self.dacl =
        self.aces = list()
        for i in range(self.dacl.GetAceCount()):

    def dump_values(self):
        (subkey_count, value_count, last_modified) = _winreg.QueryInfoKey(self.key)
        print "Values:"
        for i in range(value_count):
            (name, data, value_type) = _winreg.EnumValue(self.key, i)
            print "\t{0}: {1}".format(name, data)

    def dump_subkeys(self):
        (subkey_count, value_count, last_modified) = _winreg.QueryInfoKey(self.key)
        print "Subkeys:"
        for i in range(subkey_count):
           print "\t{0}".format(_winreg.EnumKey(self.key, i))

    def dump_ace(self, ace):
        print "Ace: {0}".format(ace.ace)
        print " Type: {0}".format(ace.getType())
        print " Flags: {0}".format(", ".join(ace.getFlags()))  
        account = win32security.LookupAccountSid(None, ace.pysid);
        print " Account: {0}\{1}".format(account[1], account[0])
        print " Access:"
        if ace.mask & _winreg.KEY_ALL_ACCESS == _winreg.KEY_ALL_ACCESS:
            print "\t{0}".format(self.registry_rights[_winreg.KEY_ALL_ACCESS])
            for (p, v) in self.registry_rights.items():
                if p & ace.mask == p:
                   print "\t{0}".format(v)
    def dump_dacl(self):
        for ace in self.aces:
if __name__ == '__main__':
    r = RegKey(r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",

Open in new window

Crap.  Sorry about that.  I could've sworn this was in the python section.  But just noticed you wanted perl.  Obviously not getting enough sleep.  I'll see about throwing together a perl version.
I knew I wasn't completely crazy.  You did ask about it in python:

Anyway... bored and there's nothing much on TV so I'll throw together a perl version too.
Here's a perl version.
use Win32::TieRegistry (Delimiter=>"/",

use Win32::API;

Win32::API::Struct->typedef('ACL_SIZE_INFORMATION', qw (
	DWORD AceCount;
	DWORD AclBytesInUse;
	DWORD AclBytesFree;
Win32::API::Struct->typedef('ACE', qw (
	BYTE AceType;
	BYTE AceFlags;
	WORD AceSize;
	DWORD AccessMask;
	LPDWORD pAccessMask;
	DWORD SidStart;

Win32::API::More->Import("advapi32", "BOOL GetSecurityDescriptorDacl(LPVOID pSecurityDescriptor, LPBOOL lpbDaclPresent, LPVOID pDacl, LPBOOL lpbDaclDefaulted)");
Win32::API::More->Import("advapi32", "BOOL GetAclInformation(DWORD pAcl, LPACL_SIZE_INFORMATION pAclInfo, DWORD nAclInfoLen, DWORD dwAclInfoClass)");
Win32::API::More->Import("advapi32", "BOOL GetAce(DWORD pAcl, DWORD dwAceIndex, LPVOID ppAce)");
Win32::API::More->Import("advapi32", "BOOL LookupAccountSid(DWORD lpSystemName, DWORD lpSid, LPTSTR lpName, LPDWORD cchName, LPTSTR lpReferencedDomainName, LPDWORD cchReferencedDomainName, LPDWORD peUse)");
Win32::API::More->Import("advapi32", "BOOL ConvertSidToStringSid(DWORD Sid, LPVOID ppStringSid)");

sub DumpSubKeys {
   my $key = shift;
   print "Subkeys:\n";
   for (keys(%{$key})) {
      print "\t$_\n" unless m#^/#;

sub DumpValues {
   my $key = shift;
   print "Values:\n";
   for (keys(%{$key})) {
       $value = $key->{$_};
       print "\t$_ => $value\n" if m#^/#;

sub DumpACL {

   my %access_map = (
	KEY_ALL_ACCESS, "All access",
	KEY_WRITE, "Write",
	KEY_READ, "Read",
	KEY_EXECUTE, "Execute",
	KEY_SET_VALUE, "Set value",
	KEY_CREATE_SUB_KEY, "Create subkey",
	KEY_ENUMERATE_SUB_KEYS, "Enum subkeys",
	KEY_NOTIFY, "Notify",
	KEY_CREATE_LINK, "Create link" );
   my $key = shift;
   my $pSecurityDescriptor = 0;
   $key->RegGetKeySecurity(DACL_SECURITY_INFORMATION, $pSecurityDescriptor);

   my $pPresent = 0;
   my $pDACL = pack "L", 0;
   my $pDefaulted = 0;
   if (GetSecurityDescriptorDacl($pSecurityDescriptor, $pPresent, $pDACL, $pDefaulted)) {
      $pDACL = unpack "L", $pDACL;

      my $pInfo = Win32::API::Struct->new('ACL_SIZE_INFORMATION');
      $pInfo->{'AceCount'} = 0;
      $pInfo->{'AclBytesInUse'} = 0;
      $pInfo->{'AclBytesFree'} = 0;

      if (GetAclInformation($pDACL, $pInfo, $pInfo->sizeof, 2)) {
         for (my $i=0; $i < $pInfo->{AceCount}; $i++) {
             my $pAce = Win32::API::Struct->new('ACE');
             $pAce->{AceType} = 0;
             $pAce->{AceFlags} = 0;
             $pAce->{AceSize} = 0;
             $pAce->{AccessMask} = 0;
             $pAce->{pAccessMask} = 0;
             $pAce->{SidStart} = 0;

             my $ppAce = pack "L", 0;
             if (GetAce($pDACL, $i, $ppAce)) {
                 $ppAce = unpack "L", $ppAce;

                 print " Type: $pAce->{'AceType'}\n";
                 print " Flags: $pAce->{'AceFlags'}\n";
                 print " Mask: $pAce->{'AccessMask'}\n";

                 my $name = " " x 260; 
		 my $lName = length($name);
                 my $domainName = " " x 260;
                 my $ldomainName = length($domainName);
                 my $peUse = 0;
                 if (LookupAccountSid(0, $ppAce + 8, $name, $lName, $domainName, $ldomainName, $peUse)) {
                    $domainName =~ s/\x00.*//;
                    $name =~ s/\x00.*//;
                    print " Account: $domainName\\$name\n";
                 else {
                    print "LookupAccountSid Error = $^E\n";

                 print " Access:\n";
                 for my $k (keys(%access_map)) {
                     print "\t$access_map{$k}\n" if ($k & $pAce->{'AccessMask'}) == $k;

             else {
                 print $^E;

my $key = $Registry->{"CUser/Software/Microsoft/Windows/CurrentVersion/Internet Settings"};

Open in new window


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.