The cmdlet Get-ACL is very capable when it comes to NTFS permissions, but it cannot read share permissions. This function makes an effort to provide a simple way to return share security (and other information) from a share.
The function makes use of two WMI Classes, Win32_Share and Win32_LogicalShareSecuritySetting. To simplify enumeration each Access Control Entry found within the shares Discretionary Access Control List is converted to a FileSystemAccessRule before being added to the Access object, allowing the access to be displayed in a similar way to Access from Get-ACL.
Security information is only returned for shares of type 0, standard shared folders. Security for automatically generated administrative shares will not show. Access is added to the remainder of the information returned by Win32_Share. The Control Flags for the security descriptor are available, but not interesting as they are set to DiscretionaryAclPresent and SelfRelative.
The function accepts two parameters, the name of the share, and optionally the name of a computer. With no parameters, information for all shares on the computer is returned. WQL wildcards are supported (% and _) within the share name.
Get-ShareACL
Function Get-ShareACL {
Param(
[String]$Name = "%",
[String]$Computer = $Env:ComputerName
)
$Shares = @()
Get-WMIObject Win32_Share `
-Computer $Computer -Filter "Name LIKE '$Name'" | `
%{
$Access = @();
If ($_.Type -eq 0) {
$SD = (Get-WMIObject -Class Win32_LogicalShareSecuritySetting `
-Computer $Computer `
-Filter "Name='$($_.Name)'").GetSecurityDescriptor().Descriptor
$SD.DACL | %{
$Trustee = $_.Trustee.Name
If ($_.Trustee.Domain -ne $Null) {
$Trustee = "$($_.Trustee.Domain)\$Trustee"
}
$Access += New-Object Security.AccessControl.FileSystemAccessRule( `
$Trustee, $_.AccessMask, $_.AceType)
}
}
$_ | Select-Object Name, Path, Description, Caption, `
@{n='Type';e={ Switch ($_.Type) {
0 { "Disk Drive" }
1 { "Print Queue" }
2 { "Device" }
2147483648 { "Disk Drive Admin" }
2147483649 { "Print Queue Admin" }
2147483650 { "Device Admin" }
2147483651 { "IPC Admin" } }} }, `
MaximumAllowed, AllowMaximum, Status, InstallDate, `
@{n='Access';e={ $Access }}
}
}
Example
PS C:\> Get-ShareACL Test
Name : Test
Path : C:\Test
Description :
Caption : Test
Type : Disk Drive
MaximumAllowed :
AllowMaximum : True
Status : OK
InstallDate :
Access : {System.Security.AccessControl.FileSystemAccessRule}
PS C:\> (Get-ShareACL Test).Access
FileSystemRights : ReadAndExecute
AccessControlType : Allow
IdentityReference : somedomain\chrisdent
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.
Kleine Tipps für Zwischendurch (Teil 13) – Umgang mit UNC-Pfaden « Peter’s PowerShell Blog (German only) says:
[...] Wie sich per WMI und der Win32_LogicalShareSecuritySetting-Klasse die Freigabeberechtigungen auslesen lassen, verrät ein interessanter Blog-Eintrag. [...]
May 22, 2009, 12:28 pmJustin McAlister says:
Hi Chris,
I have been trying to do something similar, and was wondering if you came up with the same results. So with share level permissions there are really only 3 levels of access granting Read, Change, and Full Control. So I put this together and it reports against those 3 without any issues:
(GWMI Win32_LogicalShareSecuritySetting -Computer SERVERNAME).GetSecurityDescriptor().Descriptor.DACL | Select ` @{N="Account Name";E={ If($_.Trustee.Domain -eq $null){$_.Trustee.Name} Else{$_.Trustee.Domain + "\" + $_.Trustee.Name} }}, ` @{N="Share Permissions";E={ Switch($_.AccessMask){ 2032127 {$strSharePerm = "Full Control"} 1179817 {$strSharePerm = "Read"} 1245631 {$strSharePerm = "Change"} Default {$strSharePerm = "Unknown"} } $strSharePerm }}Please excuse the ugly formatting, and I am sure there is a far better way to do it, but my issue is with implicitly denied share permissions. The .AccessMask property value for allow full control appears to be the same as deny full control. Same with read and change. Now it’s a rare case where I come acrossed deny share permissions, but it’s possible.
I was wondering if you has the same issue with your function. This is omnipower321 from EE by the way. You have answered a ton of my questions, and I am a fan of your site.
April 26, 2010, 7:13 pmChris says:
My function cheats a little, passing the values from the ACE into the constructor for Security.AccessControl.FileSystemAccessRule. You’re spot on with the access mask value behaviour. To finish it off you need to read the AceType, that’ll tell you if it’s Allow or Deny.
Chris
April 26, 2010, 7:24 pmJustin McAlister says:
Got it! Thank you very much.
April 26, 2010, 7:37 pmMladen Milunovic says:
Hi, here is a script that list NTFS permissions for remote shares. Only thing is you have to enter shares manualy in to text file.
#========================================================================== # NAME: ACL on Shared folder # AUTHOR: Mladen # DATE : 01/12/2010 # COMMENT: Check permissions on NTFS shared folder and send report to excel # REQUIREMENTS: QuestAD for PowerShell (Quest ActiveRoles), Excel, Acces to share # shares.txt is file with shares in format \\server\share1 #========================================================================== #$erroractionpreference = "SilentlyContinue" $a = New-Object -comobject Excel.Application $a.visible = $True $b = $a.Workbooks.Add() $c = $b.Worksheets.Item(1) $c.Cells.Item(1,1) = "Share" $c.Cells.Item(1,2) = "Account" $c.Cells.Item(1,3) = "Permission" $c.Cells.Item(1,4) = "User Name" $d = $c.UsedRange $d.Interior.ColorIndex = 19 $d.Font.ColorIndex = 11 $d.Font.Bold = $True $intRow = 2 $colShares = get-content shares.txt foreach ($strShare in $colShares) { $c.Cells.Item($intRow, 1) = $strShare $c.Cells.Item($intRow, 1).Font.Bold = $True $acl = Get-Acl $strShare $perm = $acl.Access foreach ($object in $perm) { $intRow = $intRow + 1 $userName = [string]$object.IdentityReference $c.Cells.Item($intRow, 2) = $userName $c.Cells.Item($intRow, 3) = [string]$object.FileSystemRights $fullName = Get-QADUser $userName $c.Cells.Item($intRow, 4) = $fullName.Name } $intRow = $intRow + 1 } $d.EntireColumn.AutoFit()Regards,
December 23, 2010, 9:09 amMladen.
Gord Moore says:
Nice piece of kit – very nice little script that was just what I was after.
November 4, 2011, 1:25 am