I wanted a report - in one worksheet - containing specific
bits of information regards volumes on NetApp 7-Mode controllers, to aid with
planning some 7 to C migrations. The report only concerns itself with volumes
that are read/write (ignores readonly snapmirror destination volumes) and has
the following columns:
- Root (Is this volume the root vol?)
- Source
Controller
- Source Volume (Any read/write volume, whether it has a
snapmirror destination or not)
- Destinations
Count
- Destination
Controller(s)
- Destination
Volume(s)
- SV Primary Count
(Count of SnapVaults where this
volume is Primary/Source)
- SV Secondary
Count (Count of SnapVaults where this
volume is Secondary/Destination)
- Files Used (Files in the volume)
- Size Total (GB)
- Size Used (GB)
- Qtree Count
- Vol Security
Style
- Shares Count (Shares in the volume)
- Exports Count (Exports in the volume)
- LUNs Count (LUNs in the volume)
- Vfilers*
*This just detects
if the controller has vFilers or not. The script as written does not handle
vFilers (for my requirement I had no need.)
There are two modes: -Collect and -Report. The first
collects the data and saves as XML. The second reports the data using the saved
XMLs for input, and exports to CSV.
.\Get-NaVolumeReport.ps1 -Collect
.\Get-NaVolumeReport.ps1 -Report
It requires a file (default is “Controllers.txt”) with 7-mode
controller names/IPs in. And you’ll want to use Add-NaCredential to add 7-Mode
controller credentials into your PowerShell credentials cache first.
Image: An example
of the CSV formatted in Excel (the data is intentionally blurred)
The Script
########################
##
Get-NaVolumeReport ##
########################
##
TIP: Add controller credentials with Add-NaCredential ##
Param(
[Switch]$Collect, # Use this switch to
collect data
[Switch]$Report, # Use this switch to generate CSVs
[String]$Controllers_Text_File =
"Controllers.txt"
)
If(!(Test-Path
$Controllers_Text_File)){"ERROR: Failed to load
$Controllers_Text_File!";EXIT}
[System.Array]$Controllers
= Get-Content $Controllers_Text_File
##
INPUTS ##
[System.Array]$Gets
= ,
"Get-NaVol",
"Get-NaSnapMirror",
"Get-NaSnapmirrorDestination",
"Get-NaSnapvaultPriDestinations",
"Get-NaSnapVault",
"Get-NaQtree",
"Get-NaCifsShare",
"Get-NaNfsExport",
"Get-NaVfiler",
"Get-NaLun"
##
COLLECT FUNCTION ##
Function
Collect{
"INFO: Finding the root vol"
$VolRoot = (Get-NaVolRoot).Name
If($VolRoot){$VolRoot >
"$Ctr\$Ctr.volroot.txt"}
Foreach($Get in $Gets){
"INFO: Collecting $Get"
[System.Array]$NaData = Invoke-Expression
([String]$Get)
If($NaData){$NaData | Export-CLIXML
"$Ctr\$Ctr.$Get.XML"}
}
}
##
GENERIC ADD MEMBER FUNCTION ##
Function
AddM{
Param([System.Object]$O,[String]$N,[String]$V)
Add-Member -InputObject $O -MemberType
NoteProperty -Name $N -Value $V
}
##
REPORT FUNCTION ##
Function
Report{
## ACQUIRE ROOT VOL INFO ##
[String]$VolRoot = ""
If(Test-Path
"$Ctr\$Ctr.volroot.txt"){[String]$VolRoot = Get-Content
"$Ctr\$Ctr.volroot.txt"}
## ACQUIRE XMLs ##
[System.Object]$CtrInfo = @{}
Foreach($Get in $Gets){
If(Test-Path
"$Ctr\$Ctr.$Get.xml"){$CtrInfo."$Get" = Import-CLIXML
"$Ctr\$Ctr.$Get.XML" }
}
## ACQUIRE SNAPMIRRORED VOLS ##
[System.Array]$SnapMirroredVols = @()
If($CtrInfo."Get-NaSnapMirror"){
[System.Array]$SnapMirroredVols =
($CtrInfo."Get-NaSnapMirror" | Where{$_.state -eq
"snapmirrored"}).Destination
If($SnapMirroredVols){$SnapMirroredVols =
$SnapMirroredVols | Foreach{$_.Split(":")[1]}}
}
## CYCLE THROUGH VOLUMES ##
Foreach($Vol in
$CtrInfo."Get-NaVol"){
[String]$VolName = $Vol.Name
"INFO: Processing $VolName"
## ONLY REPORT ON SOURCE VOLUMES ##
If($SnapMirroredVols -contains
$VolName){"INFO: ... $VolName is a SnapMirror DR volume"}
else {
##
START POPULATING REPORT ##
$VolObj = New-Object PSObject
If($VolName -eq $VolRoot){$Root =
"YES"}else{$Root = "NO"}
AddM $VolObj "Root" $Root
AddM $VolObj "Source
Controller" $Ctr
AddM $VolObj "Source Volume" $VolName
## SNAPMIRROR DESTINATIONS ##
[System.Array]$Destination =
$CtrInfo."Get-NaSnapmirrorDestination" | Where{$_.SourceLocation -eq
($Ctr + ":" + $VolName)}
$i = 1;[String]$DestinationCtr =
"";[String]$DestinationVol = ""
If($Destination){
$Destination | Foreach{
If($Destination.Count -gt
1){$DestinationCtr += "$i) ";$DestinationVol += "$i) "}
$DestinationCtr +=
$_.DestinationLocation.Split(":")[0]
$DestinationVol += $_.DestinationLocation.Split(":")[1]
If($i -lt
$Destination.Count){$DestinationCtr += " / ";$DestinationVol +=
" / "}
$i++
}
}
AddM $VolObj "Destinations
Count" $Destination.Count
AddM $VolObj "Destination
Controller(s)" $DestinationCtr
AddM $VolObj "Destination
Volume(s)" $DestinationVol
## VOLUME MOUNT POINT INFO ##
$MountPoint = "/vol/$Volname"
$MPL = $MountPoint.length
## SNAPVAULT PRIMARY AND SECONDARY QT
COUNT ##
$SVprimaries = @()
$SVsecondaries = @()
$CtrInfo."Get-NaSnapvaultPriDestinations" | Foreach{
If($_.SourcePath.Length -ge $MPL){
If($_.SourcePath.substring(0,$MPL)
-eq $MountPoint){$SVprimaries += $_}
}
}
$CtrInfo."Get-NaSnapVault" |
Foreach{
If($_.SecondaryPath.Length -ge $MPL){
If($_.SecondaryPath.substring(0,$MPL)
-eq $MountPoint){$SVsecondaries += $_}
}
}
AddM $VolObj "SV Primary
Count" ($SVprimaries.Count)
AddM $VolObj "SV Secondary
Count" ($SVsecondaries.Count)
## OTHER VOLUME PROPERTIEs ##
AddM $VolObj "Files Used" $Vol.FilesUsed
AddM $VolObj "Size Total (GB)"
([math]::Round((($Vol.sizeTotal) / 1024 / 1024 / 1024),2))
AddM $VolObj "Size Used
(GB)"
([math]::Round((($Vol.sizeUsed) / 1024 / 1024 / 1024),2))
## QTREES COUNT AND VOLUME SECURITY STYLE
##
[System.Array]$Qtrees =
$CtrInfo."Get-NaQtree" | Where{$_.Volume -eq $VolName}
[String]$Security =
($CtrInfo."Get-NaQtree" | Where{($_.Volume -eq $VolName) -and
($_.Qtree -eq "")}).Security
AddM $VolObj "Qtree Count" $Qtrees.count
AddM $VolObj "Vol Security
Style" $Security
## CIFS SHARES ##
$TempShares = @()
$CtrInfo."Get-NaCifsShare" |
Foreach{
If($_.MountPoint.Length -ge $MPL){
If($_.MountPoint.substring(0,$MPL)
-eq $MountPoint){$TempShares += $_}
}
}
AddM $VolObj "Shares Count"
-Value $TempShares.Count
## Exports ##
$TempExports = @()
$CtrInfo."Get-NaNfsExport" |
Foreach{
If($_.Pathname.Length -ge $MPL){
If($_.Pathname.substring(0,$MPL) -eq
$MountPoint){$TempExports += $_}
}
}
AddM $VolObj "Exports Count"
$TempExports.Count
## LUNs ##
$TempLUNs = @()
$CtrInfo."Get-NaLun" | Foreach{
If($_.Path.Length -ge $MPL){
If($_.Path.substring(0,$MPL) -eq
$MountPoint){$TempLUNs += $_}
}
}
AddM $VolObj "LUNs Count"
$TempLUNs.Count
## VFILER CHECK (NOT CURRENTLY PROGRAMMED
TO HANDLE VFILERS) ##
[String]$HasVfilers = "NO"
If($CtrInfo."Get-NaVfiler"){
If($CtrInfo."Get-NaVfiler".count -gt 1){ $HasVfilers =
"YES" }
}
AddM $VolObj "Vfilers"
$HasVfilers
## ADD DATA TO THE REPORT ##
$Global:ReportCSV += $VolObj
}
}
}
##
MAIN PROGRAM with -Collect ##
If($Collect){
If(!(Get-Module DataONTAP)){Import-Module
DataONTAP}
If(!(Get-Module DataONTAP)){"ERROR: No
DataONTAP PSTK!";EXIT}
Foreach($Ctr in $Controllers){
[Void](New-Item -ItemType Directory -Force
-Path $Ctr)
If(Test-Connection $Ctr){
$global:currentnacontroller = $NULL
"INFO: Connecting to $Ctr"
[Void](Connect-NaController -Name $Ctr)
If($global:currentnacontroller){"INFO: Connected to
$Ctr";Collect}
else{"ERROR: Unable to connect to
$Ctr"}
}else{"ERROR: Unable to ping
$Ctr"}
}
}
##
MAIN PROGRAM with -Report ##
If($Report){
[System.Array]$Global:ReportCSV = @()
Foreach($Ctr in $Controllers){"INFO:
Processing $Ctr";Report}
$Global:ReportCSV | Export-CSV
"NaVolumeReport.CSV" -NoTypeInformation
}
Comments
Post a Comment