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!