jimbobmcgee
jimbobmcgee

Reputation: 1721

Changing ACL of registry key, editing a value, then changing it back

I have a Powershell script which changes a registry value that is usually owned by TrustedInstaller. The basic workflow is:

  1. Try to open the key for editing

    1. If this fails, try to open the key for permissions

      1. If this fails, try to open the key for taking ownership
      2. Backup the ACL with if ($backupAcl -eq $null) { $backupAcl = $key.GetAccessControl(); }
      3. Get a working copy of the ACL with $acl = $key.GetAccessControl();
      4. Set the owner with $acl.SetOwner($me);
      5. Open the key for permissions changes
    2. Backup the ACL with if ($backupAcl -eq $null) { $backupAcl = $key.GetAccessControl(); }

    3. Get a working copy of the ACL with $acl = $key.GetAccessControl();
    4. Apply the permissions with $acl.AddAccessRule($rule); $acl.SetAccessControl($acl);
    5. Open the key for editing
  2. Change the values I need to change with $key.SetValue(...)

  3. Revert any changes to permissions made earlier.

The code I am using to revert the permissions is as follows:

$key = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey($subKeyName, $regOpenMode, $regTakeOwnChangePerms);

Write-Host "Setting permissions to:"
Format-List -InputObject $aclBackup;

$key.SetAccessControl($aclBackup);

Write-Host "Permissions set to:"
Format-List -InputObject $key.GetAccessControl();

$key.Close();

...however, it never actually sets the ACL back to what it was.

Other than this, the script works fine -- the ACL is set to what it needs to be to change the values (so I know I can change the ACL) and the values themselves are changed (so I know I have changed the ACL).

But the reversion never takes. No exceptions are raised -- it just never takes.

Why not? And how can I revert the ACL to what it was when the script started?

Upvotes: 2

Views: 1993

Answers (2)

jimbobmcgee
jimbobmcgee

Reputation: 1721

I got it. It seems you cannot re-use ObjectSecurity objects in this fashion, so I had to serialize the backup ACL using the GetSecurityDescriptorBinaryForm() method and deserialize it back again using the SetSecurityDescriptorBinaryForm(...) method.

Once I had done that, though, I got another error - The security identifier is not allowed to be the owner of this object.

I had to overcome this by requesting the SeRestorePrivilege system privilege, which I did with the Enable-Privelege function from http://social.technet.microsoft.com/Forums/en/winserverpowershell/thread/e718a560-2908-4b91-ad42-d392e7f8f1ad (a function I was already using to request the SeTakeOwnershipPrivilege needed to take ownership in the first place).

Once I had this privilege, I could overwrite the ACL with the deserialized one I had in my cache.

So, to backup the ACL:

if ($aclBackup -eq $null) { 
    $aclBackup = $key.GetAccessControl().GetSecurityDescriptorBinaryForm(); 
}

And to restore it:

if (Enable-Privilege SeRestorePrivilege) {
    $acl = New-Object System.Security.AccessControl.RegistrySecurity;
    $acl.SetSecurityDescriptorBinaryForm($aclBackup, $aclIncludeAll);

    $key = $keyRoot.OpenSubKey($subKeyName, $regOpenMode, $regTakeOwnChangePerms);
    $key.SetAccessControl($acl);
    $key.Close();
}

Hopes this helps someone else in the future...

Upvotes: 1

Christopher Douglas
Christopher Douglas

Reputation: 1550

Since you're making modifications to an object in memory you will need to use the command Set-ACL to effect the change down to the actual file ACL.

Using Get ACL will read the access list from a registry key. I do not think you need this line.

$key = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey($subKeyName, $regOpenMode, $regTakeOwnChangePerms);

Try

$ACLobject = Get-ACL -Path $RegKey
$ACLObject |Set-ACL -Path $newRegKey

In between that you can manipulate the properties of $ACLobject any way you like.

Upvotes: 0

Related Questions