Skip to content
Menu
Tech Automation Blog
  • About Author
  • Contact
Tech Automation Blog

Automated File share audit using Powershell

Posted on September 3, 2019February 27, 2022

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

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on LinkedIn (Opens in new window) LinkedIn
May 2025
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« May    

Recent Posts

  • Monitor and alert Azure Service Health issues May 5, 2020
  • AWS IAM User access review May 3, 2020
  • Integrate Azure Security Center with Event Hub April 28, 2020
  • Add Tags to Azure Subscription April 24, 2020
  • Automate Azure billing report in Excel March 6, 2020

Categories

©2025 Tech Automation Blog | Powered by SuperbThemes