# encoding: ascii
# api: powershell
# title: Remove broken NTFS perm
# description: COMMENT:
# version: 4.0
# type: script
# author: Stephen Wheet
# license: CC0
# x-poshcode-id: 4985
# x-archived: 2014-03-21T14:07:36
# x-published: 2014-03-13T20:53:00
#
# This script was created to find unknown SIDs or old domain permissions
# on folders. It ignores folders where inheirtance
# is turned on.
# Version 2: completely changed the query method and ACL removal
# Version 3: Added ability to query AD for servers, and handles getting
# getting shares automatically from Netapp and Windows servers
# Version 4: Cleaned up folder checking and added checking for local
# account checking so we could ignore.
#
#==========================================================================
# NAME: getunknownsids.ps1
#
# AUTHOR: Stephen Wheet
# Version: 4.0
# Date: 6/11/10
#
# COMMENT:
# This script was created to find unknown SIDs or old domain permissions
# on folders. It ignores folders where inheirtance is turned on.
#
# This works on NETAPPS and WINDOWS servers. You will need the DLL's
#
# Version 2: completely changed the query method and ACL removal
# Version 3: Added ability to query AD for servers, and handles getting
# getting shares automatically from:
# NETAPP FILERS
# Windows servers
# Version 4: Cleaned up folder checking and added checking for local
# account checking so we could ignore.
#
#==========================================================================
Function checkshare {
Param($PassedShareName)
Process
{
$path = "\\$serverFQDN\$PassedShareName"
$filename = $path.Replace("\","-") + ".csv"
#Place Headers on out-put file
$list = "Task,Path,Access Entity,"
$list | format-table | Out-File "c:\reports\unknownsids\$filename"
#Populate Folders Array
Write-Host "Writing results to : $filename"
$date = Get-Date
Write-Host $date
Write-Host "Getting Folders in: $Path"
#PSIscontainer means folders only
[Array] $folders = Get-ChildItem -path $path -recurse | ? {$_.PSIsContainer}
#Process data in array
ForEach ($folder in [Array] $folders)
{
#Check to see if there are any folders
If ($folder.pspath){
#Convert Powershell Provider Folder Path to standard folder path
$PSPath = (Convert-Path $folder.pspath)
Write-Host "Checking Dir: $PSPath"
#Check to make sure valid
If ($PSPath){
#Get the ACL's from each folder
$error.clear()
$acl = Get-Acl -Path $PSPath
#Write log if no access
if (!$?) {
$errmsg = "Error,$PSPath,ACCESS DENIED"
$errmsg | format-table | Out-File -append "$filename"
} #end IF
$ACL.Access |
?{!$_.IsInherited} |
?{ $_.IdentityReference -like $unknownsid -or $_.IdentityReference -like $olddomain } |
% {$value = $_.IdentityReference.Value
#Check for Local account
$localsid = 0
If ($value -like $unknownsid){
$checkforlocal = $value.split("-")
$total =$checkforlocal.count -1
if ($checkforlocal[$total] -match "100?" -or $checkforlocal[$total] -match "500"){
$localsid = 1
# You can uncomment the below if you want to report on local accounts.
#$list = ("Local,$PSPath,$value")
#$list | format-table | Out-File -append "$filename"
} #end IF
} #end IF
If (!$localsid){
Write-host "Found - $PSPath - $value"
$list = ("Found,$PSPath,$value")
$list | format-table | Out-File -append "$filename"
#Remove Bad SID
if ($removeacl) { $ACL.RemoveAccessRuleSpecific($_)
Write-host "Deleting - $PSPath - $value"
$list = ("Deleting,$PSPath,$value")
$list | format-table | Out-File -append "$filename"
}#end IF
if ($removeacl -and $value) {
$date = Get-Date
Write-Host $date
Write-host "Setting - $PSPath"
$list = ("Setting,$PSPath")
$list | format-table | Out-File -append "$filename"
Set-ACL $PSpath $ACL
$value = ""
} #end IF
} #end if
} #end foreachobj
} #end if
} #end if
} #end ForEach
}#end Process
} #end function
get-pssnapin -registered | add-pssnapin -passthru
[void][Reflection.Assembly]::LoadFile('C:\reports\ManageOntap.dll') #Need this DLL from netapp 3.5SDK
$ReqVersion = [version]"1.2.2.1254"
$QadVersion = (Get-PSSnapin Quest.ActiveRoles.ADManagement).Version #Need Quest plugins installed
if($QadVersion -lt $ReqVersion) {
throw "Quest AD cmdlets version '$ReqVersion' is required. Please download the latest version"
} #end If
#Set variables
$value = ""
$unknownsid = "*S-1-5-21-*" #Broken SID Verify the Broken SID number on your system and replace
$olddomain = "Domain.local*" #Old w2k/nt4 domain
$ErrorActionPreference = "SilentlyContinue"
$removeacl = 0 #change to 1 if you want to remove the SID, 0 for only logging
$localsid = 0
#Get all the servers from the specified OU
$Servers = get-QADComputer -SearchRoot 'domain.local/ou/Server' # change the container.
Foreach ($server in $Servers ) {
$serverFQDN = $server.dnsname
write-host $serverFQDN
#Test ping server to make sure it's up before querying it
$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.Send($serverFQDN)
if ($Reply.status -eq "Success"){
Write-Host "Online"
#Check for Netapp .. if found get the shares differently
If ($serverFQDN -like "*netapp*"){
$server = new-object netapp.manage.naserver($serverFQDN,1,0)
#pass authentication
$server.Style = "RPC"
# Issue command to get the shares
$NaElement = New-Object NetApp.Manage.NaElement("system-cli")
$arg = New-Object NetApp.Manage.NaElement("args")
$arg.AddNewChild('arg','cifs')
$arg.AddNewChild('arg','shares')
$NaElement.AddChildElement($arg)
$CifsString = $server.InvokeElem($NaElement).GetChildContent("cli-output")
# Split the returned txt up .. the $null makes it skip a line
$null,$null,$Lines = $CifsString.Split("`n")
Foreach ($line in $Lines ) {
# Had to trick it so skip the line with permissions, then exclude ETC$ adn c$
if (!$line.startswith(" ") -and $line -notlike "*Etc$*" -and $line -notlike "*C$*"){
$l= $line.Split(" ")
checkshare -PassedShareName $l[0] #Pass share to function
} #end if
} #end foreach
} #end if
Else{ #Else if a Windows server query via WMI
Get-WMIObject Win32_Share -Computer $serverFQDN |
where {$_.Name -like "*$*" -and $_.Name -notlike "*ADMIN*" -and $_.Name -notlike "*IPC*" -and $_.Name -notlike "*lib*"} |
%{
#Set path
$sharename = $_.name
checkshare -PassedShareName $sharename #Pass share to function
} #end ForEachObj
} #End Else
} #End If
} #end ForEach