PowerShell Pipeline

Managing Owners of Files and Folders with PowerShell

Here is how to update the owner permissions on a file that cannot be accessed.

If you have been in almost any IT role or even just working with your computer at home, odds are that you have had to work with file permissions and, at some point, been required to change the owner of a file or folder. You may have to do this for a number of reasons, such as gaining access to a folder so that you can set permissions in the event something has happened that removed all permissions from the object.

The first thing that we need to do is find a folder that is in need of an owner update. In my case, I have a folder that had ownership from an account that no longer exists -- which results in a SID being displayed instead of the user account.

PS C:\Users\proxb\Desktop> Get-Acl .\Test | Format-List
Path   :  Microsoft.PowerShell.Core\FileSystem::C:\Users\proxb\Desktop\Test
Owner  : O:S-1-5-21-1622209884-4033722606-793030036-1005
Group  : PROX-PC\proxb
Access : NT AUTHORITY\SYSTEM Allow  FullControl
BUILTIN\Administrators Allow  FullControl
PROX-PC\proxb Allow  FullControl
Audit  :
Sddl   : O:S-1-5-21-1622209884-4033722606-793030036-1005G:S-1-5-21-1622209884-4033722606-793030036-1001D:AI(A;OICII
D;FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-1622209884-4033722606-793030036-1001)

We can see that the Owner property is just a SID and means that we could have potential issues if something happened to the existing permissions on the folder. We could use Windows Explorer to graphically locate the folder and view the properties and then set a new owner of the folder, but what fun is that? We also can make use of a utility called takeown.exe, which has a set of switches that can be used to set the owner of a folder and subfolders to either the current user or the built-in Administrators group. Definitely nice, but I don't want to be limited to what account or group that can own the folder. Instead, we will dip our toes into some .NET types to help with making the change of ownership from the SID to another user account.

First thing that we need to do is get the current ACL object of the folder.

$ACL = Get-Acl .\Test 

Let's take a look at the object and see if we can find a method that will help us change the owner.

 

PS C:\Users\proxb\Desktop> $ACL | Get-Member

 

   TypeName: System.Security.AccessControl.DirectorySecurity

Name                            MemberType     Definition                                                         
----                            ----------     ----------                                                         
Access                          CodeProperty   System.Security.AccessControl.AuthorizationRuleCollection Access{...
CentralAccessPolicyId           CodeProperty   System.Security.Principal.SecurityIdentifier CentralAccessPolicyI...
CentralAccessPolicyName         CodeProperty   System.String CentralAccessPolicyName{get=GetCentralAccessPolicyN...
Group                           CodeProperty   System.String Group{get=GetGroup;}                                  
Owner                           CodeProperty   System.String Owner{get=GetOwner;}                                 
Path                            CodeProperty   System.String Path{get=GetPath;}                                    
Sddl                            CodeProperty   System.String Sddl{get=GetSddl;}                                   
AccessRuleFactory               Method         System.Security.AccessControl.AccessRule AccessRuleFactory(System...
AddAccessRule                   Method         void AddAccessRule(System.Security.AccessControl.FileSystemAccess...
AddAuditRule                    Method         void AddAuditRule(System.Security.AccessControl.FileSystemAuditRu...
AuditRuleFactory                Method         System.Security.AccessControl.AuditRule AuditRuleFactory(System.S...
Equals                          Method         bool Equals(System.Object obj)                                     
GetAccessRules                  Method         System.Security.AccessControl.AuthorizationRuleCollection GetAcce...
GetAuditRules                   Method         System.Security.AccessControl.AuthorizationRuleCollection GetAudi...
GetGroup                        Method         System.Security.Principal.IdentityReference GetGroup(type targetT...
GetHashCode                     Method         int GetHashCode()                                                  
GetOwner                        Method         System.Security.Principal.IdentityReference GetOwner(type targetT...
GetSecurityDescriptorBinaryForm Method         byte[] GetSecurityDescriptorBinaryForm()                           
GetSecurityDescriptorSddlForm   Method         string GetSecurityDescriptorSddlForm(System.Security.AccessContro...
GetType                         Method         type GetType()                                                     
ModifyAccessRule                Method         bool ModifyAccessRule(System.Security.AccessControl.AccessControl...
ModifyAuditRule                 Method         bool ModifyAuditRule(System.Security.AccessControl.AccessControlM...
PurgeAccessRules                Method         void PurgeAccessRules(System.Security.Principal.IdentityReference...
PurgeAuditRules                 Method         void PurgeAuditRules(System.Security.Principal.IdentityReference ...
RemoveAccessRule                Method         bool RemoveAccessRule(System.Security.AccessControl.FileSystemAcc...
RemoveAccessRuleAll             Method         void RemoveAccessRuleAll(System.Security.AccessControl.FileSystem...
RemoveAccessRuleSpecific        Method         void RemoveAccessRuleSpecific(System.Security.AccessControl.FileS...
RemoveAuditRule                 Method         bool RemoveAuditRule(System.Security.AccessControl.FileSystemAudi...
RemoveAuditRuleAll              Method         void RemoveAuditRuleAll(System.Security.AccessControl.FileSystemA...
RemoveAuditRuleSpecific         Method         void RemoveAuditRuleSpecific(System.Security.AccessControl.FileSy...
ResetAccessRule                 Method         void ResetAccessRule(System.Security.AccessControl.FileSystemAcce...
SetAccessRule                   Method         void SetAccessRule(System.Security.AccessControl.FileSystemAccess...
SetAccessRuleProtection         Method         void SetAccessRuleProtection(bool isProtected, bool preserveInher...
SetAuditRule                    Method         void SetAuditRule(System.Security.AccessControl.FileSystemAuditRu...
SetAuditRuleProtection          Method         void SetAuditRuleProtection(bool isProtected, bool preserveInheri...
SetGroup                        Method         void SetGroup(System.Security.Principal.IdentityReference identity)
SetOwner                        Method         void SetOwner(System.Security.Principal.IdentityReference identity)
SetSecurityDescriptorBinaryForm Method         void SetSecurityDescriptorBinaryForm(byte[] binaryForm), void Set...
SetSecurityDescriptorSddlForm   Method         void SetSecurityDescriptorSddlForm(string sddlForm), void SetSecu...
ToString                        Method         string ToString()                                                  
PSChildName                     NoteProperty   string PSChildName=Test                                            
PSDrive                         NoteProperty   PSDriveInfo PSDrive=C                                              
PSParentPath                    NoteProperty   string PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\User...
PSPath                          NoteProperty   string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\Users\prox...
PSProvider                      NoteProperty   ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem       
AccessRightType                 Property       type AccessRightType {get;}                                        
AccessRuleType                  Property       type AccessRuleType {get;}                                         
AreAccessRulesCanonical         Property       bool AreAccessRulesCanonical {get;}                                
AreAccessRulesProtected         Property       bool AreAccessRulesProtected {get;}                                
AreAuditRulesCanonical          Property       bool AreAuditRulesCanonical {get;}                                 
AreAuditRulesProtected          Property       bool AreAuditRulesProtected {get;}                                 
AuditRuleType                   Property       type AuditRuleType {get;}                                          
AccessToString                  ScriptProperty System.Object AccessToString {get=$toString = "";...               
AuditToString                   ScriptProperty System.Object AuditToString {get=$toString = "";... 

Looking at the Owner property, I can see that it only has a Get verb available, which tells us that the property is read only and cannot be easily change just by setting the Owner property with a new value. Instead, looking at the available methods, we can see there is a SetOwner() method that we can use.

Now let's take a quick look at what the SetOwner() method is expecting for input for its parameter.

PS C:\Users\proxb\Desktop> $ACL.SetOwner

OverloadDefinitions                                                 
-------------------                                                 
void SetOwner(System.Security.Principal.IdentityReference identity)

I was half expecting that it would just end up being a string type for a username, but instead we have an identity parameter expecting a type of System.Security.Principal.IdentityReference instead. Don't be too intimidated by this particular type, as we will quickly create an object that meets this type requirement.

Just for kicks, let's see what happens if we try to force a string input of a user account to SetOwner() and see if we get an error or not.

PS C:\Users\proxb\Desktop> $ACL.SetOwner('smithb')
Cannot convert argument "identity", with value: "smithb", for "SetOwner" to type
"System.Security.Principal.IdentityReference": "Cannot convert the "smithb" value of type "System.String" to type
"System.Security.Principal.IdentityReference"."
At line:1 char:1
+ $ACL.SetOwner('smithb')
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

As you can see, the method will not try to coerce the string type to the IdentityReference type that it is expecting and throws an error. With that, we now need to make our IdentityReference object so that we can use it to successfully change the owner of the folder.

So I may not have been completely honest in that last sentence. Instead of the IdentityReference object, I will instead create an object using the System.Security.Principal.NTAccount object. The constructor of this type allows for two possible parameters to supply in a single string username or a string domain along with a string username.

PS C:\Users\proxb\Desktop>  [System.Security.Principal.NTAccount]::new

OverloadDefinitions                                                                                               
-------------------                                                                                                
System.Security.Principal.NTAccount new(string domainName, string accountName)                                    
System.Security.Principal.NTAccount new(string name)  

Note that the New() method is only available in PowerShell v5 which we can use to view all of the possible constructors. If you are using a version lower than 5, you can use my Get-Constructor function to assist with locating constructors of an object.

Since I am not worried about domains, I will just roll with my username "smithb" to create the object and then we can see if it will work with SetOwner().

PS C:\Users\proxb\Desktop> $User = New-Object  System.Security.Principal.NTAccount("smithb")
$User

Value
-----
smithb

So far, so good. Now we can move forward with our attempt to change the owner to our account and see if it sticks.
$ACL.SetOwner($User)
Set-Acl -Path .\Test -AclObject $ACL

Notice that I have to use Set-Acl with the $ACL object to reapply the object back to the folder. Just setting the owner using SetOwner() will not make the change to the folder. Once we have done that, we can verify that it actually worked by viewing the ACL of the folder one last time.

 

PS C:\Users\proxb\Desktop> Get-Acl .\Test | Format-List

 

Path   : Microsoft.PowerShell.Core\FileSystem::C:\Users\proxb\Desktop\Test
Owner  : PROX-PC\smithb
Group  : PROX-PC\proxb
Access : NT AUTHORITY\SYSTEM Allow  FullControl
BUILTIN\Administrators Allow  FullControl
PROX-PC\proxb Allow  FullControl
Audit  :
Sddl   : O:S-1-5-21-1622209884-4033722606-793030036-1006G:S-1-5-21-1622209884-4033722606-793030036-1001D:AI(A;OICIID;
FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-1622209884-4033722606-793030036-1001)

Just as we planned it! The owner has been changed from a SID of a long-gone account to smithb. You can now take this knowledge and create your own script (or one that I wrote) to quickly set the owner of a folder or folders quickly using PowerShell!

comments powered by Disqus
Most   Popular