Showing posts with label ntfs. Show all posts
Showing posts with label ntfs. Show all posts

Wednesday, September 30, 2009

SetNTFSOwner

So, it has been quite a while now since my last blog, and i'm starting to go into the DT's. Finally, I have some release!

One of my glorious tasks I have in my current role is to migrate File servers due to lifecycle events, acquisitions, upgrades...what-nots. While doing this users have a tendancy of copying data to their local workstation, then moving it back. Welcome to maintained Ownership of files/folders. Part of my team's responsiblities is to manage NTFS permisions on our servers. When the Owner is set to anything other than "BUILTIN\Administrators" permissions abilities can be lost until the local group has been given ownership again.

One of my best friends in PoShing is Google. Now, search google for powershell set ntfs owner and you'll find blisteringly long scripts and confusing answers, even some that say you must use third-party cmdlets. Lets do this as simple as possible, natively in PoSh:

FUNCTION

function SetNTFSOwner {
  param (
    [string]$path,
    [string]$owner
  )

  $children = Get-ChildItem $path -Recurse | % {$_.FullName} foreach ($child in $children) {
    $acl = Get-Acl $child
    $split = $owner.Split("\")
    if ($acl.Owner -ne $owner) {
        if ($owner -match "BUILTIN") { $objGroup = New-Object System.Security.Principal.NTAccount($split[1]) }
        else { $objGroup = New-Object System.Security.Principal.NTAccount($split[0],$split[1]) }
        $strSID = $objGroup.Translate([System.Security.Principal.SecurityIdentifier])
        $acl.SetOwner($strSID)
    }
    Set-Acl -Path $child -AclObject $acl
  }
}
 code: copy : expand : collapse

STEP-BY-STEP
param (
    [string]$path,
    [string]$owner
)
Our script will take two parameters, and both are required: -path and –owner. The information must be passed to know what folders need changed, and who the owner should be.

$children = Get-ChildItem $path -Recurse | % {$_.FullName}
From the path we need to get all child folders and files. Gathering just the parent level could leave trailing files or folders that had still other owners set.

$acl = Get-ACL $child
Get-ACL gathers the security of the individual file/folder

$split = $owner.Split("\")
splits the $owner string into an object with two values

if ($acl.Owner -ne $owner)
Here we’ll validate the current Owner against our preferred Owner. There is no reason to spend the cycles setting ACL’s if they are already correct.

if ($owner -match "BUILTIN") { $objGroup = New-Object System.Security.Principal.NTAccount($split[1]) }
else { $objGroup = New-Object System.Security.Principal.NTAccount($split[0],$split[1]) }
When retrieving accounts with the System.Security.Principal.NTAccount .NET Class Local and Domain accounts must be handled differently. Local accounts use a single string to retrieve; the User/Group name only. Domain accounts must use two strings; the Domain and User/Group name.

$strSID = $objGroup.Translate([System.Security.Principal.SecurityIdentifier])
$acl.SetOwner($strSID)
The SID for the account is translated from the NTAccount using the .NET class System.Security.Principal.SecurityIdentifier. The unique SID must be passed using the .SetOwner method of our collected ACL.

We now have the corrected settings stored in our object $acl. It’s time to write it back to our file/folder.

Set-Acl -Path $child -AclObject $acl
Since we gathered the ACL using Get-ACL the object is in correct format already. It is simply set back to the object we gathered it from.

Bingo, Done!

It is important to know that this script should be run from the local workstation or sever to where the data resides. It can be run on a remote file store passing the path using its full UNC and the group name as “%COMPUTERNAME%\%GROUP”, but will be extremely slow.

USAGE
SetNTFSOwner "folder\or\file" "DOMAIN\owner"
This function can be piped to easily. If you wanted to set the owner on all subdirectories, but not the parent simply:
Get-ChildItem %PATH% | % {SetNTFSOwner $_ "DOMAIN\Owner"
or for a list already gathered:
Get-Content %file% | % {SetNTFSOwner $_ "DOMAIN\Owner"

ALIASES
% = ForEach-Object