Errors with class objects using get-acl to edit registry permissions

Tagged: 

This topic contains 11 replies, has 3 voices, and was last updated by Profile photo of Jack Neff Jack Neff 1 year, 8 months ago.

  • Author
    Posts
  • #23220
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Hi All,

    First time posting, I am trying to make a script that will grab a bunch of registry hives and update the permissions on the hives for a particular user group across multiple frontend servers.

    So far I have a script as follows:

    Invoke-Command -ComputerName lab1 {
    
    Get-Content -Path C:\_sources\test.txt | ForEach-Object {
    $acl = Get-Acl 
    $rule = New-Object System.Security.AccessControl.RegistryAccessRule ("DOMAIN\Test Group","FullControl","Allow")
    $acl.SetAccessControl($rule)
    $acl | Set-Acl
    }
    
    }
    

    The two keys that I'm testing this script with are:

    HKLM:\System\CurrentControlSet\Services\WinSock2\Parameters
    HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect

    They are located within the test.txt on the C drive and is what the get-content portion of the code is extracting.

    When I run this script I am getting an error that looks like the following:

    Cannot convert argument "0", with value: "System.Security.AccessControl.RegistryAccessRule", for "SetAccessRule" to type
    "System.Security.AccessControl.FileSystemAccessRule": "Cannot convert the "System.Security.AccessControl.RegistryAccessRule" value of type
    "System.Security.AccessControl.RegistryAccessRule" to type "System.Security.AccessControl.FileSystemAccessRule"."

    I have looked into this error, and from what I can see it is that when I am calling the System.Security.AccessControl.RegistryAccessRule class I am trying to invoke the SetAccessRule method which is a file system access rule method; hence the error.

    Looking on MSDN (https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryaccessrule(v=vs.110).aspx) I can see that SetAccessControl is a method that I should be using for the System.Security.AccessControl.RegistryAccessRule class but when i'm using powershell ISE it can't find the SetAccessControl method; and if I run it regardless I get the error:

    Method invocation failed because [System.Security.AccessControl.DirectorySecurity] doesn't contain a method named 'SetAccessControl'.

    I'm a little confused by this and not sure where to go from here... Any help or guidance will be greatly appreciated.

    Thank you

  • #23221
    Profile photo of Jack Neff
    Jack Neff
    Participant

    Might just be invoking the wrong method. Try this:

    $Keys = "HKLM:\System\CurrentControlSet\Services\WinSock2\Parameters", "HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect"
    
    Invoke-Command -ComputerName lab1 -ArgumentList $Keys {
     
        param ($RegKeys)
        
        foreach ($Key in $RegKeys) {
            $ACL = Get-Acl -Path $Key 
            $Rule = New-Object System.Security.AccessControl.RegistryAccessRule ("DOMAIN\Test Group","FullControl","Allow")
            $ACL.AddAccessRule($Rule)
            $ACL | Set-Acl
        }
    }
    
  • #23222
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Oh right, I see.. that worked! Thanks for your help Jack much appreciated 🙂

  • #23249
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Hi, after having a better look at this I'm not sure about somethings. In the script provided by Jack the $regkeys value, what is this? there doesn't seem to be any reference to it in the script. Should $Keys at the start be $Regkeys? It appears as though only the first registry key had the permissions changed.. I suspect that is because of the variable names not matching? Just getting started in powershell really so just trying to understand what Jack is trying to say there.

    Thanks

  • #23250
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    After some troubleshooting I have found that the key does not exist on the server – however if I log onto the server I can see the key in the registry. I have found that the script is applying these permissions locally... I'm currently investigating why but looks like the issue might be around the invoke-command

  • #23251
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    I have modified the script to now run as follows:

    Invoke-Command -ComputerName lab1 -ScriptBlock { 
    
    $a = Get-Content C:\_sources\Test.txt
     
        foreach ($a in $b) {
            $ACL = Get-Acl -Path $b 
            $Rule = New-Object System.Security.AccessControl.RegistryAccessRule ("Domain\Users","FullControl","Allow")
            $ACL.AddAccessRule($Rule)
            $ACL | Set-Acl
        }
    }
    

    I'm now back to getting the error code: Method invocation failed because [System.Object[]] doesn't contain a method named 'AddAccessRule'.

    Looking at the methods that I have available to me I can use, Equals, GetHashCode, GetType or ToString...

    Not sure if I have completely butchered the script or if i'm looking at doing this the wrong way; anyone able to see where I have failed at this?

    Thank you all for your time.

  • #23281
    Profile photo of Jack Neff
    Jack Neff
    Participant

    Sorry Tim, been slammed at work the last few days. Let me rewind to my original script and explain whats going on there. The value of $Regkeys is being passed from -Argumentlist parameter because code inside the -Scriptblock { curly braces } has it's own scope. I responded to someone in this forum with a similar issue the other day. [url]https://powershell.org/forums/topic/trouble-with-targetpath/[/url] So what's really happening is I'm first loading $Keys with an array of strings (in this case two strings representing registry key paths) and then I'm passing that array into the scriptblock to be loaded into a new variable named $RegKeys. Even though I don't have to make the variable names different, I like to for clarity. By the way, you don't have to change your script to work this way you can continue to pull the string values from a text file if you want, I just wanted to show you that you can accomplish this task without needing a companion file. Sorry if I made things more confusing.

    Now, on to your latest script. The problem you are running into there is you reversed the variables in the foreach statement. You are loading variable $a with your array so your foreach statement should read "foreach ($b in $a)".

    One place where I'm confused is that you say the second reg key doesn't exist until you login. This isn't normally the case with keys in HKLM and you should be able to access any of its subkeys remotely. Use the following code to remotely verify the key is there:

    $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', 'lab1.bluefire.bfms.local')
    $RegKey.OpenSubKey("SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect")
    if ($RegKey -eq $null){ Write-Output "Key does not exist" } else { Write-Output "Key exists" }
    

    If that comes back saying it doesn't exist double-check the path and make sure you are in HKLM and not HKCU. Because if the script works on the first key it should work on the second.

  • #23290
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Hi Jack,

    Thanks for taking the time to explain this to me, I now understand what you were saying in the original script. Let me try and make what I was saying clearer...

    Currently I am connected to a management box, I'll call it serverA. I have three client servers that I would like to change these registry keys permissions on (there a more than two i'm just testing with two at the moment) so the script once confirmed working will be modified to allow the keys permissions to be changed on those three servers. I'm currently connecting from ServerA to lab1, which is a UAT server for the client, via the shell script to make these changes to the keys taking in the method change that you mentioned in your previous post.

    I know that the key HKLM:SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect does not exist on serverA but it does exist on Lab1. For some reason my invoke command doesn't seem to be connecting to the lab1 server and running the foreach statement; instead it is trying to add the permissions to the local registry on serverA. If I go directly to the server and run the script which you corrected me on with:

    $a = Get-Content C:\_sources\Test.txt
    
    foreach ($b in $a) {
            $ACL = Get-Acl -Path $a 
            $Rule = New-Object System.Security.AccessControl.RegistryAccessRule ("DOMAIN\UserGroup","FullControl","Allow")
            $ACL.AddAccessRule($Rule)
            $ACL | Set-Acl
        }
    

    Removing the invoke command because i'm already connected to that server. I get the error stating that the Method invocation failed because [System.Object[]] doesn't contain a method named 'AddAccessRule'. Where as if I was to run this on ServerA the permissions are added to the first key:

    HKLM:\System\CurrentControlSet\Services\WinSock2\Parameters

    But fails on the 2nd, HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect because that doesn't exist on ServerA. So i'm not understanding why this is working on serverA but not on lab1... is it perhaps a powershell version thing? I'm not sure because even from the ISE I can't see the method AddAccessRule.

    Hopefully that is more clear. I would like also like to add that I appreciate you taking the time out to help me with this one and thanks for taking the time to explain the string array... I think I was getting confused because I was thinking that was a variable and not sure how that was reflected in the foreach statement.

    Thanks

  • #23291
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Hi Jack,

    Thanks for taking the time to explain this to me, I now understand what you were saying in the original script. Let me try and make what I was saying clearer...

    Currently I am connected to a management box, I'll call it serverA. I have three client servers that I would like to change these registry keys permissions on (there a more than two i'm just testing with two at the moment) so the script once confirmed working will be modified to allow the keys permissions to be changed on those three servers. I'm currently connecting from ServerA to lab1, which is a UAT server for the client, via the shell script to make these changes to the keys taking in the method change that you mentioned in your previous post.

    I know that the key HKLM:SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect does not exist on serverA but it does exist on Lab1. For some reason my invoke command doesn't seem to be connecting to the lab1 server and running the foreach statement; instead it is trying to add the permissions to the local registry on serverA. If I go directly to the server and run the script which you corrected me on with:

    $a = Get-Content C:\_sources\Test.txt
    
    foreach ($b in $a) {
            $ACL = Get-Acl -Path $a 
            $Rule = New-Object System.Security.AccessControl.RegistryAccessRule ("DOMAIN\UserGroup","FullControl","Allow")
            $ACL.AddAccessRule($Rule)
            $ACL | Set-Acl
        }
    

    Removing the invoke command because i'm already connected to that server. I get the error stating that the Method invocation failed because [System.Object[]] doesn't contain a method named 'AddAccessRule'. Where as if I was to run this on ServerA the permissions are added to the first key:

    HKLM:\System\CurrentControlSet\Services\WinSock2\Parameters

    But fails on the 2nd, HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect because that doesn't exist on ServerA. So i'm not understanding why this is working on serverA but not on lab1... is it perhaps a powershell version thing? I'm not sure because even from the ISE I can't see the method AddAccessRule.

    Hopefully that is more clear. I would like also like to add that I appreciate you taking the time out to help me with this one and thanks for taking the time to explain the string array... I think I was getting confused because I was thinking that was a variable and not sure how that was reflected in the foreach statement.

    Thanks

  • #23293
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Hi Jack,

    I've been able to get it work once i've updated the powershell version to version 4. Ha... should have checked that sooner. Thanks for all your help on this – much appreciated

  • #23294
    Profile photo of Tim Gearie
    Tim Gearie
    Participant

    Hi Jack,

    I've been able to get it work once i've updated the powershell version to version 4. Ha... should have checked that sooner. Thanks for all your help on this – much appreciated

  • #23295
    Profile photo of Jack Neff
    Jack Neff
    Participant

    Wow then I have to apologize I didn't realize that cmdlet was only PoSH 4! Glad you got it sorted!

You must be logged in to reply to this topic.