For any organization, it is very important to have proper Governance around File server and share access management. For regulated Organization, it is really very critical to do regular auditing on shares, access management and identify any discrimination and mitigate those ASAP.
In recent past, I worked on a project for one customer where we wanted to audit all Windows and NAS shares (CIFS) globally on a regular basis and report on all audit findings. Instead of using any third party software, we decided to write our own solution.
Today, I am going to share a simple Powershell script to run scan for file shares on a list of servers provided. This script will scan up to three levels of directories, collect all NTFS permissions, when it was last accessed or modified and if the folder has any public access or not – meaning , if access provided to “everyone” etc. Finally, it will send an email to the provided recipients.
The complete solution runs this scan on the list of File Servers periodically, generates the CSV file report and ingests to a Database. This whole back-end process is front ended by a web site, which provides different reports and graphs with the polished data from the back-end. This is not the nicest solution; however, it is a good working solution which helped the Organization a lot in identifying issues and resolving those quickly. I actually moved ahead and used the ServiceNow (ITSM tool) API to raise Tickets to document audit findings and assigned to the right support group to track the remediation.
I am going to share the Share scan script today. ServiceNow Integration, Database ingestion scripts will be shared in future blogs. Stay tuned for that! This script will work for Windows File servers and CIFS shares only. So, I am sorry, if this is of no use for you. However, you got the idea to start something from here. Don’t forget to share your comments and suggestions here. Thanks!
<#
.Description
This script is designed to perform a Audit scan on all file shares from a list of designated Windows and
NAS File Servers(CIFS).It will also scan folder underneath root shares up to 3 layers of nested folders.
It will result NTFS Permission, share name, Inheritance settings. It will check if Everyone, Builtin accounts have access to any share/folder
and report those as public folder/share. This script will also generate audit report on The Folder Create Date,Last Access Date and Last Write Date.
This script will also generate a report on the status of the Folder if it is empty or not.
Finally it will Send email notification with the status of the scan.
.PARAMETER serverList
List of SAN and Windows Files Servers - ServerList.txt
.PARAMETER smtpServer
An working SMTP Server in your organization through which email can be relayed
.PARAMETER mailForm
An email id from which email will be sent. This can be an Invalid email Id, if you don't want a reploy to this email Id.
.PARAMETER mailTo
A valid email Id to send email notification.
.Example
Run-ShareAudit.ps1
.Outputs
A .csv file With Audit Scan report - ShareAuditReport.csv
A .log file which contains a log file of the whole scan process logging each folder ShareAuditLog.log
A .csv file comtaining an error generated during the scan process which we will fix later ShareAuditErrorLog.csv
.Notes
AUTHOR: Arindam Hazra
REQUIRED UTILITIES: Powershell
#>
Param(
[Parameter(Mandatory=$true)]
[String]$serverList,
[Parameter(Mandatory=$true)]
[String]$smtpServer,
[Parameter(Mandatory=$true)]
[String]$mailFrom,
[Parameter(Mandatory=$true)]
[String]$mailTo
)
try{stop-transcript|out-null}
catch [System.InvalidOperationException]{}
$systemName = $env:COMPUTERNAME
$path = $(Get-Location).Path
$aPath = Join-Path $path "ShareAuditLog.log"
$ePath = Join-Path $path "ShareErrorLog.csv"
$oPath = Join-Path $path "ShareReport.csv"
if(!(Test-Path $serverList)){
Write-Host "ERROR: Path not found.Check the path and try again!" -ForegroundColor Red
}
$repDate = (Get-Date).ToString("dd-MMM-yyyy")
$subject = "ShareAudit Script Execution has been completed on File Shares: $($repDate)"
$body = "ShareAudit Script Execution has been completed on File Shares: $repDate. The Report is available at $($oPath) on $($systemName)"
if(Test-Path -Path $aPath){Remove-item $aPath}
Start-Transcript -path $aPath -NoClobber -Append -Force
if(Test-Path -Path $ePath){Remove-item $ePath}
New-Item -Path $path -Name ShareErrorLog.csv -Type File
write-host "Start Time - $((Get-Date).ToString("dd-MMM-yyyy HH:mm:ss"))" -Foregroundcolor Green
if(Test-Path $oPath){remove-item -Path $oPath -Force}
New-Item -Path $path -Name ShareReport.csv -Type File
Function Get-FolderSize($sPath)
{
Try
{
If(!(Test-Path -path $sPath)){$size = "NA"}
ElseIf((Get-Item -Path $sPath | Get-ChildItem -force | Measure-Object).Count -eq 0){$size = "EMPTY"}
Else{$size = "NOT EMPTY"}
Return $size
}
catch{Write-host "Error: $_ `r`n";Continue}
}
Function Get-CDate($sPath)
{
Try
{
$cDate = ((Get-ItemProperty $sPath | Select-Object CreationTime).CreationTime).ToString("dd-MMM-yyyy HH:mm:ss")
$laDate = ((Get-ItemProperty $sPath | Select-Object LastAccessTime).LastAccessTime).ToString("dd-MMM-yyyy HH:mm:ss")
$lwDate = ((Get-ItemProperty $sPath | Select-Object LastWriteTime).LastWriteTime).ToString("dd-MMM-yyyy HH:mm:ss")
Return $cDate,$laDate,$lwDate
}
catch{Write-host "Error: $_ `r`n";Continue}
}
Function Get-Inheritance($sPath)
{
Try
{
$tempACL = Get-Acl -Path $sPath -ErrorAction "SilentlyContinue"
if($null -ne $tempACL)
{
$inherit = $tempAcl.AreAccessRulesProtected
If($inherit -eq $true){$inherit = "NO"}else{$inherit = "YES"}
Return $inherit
}
}
catch
{
"$sPath ,$_ `r`n" | Out-File $ePath -append
Write-host "Error: $_ `r`n";Continue
}
}
Function Get-NTFSPerms($sPath)
{
Try
{
$tempACL = Get-Acl -Path $sPath -ErrorAction "SilentlyContinue"
if($null -ne $tempACL)
{
foreach($a in $tempACL.Access){
$aA = $a.IdentityReference
$aB = $a.FileSystemRights
$obj = $obj + "$aA > $aB |"
}
$obj = $obj -replace(",",";")
Return $obj
}
}
catch
{
"$sPath ,$_ `r`n" | Out-File $ePath -append
Write-host "Error: $_ `r`n";Continue
}
}
foreach ($line in Get-Content -Path $serverList)
{
$nasName = $line
$adsi = [adsi]"WinNT://$nasName/LanmanServer"
$shares = $adsi.Children | Where-Object {$_.SchemaClassName -eq 'FileShare'} -ErrorAction "SilentlyContinue"
foreach($share in $shares)
{
$shareName = $share.Name
$shareLocation = ($share.Path) -Replace ":","$"
$tempPath = "\\$nasName\$shareName"
Write-Host $tempPath "`r`n" -Foregroundcolor Green
$mainNTFSPermission = Get-NTFSPerms $tempPath
if($mainNTFSPermission -like "*Everyone*" -or $mainNTFSPermission -like "*Authenticated Users*"){
$isPublic = "YES"
}else{$isPublic = "NO"}
$inheritance = Get-Inheritance $tempPath
$createDate,$lAccessDate,$lWriteDate = Get-CDate $tempPath
$folderSize = Get-FolderSize $tempPath
$z = "$nasName,$shareName,$temppath,$mainNTFSPermission,$isPublic,$inheritance,$createDate,$lAccessDate,$lWriteDate,$folderSize"
$z | Out-File $oPath -append -Encoding ASCII
#################### LEVEL 1 #########################
$grpLevel1 = Get-ChildItem $tempPath | Where-Object{$_.PSIsContainer -eq $True}
Foreach($f in $grpLevel1)
{
$tempShareLocation = $tempSharePath = ""
$tempShareLocation = "$shareLocation\$f"
$tempSharePath = Join-path $tempPath $f
Write-Host $tempSharePath "`r`n" -Foregroundcolor Green
$mainNTFSPermission = Get-NTFSPerms $tempSharePath
if($mainNTFSPermission -like "*Everyone*" -or $mainNTFSPermission -like "*Authenticated Users*"){
$isPublic = "YES"
}else{$isPublic = "NO"}
$inheritance = Get-Inheritance $tempSharePath
$createDate,$lAccessDate,$lWriteDate = Get-CDate $tempSharePath
$folderSize = Get-FolderSize $tempSharePath
$z = "$nasName,$shareName,$tempSharePath,$mainNTFSPermission,$isPublic,$inheritance,$createDate,$lAccessDate,$lWriteDate,$folderSize"
$z | Out-File $oPath -append -Encoding ASCII
#################### LEVEL 2 #########################
$grpLevel2 = Get-ChildItem (Join-path $tempPath $f) | Where-Object{$_.PSIsContainer -eq $True}
ForEach($g in $grpLevel2)
{
$tempShareLocation1 = $tempSharePath1 = ""
$tempShareLocation1 = "$tempSharePath\$g"
$tempSharePath1 = Join-path $tempSharePath $g
Write-Host $tempSharePath1 "`r`n" -Foregroundcolor Green
$mainNTFSPermission = Get-NTFSPerms $tempSharePath1
if($mainNTFSPermission -like "*Everyone*" -or $mainNTFSPermission -like "*Authenticated Users*"){
$isPublic = "YES"
}else{$isPublic = "NO"}
$inheritance = Get-Inheritance $tempSharePath1
$createDate,$lAccessDate,$lWriteDate = Get-CDate $tempSharePath1
$folderSize = Get-FolderSize $tempSharePath1
$z = "$nasName,$shareName,$tempSharePath1,$mainNTFSPermission,$isPublic,$inheritance,$createDate,$lAccessDate,$lWriteDate,$folderSize"
$z | Out-File $oPath -append -Encoding ASCII
#################### LEVEL 3 #########################
$grpLevel3 = Get-ChildItem (Join-path $tempSharePath $g) | Where-Object{$_.PSIsContainer -eq $True}
ForEach($i in $grpLevel3)
{
$tempShareLocation2 = $tempSharePath2 = ""
$tempShareLocation2 = "$tempSharePath1\$i"
$tempSharePath2 = Join-path $tempSharePath1 $I
Write-Host $tempSharePath2 "`r`n" -Foregroundcolor Green
$mainNTFSPermission = Get-NTFSPerms $tempSharePath2
if($mainNTFSPermission -like "*Everyone*" -or $mainNTFSPermission -like "*Authenticated Users*"){
$isPublic = "YES"
}else{$isPublic = "NO"}
$inheritance = Get-Inheritance $tempSharePath2
$createDate,$lAccessDate,$lWriteDate = Get-CDate $tempSharePath2
$folderSize = Get-FolderSize $tempSharePath2
$z = "$nasName,$shareName,$tempSharePath2,$mainNTFSPermission,$isPublic,$inheritance,$createDate,$lAccessDate,$lWriteDate,$folderSize"
$z | Out-File $oPath -append -Encoding ASCII
}
}
}
}
}
Write-Host "Report is available here : $oPath" -Foregroundcolor Green
write-host "End Time - $((Get-Date).ToString("dd-MMM-yyyy HH:mm:ss"))" -Foregroundcolor Green
$mailMessageParameters = @{
From = $mailFrom
To = $mailTo
Subject = $subject
SmtpServer = $smtpServer
Body = $body | Out-String
}
Send-MailMessage @mailMessageParameters
Stop-Transcript
Exit