Skip to content

Instantly share code, notes, and snippets.

@Juanito99
Last active January 16, 2025 13:51
Show Gist options
  • Save Juanito99/44bcc30cd96128b0bcf3fc31c6436474 to your computer and use it in GitHub Desktop.
Save Juanito99/44bcc30cd96128b0bcf3fc31c6436474 to your computer and use it in GitHub Desktop.
List File-Shares with Share and NTFS Permissions in PowerShell
<#
License terms
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
#>
#get all Shares
$shares = Get-WmiObject -Class Win32_Share
$shareList = New-Object -TypeName System.Collections.ArrayList
foreach ($share in $shares) {
#excluding default shares
if (($share.Name -notmatch '(?im)^[a-z]{1,1}\$') -and ($share.Name -notmatch '(?im)^[admin]{5,5}\$') -and ($share.Name -notmatch '(?im)^[ipc]{3,3}\$') -and ($share.Name -notmatch '(?im)^[print]{5,5}\$') ) {
$shareAccessInfo = ''
$ntfsAccessInfo = ''
#extract permissions from the current share
$fileAccessControlList = Get-Acl -Path $($share.Path) | Select-Object -ExpandProperty Access | Select-Object -Property FileSystemRights, AccessControlType, IdentityReference
#excluding uncritical information as Builtin Accounts as Administratrators, System, NT Service and Trusted installer
foreach ($fileAccessControlEntry in $fileAccessControlList) {
if (($fileAccessControlEntry.FileSystemRights -notmatch '\d') -and ($fileAccessControlEntry.IdentityReference -notmatch '(?i)Builtin\\Administrators|NT\sAUTHORITY\\SYSTEM|NT\sSERVICE\\TrustedInstaller')) {
$ntfsAccessInfo += "$($fileAccessControlEntry.IdentityReference); $($fileAccessControlEntry.AccessControlType); $($fileAccessControlEntry.FileSystemRights)" + ' | '
}
} #END foreach ($fileAccessControlEntry in $fileAccessControlList)
$ntfsAccessInfo = $ntfsAccessInfo.Substring(0,$ntfsAccessInfo.Length - 3)
$ntfsAccessInfo = $ntfsAccessInfo -replace ',\s?Synchronize',''
#getting share permissions
$shareSecuritySetting = Get-WmiObject -Class Win32_LogicalShareSecuritySetting -Filter "Name='$($share.Name)'"
$shareSecurityDescriptor = $shareSecuritySetting.GetSecurityDescriptor()
$shareAcccessControlList = $shareSecurityDescriptor.Descriptor.DACL
#converting share permissions to be human readable
foreach($shareAccessControlEntry in $shareAcccessControlList) {
$trustee = $($shareAccessControlEntry.Trustee).Name
$accessMask = $shareAccessControlEntry.AccessMask
if($shareAccessControlEntry.AceType -eq 0) {
$accessType = 'Allow'
} else {
$accessType = 'Deny'
}
if ($accessMask -match '2032127|1245631|1179817') {
if ($accessMask -eq 2032127) {
$accessMaskInfo = 'FullControl'
} elseif ($accessMask -eq 1179817) {
$accessMaskInfo = 'Read'
} elseif ($accessMask -eq 1245631) {
$accessMaskInfo = 'Change'
} else {
$accessMaskInfo = 'unknown'
}
$shareAccessInfo += "$trustee; $accessType; $accessMaskInfo" + ' | '
}
} #END foreach($shareAccessControlEntry in $shareAcccessControlList)
if ($shareAccessInfo -match '|') {
$shareAccessInfo = $shareAccessInfo.Substring(0,$shareAccessInfo.Length - 3)
}
#putting extracted information together into a custom object
$myShareHash = @{'Name'=$share.Name}
$myShareHash.Add('FileSystemSPath',$share.Path )
$myShareHash.Add('Description',$share.Description)
$myShareHash.Add('NTFSPermissions',$ntfsAccessInfo)
$myShareHash.Add('SharePermissions',$shareAccessInfo)
$myShareObject = New-Object -TypeName PSObject -Property $myShareHash
$myShareObject.PSObject.TypeNames.Insert(0,'MyShareObject')
#store the custom object in a list
$null = $shareList.Add($myShareObject)
} #END if (($share.Name -notmatch '(?im)^[a-z]{1,1}\$') -and ($share.Name -notmatch '(?im)^[admin]{5,5}\$') -and ($share.Name -notmatch '(?im)^[ipc]{3,3}\$') )
} #END foreach ($share in $shares)
$shareList
@rich-houk
Copy link

I ran this against a Windows 2016 server and it returned an AccessMask of 1179819 for a Read permission on a share. This was a share with Everyone Read only being the only permission. The missing value exposed an issue with the nested loop that checks the accessmask and returns accessmaskinfo. It never reached the Unknown due to the line below, causing the Substring command in the line setting the $shareAccesInfo to fail with the second arg less than zero. I think the line below and the corresponding ending } should be removed.
if ($accessMask -match '2032127|1245631|1179817') {

also I added the following to the if-elseif section for accessmask
} elseif ($accessMask -eq 1179819) {
$accessMaskInfo = 'Read'

I hope I described the issue well enough.

@DHCook
Copy link

DHCook commented Feb 16, 2023

Hello @Juanito99 ,

Great script! Exactly what I needed to enumerate shares and get the share permissions.

I wanted to correct the regular expression matching being done in the IF statement. You have:
if (($share.Name -notmatch '(?im)^[a-z]{1,1}\$') -and ($share.Name -notmatch '(?im)^[admin]{5,5}\$') -and ($share.Name -notmatch '(?im)^[ipc]{3,3}\$') -and ($share.Name -notmatch '(?im)^[print]{5,5}\$'))


Breaking them down, the first is:
(?im)^[a-z]{1,1}\$

The quantifier {1,1} can be simplified to {1}
(?im)^[a-z]{1}\$


The last 3 are trying to match admin, ipc, and print.
(?im)^[admin]{5,5}\$
(?im)^[ipc]{3,3}\$
(?im)^[print]{5,5}\$

Using brackets will search for each character individually, not as a word. For example, if we just look at the search for admin:
(?im)^[admin]{5,5}\$

This search is looking for any 5-character combination of the letters a, d, m, i, and n. Along with admin, the following will also match:
aaaaa$
dainm$
MINAD$
MMNNA$

To perform a literal search of the characters/word, use the following:
(?im)^admin\$
(?im)^ipc\$
(?im)^print\$


To shorten the whole thing, you can combine all of these into one query by creating a group:
if ($share.Name -notmatch '(?im)^([a-z]{1}|admin|ipc|print)\$$')

Also added a second $ at the end to match end of string/line.

@Juanito99
Copy link
Author

Juanito99 commented Feb 16, 2023

I was able to figure it out and added it to an onboarding script I use when scoping new AD based environments. This is very helpful and a great time saver. Thank you very much for this, and as to not be the guy that says "I figured it out" without leaving the solution, please see my added tidbits to allow for a call to AD to pull all active servers, export to list, and then run your code against all servers in the list, resulting in a subsequent CSV dump of all known shares, share permissions, and NTFS permissions across the AD Domain servers. Again, thank you very much for this.

Get Server Shares Permissions

..

Thank you @MrMcGuinty Very appreciated :-)

@Juanito99
Copy link
Author

Sorry @rich-houk , I am presently not able to adjust the script. Hope I can find some time in the future.

@Juanito99
Copy link
Author

Hello @Juanito99 ,

Great script! Exactly what I needed to enumerate shares and get the share permissions.

I wanted to correct the regular expression matching being done in the IF statement. You have: if (($share.Name -notmatch '(?im)^[a-z]{1,1}\$') -and ($share.Name -notmatch '(?im)^[admin]{5,5}\$') -and ($share.Name -notmatch '(?im)^[ipc]{3,3}\$') -and ($share.Name -notmatch '(?im)^[print]{5,5}\$'))

Breaking them down, the first is: (?im)^[a-z]{1,1}\$

The quantifier {1,1} can be simplified to {1} (?im)^[a-z]{1}\$

The last 3 are trying to match admin, ipc, and print. (?im)^[admin]{5,5}\$ (?im)^[ipc]{3,3}\$ (?im)^[print]{5,5}\$

Using brackets will search for each character individually, not as a word. For example, if we just look at the search for admin: (?im)^[admin]{5,5}\$

This search is looking for any 5-character combination of the letters a, d, m, i, and n. Along with admin, the following will also match: aaaaa$ dainm$ MINAD$ MMNNA$

To perform a literal search of the characters/word, use the following: (?im)^admin\$ (?im)^ipc\$ (?im)^print\$

To shorten the whole thing, you can combine all of these into one query by creating a group: if ($share.Name -notmatch '(?im)^([a-z]{1}|admin|ipc|print)\$$')

Also added a second $ at the end to match end of string/line.

@DHCook Great feedback! - Thank you :-)

@ITguy3357
Copy link

How would I modify this to not exclude ANY permission holders, such as Administrators? My attempts at cutting those sections are resulting in the script producing no output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment