locked
Taking Ownership of folders and files RRS feed

  • Question

  • So I am doing what sure seems like way too much work to do something rather simple in GUI. There seem to be many topics on this and I base my code off of their results, but it isn't working entirely. Hopefully an easy one for you folks!  I am trying to take ownership of a path, be it a file or folder.  I DO NOT want to use a separate module like PSCX as not all machines will have the module.

    I created a function based off the code I found at the end of http://social.technet.microsoft.com/Forums/en-US/87679d43-04d5-4894-b35b-f37a6f5558cb/ that I can pass a path to singularly or I was hoping to be able to pipe Get-ChildItem to it.  When I do "Get-ChildItem -Path D:\Permissions\TopFolder -Recurse -Force | Take-Ownership" it seemed to work, but then I noticed it only seems to work going one layer deep. The text output for troubleshooting shows it recursing all the way through, but yet Owner is not being set all the way down.

    Folder layout:
    D:\Permissions\TopFolder
    D:\Permissions\TopFolder\FirstFolder
    D:\Permissions\TopFolder\FirstFile.txt
    D:\Permissions\TopFolder\FirstFolder\SecondFolder
    D:\Permissions\TopFolder\FirstFolder\SecondFile.txt
    D:\Permissions\TopFolder\FirstFolder\SecondFolder\ThirdFolder
    D:\Permissions\TopFolder\FirstFolder\SecondFolder\ThirdFile.txt

    Function Take-Ownership {
        [CmdletBinding(DefaultParameterSetName=”Set01”)]
        Param(
            [parameter(Mandatory=$true,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True,Position=1,ParameterSetName='Set01')]
            [string]$Path,
            
            [parameter(Mandatory=$true,ValueFromPipelinebyPropertyName=$True,ParameterSetName='Set02')]
            [Alias('FullName')][string]$FullPath
        ) # End of Param()
    
        Begin {
        
            #----------------------------------------------------------------
            # Check that script was Run as Administrator
            #----------------------------------------------------------------
            If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
            [Security.Principal.WindowsBuiltInRole] "Administrator")) {
                Write-Host -ForegroundColor Red -BackgroundColor Black "`n ERROR: You MUST have Administrator rights to run this script!"
                Write-Host -ForegroundColor Red -BackgroundColor Black "        Re-run this script as an Administrator!`n"
                Break
            }
    
            #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
    
            # Activate necessary admin privileges to make changes without NTFS perms on the folder
            [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 File Permissions
        
            $Admin      = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
            $NewDirACL  = New-Object System.Security.AccessControl.DirectorySecurity
            $NewFileACL = New-Object System.Security.AccessControl.FileSecurity
            $NewDirACL.SetOwner($Admin)
            $NewFileACL.SetOwner($Admin)
    
        } # End of Begin {}
        
        Process {
            if( $FullPath.Length -gt 0 ) {
                if( Test-Path $FullPath ) {
                    $Path = $FullPath
                }
            }
            
            if( Test-Path $Path -PathType Container ) {
                "Take Ownership:  $Path"
                $Folder = Get-Item $Path -Force
                $Folder.SetAccessControl($NewDirACL)
            } elseif( Test-Path $Path -PathType Leaf ) {
                "Take Ownership:  $Path"
                $File = Get-Item $Path -Force
                $File.SetAccessControl($NewFileACL)
            } else {
                Write-Host -ForegroundColor Red -BackgroundColor Black "ERROR:  Path does not exist:  $Path"
            }
                
        } # End of Process {}
    
        End { } # End of End {}
    
    } # End of Function Take-Ownership
    
    

    To run this I have been doing:

    PS D:\> $Folder = 'D:\Permissions\TopFolder' PS D:\> Get-Item $Folder | Get-Acl Directory: D:\Permissions Path Owner ---- ----- TopFolder DOMAIN\user1 PS D:\> Get-ChildItem $Folder -Force -Recurse | Get-Acl Directory: D:\Permissions\TopFolder Path Owner ---- ----- FirstFolder DOMAIN\user1 FirstFile.txt DOMAIN\user1 Directory: D:\Permissions\TopFolder\FirstFolder Path Owner ---- ----- SecondFolder DOMAIN\user1 SecondFile.txt DOMAIN\user1 Directory: D:\Permissions\TopFolder\FirstFolder\SecondFolder Path Owner ---- ----- ThirdFolder DOMAIN\user1 ThirdFile.txt DOMAIN\user1 PS D:\> PS D:\> Get-Item $Folder | Take-Ownership Take Ownership: D:\Permissions\TopFolder PS D:\> Get-ChildItem $Folder -Force -Recurse | Take-Ownership Take Ownership: D:\Permissions\TopFolder\FirstFolder Take Ownership: D:\Permissions\TopFolder\FirstFile.txt Take Ownership: D:\Permissions\TopFolder\FirstFolder\SecondFolder Take Ownership: D:\Permissions\TopFolder\FirstFolder\SecondFile.txt Take Ownership: D:\Permissions\TopFolder\FirstFolder\SecondFolder\ThirdFolder Take Ownership: D:\Permissions\TopFolder\FirstFolder\SecondFolder\ThirdFile.txt PS D:\> PS D:\> PS D:\> Get-Item $Folder | Get-Acl Directory: D:\Permissions Path Owner ---- ----- TopFolder BUILTIN\Administrators PS D:\> Get-ChildItem $Folder -Force -Recurse | Get-Acl Directory: D:\Permissions\TopFolder Path Owner ---- ----- FirstFolder BUILTIN\Administrators FirstFile.txt BUILTIN\Administrators Directory: D:\Permissions\TopFolder\FirstFolder Path Owner ---- ----- SecondFolder DOMAIN\user1 SecondFile.txt DOMAIN\user1 Directory: D:\Permissions\TopFolder\FirstFolder\SecondFolder Path Owner ---- ----- ThirdFolder DOMAIN\user1 ThirdFile.txt DOMAIN\user1 PS D:\>


    I don't know why this isn't working.  The output text shows I went through the subfolders and files...HELP!


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

    Monday, March 31, 2014 8:33 PM

Answers

  • Here is the end result. I am looking to add a '-Recurse'/'-Force' switches to give another option to not have to Get-ChildItem and pipe it to the function and possibly a '-User' parameter to be able to specify who to set as owner, but both of those ideas are untested.

    Here is the code.  Hope it helps someone else.

    Function Take-Ownership {
    <#
    .SYNOPSIS
    
    This function takes ownership of a file or folder and sets it back to 'BUILTIN\Administrators'.
    
    .DESCRIPTION
    
    This function takes ownership of a file or folder and sets it back to 'BUILTIN\Administrators'.  
    This will work even when the user does not have ownership or existing permissions on the file or folder.
    
    .EXAMPLE 
    
    PS C:\> Take-Ownership -Path $Path
    Takes ownership of the individual folder or file.  The -Path is optional as long as $Path 
    is the first parameter.
      
    .EXAMPLE 
    
    PS C:\> Get-Item $Path | Take-Ownership
    Takes ownership of the individual folder or file.  
    
    .EXAMPLE 
    
    PS C:\> Get-ChildItem $Path -Recurse -Force | Take-Ownership
    Recurse through all folders and files, including hidden, and takes ownership.
    
    #>
        [CmdletBinding()]
        Param(	
            [parameter(Mandatory = $true, ValueFromPipeline = $True, ValueFromPipelinebyPropertyName = $True, Position = 0)]
    	    [Alias('FullName')]
    	    [string]$Path
        ) # End of Param()
    
        Begin {
        
            #----------------------------------------------------------------
            # Check that script was Run as Administrator
            #----------------------------------------------------------------
            If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
            [Security.Principal.WindowsBuiltInRole] "Administrator")) {
                Write-Host -ForegroundColor Red -BackgroundColor Black "`n ERROR: You MUST have Administrator rights to run this script!"
                Write-Host -ForegroundColor Red -BackgroundColor Black "        Re-run this script as an Administrator!`n"
                Return
            }
    
            #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
    
            # Activate necessary admin privileges to make changes without NTFS perms on the folder
            [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 File Permissions
     
        } # End of Begin {}
        
        Process {
        
            #------------------------------------------------------------------------------
            # Process for taking Ownership of the folder
            # - Specify the NT Account user to set as Owner (BUILTIN\Administrators)
            # - Create a new ACL object for the sole purpose of defining a new owner
            # - Establish the new ACL as owned by BUILTIN\Administrators, thus 
            #   guaranteeing the following ACL changes can be applied.
            # - Then apply that update to the existing folder's ACL which merges
            #   the proposed changes (new owner) into the folder's actual ACL
            # - - IN OUR CASE OVERWRITING THE OWNER
            # - Additional Documentation:  
            #   http://msdn.microsoft.com/en-us/library/System.Security.AccessControl(v=vs.110).aspx
            #------------------------------------------------------------------------------
            $Admin      = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
            $NewDirACL  = New-Object System.Security.AccessControl.DirectorySecurity
            $NewFileACL = New-Object System.Security.AccessControl.FileSecurity
            $NewDirACL.SetOwner($Admin)
            $NewFileACL.SetOwner($Admin)
    
            if( Test-Path $Path -PathType Container ) {
                $Folder = Get-Item $Path -Force
                $Folder.SetAccessControl($NewDirACL)
            } elseif( Test-Path $Path -PathType Leaf ) {
                $File = Get-Item $Path -Force
                $File.SetAccessControl($NewFileACL)
            } else {
                Write-Host -ForegroundColor Red -BackgroundColor Black "ERROR:  Path does not exist:  $Path"
            }
                
        } # End of Process {}
    
        End { } # End of End {}
    
    } # End of Function Take-Ownership
    
    


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

    • Marked as answer by Chase Roth Tuesday, April 1, 2014 7:02 PM
    Tuesday, April 1, 2014 7:01 PM
  • Hi Chase,

    I had the same issue on my test System (Win 7 x64, PS V2), and found a solution that worked for me:

    Move the following four lines into the Process Block:

    $NewDirACL  = New-Object System.Security.AccessControl.DirectorySecurity
    $NewFileACL = New-Object System.Security.AccessControl.FileSecurity
    $NewDirACL.SetOwner($Admin)
    $NewFileACL.SetOwner($Admin)

    Turns out it dislikes reusing Acl objects ...

    Cheers,
    Fred


    There's no place like 127.0.0.1

    • Marked as answer by Chase Roth Tuesday, April 1, 2014 7:02 PM
    Tuesday, April 1, 2014 12:43 PM

All replies

  • Hi Chase,

    can't guarantee I found the issue, I did find some odd things however ...

    • Your Parametersets appear somewhat redundant, since you handle both inputs the same.
    • Positional indexes for parameters start at 0, not 1.
    • You exit your elevation validation with "break". This can be a bad idea, I recommend either throwing an exception or using return.
    • You create new ACLs instead of manipulating existing ones. Don't think that's too great an idea and there is no need. Example on alternative following ...
    if (Test-Path $Path)
    {
    	$item = Get-Item $Path
    	"Take Ownership:  $($item.FullName)"
    	$Acl = Get-Acl $item
    	$Acl.SetOwner($Admin)
    	$Acl | Set-Acl $item
    }
    else
    {
    	Write-Host -ForegroundColor Red -BackgroundColor Black "ERROR:  Path does not exist:  $Path"
    }

    Hope this helps,
    Cheers,
    Fred


    There's no place like 127.0.0.1

    Tuesday, April 1, 2014 7:16 AM
  • Hi Chase,

    can't guarantee I found the issue, I did find some odd things however ...

    • Your Parametersets appear somewhat redundant, since you handle both inputs the same.
    • Positional indexes for parameters start at 0, not 1.
    • You exit your elevation validation with "break". This can be a bad idea, I recommend either throwing an exception or using return.
    • You create new ACLs instead of manipulating existing ones. Don't think that's too great an idea and there is no need.

    Fred, thanks for the follow up.  See my responses to you suggestions/information below.

    Your Parametersets appear somewhat redundant, since you handle both inputs the same

    The reason behind the parameter sets being very close to the same is to be able to take in the Piped input.  If I pipe Get-ChildItem by default I found it will use the "Path" which is just the folder or file name (you can see in my Get-Acl above similar results).  So when Get-Item runs it tried to use just the file or folder name and can't find it since it could be multiple layers down and the path is not valid.

    I used the second parameter of FullPath because I like the name better than FullName and I thought it more descriptive, but I used the Alias "FullName" since Get-ChildItem does send FullName as one of its properties when it Pipes data to the next command.  FullName is the entire path to the file or folder so Get-Item can be successful. 

    Is there a different way you can show me to accomplish the same idea?

    Positional indexes for parameters start at 0, not 1

    Oops.  That was an oversight.  I'll make that change.  Thanks.

    You exit your elevation validation with "break". This can be a bad idea, I recommend either throwing an exception or using return

    Ok.  I change change that to "return", but I don't know how to "throw an exception".  Is one better than the other?

    You create new ACLs instead of manipulating existing ones. Don't think that's too great an idea and there is no need

    I believe I must do it that way.  The reason I created this function is because I can't access a home folder for example, someone changed permissions on and I no longer have rights or owner of the folder or file.  So in that case I do not have privileges to do the Get-Acl command.  It fails.  So I have to elevate myself by granting  the necessary privileges to take ownership, then create a blank ACL, apply the owner, and finally apply it to the folder or file.

    I found I could not apply DirectorySecurity to a File and I could not apply FileSecurity to a folder, so unless there is a different security context I can use I found I need to determine whether the item is a file or folder so I can apply the right one.

    -----------------------

    Fred, thanks for the suggestions. I'll be making some of those changes as mentioned.  My issue still remains thought I believe in that it is not Recursing down and taking ownership even though the text output shows the "FullName"/"FullPath" is a valid path.

    Any further thoughts or suggestions?  I think I'll try to just output the commands to the screen and see what the actual commands are saying to do instead of executing them for troubleshooting...maybe that will show me something.


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



    • Edited by Chase Roth Tuesday, April 1, 2014 10:42 AM typos
    Tuesday, April 1, 2014 10:39 AM
  • Hi Chase,

    regarding the parameterset thing: This works just fine for me:

    [CmdletBinding()]
    Param (
    	[parameter(Mandatory = $true, ValueFromPipeline = $True, ValueFromPipelinebyPropertyName = $True, Position = 0)]
    	[Alias('FullName')]
    	[string]$Path
    )

    Exception vs. Return
    Using return is perfectly fine when using in direct user interaction as the actual function called by the user. It's less cool if you use the function in another function, since it won't know whether things worked out. You can throw an exception by doing something like this:

    # Simple
    throw "Function was called without elevation! Reexecute as Administrator."
    
    # Not as simple
    throw (New-Object System.InvalidOperationException("Function was called without elevation! Reexecute as Administrator."))

    The former way is faster do and easier to read. The latter method allows differentiation between exception types (easier to handle in a try-catch statement, especially when differentiating between multiple error opportunities). Both methods will write one of these ugly red statements into the shell, when used interactively.

    ACL Question
    If you overwrite the old acl with the new one, do you keep your individual folder permissions or does it end up being blank?

    Anyway, I'll load it up on my test system and give it a run. What Powershell Version are you using? On what OS?

    Cheers,
    Fred



    There's no place like 127.0.0.1

    Tuesday, April 1, 2014 12:11 PM
  • Hi Chase,

    I had the same issue on my test System (Win 7 x64, PS V2), and found a solution that worked for me:

    Move the following four lines into the Process Block:

    $NewDirACL  = New-Object System.Security.AccessControl.DirectorySecurity
    $NewFileACL = New-Object System.Security.AccessControl.FileSecurity
    $NewDirACL.SetOwner($Admin)
    $NewFileACL.SetOwner($Admin)

    Turns out it dislikes reusing Acl objects ...

    Cheers,
    Fred


    There's no place like 127.0.0.1

    • Marked as answer by Chase Roth Tuesday, April 1, 2014 7:02 PM
    Tuesday, April 1, 2014 12:43 PM
  • Hi Chase,

    I had the same issue on my test System (Win 7 x64, PS V2), and found a solution that worked for me:

    Move the following four lines into the Process Block:

    $NewDirACL  = New-Object System.Security.AccessControl.DirectorySecurity
    $NewFileACL = New-Object System.Security.AccessControl.FileSecurity
    $NewDirACL.SetOwner($Admin)
    $NewFileACL.SetOwner($Admin)

    Turns out it dislikes reusing Acl objects ...

    Cheers,
    Fred


    There's no place like 127.0.0.1

    You are absolutely right!  I moved the ACL stuff into the Process block and it worked!  I also made the other suggested change you gave regarding the parameters making 'FullName' an Alias of $Path.  Man I couldn't see past my own nose on that one!

    Fred, thanks for your very helpful input and ultimately resolving my issue!  +1 for each of your posts.  As an FYI for anyone I am using Win7x64 PSv3.0.


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


    • Edited by Chase Roth Tuesday, April 1, 2014 6:20 PM
    Tuesday, April 1, 2014 6:19 PM
  • Here is the end result. I am looking to add a '-Recurse'/'-Force' switches to give another option to not have to Get-ChildItem and pipe it to the function and possibly a '-User' parameter to be able to specify who to set as owner, but both of those ideas are untested.

    Here is the code.  Hope it helps someone else.

    Function Take-Ownership {
    <#
    .SYNOPSIS
    
    This function takes ownership of a file or folder and sets it back to 'BUILTIN\Administrators'.
    
    .DESCRIPTION
    
    This function takes ownership of a file or folder and sets it back to 'BUILTIN\Administrators'.  
    This will work even when the user does not have ownership or existing permissions on the file or folder.
    
    .EXAMPLE 
    
    PS C:\> Take-Ownership -Path $Path
    Takes ownership of the individual folder or file.  The -Path is optional as long as $Path 
    is the first parameter.
      
    .EXAMPLE 
    
    PS C:\> Get-Item $Path | Take-Ownership
    Takes ownership of the individual folder or file.  
    
    .EXAMPLE 
    
    PS C:\> Get-ChildItem $Path -Recurse -Force | Take-Ownership
    Recurse through all folders and files, including hidden, and takes ownership.
    
    #>
        [CmdletBinding()]
        Param(	
            [parameter(Mandatory = $true, ValueFromPipeline = $True, ValueFromPipelinebyPropertyName = $True, Position = 0)]
    	    [Alias('FullName')]
    	    [string]$Path
        ) # End of Param()
    
        Begin {
        
            #----------------------------------------------------------------
            # Check that script was Run as Administrator
            #----------------------------------------------------------------
            If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
            [Security.Principal.WindowsBuiltInRole] "Administrator")) {
                Write-Host -ForegroundColor Red -BackgroundColor Black "`n ERROR: You MUST have Administrator rights to run this script!"
                Write-Host -ForegroundColor Red -BackgroundColor Black "        Re-run this script as an Administrator!`n"
                Return
            }
    
            #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
    
            # Activate necessary admin privileges to make changes without NTFS perms on the folder
            [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 File Permissions
     
        } # End of Begin {}
        
        Process {
        
            #------------------------------------------------------------------------------
            # Process for taking Ownership of the folder
            # - Specify the NT Account user to set as Owner (BUILTIN\Administrators)
            # - Create a new ACL object for the sole purpose of defining a new owner
            # - Establish the new ACL as owned by BUILTIN\Administrators, thus 
            #   guaranteeing the following ACL changes can be applied.
            # - Then apply that update to the existing folder's ACL which merges
            #   the proposed changes (new owner) into the folder's actual ACL
            # - - IN OUR CASE OVERWRITING THE OWNER
            # - Additional Documentation:  
            #   http://msdn.microsoft.com/en-us/library/System.Security.AccessControl(v=vs.110).aspx
            #------------------------------------------------------------------------------
            $Admin      = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
            $NewDirACL  = New-Object System.Security.AccessControl.DirectorySecurity
            $NewFileACL = New-Object System.Security.AccessControl.FileSecurity
            $NewDirACL.SetOwner($Admin)
            $NewFileACL.SetOwner($Admin)
    
            if( Test-Path $Path -PathType Container ) {
                $Folder = Get-Item $Path -Force
                $Folder.SetAccessControl($NewDirACL)
            } elseif( Test-Path $Path -PathType Leaf ) {
                $File = Get-Item $Path -Force
                $File.SetAccessControl($NewFileACL)
            } else {
                Write-Host -ForegroundColor Red -BackgroundColor Black "ERROR:  Path does not exist:  $Path"
            }
                
        } # End of Process {}
    
        End { } # End of End {}
    
    } # End of Function Take-Ownership
    
    


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

    • Marked as answer by Chase Roth Tuesday, April 1, 2014 7:02 PM
    Tuesday, April 1, 2014 7:01 PM