Windows shares are configured to grant access to certain users or groups on a Windows server. It sounds simple, but there are many questions to be asked beyond if a particular person/group has access to this share or not. Some of these questions (that must be answered) are:
- What kind of access does the user have? (read, change, full control, etc?)
- What if there are multiple users who need different permissions? (Maybe administrators get full control, but regular users get read only)
- Does the share inherit permissions from parents folders, does it pass permissions to child folders?
There are many classes within the Windows Management Instrumentation (about WMI here) that are associated with Windows share security. The classes that are used for share permissions are:
- Win32_Share
- Win32_LogicalShareSecuritySetting
- Win32_SecurityDescriptor
- Win32_ACE
- Win32_Trustee
Combined, all of these WMI classes contain the properties and methods needed to access and manipulate share permissions in powershell. Lets talk about what each of them are and the properties and methods that they contain. The links are the MSDN page for that respective class.
Win32_Share (MSDN page)
Shares are instances of this class. This class has methods which allow you to create/delete shares, etc. To view the shares on your server with powershell, you can use the get-WMIObject cmdlet (gwmi for short). Typically you would want to filter the shares by type, to do that in powershell: gwmi win32_share -filter "type=0"
, type 0 share a disk drive (“normal” shares).
Win32_LogicalShareSecuritySetting (MSDN page)
This class is sort of an intermediate class in between the share and the actual security info. The methods “GetSecurityDescriptor” and “SetSecurityDescriptor” which can be used to get/set the permissions. Win32_LogicalShareSecuritySetting also contains info on what types of security measures are attached to the share (see control flags on MSDN page). To get the Logical Share Security Setting for a specific share, you can type:
gwmi Win32_LogicalShareSecuritySetting -filter "Name='ShareNameHere'"
Replace “ShareNameHere” with the name of the share you want to find security settings for.
Win32_SecurityDescriptor (MSDN here)
Here is where we start to get close to the actual permissions. The security descriptor contains numerous properties, one of them being DACL, which is important for share permissions. DACL stands for Discretionary Access Control List, and it is basically an array (“list”) which has the entries for each user with permissions for that share. Each user has their own entry in the DACL, which is called an ACE (Access Control Entry). To view the security descriptor, we can use the ‘GetSecurityDescriptor’ method in the LogicalShareSecuritySetting as discussed above. If the LogicalShareSecuritySetting of a share is stored in a variable $shareSec, then type:
$Return = $ShareSec.invokeMethod('GetSecurityDescriptor',$null,$null)
$SD = $Return.Descriptor
Win32_ACE (MSDN here, also AceType, AceFlags, AccessMask are here)
So, if we want to look at a particular entry (ACE) in the DACL:
$sd.DACL[0]
The [0] is needed because DACL is essentially an array that we have to index into, so DACL[0] is the first entry. Now we are nearly there. ACE is the WMI object that contains the actual info about who the user is and what permission they have to the share. The properties of Win32_ACE include: Access Mask, Ace Flags, Ace Type, and Trustee. These properties will tell us everything we need to know about the permissions contained in this ACE (DACL[0] for instance). Lets talk about what these properties mean.
- Access mask: this says what permission the user has to access the share. Each access mask is a unique combination of integers which tell what the user is allowed to do (read, write, change, execute, etc.) Look at the values on the MSDN page (under Win32_ACE) for more information.
- ACE Flags: this has to do with permission inheritance. Will the share inherit permissions from parent folders, will it pass them to child folders? The MDSN page shows integers (1,2,4,8, and 16) for ACE flags, add each integer with a value that applies to the share to get a unique integer. This is “ACE flags.” For instance, if non-container (integer = 1) and container (integer = 2) child objects inherit permissions (with no other inheritances) then ACE flags is 3, because you add 1+2.
- ACE type: this one is easy. 0 means allow, 1 means deny. It is important to pay attention to this property. If the access mask says “read,” that does not give the user permission! The user is either allowed or denied the specific permission in the access mask based on ACE type.
- Trustee: this is basically the user that the ACE is referring to. Yet, its more complicated than that because Trustee is a WMI class (not just a string containing a username), so we will go into that more.
Win32_Trustee (MSDN here)
This class contains properties that give info about the user. The properties are name (username), domain, and SID. SID stands for security identifier, it is basically a unique code that verifies the user.
This can all be very confusing because there are so many levels to pass through to get to the actual permissions. I think the best way to think about it is this visual hierarchy:
Remember that the security descriptor isn’t “contained” within the logical share security setting, per se, but the logical share security setting contains the method used to retrieve the security descriptor.
Say we want to find the access mask and user name for an ACE on a particular share. This is the full code we would need in Powershell:
$shares = gwmi win32_Share -filter "Type=0"
$share = $shares[0] # assuming there is more than 1 share in $shares, just picking an #arbitrary share
$shareSec = gwmi Win32_LogicalShareSecuritySetting -filter "name='$($share.name)'"
$sd = $shareSec.invokeMethod('GetSecurityDescriptor',$null,$null)
$Username = $sd.Descriptor.DACL[0].Trustee.Name #If there is more than 1 user with
# permissions (and thus more than 1 ACE) could use DACL[1,2,etc.]
$AccessMask = $sd.Descriptor.DACL[0].AccessMask
When you begin to understand the hierarchy of share security and what objects are contained within, you can do a lot of useful things with Powershell to maintain shares. This includes tasks such as building new shares with permissions, creating new permissions for existing shares, and exporting/importing share permissions to/from CSV files for backup/recovery. In my next few posts I will discuss these useful techniques, especially backing up Share Info with Powershell and CSV files.
Pingback: Exporting Share Info and Permissions with PowerShell and CSV files | Windows Stuff That Your Dreams Dreamed Of
Pingback: Importing Share Info and Permissions with PowerShell and a CSV file | Windows Stuff That Your Dreams Dreamed Of
Pingback: Importing Share Info and Permissions with Powershell and a CSV file (cont’d) | Windows Stuff That Your Dreams Dreamed Of
Very usefull information. My question (hoping you can assist) is how do I set the share permissions for Authenticated Users Change and remove Everyone? Every time I run this, I create the share but Everyone is granted FULL. Can you help?
$Computer = “localhost”
$Class = “Win32_Share”
$Method = “Create”
$name = “TEMP”
$path = “C:\temp”
$description = “This is shared for me to test”
$sd = ([WMIClass] “\\$Computer\root\cimv2:Win32_SecurityDescriptor”).CreateInstance()
$ACE = ([WMIClass] “\\$Computer\root\cimv2:Win32_ACE”).CreateInstance()
$Trustee = ([WMIClass] “\\$Computer\root\cimv2:Win32_Trustee”).CreateInstance()
$Trustee.Name = “Authenticated Users”
$Trustee.Domain = “NT AUTHORITY”
$Trustee.SID = @(1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0)
$ace.AccessMask = 1245631
$ace.AceFlags = 4
$ace.AceType = 0
$ACE.Trustee = $Trustee
$sd.DACL += $ACE.psObject.baseobject
$mc = [WmiClass]”\\$Computer\ROOT\CIMV2:$Class”
$InParams = $mc.psbase.GetMethodParameters($Method)
$InParams.Access = $Null
$InParams.Description = $description
$InParams.MaximumAllowed = $Null
$InParams.Name = $name
$InParams.Password = $Null
$InParams.Path = $path
$InParams.Type = [uint32]0
$R = $mc.PSBase.InvokeMethod($Method, $InParams, $Null)
switch ($($R.ReturnValue))
{
0 {Write-Host “Share:$name Path:$path Result:Success”; break}
2 {Write-Host “Share:$name Path:$path Result:Access Denied” -foregroundcolor red -backgroundcolor yellow;break}
8 {Write-Host “Share:$name Path:$path Result:Unknown Failure” -foregroundcolor red -backgroundcolor yellow;break}
9 {Write-Host “Share:$name Path:$path Result:Invalid Name” -foregroundcolor red -backgroundcolor yellow;break}
10 {Write-Host “Share:$name Path:$path Result:Invalid Level” -foregroundcolor red -backgroundcolor yellow;break}
21 {Write-Host “Share:$name Path:$path Result:Invalid Parameter” -foregroundcolor red -backgroundcolor yellow;break}
22 {Write-Host “Share:$name Path:$path Result:Duplicate Share” -foregroundcolor red -backgroundcolor yellow;break}
23 {Write-Host “Share:$name Path:$path Result:Reedirected Path” -foregroundcolor red -backgroundcolor yellow;break}
24 {Write-Host “Share:$name Path:$path Result:Unknown Device or Directory” -foregroundcolor red -backgroundcolor yellow;break}
25 {Write-Host “Share:$name Path:$path Result:Network Name Not Found” -foregroundcolor red -backgroundcolor yellow;break}
default {Write-Host “Share:$name Path:$path Result:*** Unknown Error ***” -foregroundcolor red -backgroundcolor yellow;break}
}
Jeff,
Thanks for your comment. It seems that you have $null for your InParams.Access value. You should have your built security descriptor here ($sd.psobject.baseobject). This should set access according to your access mask value, I assume it was defaulting to full control.