Introduction
The following script is a little something I cooked up to
do an audit of all the shares on a Clustered Data ONTAP Cluster (or Clusters).
It creates an Excel report with CIFS shares, share ACLs, and NTFS Security
information on the folder at the root of the share (includes owner, DACLs, and
SACLs). It has a bonus feature in that it detects shares which have had their
root folder deleted.
The framework of the script can easily be manipulated to
generate Excel reports on other things.
Notes
1) The standard readonly role is not quite sufficient for
running Get-NcFileDirectorySecurity. To make/modify your readonly role so that
it can be used to run this script, apply the below via the Clustershell ::>
security
login role create CORP_readonly -cmddirname DEFAULT -Access readonly
security
login role create CORP_readonly -cmddirname security -Access none
security
login role create CORP_readonly -cmddirname "security login
password" -Access all
security
login role create CORP_readonly -cmddirname set
-Access all
security
login role create CORP_readonly -cmddirname "vserver security
file-directory show" -Access all
security
login create -username readonly -application ontapi -role CORP_readonly
-authmethod password
2) To enable running the script from a network share, you
need to enable the below (if your permissions allow) as detailed here:
To enable
client-side SSP for winrm, run the following line:
PS>
Enable-WSManCredSSP -Role client -DelegateComputer *
If your corporate laptop has folder re-direction, placing
the Data ONTAP PowerShell Toolkit folder (DataONTAP) in your downloads folder
should work since this is rarely re-directed.
The Script
Formatted for blogger!
Copy and paste the following into a text editor, and save
as say “CDOT_Share_ACL_NTFS_Reporter.PS1” (the name doesn’t matter),
then either right-click the file and “Run with PowerShell”, or run in
PowerShell as:
PS>
.\ CDOT_Share_ACL_NTFS_Reporter.PS1
##########################################################
## CDOT Share, Share ACL, and NTFS Permissions Reporter ##
##########################################################
Param(
[String]$PSTKpath, # If DataONTAP
is not in the default location or ...\Downloads\DataONTAP, this overrides the
prompt
[String]$ClusterName, # If not
Clusters.TXT file, this overrides the prompt for a Cluster Name
[String]$UserName, # Used to
override prompt for User Name for Cluster connect
[Switch]$NoCachedCreds # Used to override looking for Cached Credentials
);""
## GENERIC DISPLAY FUNCTIONS ##
[System.Object]$Color
= @{};
"W=White","G=Green","Y=Yellow","R=Red","C=Cyan","M=Magenta"
| Foreach { [String]$Color.($_.Split("=")[0]) =
$_.Split("=")[1] }
Function
Wr { Param ([Switch]$N); $i = 0; While ($i -lt $Args.Count){ Write-Host
$Args[$i+1] -ForegroundColor $Color.($Args[$i]) -NoNewLine; $i+=2 }; If(!$N){
Write-Host } }
Function
Countdown { Param ([Int]$Count); while ($Count -gt 0){ Wr R "$Count "
-N; sleep 1; $Count-- } }
## STEP 1: LOAD THE DATA ONTAP POWERSHELL TOOLKIT ##
## ============================================== ##
Wr
G "1) Loading the Data ONTAP PowerShell Toolkit ..."; ""
[Void](Import-Module
DataONTAP -ErrorAction SilentlyContinue)
If(!(Get-Module
DataONTAP)){
[Void](Import-Module
([Environment]::GetFolderPath("UserProfile") +
"\Downloads\DataONTAP") -ErrorAction SilentlyContinue)
}
If(!(Get-Module
DataONTAP)){
Wr C "Enter path to the DataONTAP
folder: " -N
If($PSTKpath){ Wr W $PSTKpath } else {
$PSTKpath = Read-Host }
[Void](Import-Module $PSTKpath -ErrorAction
SilentlyContinue); ""
}
If(!(Get-Module
DataONTAP)){
Wr R "Unable to load the DataONTAP
PowerShell Toolkit. Exiting after 10 seconds!"; "";
Countdown 10; ""; "";
Exit
}
Wr
G "Loaded the Data ONTAP PowerShell Toolkit!"; ""
## STEP 2: GET THE CLUSTERS ##
## ======================== ##
Wr
G "2) Get the Cluster(s) ..."; ""
[System.Array]$Clusters
= @()
If(Test-Path
Clusters.txt){
[System.Array]$ClustersTXT = Get-Content
Clusters.txt
$ClustersTXT | foreach {
#> Record
Clusters ignoring blank and comments (#) lines <#
If ( !($_ -eq "") -and
!($_.StartsWith("#")) ){ $Clusters += $_ }
}
}
else {
Wr C "Enter the cluster to connect to:
" -N
If ($ClusterName){ Wr W $ClusterName } else {
$ClusterName = Read-Host }
$Clusters += $ClusterName; ""
}
## STEP 3: CREDENTIALS TO CONNECT ##
## ============================== ##
Wr
G "3) Credentials to connect ..."; ""
#> 3.1: Generate FileName for saved credentials file <#
$whoAmI = (whoAmI).ToUpper()
$SplitMe = $whoAmI.Split("\")
If($SplitMe.Count
-eq 2){ $User = $SplitMe[0] + $SplitMe[1] }
else
{ $User = $whoAmI }
$filePath
= $User + ".cred"
$test = Test-Path $filePath
If($NoCachedCreds){$test
= $null}
#> 3.2: Acquire credentials <#
[System.Array]$CredsFile
= @()
If(!$test){
# ... if no credentials file, prompt and save one
Wr C "Enter username for account to log
into the Clusters [$whoAmI]: " -N
If($UserName){ Wr W $UserName } else {
$Username = Read-Host }
If($UserName -eq ""){$UserName =
$whoAmI}
Wr C "Password: " -N
$Password
= Read-Host -AsSecureString
$SecureString = $Password |
ConvertFrom-SecureString
$CredsFile
+= $Username
$CredsFile
+= $SecureString
$CredsFile | Out-File -FilePath $filePath
}
else { # ... otherwise get credentials from the file
Wr G "Obtaining credentials from file
$filePath ..."
$CredsFile
= Get-Content $filePath
$Username
= $CredsFile[0]
$Password
= $CredsFile[1] | ConvertTo-SecureString
};""
$Credential
= New-Object System.Management.Automation.PsCredential($Username,$Password)
## STEP 4: TEST THE CREDENTIALS WORK ##
## ================================= ##
Wr
G "4) Checking connection to Cluster(s) ..."; ""
$Clusters
| foreach {
Wr C "Checking connection to " Y
"$_" C " ..."; ""
$Connect = Connect-NcController -Name $_
-Credential $Credential -ErrorAction SilentlyContinue
If (!$Connect){
Wr R "Unable to connect to " Y
"$_" R " with provided credentials. Removing credentials file.
Exiting after 10 seconds!"; ""
Remove-Item -Path $filePath
Countdown 10; ""; "";
exit
} else {
Wr G "Successfully connected to $_
"; ""
}
}
## STEP 5: GET THE REQUIRED INFORMATION - CIFS SHARES, ACLS,
NTFS PERMISSIONS ##
##
========================================================================== ##
Wr
G "5) Acquiring Shares, ACLs and NTFS Permissions ..."; ""
[System.Object]$Data
= @{} # Data Hashtable
[Int]$Index = 1
$Clusters
| foreach {
[Void](Connect-NcController -Name $_
-Credential $Credential -ErrorAction SilentlyContinue)
#> Get Data SVMs
<#
$vsQuery = Get-NcVserver -Template
$vsQuery.VserverType = "data"
$SVMs = (Get-NcVserver -Query
$vsQuery).Vserver
#> Cycle through Data
SVMs <#
Foreach ($SVM in $SVMs){
Wr G "Processing CIFS Shares for
Cluster $_ and SVM $SVM ..."; ""
$Attrs = Get-NcCifsShare -Template
$Attrs.ShareName = ""
$Attrs.Path = ""
$Attrs.Acl = ""
$CifsShares = Get-NcCifsShare -Attributes $Attrs
-VserverContext $SVM
$CifsSharesCount = $CifsShares.Count
#> Cycle through
the CIFS Shares on the SVM <#
Foreach ($Share in $CifsShares){
Wr C "$CifsSharesCount " -N
[System.Object]$Data.$Index = @{} #
Data.Index Hashtable
[String]$Data.$Index.Cluster = $_ #
+ Cluster Name
[String]$Data.$Index.Vserver = $SVM # +
SVM
[String]$Data.$Index.ShareName =
$Share.ShareName # + Share Name
[String]$Data.$Index.Path = $Share.Path # + Share
Path
[System.Array]$Data.$Index.Acl =
$Share.Acl # + Share ACL(s)
[Int]$Data.$Index.ACLs = ($Share.Acl).Count # + Share ACL(s) count
#> Processing
NTFS Security Descriptor <#
[System.Array]$NTFSsec = @()
If ($Share.Path -ne "/"){
[System.Array]$NTFSsec =
(Get-NcFileDirectorySecurity -Path ($Share.Path) -LookupNames -VserverContext
$SVM -ErrorAction SilentlyContinue).acls
If($NTFSsec){
[System.Array]$DACLs = @()
[Int]$DACL_rows = 0
Foreach ($line in $NTFSsec){
If ($line.StartsWith("NTFS Security
Descriptor")){}
elseif
($line.StartsWith("Control:")){ $Data.$Index.Control =
$line.substring(8) }
elseif
($line.StartsWith("Owner:")) {
$Data.$Index.Owner = $line.substring(6)
}
elseif
($line.StartsWith("Group:")) {
$Data.$Index.Group = $line.substring(6)
}
else {
$DACLs += $line
$DACL_rows ++
}
}
[System.Array]$Data.$Index.DACLs =
$DACLs
[Int]$Data.$Index.DACL_rows = $DACL_rows
} else {
""; Wr Y "Unable to
Get-NcFileDirectorySecurity for share " R $Share.ShareName Y " path
" R $Share.Path W " "
}
} elseif ( ($Share.Path -eq
"/") -or !$NTFSsec ) {
[String]$Data.$Index.Control = ""
[String]$Data.$Index.Owner = ""
[String]$Data.$Index.Group = ""
[System.Array]$Data.$Index.DACLs = @()
[Int]$Data.$Index.DACL_rows = 1
}
$CifsSharesCount --
$Index ++
}
""; ""
}
}
## STEP 6: CONSTRUCT EXCEL WORKBOOK ##
## ================================ ##
Wr
G "6) Constructing Excel Workbook ..."; ""
#> Excel Workbook - Initialize <#
Add-Type
-AssemblyName Microsoft.Office.Interop.Excel
$xlFixedFormat
= [Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
$xl = New-Object -ComObject "Excel.Application"
$wb = $xl.Workbooks.Add()
$xl.Worksheets.Item("Sheet2").Delete()
$xl.Worksheets.Item("Sheet3").Delete()
$ws = $wb.ActiveSheet
$worksheets = 1
$row = 3
$cells = $ws.Cells
$ws.name = "Shares, ACLs, NTFS ..."
#> Excel Workbook - Column Headers <#
$col
= 1
$cells.item($row,1).EntireRow.Interior.ColorIndex
= 15
"Cluster","SVM","Share:Name","Share:Path","Share:ACL(s)","NTFS:Control","NTFS:Owner","NTFS:Group","NTFS:DACL(s)"
| foreach {
$cells.item($row,$col) = $_
$cells.item($row,$col).font.bold = $True
$col++
}
$row
+= 2
#> Excel Workbook - Data <#
$i
= 1
while
($i -lt $Index){
Wr C ($Index - $i) C " " -N
$cells.item($row,1) = $Data.$i.Cluster
$cells.item($row,2) = $Data.$i.Vserver
$cells.item($row,3) = $Data.$i.ShareName
$cells.item($row,4) = $Data.$i.Path
#> Process Share ACLs
into column <#
If($Data.$i.ACLs -gt 0){
$h = 0
while($h -lt $Data.$i.ACLs){
$cells.item($row + $h,5) = $Data.$i.Acl[$h]
$h++
}
}
$cells.item($row,6) = $Data.$i.Control
$cells.item($row,7) = $Data.$i.Owner
$cells.item($row,8) = $Data.$i.Group
#> Process DACLs into
column <#
If($Data.$i.DACL_rows -gt 0){
$j = 0
While ($j -lt $Data.$i.DACL_rows){
$cells.item($row + $j,9) =
$Data.$i.DACLs[$j]
$j++
}
}
#> Accumulate row
count <#
If($Data.$i.ACLs -eq 0){ $Data.$i.ACLs = 1 }
If($Data.$i.ACLs -gt $Data.$i.DACL_rows){
$row += $Data.$i.ACLs } else { $row += $Data.$i.DACL_rows }
$row++
$i++
};"";""
#> Excel Workbook - Autofit Excel Columns <#
$range
= $ws.UsedRange
$range.EntireColumn.Autofit()
| out-null
#> Excel Workbook - Main Heading (after the Autofit) <#
$dateString = Get-Date -uformat "%Y%m%d"
$cells.item(1,1)
= "$dateString - NetApp CDOT Share, ACL, and NTFS Security Report"
$cells.item(1,1).EntireRow.font.bold = $true
$cells.item(1,1).EntireRow.font.size = 16
$cells.item(1,1).EntireRow.Interior.ColorIndex
= 37
#> Display and Save the Excel Workbook <#
$SavePath
= $Pwd.Path + "\" + $dateString +
"_CDOT_Share_ACL_NTFS_Report.xlsx"
$Test = Test-Path $SavePath
If($Test){
Remove-Item -Path $SavePath -Force }
$xl.ActiveWorkbook.SaveAs($SavePath,$xlFixedFormat)
$xl.Visible
= $True
Wr
G "Excel Workbook displayed and saved at " Y "$SavePath";
""
#> Cleanup EXCEL processes <#
while
([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)) {'cleanup
Excel'}
[gc]::collect()
| Out-Null;[gc]::WaitForPendingFinalizers() | Out-Null
Comments
Post a Comment