locked
Solved - How to take ownership and change permissions for blocked files and folders in Powershell RRS feed

  • Question

  • Hello,
    I was trying to take ownership & fix permissions on Home Folder/My Documents structures, I ran into the common problem in PowerShell where Set-Acl & Get-Acl return access denied errors. The error occurs because the Administrators have been removed from file permissions and do not have ownership of the files,folders/directories. (Assuming all other permissions like SeTakeOwnershipPrivilege have been enabled.

    I was not able to find any information about someone successfully using native PS to resolve the issue.  As I was able to solve the issues surrounding Get-Acl & Set-Acl, I wanted to share the result for those still looking for an answer.
    ----
    Question: How do you use only Powershell take ownership and reset permissions for files or folders you do not have permissions or ownership of?
    ----

    Problem: 
    Using the default function calls to the object fail for a folder that the administrative account does not have permissions or file ownership. You get the following error for Get-Acl:

    PS C:\> Get-Acl -path F:\testpath\locked
    Get-Acl : Attempted to perform an unauthorized operation.
    + get-acl <<<<  -path F:\testpath\locked
    + CategoryInfo          : NotSpecified: (:) [Get-Acl], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetAclCommand

    If you create a new ACL and attempt to apply it using Set-Acl, you get:

    PS C:\> Set-Acl -path F:\testpath\locked -AclObject $DirAcl
    Set-Acl : Attempted to perform an unauthorized operation.
    At line:1 char:8
    + Set-Acl <<<<  -path "F:\testpath\locked" -AclObject $DirAcl
    + CategoryInfo          : PermissionDenied: (F:\testpath\locked:String) [Set-Acl], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetAclCommand

    Use of other functions like .GetAccessControl will result in a similar error: "Attempted to perform an unauthorized operation."

    How do you replace owner on all subcontainers and objects in Powershell with resorting to external applications like takeown, icacls, Windows Explorer GUI, etc.?

    Tony

    Friday, May 25, 2012 7:20 PM

Answers

  • That is a beautifully elegant answer, but for those who don't want to load the PSCX 3rd party code, and want to leverage pure PowerShell and system DLLs, here is an alternate solution

    #P/Invoke'd C# code to enable required privileges to take ownership and make changes when NTFS permissions are lacking $AdjustTokenPrivileges = @" using System; using System.Runtime.InteropServices;  public class TokenManipulator  {   [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]   internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,   ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);   [DllImport("kernel32.dll", ExactSpelling = true)]   internal static extern IntPtr GetCurrentProcess();   [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]   internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr   phtok);   [DllImport("advapi32.dll", SetLastError = true)]   internal static extern bool LookupPrivilegeValue(string host, string name,   ref long pluid);   [StructLayout(LayoutKind.Sequential, Pack = 1)]   internal struct TokPriv1Luid   {    public int Count;    public long Luid;    public int Attr;   }   internal const int SE_PRIVILEGE_DISABLED = 0x00000000;   internal const int SE_PRIVILEGE_ENABLED = 0x00000002;   internal const int TOKEN_QUERY = 0x00000008;   internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;   public static bool AddPrivilege(string privilege)   {    try    {     bool retVal;     TokPriv1Luid tp;     IntPtr hproc = GetCurrentProcess();     IntPtr htok = IntPtr.Zero;     retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);     tp.Count = 1;     tp.Luid = 0;     tp.Attr = SE_PRIVILEGE_ENABLED;     retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);     retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);     return retVal;    }    catch (Exception ex)    {     throw ex;    }   }   public static bool RemovePrivilege(string privilege)   {    try    {     bool retVal;     TokPriv1Luid tp;     IntPtr hproc = GetCurrentProcess();     IntPtr htok = IntPtr.Zero;     retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);     tp.Count = 1;     tp.Luid = 0;     tp.Attr = SE_PRIVILEGE_DISABLED;     retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);     retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);     return retVal;    }    catch (Exception ex)    {     throw ex;    }   }  } "@ add-type $AdjustTokenPrivileges

    #example for testing

    $Folder = Get-Item "F:\testpath\locked"

    #Activate necessary admin privileges to make changes without NTFS perms [void][TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions [void][TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking [void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override FilePermissions #Obtain a copy of the initial ACL #$FolderACL = Get-ACL $Folder - gives error when run against a folder with no admin perms or ownership #Create a new ACL object for the sole purpose of defining a new owner, and apply that update to the existing folder's ACL $NewOwnerACL = New-Object System.Security.AccessControl.DirectorySecurity #Establish the folder as owned by BUILTIN\Administrators, guaranteeing the following ACL changes can be applied $Admin = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators") $NewOwnerACL.SetOwner($Admin) #Merge the proposed changes (new owner) into the folder's actual ACL $Folder.SetAccessControl($NewOwnerACL)



    www.computingimprovements.com



    • Edited by barnabya Thursday, January 30, 2014 6:29 PM
    • Proposed as answer by barnabya Thursday, January 30, 2014 6:29 PM
    • Marked as answer by Tony Britton Friday, October 17, 2014 7:36 PM
    Thursday, January 30, 2014 6:27 PM
  • Hello,
    Last, here is the script I used to reset permissions on the "My Documents" tree structure that admins did not have access to:
    Example:  Powershell script to parse a directory of User-owned "My Document" redirection folders and reset permissions.

    #Script to Reset MyDocuments Folder permissions
    $domainName = ([ADSI]'').name 
     Import-Module "PSCX" -ErrorAction Stop
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true) #Necessary to set Owner Permissions
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true) #Necessary to bypass Traverse Checking
     #Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeSecurityPrivilege", $true) #Optional if you want to manage auditing (SACL) on the objects
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true) #Necessary to override FilePermissions & take Ownership
     $Directorypath = "F:\Userpath" #locked user folders exist under here
     $LockedDirs = Get-ChildItem $Directorypath -force #get all of the locked directories.
     Foreach ($Locked in $LockedDirs) {
      Write-Host "Resetting Permissions for "$Locked.Fullname
     #######Take Ownership of the root directory
      $blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity
      $blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')
      $Locked.SetAccessControl($blankdirAcl)
      
     ###################### Setup & apply correct folder permissions to the root user folder
      #Using recommendation from Ned Pyle's Ask Directory Services blog:
      #Automatic creation of user folders for home, roaming profile and redirected folders.
      $inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit"
      $propagation = [system.security.accesscontrol.PropagationFlags]"None"
      $fullrights = [System.Security.AccessControl.FileSystemRights]"FullControl"
      $allowrights = [System.Security.AccessControl.AccessControlType]"Allow"
      $DirACL = New-Object System.Security.AccessControl.DirectorySecurity
      #Administrators: Full Control
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators",$fullrights, $inherit, $propagation, "Allow")))
      #System: Full Control
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM",$fullrights, $inherit, $propagation, "Allow")))
      #Creator Owner: Full Control
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("CREATOR OWNER",$fullrights, $inherit, $propagation, "Allow")))
      #Useraccount: Full Control (ideally I would error check the existance of the user account in AD)
      #$DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("$domainName\$Locked.name",$fullrights, $inherit, $propagation, "Allow")))
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("$domainName\$Locked",$fullrights, $inherit, $propagation, "Allow")))
      #Remove Inheritance from the root user folder
      $DirACL.SetAccessRuleProtection($True, $False) #SetAccessRuleProtection(block inheritance?, copy parent ACLs?)
      #Set permissions on User Directory
      Set-Acl -aclObject $DirACL -path $Locked.Fullname
      Write-Host "commencer" -NoNewLine
     ##############Restore admin access & then restore file/folder inheritance on all subitems
      #create a template ACL with inheritance re-enabled; this will be stamped on each subitem to re-establish the file structure with inherited ACLs only.
      #$NewOwner = New-Object System.Security.Principal.NTAccount("$domainName","$Locked.name") #ideally I would error check this.
      $NewOwner = New-Object System.Security.Principal.NTAccount("$domainName","$Locked") #ideally I would error check this.
      $subFileACL = New-Object System.Security.AccessControl.FileSecurity
      $subDirACL = New-Object System.Security.AccessControl.DirectorySecurity
      $subFileACL.SetOwner($NewOwner)
      $subDirACL.SetOwner($NewOwner)
      ######## Enable inheritance ($False) and not copy of parent ACLs ($False)
      $subFileACL.SetAccessRuleProtection($False, $False) #SetAccessRuleProtection(block inheritance?, copy parent ACLs?)
      $subDirACL.SetAccessRuleProtection($False, $False) #SetAccessRuleProtection(block inheritance?, copy parent ACLs?)
      #####loop through subitems
      $subdirs = Get-ChildItem -path $Locked.Fullname -force -recurse #force is necessary to get hidden files/folders
      foreach ($subitem in $subdirs) {
       #take ownership to insure ability to change permissions
       #Then set desired ACL
       if ($subitem.Attributes -match "Directory") {
        # New, blank Directory ACL with only Owner set
        $blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity
        $blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')
        #Use SetAccessControl to reset Owner; Set-Acl will not work.
        $subitem.SetAccessControl($blankdirAcl)
        #At this point, Administrators have the ability to change the directory permissions
        Set-Acl -aclObject $subDirACL -path $subitem.Fullname -ErrorAction Stop
       } Else {
        # New, blank File ACL with only Owner set 
        $blankfileAcl = New-Object System.Security.AccessControl.FileSecurity
        $blankfileAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')
        #Use SetAccessControl to reset Owner; Set-Acl will not work.
        $subitem.SetAccessControl($blankfileAcl)
        #At this point, Administrators have the ability to change the file permissions
        Set-Acl -aclObject $subFileACL -path $subitem.Fullname -ErrorAction Stop
       }
       Write-Host "." -NoNewline
      }
      Write-Host "fin."
     }
     Write-Host "Script Complete."

    I hope you find this useful.

    Thank you,
    Tony

    Final Thought: There are great non-PS tools like Set-Acl and takeown which are external to PS & can also do the job wonderfully.  It may be much simpler to call those tools than recreate the wheel in pure code.  Feel free to use whatever best suits your time, scope & cost.



    • Marked as answer by Tony Britton Friday, May 25, 2012 7:29 PM
    • Edited by Tony Britton Friday, October 17, 2014 7:43 PM updated per Chockymonster's notes
    Friday, May 25, 2012 7:29 PM
  • Hello,
    I am answering my own question to avoid a difficult-to-read 2 page post .
    Answer:  The pure PowerShell solution is to use a bare AccessControl object with only the Owner set and then use SetAccessControl to apply the change.  Once this change has taken effect, you can then use Get-Acl & Set-Acl as normal. 
    This is really just the same process you walk through using the GUI; Change the ownership only, then modify as desired.

    Solution:
    (First: Thanks to AlfredHall & Sheng Jiang for starting me in the right direction in their discussion here)
    0) Run PS as administrator if UAC is enabled.
    1) Use PSCX to elevate your privileges

    Import-Module "PSCX"
    Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true) #Necessary to set Owner Permissions
    Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true) #Necessary to bypass Traverse Checking
    Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true) #Necessary to override FilePermissions & take Ownership

    2) Create a new, Owner-only ACL with only the Owner specified with the administrative group as the owner. 

    $blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity
    $blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')

    3) Use SetAccessControl to set that Owner.

    (Get-Item "F:\testpath\locked").SetAccessControl($blankdirAcl)

    4) Modify File Permissions, Auditing, Ownership using Get-Acl, Set-Acl as normal.

    ---------

    By using the new Owner-only ACL object and SetAccessControl, Ownership has now changed to Administrators and you can use Get-Acl,Set-Acl as desired.

    Key Note: That new Owner-Only ACL object has to be recreated for each new object you want to affect.  Trying to reuse the Owner-Only object fails on subsequent file/dir objects.
    There is a note in the MSDN Method dictionary for SetAccessControl:
    The SetAccessControl method persists only FileSecurity objects that have been modified after object creation.  If a FileSecurity object has not been modified, it will not be persisted to a file.  Therefore, it is not possible to retrieve a FileSecurity object from one file and reapply the same object to another file.
    I translate that to mean: once applied to a file/folder, it cannot be re-used. (Though I am sure someone will correct me here - my grasp on "persist" is a little weak.)

    Hopefully you will find the answer helpful in your scripting travels.

    Thank you,

    Tony

    Friday, May 25, 2012 7:25 PM

All replies

  • Hello,
    I am answering my own question to avoid a difficult-to-read 2 page post .
    Answer:  The pure PowerShell solution is to use a bare AccessControl object with only the Owner set and then use SetAccessControl to apply the change.  Once this change has taken effect, you can then use Get-Acl & Set-Acl as normal. 
    This is really just the same process you walk through using the GUI; Change the ownership only, then modify as desired.

    Solution:
    (First: Thanks to AlfredHall & Sheng Jiang for starting me in the right direction in their discussion here)
    0) Run PS as administrator if UAC is enabled.
    1) Use PSCX to elevate your privileges

    Import-Module "PSCX"
    Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true) #Necessary to set Owner Permissions
    Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true) #Necessary to bypass Traverse Checking
    Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true) #Necessary to override FilePermissions & take Ownership

    2) Create a new, Owner-only ACL with only the Owner specified with the administrative group as the owner. 

    $blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity
    $blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')

    3) Use SetAccessControl to set that Owner.

    (Get-Item "F:\testpath\locked").SetAccessControl($blankdirAcl)

    4) Modify File Permissions, Auditing, Ownership using Get-Acl, Set-Acl as normal.

    ---------

    By using the new Owner-only ACL object and SetAccessControl, Ownership has now changed to Administrators and you can use Get-Acl,Set-Acl as desired.

    Key Note: That new Owner-Only ACL object has to be recreated for each new object you want to affect.  Trying to reuse the Owner-Only object fails on subsequent file/dir objects.
    There is a note in the MSDN Method dictionary for SetAccessControl:
    The SetAccessControl method persists only FileSecurity objects that have been modified after object creation.  If a FileSecurity object has not been modified, it will not be persisted to a file.  Therefore, it is not possible to retrieve a FileSecurity object from one file and reapply the same object to another file.
    I translate that to mean: once applied to a file/folder, it cannot be re-used. (Though I am sure someone will correct me here - my grasp on "persist" is a little weak.)

    Hopefully you will find the answer helpful in your scripting travels.

    Thank you,

    Tony

    Friday, May 25, 2012 7:25 PM
  • According to this http://blogs.technet.com/b/heyscriptingguy/archive/2008/04/15/how-can-i-use-windows-powershell-to-determine-the-owner-of-a-file.aspx

    It sounds like you cant give ownership to another user like yourself to fix the permissions, you will need to use a third party tool to take over ownership, then apply permissions.

    Or I may have read it wrong as I just skimmed through, you may be able to give yourself ownership of the file.


    • Edited by clayman2 Friday, May 25, 2012 7:28 PM
    Friday, May 25, 2012 7:27 PM
  • Hello,
    Last, here is the script I used to reset permissions on the "My Documents" tree structure that admins did not have access to:
    Example:  Powershell script to parse a directory of User-owned "My Document" redirection folders and reset permissions.

    #Script to Reset MyDocuments Folder permissions
    $domainName = ([ADSI]'').name 
     Import-Module "PSCX" -ErrorAction Stop
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true) #Necessary to set Owner Permissions
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true) #Necessary to bypass Traverse Checking
     #Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeSecurityPrivilege", $true) #Optional if you want to manage auditing (SACL) on the objects
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true) #Necessary to override FilePermissions & take Ownership
     $Directorypath = "F:\Userpath" #locked user folders exist under here
     $LockedDirs = Get-ChildItem $Directorypath -force #get all of the locked directories.
     Foreach ($Locked in $LockedDirs) {
      Write-Host "Resetting Permissions for "$Locked.Fullname
     #######Take Ownership of the root directory
      $blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity
      $blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')
      $Locked.SetAccessControl($blankdirAcl)
      
     ###################### Setup & apply correct folder permissions to the root user folder
      #Using recommendation from Ned Pyle's Ask Directory Services blog:
      #Automatic creation of user folders for home, roaming profile and redirected folders.
      $inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit"
      $propagation = [system.security.accesscontrol.PropagationFlags]"None"
      $fullrights = [System.Security.AccessControl.FileSystemRights]"FullControl"
      $allowrights = [System.Security.AccessControl.AccessControlType]"Allow"
      $DirACL = New-Object System.Security.AccessControl.DirectorySecurity
      #Administrators: Full Control
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators",$fullrights, $inherit, $propagation, "Allow")))
      #System: Full Control
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM",$fullrights, $inherit, $propagation, "Allow")))
      #Creator Owner: Full Control
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("CREATOR OWNER",$fullrights, $inherit, $propagation, "Allow")))
      #Useraccount: Full Control (ideally I would error check the existance of the user account in AD)
      #$DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("$domainName\$Locked.name",$fullrights, $inherit, $propagation, "Allow")))
      $DirACL.AddAccessRule((new-object System.Security.AccessControl.FileSystemAccessRule("$domainName\$Locked",$fullrights, $inherit, $propagation, "Allow")))
      #Remove Inheritance from the root user folder
      $DirACL.SetAccessRuleProtection($True, $False) #SetAccessRuleProtection(block inheritance?, copy parent ACLs?)
      #Set permissions on User Directory
      Set-Acl -aclObject $DirACL -path $Locked.Fullname
      Write-Host "commencer" -NoNewLine
     ##############Restore admin access & then restore file/folder inheritance on all subitems
      #create a template ACL with inheritance re-enabled; this will be stamped on each subitem to re-establish the file structure with inherited ACLs only.
      #$NewOwner = New-Object System.Security.Principal.NTAccount("$domainName","$Locked.name") #ideally I would error check this.
      $NewOwner = New-Object System.Security.Principal.NTAccount("$domainName","$Locked") #ideally I would error check this.
      $subFileACL = New-Object System.Security.AccessControl.FileSecurity
      $subDirACL = New-Object System.Security.AccessControl.DirectorySecurity
      $subFileACL.SetOwner($NewOwner)
      $subDirACL.SetOwner($NewOwner)
      ######## Enable inheritance ($False) and not copy of parent ACLs ($False)
      $subFileACL.SetAccessRuleProtection($False, $False) #SetAccessRuleProtection(block inheritance?, copy parent ACLs?)
      $subDirACL.SetAccessRuleProtection($False, $False) #SetAccessRuleProtection(block inheritance?, copy parent ACLs?)
      #####loop through subitems
      $subdirs = Get-ChildItem -path $Locked.Fullname -force -recurse #force is necessary to get hidden files/folders
      foreach ($subitem in $subdirs) {
       #take ownership to insure ability to change permissions
       #Then set desired ACL
       if ($subitem.Attributes -match "Directory") {
        # New, blank Directory ACL with only Owner set
        $blankdirAcl = New-Object System.Security.AccessControl.DirectorySecurity
        $blankdirAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')
        #Use SetAccessControl to reset Owner; Set-Acl will not work.
        $subitem.SetAccessControl($blankdirAcl)
        #At this point, Administrators have the ability to change the directory permissions
        Set-Acl -aclObject $subDirACL -path $subitem.Fullname -ErrorAction Stop
       } Else {
        # New, blank File ACL with only Owner set 
        $blankfileAcl = New-Object System.Security.AccessControl.FileSecurity
        $blankfileAcl.SetOwner([System.Security.Principal.NTAccount]'BUILTIN\Administrators')
        #Use SetAccessControl to reset Owner; Set-Acl will not work.
        $subitem.SetAccessControl($blankfileAcl)
        #At this point, Administrators have the ability to change the file permissions
        Set-Acl -aclObject $subFileACL -path $subitem.Fullname -ErrorAction Stop
       }
       Write-Host "." -NoNewline
      }
      Write-Host "fin."
     }
     Write-Host "Script Complete."

    I hope you find this useful.

    Thank you,
    Tony

    Final Thought: There are great non-PS tools like Set-Acl and takeown which are external to PS & can also do the job wonderfully.  It may be much simpler to call those tools than recreate the wheel in pure code.  Feel free to use whatever best suits your time, scope & cost.



    • Marked as answer by Tony Britton Friday, May 25, 2012 7:29 PM
    • Edited by Tony Britton Friday, October 17, 2014 7:43 PM updated per Chockymonster's notes
    Friday, May 25, 2012 7:29 PM
  • clayman2, if you actually run the script, you will see that it does work. It has generally been a "formal" understanding that powershell is unable to do this, and yet with the usage of .Net, anything is possible, it's just the amount of time and code you put behind it.

    Tuesday, May 29, 2012 4:01 PM
  • Todd,

      Thank you for the effort you put into this script.  It seems that it will do exactly what I'm looking for once I can get it work without errors.  Currently I have only changed the DirectoryPath within the script to point to the location of my user Home Directories.  When I run it i receive the following errors

    I've tried everything that I could think of to fix the errors to no avail.  Any assistance would be greatly appreciated!

    Thanks,
    Eric

    PS D:\> D:\Scripts\Own_Perms.ps1
    Resetting Permissions for  \\jitfdm01\userdata$\permissions\jitf152
    Exception calling "AddAccessRule" with "1" argument(s): "Some or all identity references could not be translated."
    At D:\Scripts\Own_Perms.ps1:31 char:24
    +   $DirACL.AddAccessRule <<<< ((new-object System.Security.AccessControl.FileSystemAccessRule("domainName\$user",$full
    rights, $inherit, $propagation, "Allow")))
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    commencerException calling "SetOwner" with "1" argument(s): "Some or all identity references could not be translated."
    At D:\Scripts\Own_Perms.ps1:42 char:23
    +   $subFileACL.SetOwner <<<< ($NewOwner)
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    Exception calling "SetOwner" with "1" argument(s): "Some or all identity references could not be translated."
    At D:\Scripts\Own_Perms.ps1:43 char:22
    +   $subDirACL.SetOwner <<<< ($NewOwner)
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.
    At D:\Scripts\Own_Perms.ps1:65 char:30
    +     $subitem.SetAccessControl <<<< ($blankfileAcl)
        + CategoryInfo          : InvalidOperation: (SetAccessControl:String) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull

    Set-Acl : Cannot bind argument to parameter 'Path' because it is null.
    At D:\Scripts\Own_Perms.ps1:67 char:41
    +     Set-Acl -aclObject $subFileACL -path <<<<  $subitem.Fullname -ErrorAction Stop
        + CategoryInfo          : InvalidData: (:) [Set-Acl], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.SetAclComma
       nd

    .fin.

    Wednesday, August 22, 2012 7:51 PM
  • Hi Eric,

    The issue you have run into is that your foldername does not match a username in your domain.

    Line 31 is attempting to grant access to  $domainName\$Locked.name (which in your case is jitf152)

    Lines 42/43 are then attempted to set owner permissions to that same account (which does not exist and therefore fails)

    Lines 65/67 is somehow getting a null directory name. It may just be the result of the earlier failures or it could be a problem with a particular folder - I would need to know what the folder and path were to understand more.

    I hope that helps.

    Tony

    Tuesday, December 4, 2012 8:05 PM
  • I have tried the above script, and takeown (in elevated cmd shells), yet nothing I have tried is able to reset the ownership of one specific file.

    In all cases an access-denied error is reported.

    Monday, July 8, 2013 4:10 PM
  • I was having the same problems as you.

    The script was erroring on lines 31, 42 and 43.

    The users did exist in the domain so there should have been no issues but the errors occured.

    I added 

    Write-Host  $NewOwner -NoNewLine on the line after the $NewOwner variable is declared.

    When the output was written back I noticed that .name was being appended to the Domain\username

    Looking at where the $Newowner variable is defined I saw this

     $NewOwner = New-Object System.Security.Principal.NTAccount("$domainName","$Locked.name") #ideally I would error check this.

    Removing the .name from the $Locked fixed returns the correct username being inserted into the variable. 

    There are 2 lines that need changing, line 31 and 39

    Once the .name is removed the script runs perfectly.

    Hopefully this helps someone!

    Friday, August 9, 2013 2:11 PM
  • Thanks! Great script.

    I would like to set permissions on some roaming profiles. I have both username & username.v2 folders in this profiles folder.

    Can someone help with what I would need to do to remove the .v2 from the username when setting the permissions on the .v2 folders?

    I.e. I want to set the owner and full control permissions on username.v2 to "$domainName\$Locked", but locked would be set to username.v2 not username

    I guess if the value of $Locked has .v2 on the end, remove it before setting the Full Control and new owner or create a new variable and use that?

    Any help would be greatly appreciated :)

    Cheers


    • Edited by Grubsy Tuesday, November 5, 2013 5:22 AM
    Tuesday, November 5, 2013 5:21 AM
  • That is a beautifully elegant answer, but for those who don't want to load the PSCX 3rd party code, and want to leverage pure PowerShell and system DLLs, here is an alternate solution

    #P/Invoke'd C# code to enable required privileges to take ownership and make changes when NTFS permissions are lacking $AdjustTokenPrivileges = @" using System; using System.Runtime.InteropServices;  public class TokenManipulator  {   [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]   internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,   ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);   [DllImport("kernel32.dll", ExactSpelling = true)]   internal static extern IntPtr GetCurrentProcess();   [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]   internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr   phtok);   [DllImport("advapi32.dll", SetLastError = true)]   internal static extern bool LookupPrivilegeValue(string host, string name,   ref long pluid);   [StructLayout(LayoutKind.Sequential, Pack = 1)]   internal struct TokPriv1Luid   {    public int Count;    public long Luid;    public int Attr;   }   internal const int SE_PRIVILEGE_DISABLED = 0x00000000;   internal const int SE_PRIVILEGE_ENABLED = 0x00000002;   internal const int TOKEN_QUERY = 0x00000008;   internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;   public static bool AddPrivilege(string privilege)   {    try    {     bool retVal;     TokPriv1Luid tp;     IntPtr hproc = GetCurrentProcess();     IntPtr htok = IntPtr.Zero;     retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);     tp.Count = 1;     tp.Luid = 0;     tp.Attr = SE_PRIVILEGE_ENABLED;     retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);     retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);     return retVal;    }    catch (Exception ex)    {     throw ex;    }   }   public static bool RemovePrivilege(string privilege)   {    try    {     bool retVal;     TokPriv1Luid tp;     IntPtr hproc = GetCurrentProcess();     IntPtr htok = IntPtr.Zero;     retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);     tp.Count = 1;     tp.Luid = 0;     tp.Attr = SE_PRIVILEGE_DISABLED;     retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);     retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);     return retVal;    }    catch (Exception ex)    {     throw ex;    }   }  } "@ add-type $AdjustTokenPrivileges

    #example for testing

    $Folder = Get-Item "F:\testpath\locked"

    #Activate necessary admin privileges to make changes without NTFS perms [void][TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions [void][TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking [void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override FilePermissions #Obtain a copy of the initial ACL #$FolderACL = Get-ACL $Folder - gives error when run against a folder with no admin perms or ownership #Create a new ACL object for the sole purpose of defining a new owner, and apply that update to the existing folder's ACL $NewOwnerACL = New-Object System.Security.AccessControl.DirectorySecurity #Establish the folder as owned by BUILTIN\Administrators, guaranteeing the following ACL changes can be applied $Admin = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators") $NewOwnerACL.SetOwner($Admin) #Merge the proposed changes (new owner) into the folder's actual ACL $Folder.SetAccessControl($NewOwnerACL)



    www.computingimprovements.com



    • Edited by barnabya Thursday, January 30, 2014 6:29 PM
    • Proposed as answer by barnabya Thursday, January 30, 2014 6:29 PM
    • Marked as answer by Tony Britton Friday, October 17, 2014 7:36 PM
    Thursday, January 30, 2014 6:27 PM
  • Has anyone tried the code proposed by "barnabya" that does not require the PSCX module be loaded?  Feedback? 

    I am creating a script to terminate user accounts in active directory and would like to attempt to delete users home folder found in AD without forcing permissions, but if that fails I want to do the following WITHOUT having to load another module:

    1. force ownership of the parent and all child folders and files
    2. force inheritance of permissions from parent folder
    3. force full permissions on all child folders and files (if that isn't done in step 1 or 2)
    4. delete the folder itself and all child folders and files

     

    Does the code provided by "barnabya" do that?  I don't see the permissions being set on child folders or actually setting permissions.  It just seems to take ownership.  Is this right?  Do I still need to then force Full permissions and set inheritance after running the code?

     

    I want this whole process to be a Function to override the ownership and permissions.  As far as I see the only input I would need to throw at this when I make a Function out of it would be to provide a folder path.  Is that correct?  Does this work on a UNC path also?

    Lots of questions in one post, sorry.  Hopefully, someone can help clarify and organize for me.


    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Saturday, March 1, 2014 2:25 PM
  • barnabya's code works.

    I hope this post has helped!

    Tuesday, April 15, 2014 2:05 PM
  • I adapted this code into a Function.  The details can be found at this post:  http://social.technet.microsoft.com/Forums/en-US/27242982-a99b-48ee-8b45-27497806430f/


    Find this post helpful? Does this post answer your question? Be sure to mark it appropriately to help others find answers to their searches.

    Tuesday, April 15, 2014 7:56 PM
  • I was able to solve this with 11 lines of code using takeown and icacls. I disagree with the idea that they are external as they are included with most contemporary versions of Windows Server.

    Make sure you have the AD module installed on the server you Redirect with so that the AD verification will work. Otherwise you'll need to adjust.

    Also, this assumes that you assign the parent Redirected Folders to be the same as their AD usernames.

    $ErrorActionPreference="SilentlyContinue" #enable AD Import-Module activedirectory

    #Set Redirected Folders path

    $RedirectPath = <your path here>

    #Using provided path, gather array of user folders to populate usernames $list = "$RedirectPath" | get-childitem Foreach ($l in $list) { #username is name of folder $user = $l.name # Filepath is folder.FullName $path = $l.FullName # Force recursive ownership for BUILTIN/Administrators of the folder using builtin Takeown.exe TAKEOWN /F $path /A /R /D "Y" # Apply full access permissions for both the user and administrators with ICACLS ICACLS $path /grant Administrators:F /T #Use AD to check whether user is active/exists and act accordingly If (Get-ADUser $user) { ICACLS $path /grant "${user}:F" /T # Apply ownership back to user with ICACLS, again, if still exists in AD ICACLS $path /setowner "$user" /T } }





    • Proposed as answer by T. Gardner Sunday, September 21, 2014 2:01 AM
    • Edited by T. Gardner Sunday, September 21, 2014 2:06 AM
    • Marked as answer by Tony Britton Friday, October 17, 2014 7:51 PM
    • Unmarked as answer by Tony Britton Friday, October 17, 2014 8:13 PM
    Sunday, September 21, 2014 1:59 AM
  • That is a beautifully elegant answer, but for those who don't want to load the PSCX 3rd party code, and want to leverage pure PowerShell and system DLLs, here is an alternate solution

    Barnabya,

    That's even better! 
    Thank you for sharing!
    Tony

     

    Friday, October 17, 2014 7:49 PM
  • I was able to solve this with 11 lines of code using takeown and icacls. I disagree with the idea that they are external as they are included with most contemporary versions of Windows Server.

    Make sure you have the AD module installed on the server you Redirect with so that the AD verification will work. Otherwise you'll need to adjust.


    Sure, this can work also.

    As I noted in my post there are great non-PS tools like Set-Acl and takeown which are external to PS & can also do the job wonderfully.  It may be much simpler to call those tools than recreate the wheel in pure code. 

    Feel free to use whatever best suits your desires.



    • Edited by Tony Britton Friday, October 17, 2014 7:57 PM quoting text
    Friday, October 17, 2014 7:54 PM
  • Has anyone tried the code proposed by "barnabya" that does not require the PSCX module be loaded?  Feedback? 

    Does the code provided by "barnabya" do that?  I don't see the permissions being set on child folders or actually setting permissions.  It just seems to take ownership.  Is this right?  Do I still need to then force Full permissions and set inheritance after running the code?

    Barnabya's code replaces the following code in my example script:

     Import-Module "PSCX" -ErrorAction Stop
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true) #Necessary to set Owner Permissions
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true) #Necessary to bypass Traverse Checking
     #Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeSecurityPrivilege", $true) #Optional if you want to manage auditing (SACL) on the objects
     Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true) #Necessary to override FilePermissions & take Ownership
     

    That block of code elevates the privileges of your script to enable the overriding of file permissions.  You still need code to recurse through your user's folder structure & override the ownership/permissions as described in the 2nd post.

    Thank you,

    Tony


    Friday, October 17, 2014 8:47 PM
  • Thank you, Barnaby.  I so appreciate answers that don't require me to go vet yet another 3rd party tool.
    Monday, December 14, 2015 8:38 PM
  • That is a beautifully elegant answer, but for those who don't want to load the PSCX 3rd party code, and want to leverage pure PowerShell and system DLLs, here is an alternate solution

    #P/Invoke'd C# code to enable required privileges to take ownership and make changes when NTFS permissions are lacking $AdjustTokenPrivileges = @" using System; using System.Runtime.InteropServices;  public class TokenManipulator  {   [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]   internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,   ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);   [DllImport("kernel32.dll", ExactSpelling = true)]   internal static extern IntPtr GetCurrentProcess();   [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]   internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr   phtok);   [DllImport("advapi32.dll", SetLastError = true)]   internal static extern bool LookupPrivilegeValue(string host, string name,   ref long pluid);   [StructLayout(LayoutKind.Sequential, Pack = 1)]   internal struct TokPriv1Luid   {    public int Count;    public long Luid;    public int Attr;   }   internal const int SE_PRIVILEGE_DISABLED = 0x00000000;   internal const int SE_PRIVILEGE_ENABLED = 0x00000002;   internal const int TOKEN_QUERY = 0x00000008;   internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;   public static bool AddPrivilege(string privilege)   {    try    {     bool retVal;     TokPriv1Luid tp;     IntPtr hproc = GetCurrentProcess();     IntPtr htok = IntPtr.Zero;     retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);     tp.Count = 1;     tp.Luid = 0;     tp.Attr = SE_PRIVILEGE_ENABLED;     retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);     retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);     return retVal;    }    catch (Exception ex)    {     throw ex;    }   }   public static bool RemovePrivilege(string privilege)   {    try    {     bool retVal;     TokPriv1Luid tp;     IntPtr hproc = GetCurrentProcess();     IntPtr htok = IntPtr.Zero;     retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);     tp.Count = 1;     tp.Luid = 0;     tp.Attr = SE_PRIVILEGE_DISABLED;     retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);     retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);     return retVal;    }    catch (Exception ex)    {     throw ex;    }   }  } "@ add-type $AdjustTokenPrivileges

    #example for testing

    $Folder = Get-Item "F:\testpath\locked"

    #Activate necessary admin privileges to make changes without NTFS perms [void][TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions [void][TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking [void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override FilePermissions #Obtain a copy of the initial ACL #$FolderACL = Get-ACL $Folder - gives error when run against a folder with no admin perms or ownership #Create a new ACL object for the sole purpose of defining a new owner, and apply that update to the existing folder's ACL $NewOwnerACL = New-Object System.Security.AccessControl.DirectorySecurity #Establish the folder as owned by BUILTIN\Administrators, guaranteeing the following ACL changes can be applied $Admin = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators") $NewOwnerACL.SetOwner($Admin) #Merge the proposed changes (new owner) into the folder's actual ACL $Folder.SetAccessControl($NewOwnerACL)



    www.computingimprovements.com



    Will this code will work on CIFS shares ? like \\ServerName\Users\<Users_HomeFolderName>\
    Tuesday, July 18, 2017 12:04 PM
  • So any other ideas when Set-Acl, takeowner, and icacls does not work, still get's the "Attempt to perform an unauthorized operation" message?
    Friday, November 22, 2019 3:24 PM