NetAppSecCheck.ps1

<#
.NOTES
 
Information on running PowerShell scripts can be found here:
    -http://ss64.com/ps/syntax-run.html
    -https://technet.microsoft.com/en-us/library/bb613481.aspx
 
This script requires PowerShell 7 or later to run, information on installing or upgrading PowerShell can be found here:
    -https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.3
   
File Name: NetAppSecCheck.ps1
 
.SYNOPSIS
 
Version:
 
1.0 - Initial release
 
.DESCRIPTION
 
The intention of this script is to provide a quick check of several security configurations.
 
    Typically the following tools provide security related information for ONTAP clusters:
        -System Manager Dashboard
        -Unified Manager cluster security objectives
        -Active IQ Digital Advisor
 
If a more thorough review is necessary of your environment, engage NetApp Services and request a Data Protection and Security Assessment
 
The documents referenced in the KB article linked below should be consulted for the most up to date information
 
    -https://kb.netapp.com/onprem/ontap/os/How_to_perform_a_security_health_check_with_a_script_in_ONTAP
 
.EXAMPLE
     
    .\NetAppSecCheck.ps1
 
    All required values will be prompted for.
 
#>
 

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 5a91e6dd-0287-4a5b-860b-eed6abf74b55
 
.AUTHOR Dan Tully
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
.PRIVATEDATA
 
#>


#Requires -Version 7.0

#region Begin logging
$Now = get-date -f MM-dd-yyyy-HHmmss
Start-Transcript -UseMinimalHeader -Path ".\$Now.txt"
#endregion

#region Gather cluster address and credentials
$NTAPCluster = Read-Host "Please enter the IP address or DNS name of the cluster to evaluate"
$Credential = Get-Credential
#endregion

#region Test Connection/Authentication
Try {
     $AuthCheck = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/cluster" -Credential $Credential -SkipCertificateCheck
} Catch {
    if($_.ErrorDetails.Message) {
        Write-Host $_.ErrorDetails.Message
    } else {
        Write-Host $_
    }
    Exit
}
#endregion

#region General info
Write-Host
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host 
Write-Host "The intention of this script is to provide a quick check of several security configurations."
Write-Host
Write-Host " Typically the following tools provide security related information for ONTAP clusters:"
Write-Host " System Manager Dashboard"
Write-Host " Unified Manager cluster security objectives"
Write-Host " Active IQ Digital Advisor"
Write-Host
Write-Host "If a more thorough review is necessary of your environment, engage NetApp Services and request a Data Protection and Security Assessment"
Write-Host
Write-Host "The documents referenced in the KB article linked below should be consulted for the most up to date information"
Write-Host
Write-Host " https://kb.netapp.com/onprem/ontap/os/How_to_perform_a_security_health_check_with_a_script_in_ONTAP"
Write-Host
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-Host
#endregion

#region Display ONTAP Version
$Cluster = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/cluster" -Credential $Credential -SkipCertificateCheck
$ONTAPGen= $Cluster.Version.generation
$ONTAPMaj= $Cluster.Version.major
$ONTAPMin= $Cluster.Version.minor
$Version = [string]$ONTAPGen+"."+[string]$ONTAPMaj+"."+[string]$ONTAPMin
$ChkVersion = $ONTAPMaj + $ONTAPMin / 10

Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: Running a recommended release of ONTAP"
Write-host "Reference: SU2"
Write-host
Write-host " ONTAP Version:" $Version
Write-host
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display Telnet and RSH status
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: Telnet and Remote Shell (RSH) should be disabled"
Write-host "Reference: System Manager insights and TR-4569 section "Application methods""
$MgmtProtocols = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/protocol?fields=application,enabled" -Credential $Credential -SkipCertificateCheck
$MgmtProtocolsOut = ForEach ($_ in $MgmtProtocols.records) {
    new-object psobject -Property @{
        Application = ($_.application).ToString()
        Enabled = ($_.enabled).ToString()
    }
}
$MgmtProtocolsOut | Format-Table Application,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display Multi-admin-verify status
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: Multi-admin verification should be enabled"
write-host "Reference: TR-4569 section "Multi-admin verification""
If ($ChkVersion -ge 11.1) {
    $MAV = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/multi-admin-verify" -Credential $Credential -SkipCertificateCheck
    $MAVOut = new-object psobject -Property @{
            Enabled = ($MAV.enabled).ToString()
            "Required Approvers" = ($MAV.required_approvers).ToString()
    }
    $MAVOut | Format-Table Enabled,"Required Approvers" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " Multi-admin-verify is not supported on this release. Consider upgrading to 9.11.1 or later."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display Cluster log forwarding destinations
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: Offloading of syslog information should be configured"
Write-host "Reference: TR-4569 section "Sending out syslog""
$LogForwarding = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/log" -Credential $Credential -SkipCertificateCheck
Write-host 
If ($LogForwarding.num_records -ne 0) {
    $LogData = ForEach ($_ in $LogForwarding.records) {
        new-object psobject -Property @{
            Destination = ($_.Destination).ToString()
            Port = ($_.Port).ToString()
        }
    }
    Write-host " Cluster Log Destinations"
    $LogData | Format-Table Destination,Port | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display Self-signed certificates
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: On production systems no self-signed ceritficates should exist" 
write-host " (the recommendation is met if no results are returned)"
Write-host "Reference: TR-4569 section "Creating a CA-signed digital certificate""
Write-host
$Certs = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/certificate?self_signed=true&type=server&fields=self_signed,common_name,vserver,type" -Credential $Credential -SkipCertificateCheck
If ($Certs.num_records -ne 0) {
    $CertOut = ForEach ($_ in $Certs.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            CommonName = ($_.common_name).ToString()
            Serial = ($_.serial).ToString()
            CA = ($_.ca).ToString()
            Type = ($_.type).ToString()
            "Self-Signed" = ($_.self_signed).ToString()        
        }
    }
    $CertOut | Format-Table Vserver,CommonName,Serial,CA,Type,"Self-Signed" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display OCSP status
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: OCSP should be enabled"
Write-host "Reference: TR-4569 section "Online certificate status protocol""
$OCSP = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/config/ocsp?fields=application,is_ocsp_enabled" -Credential $Credential -SkipCertificateCheck
$OCSPOut = ForEach ($_ in $OCSP.records) {
    new-object psobject -Property @{
        Application = ($_.application).ToString()
        "OCSP Enabled" = ($_.is_ocsp_enabled).ToString()
    }
}
$OCSPOut | Format-Table Application,"OCSP Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display FIPS configuration
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: FIPS Mode should be enabled"
Write-host "Reference: System Manager insights and TR-4569 section "Managing TLS and SSL""
$FIPS = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/config?fields=is_fips_enabled" -Credential $Credential -SkipCertificateCheck
$FIPSOut = ForEach ($_ in $FIPS.records) {
    new-object psobject -Property @{
        Interface = ($_.interface).ToString()
        "FIPS Enabled" = ($_.is_fips_enabled).ToString()
    }
}
$FIPSOut | Format-Table Interface,"FIPS Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display CLI Timeout
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: CLI timeout value should match your organization's requirements"
Write-host "Reference: TR-4569 section "CLI session timeout""
$SystemTimeout = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/system/timeout" -Credential $Credential -SkipCertificateCheck
write-host
write-host " CLI session timeout:" $SystemTimeout.timeout "minutes"
write-host 
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display login banner and motd configuration
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: The login banner and message of the day (motd) should match your organization's requirements"
Write-host "Reference: System Manager insights and TR-4569 section "Login banners" and "Message of the day""
Write-host
$Banner = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/banner" -Credential $Credential -SkipCertificateCheck
$Motd = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/motd" -Credential $Credential -SkipCertificateCheck
If ($Banner.num_records -ne 0){
    Write-host " Login banner configured - true"
    Write-host
}
else{
    Write-host " Login banner configured - false"
    Write-host
}
If ($Motd.num_records -ne 0){
    Write-host " MOTD configured - true"
    Write-host
}
else{
    Write-host " MOTD configured - false"
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display cbc ciphers
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: No ciphers should exist that have names containing"cbc""
write-host " (the recommendation is met if no results are returned)"
Write-host "Reference: System Manager insights"
$SecuritySsh = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/ssh?ciphers=*cbc*" -Credential $Credential -SkipCertificateCheck
$SecSSHData = @()
If ($SecuritySsh.num_records -ne 0) {
    write-host
    write-host " Problematic Ciphers"
    ForEach ($_ in $SecuritySsh.records) {
        $Vserver = $_.vserver
        $Ciphers = $_.ciphers -split ","
        ForEach ($_ in $Ciphers) {
            If ($_.contains("cbc")) {
                $SecSSHData += New-Object -TypeName psobject -Property @{VServer=$VServer; Cipher=$_}
            }
        }
    }
    $SecSSHData | Format-Table VServer,Cipher | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    write-host
    write-host " No Problematic Ciphers Found."
    write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display NTP Servers
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: The number of servers configured for NTP should not be less than 3"
Write-host "Reference: System Manager insights and TR-4569 section "Network Time Protocol""
$NTPServers = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/time-service/ntp/server" -Credential $Credential -SkipCertificateCheck
If ($NTPServers.num_records -ne 0) {
    $NTPOut = ForEach ($_ in $NTPServers.records) {
        new-object psobject -Property @{
            "NTP Servers" = ($_.Server ).ToString()
        }
    }
    $NTPOut | Format-Table "NTP Servers" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No NTP Servers Found."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display Autosupport Configuration
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: AutoSupport should use a secure protocol (HTTPS) and should be enabled"
Write-host "Reference: System Manager insights and TR-4569 section "NetApp AutoSupport""
$ASUPConf = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/support/autosupport" -Credential $Credential -SkipCertificateCheck
$AsupOut = ForEach ($_ in $ASUPConf) {
    new-object psobject -Property @{
        Transport = ($_.transport ).ToString()
        Enabled = ($_.enabled ).ToString()
    }
}
$ASUPOut | Format-Table Transport,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display cluster agent connections for 9.10 and later
If ($ChkVersion -ge 10) {
    Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
    Write-host "Recommendation: Cloud Insights provides an external mode FPolicy server"
    Write-host "Reference: TR-4572 section "Cloud Insights""
    $ClusterAgent = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/agent/connection" -Credential $Credential -SkipCertificateCheck
    #Need to test on a configured system
    If ($ClusterAgent.num_records -ne 0) {
        $ClusterAgent.records | Format-Table | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
    }
    Else {
        Write-host
        Write-host " No Results Returned."
        Write-host
    }
    Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
    Write-host
}
#endregion

#region Display FPolicy configuration
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: FPolicy should be configured"
Write-host "Reference: System Manager insights"
$Fpolicy = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/fpolicy?fields=status,engine" -Credential $Credential -SkipCertificateCheck
If ($Fpolicy.num_records -ne 0) {
    $FpolicyOut = ForEach ($_ in $Fpolicy.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver ).ToString()
            "Policy Name" = ($_.policy_name ).ToString()
            Status = ($_.status ).ToString()
            Engine = ($_.engine ).ToString()
        }
    }
    $FpolicyOut | Format-Table VServer,"Policy Name",Status,Engine | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host
#endregion

#region Display Admin and Diag user status
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: Built in accounts should be locked"
Write-host "Reference: System Manager insights and TR-4569 section "Default administrative accounts""
$AdminUser = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/accounts?name=admin&fields=locked" -Credential $Credential -SkipCertificateCheck
$DiagUser = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/accounts?name=diag&fields=locked" -Credential $Credential -SkipCertificateCheck
$Locked = $AdminUser.records + $DiagUser.records
$LockedOut = ForEach ($_ in $Locked) {
    new-object psobject -Property @{
        Username = ($_.name ).ToString()
        Locked = ($_.locked ).ToString()
    }
}
$LockedOut | Format-table Username,Locked | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host 
#endregion

#region Display users with telnet and rsh application access
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: No logins should exist with the telnet or rsh application"
write-host " (the recommendation is met if no results are returned)"
Write-host "Reference: TR-4569 section "Application methods""
$RSH = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=rsh&fields=role,second_authentication_method,is_account_locked" -Credential $Credential -SkipCertificateCheck
$Telnet = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=telnet&fields=role,second_authentication_method,is_account_locked" -Credential $Credential -SkipCertificateCheck
If ($RSH.num_records -ne 0) {
    $RSHOut = ForEach ($_ in $RSH.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver ).ToString()
        Username = ($_.user_or_group_name ).ToString()
        Application = ($_.application ).ToString()
        AuthMethod = ($_.authentication_method ).ToString()
        "Role Name" = ($_.role ).ToString()
        Locked = ($_.is_account_locked ).ToString()
        "2ndAuthMethod" = ($_.second_authentication_method ).ToString()
    }
}
    $RSHOut | Format-table username,vserver,application,"role name",authmethod,"2ndAuthMethod",Locked | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No users found with RSH application access."
    Write-host
}
If ($Telnet.num_records -ne 0) {
    $TelnetOut = ForEach ($_ in $Telnet.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver ).ToString()
        Username = ($_.user_or_group_name ).ToString()
        Application = ($_.application ).ToString()
        AuthMethod = ($_.authentication_method ).ToString()
        "Role Name" = ($_.role ).ToString()
        Locked = ($_.is_account_locked ).ToString()
        "2ndAuthMethod" = ($_.second_authentication_method ).ToString()
    }
}
    $TelnetOut | Format-table username,vserver,application,"role name",authmethod,"2ndAuthMethod",Locked | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No users found with Telnet application access."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host
#endregion

#region Display password complexity settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: Configured password parameters should match your organization's policy"
Write-host "Reference: TR-4569 section "Password parameters""
$Passwd = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/role/config?fields=passwd-minlength,passwd-min-special-chars,passwd-min-digits,passwd-min-lowercase-chars,passwd-min-uppercase-chars,passwd-alphanum" -Credential $Credential -SkipCertificateCheck
If ($Passwd.num_records -ne 0) {
    $PasswdOut = ForEach ($_ in $Passwd.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver ).ToString()
        Role = ($_.role ).ToString()
        Alphanumeric = ($_.passwd_alphanum ).ToString()
        "Min Len" = ($_.passwd_minlength ).ToString()
        "Min Spec Chars" = ($_.passwd_min_special_chars ).ToString()
        "Min Lowercase" = ($_.passwd_min_lowercase_chars ).ToString()
        "Min Uppercase" = ($_.passwd_min_uppercase_chars ).ToString()
        "Min Digits" = ($_.passwd_min_digits ).ToString()
    }
}
    $PasswdOut | Format-table vserver,role,Alphanumeric,"Min Len","Min Spec Chars","Min Lowercase","Min Uppercase","Min Digits" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host
#endregion

#region Display various user configuration settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: For each login the authentication-method should be public key for machine access and can be password for user access"
Write-host " The second-authentication-method should not be none to enable MFA"
Write-host " The role should be the appropriate granting them the appropriate privilege to perform their job function or required tasks"
Write-host " The hash-function should be sha512"
Write-host "Reference: TR-4569 section "SHA-512 support" and "Managing SSHv2" and "Roles, applications, and authentication" and "
Write-host " TR-4647 section "ONTAP SSH two-factor chained authentication""
$Users = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?fields=second-authentication-method,hash-function,is-account-locked,role" -Credential $Credential -SkipCertificateCheck
If ($Users.num_records -ne 0) {
    $UsersOut = ForEach ($_ in $Users.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver ).ToString()
        Username = ($_.user_or_group_name ).ToString()
        Application = ($_.application ).ToString()
        AuthMethod = ($_.authentication_method ).ToString()
        "Role Name" = ($_.role ).ToString()
        Locked = ($_.is_account_locked ).ToString()
        "2ndAuthMethod" = ($_.second_authentication_method ).ToString()
        "Hash Function" = ($_.hash_function ).ToString()
    }
}
    $UsersOut | Format-table username,vserver,application,"role name",authmethod,"2ndAuthMethod",Locked,"Hash Function" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display SVM API authentication details
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: For any SVM with client-enabled access, all related logins that are performing SDK or REST API calls should "
write-host " use cert for Authentication Method field"
Write-host "Reference: TR-4569 section "Certificate-based API access""
$SSL = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/ssl?fields=client-enabled" -Credential $Credential -SkipCertificateCheck
$HTTP = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=http" -Credential $Credential -SkipCertificateCheck
$ONTAPI = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login?application=ontapi" -Credential $Credential -SkipCertificateCheck
$SSLOut = ForEach ($_ in $SSL.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver).ToString()
        "Client Enabled" = ($_.client_enabled).ToString()
    }
}
Write-host
Write-host " SSL Configuration"
$SSLOut | Format-Table VServer,"Client Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }

$HTTPOut = ForEach ($_ in $HTTP.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver).ToString()
        Username = ($_.user_or_group_name).ToString()
        Application = ($_.application).ToString()
        AuthMethod = ($_.authentication_method).ToString()
    }
}
If ($HTTP.records.num_records -ne 0) {
    write-host " HTTP Users"
    $HTTPOut | Format-Table VServer,Username,Application,AuthMethod | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No HTTP Users Found."
    Write-host
}
$ONTAPIOut = ForEach ($_ in $ONTAPI.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver).ToString()
        Username = ($_.user_or_group_name).ToString()
        Application = ($_.application).ToString()
        AuthMethod = ($_.authentication_method).ToString()
    }
}
If ($ONTAPI.records.num_records -ne 0) {
    write-host " ONTAPI Users"
    $ONTAPIOut | Format-Table VServer,Username,Application,AuthMethod | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No ONTAPI Users Found."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display REST API /api/storage/volumes access for 9.10 and later
If ($ChkVersion -ge 10) {
    Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
    Write-host "Recommendation: You can prevent ONTAP administrators from using REST APIs for file access by setting access level "
    write-host " for /api/storage/volumes to none"
    Write-host "Reference: TR-4569 section "Effect of REST APIs on NAS auditing""
    $RestRoles = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/login/rest-role?api=/api/storage/volumes&fields=access" -Credential $Credential -SkipCertificateCheck
    $RestOut = ForEach ($_ in $RestRoles.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            Role = ($_.role).ToString()
            API = ($_.api).ToString()
            Access = ($_.Access).ToString()
        }
    }
    $RestOut | Format-Table VServer,Role,API,Access | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
    Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
    Write-host
}
#endregion

#region Display SAML configuration
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host "Recommendation: SAML should be configured"
Write-host "Reference: TR-4647 section "The requirement for strong administrative credentials""
$Samlsp = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/security/saml-sp/status?fields=status,is_enabled" -Credential $Credential -SkipCertificateCheck
If ($Samlsp.records.num_records -ne 0) {    
    $SamlOut = ForEach ($_ in $Samlsp.records) {
        new-object psobject -Property @{
            Node = ($_.node).ToString()
            Status = ($_.status).ToString()
            Enabled = ($_.is_enabled).ToString()
        }
}
    $SamlOut | Format-Table Node,Status,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display CIFS signing configuration
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: For each SVM configured with CIFS the is-signing-required should be true"
write-host "Reference: TR-4569 section "CIFS SMB signing and sealing""
$CIFSSigning = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/cifs/security?is_signing_required=!null" -Credential $Credential -SkipCertificateCheck
If ($CIFSSigning.num_records -ne 0) {
    $CIFSOut = ForEach ($_ in $CIFSSigning.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            "Signing Required" = ($_.is_signing_required).ToString()
        }
    }
    $CIFSOut | Format-Table VServer,"Signing Required" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display LDAP session security settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: For each SVM configured with CIFS session-security-for-ad-ldap should be set to a minimum of sign "
write-host " to match your organization's requirements"
write-host "Reference: TR-4835 section "Microsoft LDAP channel binding requirement""
$LDAPBinding = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/cifs/security?session-security-for-ad-ldap=!null" -Credential $Credential -SkipCertificateCheck
If ($LDAPBinding.num_records -ne 0) {
    $LDAPOut = ForEach ($_ in $LDAPBinding.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            "Session Security for AD LDAP" = ($_.session_security_for_ad_ldap).ToString()
        }
    }
    $LDAPOut | Format-Table VServer,"Session Security for AD LDAP" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display Audit settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: NAS auditing should be enabled"
write-host "Reference: TR-4569 section "NAS file system auditing""
$Audit = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/vserver/audit?fields=vserver,state" -Credential $Credential -SkipCertificateCheck
If ($Audit.num_records -ne 0) {
    $AuditOut = ForEach ($_ in $Audit.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            Enabled = ($_.state).ToString()
        }
    }
    $AuditOut | Format-Table VServer,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Auditing Configuration Found."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display NIS config
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: NIS should not be configured (the recommendation is met if no results are returned)"
write-host "Reference: TR-4569 section "Authentication methods""
$NISData = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/svm/svms?nis.domain=!null" -Credential $Credential -SkipCertificateCheck
If ($NISData.num_records -ne 0) {
    $NISSVMs = ForEach ($_ in $NISData.records) {
        new-object psobject -Property @{
            VServer = ($_.name).ToString()
            NISDomain = ($_.nis.domain).ToString()
        }
    }
    $NISSVMs | Format-Table vserver,nisdomain | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display volumes without snapshot policies
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: All volumes should have Snapshot policies (the recommendation is met if no results are returned)"
write-host "Reference: System Manager insights"
$NullSS = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?snapshot_policy=null&is_cluster_volume=true" -Credential $Credential -SkipCertificateCheck
If ($NullSS.num_records -ne 0) {
    $NullSSData = ForEach ($_ in $NullSS.records) {
        new-object psobject -Property @{
            Volume = ($_.volume).ToString()
            "Snapshot Policy" = "-"
            VServer = ($_.vserver).ToString()
        }
    }
    $NullSSData | Format-Table volume,"Snapshot Policy",VServer | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Volumes with a Snapshot Policy of NULL."
    Write-host
}
$NoneSS = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?snapshot_policy=none&is_cluster_volume=true" -Credential $Credential -SkipCertificateCheck
If ($NoneSS.num_records -ne 0) {
    $NoneSSData = ForEach ($_ in $NoneSS.records) {
        new-object psobject -Property @{
            Volume = ($_.volume).ToString()
            "Snapshot Policy" = ($_.snapshot_policy).ToString()
            VServer = ($_.vserver).ToString()
        }
    }
    $NoneSSData | Format-Table volume,"Snapshot Policy",VServer | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Volumes with a Snapshot Policy of None."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display snapshot autodelete settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: Snapshot auto-deletion should not be enabled for data volumes"
write-host "Reference: System Manager insights"
$AD = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume/snapshot/autodelete?enabled=true" -Credential $Credential -SkipCertificateCheck
If ($AD.num_records -ne 0) {
    $ADData = ForEach ($_ in $AD.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            Enabled = ($_.enabled).ToString()
            Volume = ($_.volume).ToString()
        }
    }
    $ADData | Format-Table VServer,Volume,Enabled | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display anti-ransomware settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: SVMs should be configured for anti-ransomware"
write-host "Reference: System Manager insights"
If ($ChkVersion -ge 10) {    
    $AR = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/svm/svms?fields=anti_ransomware_default_volume_state" -Credential $Credential -SkipCertificateCheck
    If ($AR.num_records -ne 0) {
        $ARData = ForEach ($_ in $AR.records) {
        new-object psobject -Property @{
            VServer = ($_.name).ToString()
            "Anti Ransomware Default Volume State" = ($_.anti_ransomware_default_volume_state).ToString()
        }
    }
        $ARData | Format-Table VServer,"Anti Ransomware Default Volume State" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
    }
    Else {
        Write-host
        Write-host " No Results Returned."
        Write-host
    }
}
Else {
    Write-host
    Write-host " Anti-Ransomware Protection is not supported on this release. Consider upgrading to 9.10 or later."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display anti-ransomware settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: Volume anti-ransomware-state should be enabled"
write-host "Reference: System Manager insights"
If ($ChkVersion -ge 10) {    
    $VAR = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?is-cluster-volume=true&fields=anti-ransomware-state" -Credential $Credential -SkipCertificateCheck
    If ($VAR.num_records -ne 0) {
        $VARData = ForEach ($_ in $VAR.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            Volume = ($_.volume).ToString()
            "Anti Ransomware State" = ($_.anti_ransomware_state).ToString()
        }
    }
        $VARData | Format-Table VServer,Volume,"Anti Ransomware State" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
    }
    Else {
        Write-host
        Write-host " No Results Returned."
        Write-host
    }
}
Else {
    Write-host
    Write-host " Anti-Ransomware Protection is not supported on this release. Consider upgrading to 9.10 or later."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display snapshot locking settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: snapshot-locking-enabled should be true for all volumes with snapshots"
write-host "Reference: TR-4569 section "Snapshot copy locking""
If ($ChkVersion -ge 12.1) {
    $SSLocking = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?fields=snapshot_locking_enabled" -Credential $Credential -SkipCertificateCheck
    If ($SSLocking.num_records -ne 0) {
        $SSLockingOut = ForEach ($_ in $SSLocking.records) {
        new-object psobject -Property @{
            VServer = ($_.vserver).ToString()
            Volume = ($_.volume).ToString()
            "Snapshot Locking Enabled" = ($_.snapshot_locking_enabled).ToString()
        }
    }
        $SSLockingOut | Format-Table VServer,Volume,"Snapshot Locking Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
    }
    Else {
        Write-host
        Write-host " No Results Returned."
        Write-host
    }
}
Else {
    Write-host
    Write-host " Snapshot Copy Locking is not supported on this release. Consider upgrading to 9.12.1 or later."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display KeyManager and encryption settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: A key-manager should be configured and encryption should be enabled at either the disk, aggregate, or volume layer "
write-host "Reference: TR-4569 section "Storage encryption""
$KeyManager = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/key-managers" -Credential $Credential -SkipCertificateCheck
If ($KeyManager.num_records -ne 0) {
    Write-host
    Write-host " Key-manager is configured."
}
Else {
    Write-host
    Write-host " No Key-manager Found."
}
$DriveProt = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/storage/aggregate?fields=drive-protection-enabled,node" -Credential $Credential -SkipCertificateCheck
If ($DriveProt.num_records -ne 0) {
    $DriveProtData = ForEach ($_ in $DriveProt.records) {
    new-object psobject -Property @{
        Aggregate = ($_.aggregate).ToString()
        Node = ($_.node).ToString()
        "Drive Protection Enabled" = ($_.drive_protection_enabled).ToString()
    }
}
    $DriveProtData | Format-Table Aggregate,Node,"Drive Protection Enabled" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
$VolEnc = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/volume?fields=encryption-type,is-encrypted" -Credential $Credential -SkipCertificateCheck
If ($VolEnc.num_records -ne 0) {
    $VolEncData = ForEach ($_ in $VolEnc.records) {
    new-object psobject -Property @{
        VServer = ($_.vserver).ToString()
        Volume = ($_.volume).ToString()
        "Encryption Type" = ($_.encryption_type).ToString()
        "Is Encrypted" = ($_.is_encrypted).ToString()
    }
}
    $VolEncData | Format-Table VServer,Volume,"Encryption Type","Is Encrypted" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Results Returned."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display cluster peer encryption
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: Cluster peers should be configured with tls-psk for the encryption protocol"
write-host "Reference: TR-4569 section "Data replication encryption""
$ClusterPeer = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/private/cli/cluster/peer?fields=cluster,encryption_protocol_proposed,encryption_protocol" -Credential $Credential -SkipCertificateCheck
If ($ClusterPeer.num_records -ne 0) {
    $ClusterPeerOut = ForEach ($_ in $ClusterPeer.records) {
    new-object psobject -Property @{
        Cluster = ($_.cluster).ToString()
        "Encryption Protocol" = ($_.encryption_protocol).ToString()
    }
}
    $ClusterPeerOut | Format-Table Cluster,"Encryption Protocol" | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
}
Else {
    Write-host
    Write-host " No Cluster Peer Relationships Found."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#region Display IPSec configuration settings
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
write-host "Recommendation: When required ipsec is configured and policies created"
write-host "Reference: TR-4569 section "IPsec data-in-flight encryption""
If ($ChkVersion -ge 8) {
    $IPsec = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/ipsec?fields=*" -Credential $Credential -SkipCertificateCheck
    Write-host
    Write-host " IPsec Enabled -" $IPsec.enabled
    Write-host
    $IPsecPolicy = Invoke-RestMethod -Method GET -Uri "https://$NTAPCluster/api/security/ipsec/policies" -Credential $Credential -SkipCertificateCheck
    If ($IPsecPolicy.num_records -ne 0) {
        $IPsecPolicy.records | Format-Table | Out-String -Stream | ForEach-Object { ' ' * 8 + $_ }
    }
    Else {
        Write-host " No IPsec Policies Found."
        Write-host
    }
}
Else {
    Write-host
    Write-host " IPsec is not supported on this release. Consider upgrading to 9.8 or later."
    Write-host
}
Write-host "--------------------------------------------------------------------------------------------------------------------------------------------"
Write-host
#endregion

#stop logging
Stop-Transcript