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 This script also requires that the ONTAP cluster is running 9.6 or later File Name: NetAppSecCheck.ps1 .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, please consider contacting NetApp Services to 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 TR-4569 - https://www.netapp.com/media/10674-tr4569.pdf TR-4572 - https://www.netapp.com/media/7334-tr4572.pdf TR-4835 - https://www.netapp.com/media/19423-tr-4835.pdf TR-4647 - https://www.netapp.com/media/17055-tr4647.pdf .EXAMPLE .\NetAppSecCheck.ps1 All required values will be prompted for. #> <#PSScriptInfo .VERSION 2.0 .GUID 5a91e6dd-0287-4a5b-860b-eed6abf74b55 .AUTHOR Daniel Tully .RELEASENOTES Version: 2.0 - Updated to make future additions more modular. Added additional output for password complexity. Bug fixes, formatting. 1.2 - Added Categories for the Summary, sorted full output to match summary Cleaned up lots of formatting issues, bug fixes, addressed ONTAP version specific issues More bug fixes 1.1 - Added Summary, Full, and All output choices Cleaned up lots of formatting issues Reorganized Data Collection, Formatting, and Output sections 1.0 - Initial release #> #Requires -Version 7.0 $Separator = "─" * 120 $Spacer = " " * 7 # Header $Header = @" $Separator 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, please consider contacting NetApp Services to 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 TR-4569 - https://www.netapp.com/media/10674-tr4569.pdf TR-4572 - https://www.netapp.com/media/7334-tr4572.pdf TR-4835 - https://www.netapp.com/media/19423-tr-4835.pdf TR-4647 - https://www.netapp.com/media/17055-tr4647.pdf $Separator "@ # Gather cluster address and credentials $NTAPCluster = Read-Host "Please enter the IP address or DNS name of the cluster to evaluate" $Credential = Get-Credential # Data Collection function GetData($endpoint) { process { $Uri = "https://$NTAPCluster/api/$endpoint" Invoke-RestMethod -Method GET -Uri $Uri -Credential $Credential -SkipCertificateCheck } } function CollectData { foreach ($key in $Items.Keys) { if ($ChkVers -ge $Items[$key].RequiredVersion) { $Items[$key].Result = GetData $Items[$key].Url $Items[$key].Supported = $True } else { $Items[$key].Supported = $False } } } # Test Connection/Authentication Try { $Cluster = GetData "cluster" } Catch { if ($_.Exception.Message) { Write-Output "Error: Failed to connect or authenticate to the cluster." Write-Output $_.Exception.Message } else { Write-Output $_ } Exit } # Utility stuff $Now = Get-Date -f MM-dd-yyyy-HHmmss $Version = $Cluster.Version.full $VerSplit = $Version.split(":") $ChkVers = $Cluster.Version.major + $Cluster.Version.minor / 10 # Data collection item definition $Items = [ordered]@{ Version = @{ RequiredVersion = 0 Url = "cluster" Category = 0 } DataAtRestEncryption = @{ RequiredVersion = 7 Url = "security?fields=onboard_key_manager_configurable_status" Category = 0 } NTPServers = @{ RequiredVersion = 6 Url = "private/cli/cluster/time-service/ntp/server" Category = 1 } ASUPConfig = @{ RequiredVersion = 6 Url = "support/autosupport" Category = 1 } ASUPTransport = @{ RequiredVersion = 99 Category = 1 } CLITimeout = @{ RequiredVersion = 6 Url = "private/cli/system/timeout" Category = 1 } CloudInsights = @{ RequiredVersion = 10 Url = "private/cli/cluster/agent/connection?fields=application-url" Category = 1 } LoginBannerConfig = @{ RequiredVersion = 6 Url = "private/cli/security/login/banner" Category = 1 } MOTDConfig = @{ RequiredVersion = 6 Url = "private/cli/security/login/motd" Category = 1 } PasswordConfig = @{ RequiredVersion = 6 Url = "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,disallowed-reuse," ` + "passwd-expiry-time,passwd-expiry-warn-time,passwd-expiry-time," ` + "require-initial-passwd-update,lockout-duration,change-delay" Category = 1 } LogForwarding = @{ RequiredVersion = 6 Url = "private/cli/cluster/log" Category = 1 } SystemConfigBackup = @{ RequiredVersion = 6 Url = "support/configuration-backup" Category = 1 } ManagementProtocols = @{ RequiredVersion = 6 Url = "private/cli/security/protocol?fields=application,enabled" Category = 2 } WebServices = @{ RequiredVersion = 6 Url = "private/cli/system/services/web" Category = 2 } RSHConfig = @{ RequiredVersion = 6 Url = "private/cli/security/protocol?fields=application,enabled&application=rsh" Category = 2 } TelnetConfig = @{ RequiredVersion = 6 Url = "private/cli/security/protocol?fields=application,enabled&application=telnet" Category = 2 } BuiltinUsers = @{ RequiredVersion = 6 Url = "security/accounts?name=admin&fields=locked" Category = 3 } DiagUser = @{ RequiredVersion = 6 Url = "security/accounts?name=diag&fields=locked" Category = 3 } RestRoles = @{ RequiredVersion = 10 Url = "private/cli/security/login/rest-role?api=/api/storage/volumes&fields=access" Category = 3 } UserDetails = @{ RequiredVersion = 6 Url = "private/cli/security/login?fields=second-authentication-method,hash-function,is-account-locked,role&application=!snmp" Category = 3 } MultiAdminVerify = @{ RequiredVersion = 11.1 Url = "private/cli/security/multi-admin-verify" Category = 3 } SNMPUsers = @{ RequiredVersion = 6 Url = "private/cli/security/login?application=snmp&authentication-method=community" Category = 3 } RSHUsers = @{ RequiredVersion = 6 Url = "private/cli/security/login?application=rsh&fields=role,second_authentication_method,is_account_locked" Category = 3 } TelnetUsers = @{ RequiredVersion = 6 Url = "private/cli/security/login?application=telnet&fields=role,second_authentication_method,is_account_locked" Category = 3 } ClusterPeerEncryption = @{ RequiredVersion = 6 Url = "private/cli/cluster/peer?fields=cluster,encryption_protocol_proposed,encryption_protocol" Category = 4 } FIPS = @{ RequiredVersion = 6 Url = "private/cli/security/config?fields=is_fips_enabled" Category = 4 } IPsec = @{ RequiredVersion = 8 Url = "security/ipsec?fields=*" Category = 4 } IPsecPolicy = @{ RequiredVersion = 8 Url = "security/ipsec/policies" Category = 4 } SSHCiphers = @{ RequiredVersion = 6 Url = "private/cli/security/ssh?ciphers=*cbc*" Category = 4 } SelfSignedCerts = @{ RequiredVersion = 6 Url = "private/cli/security/certificate?self_signed=true&type=server&fields=self_signed,common_name,vserver,type" Category = 4 } SSLConfig = @{ RequiredVersion = 6 Url = "private/cli/security/ssl?fields=client-enabled" Category = 4 } HTTPUsers = @{ RequiredVersion = 6 Url = "private/cli/security/login?application=http" Category = 4 } ONTAPIUsers = @{ RequiredVersion = 6 Url = "private/cli/security/login?application=ontapi" Category = 4 } OCSPConfig = @{ RequiredVersion = 6 Url = "private/cli/security/config/ocsp?fields=application,is_ocsp_enabled" Category = 4 } SAML = @{ RequiredVersion = 6 Url = "private/cli/security/saml-sp/status?fields=status,is_enabled" Category = 4 } CIFSSvms = @{ RequiredVersion = 6 Url = "private/cli/vserver/cifs" Category = 5 } CIFSSigning = @{ RequiredVersion = 6 Url = "private/cli/vserver/cifs/security?is_signing_required=!null" Category = 5 } CIFSWorkgroup = @{ RequiredVersion = 6 Url = "private/cli/vserver/cifs?auth_style=workgroup" Category = 5 } CIFSSMB1 = @{ RequiredVersion = 6 Url = "private/cli/vserver/cifs/options?smb1_enabled=true" Category = 5 } LDAP = @{ RequiredVersion = 6 Url = "private/cli/vserver/cifs/security?session-security-for-ad-ldap=!null" Category = 5 } VScan = @{ RequiredVersion = 6 Url = "private/cli/vserver/vscan?fields=vscan-status" Category = 5 } Fpolicy = @{ RequiredVersion = 6 Url = "private/cli/vserver/fpolicy?fields=status,engine" Category = 5 } NASAuditing = @{ RequiredVersion = 6 Url = "private/cli/vserver/audit?fields=vserver,state" Category = 5 } NISServers = @{ RequiredVersion = 6 Url = "svm/svms?nis.domain=!null" Category = 5 } SnapShotAutoDelete = @{ RequiredVersion = 6 Url = "private/cli/volume/snapshot/autodelete?enabled=true" Category = 6 } NullSnapShotPolicy = @{ RequiredVersion = 6 Url = "private/cli/volume?snapshot_policy=null&is_cluster_volume=true" Category = 6 } NoneSnapShotPolicy = @{ RequiredVersion = 6 Url = "private/cli/volume?snapshot_policy=none&is_cluster_volume=true" Category = 6 } SnapShotLocking = @{ RequiredVersion = 12.1 Url = "private/cli/volume?fields=snapshot_locking_enabled" Category = 6 } SVMAntiRansomware = @{ RequiredVersion = 10 Url = "svm/svms?fields=anti_ransomware_default_volume_state" Category = 7 } VolumeAntiRansomware = @{ RequiredVersion = 10 Url = "private/cli/volume?is-cluster-volume=true&fields=anti-ransomware-state" Category = 7 } KeyManager = @{ RequiredVersion = 6 Url = "security/key-managers" Category = 8 } DriveProtection = @{ RequiredVersion = 6 Url = "private/cli/storage/aggregate?fields=drive-protection-enabled,node" Category = 8 } VolumeEncryption = @{ RequiredVersion = 6 Url = "private/cli/volume?fields=encryption-type,is-encrypted" Category = 8 } } # Category Definition $Categories = [ordered]@{ 0 = "Software Version" 1 = "General Configuration" 2 = "Administrative Protocols" 3 = "Administrative Users" 4 = "Secure Communication" 5 = "File Access" 6 = "Data Protection" 7 = "Anti-Ransomware" 8 = "Encryption" } # Process and Format Data function ProcessData { ### Begin - Software Version - Category 0 # ONTAP Version $Items.Version.FullHeader = @" $Separator Recommendation: Running a recommended release of ONTAP Reference: SU2 https://kb.netapp.com/Support_Bulletins/Customer_Bulletins/SU2 "@ $Items.Version.FullData = "$Spacer ONTAP Version: $Version`n$Spacer Data at rest encryption supported: $($Items.DataAtRestEncryption.Result.onboard_key_manager_configurable_status.supported)`n" $Items.Version.Summary = New-Object -TypeName psobject -Property @{ Item = "ONTAP Version" Finding = $VerSplit[0] Topic = $Categories[$Items.Version.Category] } $Items.DataAtRestEncryption.Summary = New-Object -TypeName psobject -Property @{ Item = "ONTAP Version Supports Encryption" Finding = $Items.DataAtRestEncryption.Result.onboard_key_manager_configurable_status.supported Topic = $Categories[$Items.DataAtRestEncryption.Category] } ### End - Software Version - Category 0 ### Begin - General Configuration - Category 1 # NTP Servers $Items.NTPServers.FullHeader = @" $Separator Recommendation: The number of servers configured for NTP should not be less than 3 Reference: System Manager insights and TR-4569 section "Network Time Protocol" "@ If ($Items.NTPServers.Result.num_records -ne 0){ $Items.NTPServers.Formatted = ForEach ($_ in $Items.NTPServers.Result.records) { New-Object psobject -Property @{ "NTP Servers" = ($_.Server).ToString() } } $Items.NTPServers.FullData = $Items.NTPServers.Formatted | Format-Table "NTP Servers" | Out-String -Stream | Add-Indentation } else { $Items.NTPServers.FullData = "`n$Spacer No NTP Servers Found.`n" } $Items.NTPServers.Summary = New-Object -TypeName psobject -Property @{ Item = "3 or more NTP Servers Configured" Finding = ($Items.NTPServers.Result.num_records -ge 3) Topic = $Categories[$Items.NTPServers.Category] } # ASUP Config $Items.ASUPConfig.FullHeader = @" $Separator Recommendation: AutoSupport should use a secure protocol (HTTPS) and should be enabled Reference: System Manager insights and TR-4569 section "NetApp AutoSupport" "@ $Items.ASUPConfig.Formatted = ForEach ($_ in $Items.ASUPConfig.Result) { New-Object psobject -Property @{ Transport = ($_.transport).ToString() Enabled = ($_.enabled).ToString() } } $Items.ASUPConfig.FullData = $Items.ASUPConfig.Formatted | Format-Table Transport, Enabled | Out-String -Stream | Add-Indentation $Items.ASUPConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "AutoSupport Enabled" Finding = $Items.ASUPConfig.Result.enabled Topic = $Categories[$Items.ASUPConfig.Category] } $Items.ASUPTransport.Summary = New-Object -TypeName psobject -Property @{ Item = "AutoSupport Transport is HTTPS" Finding = ($Items.ASUPConfig.Result.transport.contains("https")) Topic = $Categories[$Items.ASUPTransport.Category] } # CLI Timeout $Items.CLITimeout.FullHeader = @" $Separator Recommendation: CLI timeout value should match your organization's requirements Reference: TR-4569 section "CLI session timeout" "@ $Items.CLITimeout.Summary = New-Object -TypeName psobject -Property @{ Item = "CLI Timeout Enabled" Finding = ($Items.CLITimeout.Result.timeout -gt 0) Topic = $Categories[$Items.CLITimeout.Category] } $Items.CLITimeout.FullData = "`n$Spacer CLI session timeout: $($Items.CLITimeout.Result.timeout) minutes`n" # Cloud Insights $Items.CloudInsights.FullHeader = @" $Separator Recommendation: Cloud Insights provides an external mode FPolicy server Reference: TR-4572 section "Cloud Insights" "@ If ($Items.CloudInsights.Supported) { If ($Items.CloudInsights.Result.num_records -ne 0) { $Items.CloudInsights.FullData = $Items.CloudInsights.Result.records | Format-Table | Out-String -Stream | Add-Indentation $Items.CloudInsights.Summary = New-Object -TypeName psobject -Property @{ Item = "Cloud Insights Configured" Finding = ($Items.CloudInsights.Result.records.application_url.contains("cloudinsights.netapp.com")) Topic = $Categories[$Items.CloudInsights.Category] } } Else { $Items.CloudInsights.FullData = "`n$Spacer No Results Returned.`n" $Items.CloudInsights.Summary = New-Object -TypeName psobject -Property @{ Item = "Cloud Insights Configured" Finding = "False" Topic = $Categories[$Items.CloudInsights.Category] } } } Else { $Items.CloudInsights.Summary = New-Object -TypeName psobject -Property @{ Item = "Cloud Insights Configured" Finding = "Not available in this release" Topic = $Categories[$Items.CloudInsights.Category] } $Items.CloudInsights.FullData = "`n$Spacer Not available in this release.`n" } # Banner and MOTD $Items.LoginBannerConfig.FullHeader = @" $Separator Recommendation: The login banner and message of the day (motd) should match your organization's requirements Reference: System Manager insights and TR-4569 section "Login banners" and "Message of the day" "@ $Items.LoginBannerConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "Login Banner Configured" Finding = ($Items.LoginBannerConfig.Result.num_records -ne 0) Topic = $Categories[$Items.LoginBannerConfig.Category] } $Items.MOTDConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "MOTD Configured" Finding = ($Items.MOTDConfig.Result.num_records -ne 0) Topic = $Categories[$Items.MOTDConfig.Category] } $Items.LoginBannerConfig.FullData = "`n$Spacer Login banner configured - $($Items.LoginBannerConfig.Result.num_records -ne 0)" $Items.MOTDConfig.FullData = "`n$Spacer MOTD configured - $($Items.MOTDConfig.Result.num_records -ne 0)`n" # Password Complexity $Items.PasswordConfig.FullHeader = @" $Separator Recommendation: Configured password parameters should match your organization's policy Reference: TR-4569 section "Password parameters" "@ $Items.PasswordConfig.Formatted = ForEach ($_ in $Items.PasswordConfig.Result.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() "Before Reuse" = ($_.disallowed_reuse).ToString() "Expiry Time" = ($_.passwd_expiry_time).ToString() "Expiry Warn" = ($_.passwd_expiry_warn_time).ToString() "Age Before Chg" = ($_.change_delay).ToString() "ChgOnLogin" = ($_.require_initial_passwd_update).ToString() "Lockout Duration" = ($_.lockout_duration).ToString() } } $Items.PasswordConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "Password Complexity Configuration" Finding = "Review Full Output" Topic = $Categories[$Items.PasswordConfig.Category] } $Items.PasswordConfig.FullData = $Items.PasswordConfig.Formatted | Format-Table vserver, role, Alphanumeric, "Min Len", "Min Spec Chars", "Min Lowercase", "Min Uppercase", "Min Digits" | Out-String -Stream | Add-Indentation $Items.PasswordConfig.FullData += $Items.PasswordConfig.Formatted | Format-Table vserver, role, "Before Reuse", "Expiry Time", "Expiry Warn", "Age Before Chg", "ChgOnLogin", "Lockout Duration" | Out-String -Stream | Add-Indentation # Log Forwarding $Items.LogForwarding.FullHeader = @" $Separator Recommendation: Offloading of syslog information should be configured Reference: TR-4569 section "Sending out syslog" "@ If ($Items.LogForwarding.Result.num_records -ne 0) { $Items.LogForwarding.Formatted = ForEach ($_ in $Items.LogForwarding.Result.records) { New-Object psobject -Property @{ Destination = ($_.Destination).ToString() Port = ($_.Port).ToString() } } $Items.LogForwarding.FullData = $Items.LogForwarding.Formatted | Format-Table Destination, Port | Out-String -Stream | Add-Indentation } else { $Items.LogForwarding.FullData = "`n$Spacer No Results Returned.`n" } $Items.LogForwarding.Summary = New-Object -TypeName psobject -Property @{ Item = "Syslog Forwarding Configured" Finding = ($Items.LogForwarding.Result.num_records -ne 0) Topic = $Categories[$Items.LogForwarding.Category] } # System Configuration Backup $Items.SystemConfigBackup.FullHeader = @" $Separator Recommendation: System Configuration should be backed up to a remote server "@ If ($Items.SystemConfigBackup.Result.url) { $Items.SystemConfigBackup.FullData = "System Configuration Backup Destination:`n$Spacer $($Items.SystemConfigBackup.Result.url)`n" } Else { $Items.SystemConfigBackup.FullData = "`n$Spacer No Remote Destination Found.`n" } $Items.SystemConfigBackup.Summary = New-Object -TypeName psobject -Property @{ Item = "System Configuration Backup to Remote Server" Finding = (![string]::IsNullOrEmpty($Items.SystemConfigBackup.Result.url)) Topic = $Categories[$Items.SystemConfigBackup.Category] } ### End - General Configuration - Category 1 ### Begin - Administrative Protocols - Category 2 # Web Services $Items.WebServices.FullHeader = @" $Separator Recommendation: HTTP should be disabled "@ $Items.WebServices.FullData = "`n$Spacer HTTP Enabled - $($Items.WebServices.Result.http_enabled)`n" $Items.WebServices.Summary = New-Object -TypeName psobject -Property @{ Item = "HTTP Disabled" Finding = (!$Items.WebServices.Result.http_enabled) Topic = $Categories[$Items.WebServices.Category] } # Management Protocols $Items.ManagementProtocols.FullHeader = @" $Separator Recommendation: Telnet and Remote Shell (RSH) should be disabled Reference: System Manager insights and TR-4569 section "Application methods" "@ $Items.ManagementProtocols.Formatted = ForEach ($_ in $Items.ManagementProtocols.Result.records) { New-Object psobject -Property @{ Application = ($_.application).ToString() Enabled = ($_.enabled).ToString() } } $Items.ManagementProtocols.FullData = $Items.ManagementProtocols.Formatted | Format-Table Application, Enabled | Out-String -Stream | Add-Indentation $Items.RSHConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "RSH Disabled" Finding = (!$Items.RSHConfig.Result.records.enabled) Topic = $Categories[$Items.RSHConfig.Category] } $Items.TelnetConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "Telnet Disabled" Finding = (!$Items.TelnetConfig.Result.records.enabled) Topic = $Categories[$Items.TelnetConfig.Category] } ### End - Administrative Protocols - Category 2 ### Begin - Administrative Users - Category 3 # Built in accounts $Items.BuiltinUsers.FullHeader = @" $Separator Recommendation: Built in accounts should be locked Reference: System Manager insights and TR-4569 section "Default administrative accounts" "@ $Items.BuiltinUsers.Builtin = $Items.BuiltinUsers.Result.records + $Items.DiagUser.Result.records $Items.BuiltinUsers.Formatted = ForEach ($_ in $Items.BuiltinUsers.Builtin) { New-Object psobject -Property @{ Username = ($_.name).ToString() Locked = ($_.locked).ToString() } } $Items.BuiltinUsers.FullData = $Items.BuiltinUsers.Formatted | Format-Table Username, Locked | Out-String -Stream | Add-Indentation $Items.BuiltinUsers.Summary = New-Object -TypeName psobject -Property @{ Item = "Default Administrative Accounts Locked" Finding = (!$Items.BuiltinUsers.Formatted.Locked.Contains("False")) Topic = $Categories[$Items.BuiltinUsers.Category] } # REST Roles $Items.RestRoles.FullHeader = @" $Separator Recommendation: You can prevent ONTAP administrators from using REST APIs for file access by setting access level for /api/storage/volumes to none Reference: TR-4569 section "Effect of REST APIs on NAS auditing" "@ If ($Items.RestRoles.Supported) { $Items.RestRoles.Formatted = ForEach ($_ in $Items.RestRoles.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Role = ($_.role).ToString() API = ($_.api).ToString() Access = ($_.Access).ToString() } } $Items.RestRoles.FullData = $Items.RestRoles.Formatted | Format-Table VServer, Role, API, Access | Out-String -Stream | Add-Indentation } else { $Items.RestRoles.FullData = "`n$Spacer Not Supported in this release.`n" } # User Details $Items.UserDetails.FullHeader = @" $Separator Recommendation: For each login the authentication-method should be public key for machine access and can be password for user access The second-authentication-method should not be none to enable MFA The role should be appropriate to grant them privilege to perform their job function or required task The hash-function should be sha512 Reference: TR-4569 section "SHA-512 support" and "Managing SSHv2" and "Roles, applications, and authentication" and TR-4647 section "ONTAP SSH two-factor chained authentication" "@ $Items.UserDetails.Formatted = ForEach ($_ in $Items.UserDetails.Result.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() } } $Items.UserDetails.FullData = $Items.UserDetails.Formatted | Format-Table username, vserver, application, "role name", authmethod, "2ndAuthMethod", Locked, "Hash Function" | Out-String -Stream | Add-Indentation # Multi-Admin Verification $Items.MultiAdminVerify.FullHeader = @" $Separator Recommendation: Multi-admin verification should be enabled Reference: TR-4569 section "Multi-admin verification" "@ If ($Items.MultiAdminVerify.Supported) { $Items.MultiAdminVerify.Formatted = New-Object psobject -Property @{ Enabled = ($Items.MultiAdminVerify.Result.enabled).ToString() "Required Approvers" = ($Items.MultiAdminVerify.Result.required_approvers).ToString() } $Items.MultiAdminVerify.Summary = New-Object -TypeName psobject -Property @{ Item = "Multi-Admin-Verify Configured" Finding = $Items.MultiAdminVerify.Result.enabled Topic = $Categories[$Items.MultiAdminVerify.Category] } $Items.MultiAdminVerify.FullData = $Items.MultiAdminVerify.Formatted | Format-Table Enabled, "Required Approvers" | Out-String -Stream | Add-Indentation } else { $Items.MultiAdminVerify.Summary = New-Object -TypeName psobject -Property @{ Item = "Multi-Admin-Verify Configured" Finding = "Not available in this release" Topic = $Categories[$Items.MultiAdminVerify.Category] } $Items.MultiAdminVerify.FullData = "`n$Spacer Multi-admin-verify is not supported on this release. Consider upgrading to 9.11.1 or later.`n" } # SNMP Users $Items.SNMPUsers.FullHeader = @" $Separator Recommendation: SNMP Users shoud not use an authentication method of community "@ If ($Items.SNMPUsers.Result.num_records -ne 0) { $Items.SNMPUsers.Formatted = ForEach ($_ in $Items.SNMPUsers.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Username = ($_.user_or_group_name).ToString() Application = ($_.application).ToString() AuthMethod = ($_.authentication_method).ToString() } } $Items.SNMPUsers.FullData = $Items.SNMPUserss.Formatted | Format-Table username, vserver, application, authmethod | Out-String -Stream | Add-Indentation } Else { $Items.SNMPUsers.FullData = "`n$Spacer No SNMP users found with community authentication method.`n" } $Items.SNMPUsers.Summary = New-Object -TypeName psobject -Property @{ Item = "No SNMP Users with Auth Method of Community" Finding = ($Items.SNMPUsers.Result.num_records -eq 0) Topic = $Categories[$Items.SNMPUsers.Category] } # RSH and Telnet Users $Items.RSHUsers.FullHeader = @" $Separator Recommendation: No logins should exist with the Telnet or RSH application Reference: TR-4569 section "Application methods" "@ If ($Items.RSHUsers.Result.num_records -ne 0) { $Items.RSHUsers.Formatted = ForEach ($_ in $Items.RSHUsers.Result.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() } } $Items.RSHUsers.FullData = $Items.RSHUsers.Formatted | Format-Table username, vserver, application, "role name", authmethod, "2ndAuthMethod", Locked | Out-String -Stream | Add-Indentation } else { $Items.RSHUsers.FullData = "`n$Spacer No users found with RSH application access." } $Items.RSHUsers.Summary = New-Object -TypeName psobject -Property @{ Item = "No Users Present with RSH Access" Finding = ($Items.RSHUsers.Result.num_records -eq 0) Topic = $Categories[$Items.RSHUsers.Category] } If ($Items.TelnetUsers.Result.num_records -ne 0) { $Items.TelnetUsers.Formatted = ForEach ($_ in $Items.TelnetUsers.Result.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() } } $Items.TelnetUsers.FullData = $Items.TelnetUsers.Formatted | Format-Table username, vserver, application, "role name", authmethod, "2ndAuthMethod", Locked | Out-String -Stream | Add-Indentation } else { $Items.TelnetUsers.FullData = "`n$Spacer No users found with Telnet application access.`n" } $Items.TelnetUsers.Summary = New-Object -TypeName psobject -Property @{ Item = "No Users Present with Telnet Access" Finding = ($Items.TelnetUsers.Result.num_records -eq 0) Topic = $Categories[$Items.TelnetUsers.Category] } ### End - Administrative Users - Category 3 ### Begin - Secure Communication - Category 4 # Cluster Peer Details $Items.ClusterPeerEncryption.FullHeader = @" $Separator Recommendation: Cluster peers should be configured with tls-psk for the encryption protocol Reference: TR-4569 section "Data replication encryption" "@ If ($Items.ClusterPeerEncryption.Result.num_records -ne 0) { $Items.ClusterPeerEncryption.Formatted = ForEach ($_ in $Items.ClusterPeerEncryption.Result.records) { New-Object psobject -Property @{ Cluster = ($_.cluster).ToString() "Encryption Protocol" = ($_.encryption_protocol).ToString() } } $Items.ClusterPeerEncryption.FullData = $Items.ClusterPeerEncryption.Formatted | Format-Table Cluster, "Encryption Protocol" | Out-String -Stream | Add-Indentation $Items.ClusterPeerEncryption.Summary = New-Object -TypeName psobject -Property @{ Item = "Encryption Enabled for all Cluster Peers" Finding = (!$Items.ClusterPeerEncryption.Formatted."Encryption Protocol".contains("none")) Topic = $Categories[$Items.ClusterPeerEncryption.Category] } } else { $Items.ClusterPeerEncryption.FullData = "`n$Spacer No Cluster Peer Relationships Found.`n" $Items.ClusterPeerEncryption.Summary = New-Object -TypeName psobject -Property @{ Item = "Encryption Enabled for all Cluster Peers" Finding = "No Cluster Peers Found" Topic = $Categories[$Items.ClusterPeerEncryption.Category] } } # FIPS $Items.FIPS.FullHeader = @" $Separator Recommendation: FIPS Mode should be enabled Reference: System Manager insights and TR-4569 section "Managing TLS and SSL" "@ $Items.FIPS.Formatted = ForEach ($_ in $Items.FIPS.Result.records) { New-Object psobject -Property @{ Interface = ($_.interface).ToString() "FIPS Enabled" = ($_.is_fips_enabled).ToString() } } $Items.FIPS.FullData = $Items.FIPS.Formatted | Format-Table Interface, "FIPS Enabled" | Out-String -Stream | Add-Indentation $Items.FIPS.Summary = New-Object -TypeName psobject -Property @{ Item = "FIPS Mode Enabled" Finding = $Items.FIPS.Result.records.is_fips_enabled Topic = $Categories[$Items.FIPS.Category] } # IPSec $Items.IPSec.FullHeader = @" $Separator Recommendation: When required IPsec is configured and policies created Reference: TR-4569 section "IPsec data-in-flight encryption" "@ If ($Items.IPSec.Supported) { $Items.IPSec.FullData = "`n$Spacer IPsec Enabled - $($Items.IPsec.Result.enabled)`n" If ($Items.IPsecPol.Result.num_records -ne 0) { $Items.IPSecPolicy.FullData = $Items.IPsecPol.Result.records | Format-Table | Out-String -Stream | Add-Indentation } Else { $Items.IPSecPolicy.FullData = "$Spacer No IPsec Policies Found.`n" } $Items.IPSec.Summary = New-Object -TypeName psobject -Property @{ Item = "IPsec Enabled" Finding = $Items.IPsec.Result.enabled Topic = $Categories[$Items.IPSec.Category] } $Items.IPSecPolicy.Summary = New-Object -TypeName psobject -Property @{ Item = "IPsec Policies Configured" Finding = ($Items.IPsecPol.Result.num_records -ne 0) Topic = $Categories[$Items.IPSecPolicy.Category] } } Else { $Items.IPSec.FullData = "`n$Spacer IPsec is not supported on this release. Consider upgrading to 9.8 or later.`n" $Items.IPSecPolicy.FullData = "$Spacer IPsec is not supported on this release. Consider upgrading to 9.8 or later.`n" $Items.IPSec.Summary = New-Object -TypeName psobject -Property @{ Item = "IPsec Enabled" Finding = "Not available in this release" Topic = $Categories[$Items.IPSec.Category] } $Items.IPSecPolicy.Summary = New-Object -TypeName psobject -Property @{ Item = "IPsec Policies Configured" Finding = "Not available in this release" Topic = $Categories[$Items.IPSecPolicy.Category] } } # Problematic Ciphers $Items.SSHCiphers.FullHeader = @" $Separator Recommendation: No ciphers should exist that have names containing "cbc" Reference: System Manager insights $Spacer Problematic Ciphers: "@ If ($Items.SSHCiphers.Result.num_records -ne 0) { ForEach ($_ in $Items.SSHCiphers.Result.records) { $Items.SSHCiphers.VServer = $_.vserver $Items.SSHCiphers.Ciphers = $_.ciphers -split "," $Items.SSHCiphers.Formatted = @() ForEach ($_ in $Items.SSHCiphers.Ciphers) { If ($_.contains("cbc")) { $Items.SSHCiphers.Formatted += New-Object -TypeName psobject -Property @{VServer = $Items.SSHCiphers.VServer; Cipher = $_ } } } } $Items.SSHCiphers.FullData = $Items.SSHCiphers.Formatted | Format-Table VServer, Cipher | Out-String -Stream | Add-Indentation } else { $Items.SSHCiphers.FullData = "`n$Spacer No Problematic Ciphers Found.`n" } $Items.SSHCiphers.Summary = New-Object -TypeName psobject -Property @{ Item = "No Problematic Ciphers Present" Finding = ($Items.SSHCiphers.Result.num_records -eq 0) Topic = $Categories[$Items.SSHCiphers.Category] } # Self-Signed Certificates $Items.SelfSignedCerts.FullHeader = @" $Separator Recommendation: On production systems no self-signed ceritficates should exist Reference: TR-4569 section "Creating a CA-signed digital certificate" "@ If ($Items.SelfSignedCerts.Result.num_records -ne 0) { $Items.SelfSignedCerts.Formatted = ForEach ($_ in $Items.SelfSignedCerts.Result.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() } } $Items.SelfSignedCerts.FullData = $Items.SelfSignedCerts.Formatted | Format-Table Vserver, CommonName, Serial, CA, Type, "Self-Signed" | Out-String -Stream | Add-Indentation } else { $Items.SelfSignedCerts.FullData = "`n$Spacer No Results Returned.`n" } $Items.SelfSignedCerts.Summary = New-Object -TypeName psobject -Property @{ Item = "No Self-signed Certificates Present" Finding = ($Items.SelfSignedCerts.Result.num_records -eq 0) Topic = $Categories[$Items.SelfSignedCerts.Category] } # SSL Client, HTTP, and ONTAPI Users $Items.SSLConfig.FullHeader = @" $Separator Recommendation: For any SVM with client-enabled access, all related logins that are performing SDK or REST API calls should use cert for Authentication Method field Reference: TR-4569 section "Certificate-based API access" $Spacer SSL Configuration "@ $Items.SSLConfig.Formatted = ForEach ($_ in $Items.SSLConfig.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "Client Enabled" = ($_.client_enabled).ToString() } } $Items.SSLConfig.FullData = $Items.SSLConfig.Formatted | Format-Table VServer, "Client Enabled" | Out-String -Stream | Add-Indentation $Items.SSLConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "No SVMs with client-enabled SSL Access Present" Finding = (!$Items.SSLConfig.Formatted."Client Enabled".contains("True)")) Topic = $Categories[$Items.SSLConfig.Category] } $Items.HTTPUsers.Formatted = ForEach ($_ in $Items.HTTPUsers.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Username = ($_.user_or_group_name).ToString() Application = ($_.application).ToString() AuthMethod = ($_.authentication_method).ToString() } } $Items.ONTAPIUsers.Formatted = ForEach ($_ in $Items.ONTAPIUsers.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Username = ($_.user_or_group_name).ToString() Application = ($_.application).ToString() AuthMethod = ($_.authentication_method).ToString() } } If ($Items.HTTPUsers.Result.records.num_records -ne 0) { $Items.HTTPUsers.FullHeader = "$Spacer HTTP Users" $Items.HTTPUsers.FullData = $Items.HTTPUsers.Formatted | Format-Table VServer, Username, Application, AuthMethod | Out-String -Stream | Add-Indentation } Else { $Items.HTTPUsers.FullData = "`n$Spacer No HTTP Users Found.`n" } If ($Items.ONTAPIUsers.Result.records.num_records -ne 0) { $Items.ONTAPIUsers.FullHeader = "$Spacer ONTAPI Users" $Items.ONTAPIUsers.FullData = $Items.ONTAPIUsers.Formatted | Format-Table VServer, Username, Application, AuthMethod | Out-String -Stream | Add-Indentation } Else { $Items.ONTAPIUsers.FullData = "`n$Spacer No ONTAPI Users Found.`n" } # OCSP $Items.OCSPConfig.FullHeader = @" $Separator Recommendation: OCSP should be enabled Reference: TR-4569 section "Online certificate status protocol" "@ $Items.OCSPConfig.Formatted = ForEach ($_ in $Items.OCSPConfig.Result.records) { New-Object psobject -Property @{ Application = ($_.application).ToString() "OCSP Enabled" = ($_.is_ocsp_enabled).ToString() } } $Items.OCSPConfig.FullData = $Items.OCSPConfig.Formatted | Format-Table Application, "OCSP Enabled" | Out-String -Stream | Add-Indentation $Items.OCSPConfig.Summary = New-Object -TypeName psobject -Property @{ Item = "OCSP Enabled for all Applications" Finding = (!$Items.OCSPConfig.Formatted."OCSP Enabled".contains("False")) Topic = $Categories[$Items.OCSPConfig.Category] } # SAML $Items.SAML.FullHeader = @" $Separator Recommendation: SAML should be configured Reference: TR-4647 section "The requirement for strong administrative credentials" "@ If ($Items.SAML.Result.records.num_records -ne 0) { $Items.SAML.Formatted = ForEach ($_ in $Items.SAML.Result.records) { New-Object psobject -Property @{ Node = ($_.node).ToString() Status = ($_.status).ToString() Enabled = ($_.is_enabled).ToString() } } $Items.SAML.FullData = $Items.SAML.Formatted | Format-Table Node, Status, Enabled | Out-String -Stream | Add-Indentation } else { $Items.SAML.FullData = "`n$Spacer No Results Returned.`n" } $Items.SAML.Summary = New-Object -TypeName psobject -Property @{ Item = "SAML Configured" Finding = (!$Items.SAML.Formatted.enabled.contains("False")) Topic = $Categories[$Items.SAML.Category] } ### End - Secure Communication - Category 4 ### Begin - File Access - Category 5 ## CIFS Things If ($Items.CIFSSvms.Result.num_records -ne 0) { # CIFS Signing If ($Items.CIFSSigning.Result.num_records -ne 0) { $Items.CIFSSigning.Formatted = ForEach ($_ in $Items.CIFSSigning.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "Signing Required" = ($_.is_signing_required).ToString() } } $Items.CIFSSigning.FullHeader = @" $Separator Recommendation: For each SVM configured with CIFS the is-signing-required should be true Reference: TR-4569 section "CIFS SMB signing and sealing" "@ $Items.CIFSSigning.FullData = $Items.CIFSSigning.Formatted | Format-Table VServer, "Signing Required" | Out-String -Stream | Add-Indentation $Items.CIFSSigning.Summary = New-Object -TypeName psobject -Property @{ Item = "All CIFS SVMs have Signing Enabled" Finding = (!$Items.CIFSSigning.Formatted."Signing Required".contains("False")) Topic = $Categories[$Items.CIFSSigning.Category] } } Else { $Items.CIFSSigning.FullHeader = @" $Separator Recommendation: For each SVM configured with CIFS the is-signing-required should be true Reference: TR-4569 section "CIFS SMB signing and sealing" "@ $Items.CIFSSigning.FullData = "`n$Spacer No CIFS SVMs configured for required signing.`n" $Items.CIFSSigning.Summary = New-Object -TypeName psobject -Property @{ Item = "All CIFS SVMs have Signing Enabled" Finding = (!$Items.CIFSSigning.Formatted."Signing Required".contains("False")) Topic = $Categories[$Items.CIFSSigning.Category] } } # CIFS Workgroups If ($Items.CIFSWorkgroup.Result.num_records -ne 0) { $Items.CIFSWorkgroup.Formatted = ForEach ($_ in $Items.CIFSWorkgroup.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "Auth Style" = ($_.auth_style).ToString() } } $Items.CIFSWorkgroup.FullHeader = @" $Separator Recommendation: CIFS SVMs should not be configured for workgroup access "@ $Items.CIFSWorkgroup.FullData = $Items.CIFSWorkgroup.Formatted | Format-Table VServer, "Auth Style" | Out-String -Stream | Add-Indentation $Items.CIFSWorkgroup.Summary = New-Object -TypeName psobject -Property @{ Item = "No CIFS SVMs are configured for Workgroup" Finding = ($Items.CIFSWorkgroup.Result.num_records -eq 0) Topic = $Categories[$Items.CIFSWorkgroup.Category] } } Else{ $Items.CIFSWorkgroup.FullHeader = @" $Separator Recommendation: CIFS SVMs should not be configured for workgroup access "@ $Items.CIFSWorkgroup.FullData = "`n$Spacer No CIFS SVMs configured for workgroup access.`n" $Items.CIFSWorkgroup.Summary = New-Object -TypeName psobject -Property @{ Item = "No CIFS SVMs are configured for Workgroup" Finding = ($Items.CIFSWorkgroup.Result.num_records -eq 0) Topic = $Categories[$Items.CIFSWorkgroup.Category] } } # CIFS SMB1 If ($Items.CIFSSMB1.Result.num_records -ne 0) { $Items.CIFSSMB1.Formatted = ForEach ($_ in $Items.CIFSSMB1.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "SMB1 Enabled" = ($_.smb1_enabled).ToString() } } $Items.CIFSSMB1.FullHeader = @" $Separator Recommendation: CIFS SVMs should not be configured to use SMB1 "@ $Items.CIFSSMB1.FullData = $Items.CIFSSMB1.Formatted | Format-Table VServer, "SMB1 Enabled" | Out-String -Stream | Add-Indentation $Items.CIFSSMB1.Summary = New-Object -TypeName psobject -Property @{ Item = "No CIFS SVMs have SMB 1 Enabled" Finding = ($Items.CIFSSMB1.Result.num_records -eq 0) Topic = $Categories[$Items.CIFSSMB1.Category] } } Else { $Items.CIFSSMB1.FullHeader = @" $Separator Recommendation: CIFS SVMs should not be configured to use SMB1 "@ $Items.CIFSSMB1.FullData = "`n$Spacer No CIFS SVMs configured for SMB1.`n" $Items.CIFSSMB1.Summary = New-Object -TypeName psobject -Property @{ Item = "No CIFS SVMs have SMB 1 Enabled" Finding = ($Items.CIFSSMB1.Result.num_records -eq 0) Topic = $Categories[$Items.CIFSSMB1.Category] } } If ($Items.LDAP.Result.num_records -ne 0) { $Items.LDAP.Formatted = ForEach ($_ in $Items.LDAP.Result.records) { If ($Items.CIFSSvms.Result.records -match ($_.vserver)) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "Session Security for AD LDAP" = ($_.session_security_for_ad_ldap).ToString() } } } $Items.LDAP.FullHeader = @" $Separator Recommendation: For each SVM configured with CIFS session-security-for-ad-ldap should be set to a minimum of sign to match your organization's requirements Reference: TR-4835 section "Microsoft LDAP channel binding requirement" "@ $Items.LDAP.FullData = $Items.LDAP.Formatted | Format-Table VServer, "Session Security for AD LDAP" | Out-String -Stream | Add-Indentation $Items.LDAP.Summary = New-Object -TypeName psobject -Property @{ Item = "AD LDAP Session Security Enabled for all CIFS SVMs" Finding = (!$Items.LDAP.Formatted."Session Security for AD LDAP".contains("none")) Topic = $Categories[$Items.LDAP.Category] } } Else{ $Items.LDAP.FullHeader = @" $Separator Recommendation: For each SVM configured with CIFS session-security-for-ad-ldap should be set to a minimum of sign to match your organization's requirements Reference: TR-4835 section "Microsoft LDAP channel binding requirement" "@ $Items.LDAP.FullData = "`n$Spacer No CIFS SVMs Configured for LDAP Found.`n" $Items.LDAP.Summary = New-Object -TypeName psobject -Property @{ Item = "AD LDAP Session Security Enabled for all CIFS SVMs" Finding = (!$Items.LDAP.Formatted."Session Security for AD LDAP".contains("none")) Topic = $Categories[$Items.LDAP.Category] } } # VScan If ($Items.VScan.Result.num_records -ne 0) { $Items.VScan.Formatted = ForEach ($_ in $Items.VScan.Result.records) { If ($Items.CIFSSvms.Result.records -match ($_.vserver)) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "VScan Status" = ($_.vscan_status).ToString() } } } $Items.VScan.FullHeader = @" $Separator Recommendation: VScan can be configured for CIFS SVMs "@ $Items.VScan.FullData = $Items.VScan.Formatted | Format-Table VServer, "VScan Status" | Out-String -Stream | Add-Indentation $Items.VScan.Summary = New-Object -TypeName psobject -Property @{ Item = "VScan Enabled for all CIFS SVMs" Finding = (!$Items.VScan.Formatted."VScan Status".contains("off")) Topic = $Categories[$Items.VScan.Category] } } Else { $Items.VScan.FullHeader = @" $Separator Recommendation: VScan can be configured for CIFS SVMs "@ $Items.VScan.FullData = "`n$Spacer VScan not configured for any CIFS SVMs." $Items.VScan.Summary = New-Object -TypeName psobject -Property @{ Item = "VScan Enabled for all CIFS SVMs" Finding = (!$Items.VScan.Formatted."VScan Status".contains("off")) Topic = $Categories[$Items.VScan.Category] } } } Else { $Items.CIFSSigning.Summary = New-Object -TypeName psobject -Property @{ Item = "All CIFS SVMs have Signing Enabled" Finding = "No CIFS SVMs Found" Topic = $Categories[$Items.CIFSSigning.Category] } $Items.CIFSWorkgroup.Summary = New-Object -TypeName psobject -Property @{ Item = "No CIFS SVMs are configured for Workgroup" Finding = "No CIFS SVMs Found" Topic = $Categories[$Items.CIFSWorkgroup.Category] } $Items.CIFSSMB1.Summary = New-Object -TypeName psobject -Property @{ Item = "No CIFS SVMs have SMB 1 Enabled" Finding = "No CIFS SVMs Found" Topic = $Categories[$Items.CIFSSMB1.Category] } $Items.LDAP.Summary = New-Object -TypeName psobject -Property @{ Item = "AD LDAP Session Security Enabled for all CIFS SVMs" Finding = "No CIFS SVMs Found" Topic = $Categories[$Items.LDAP.Category] } $Items.VScan.Summary = New-Object -TypeName psobject -Property @{ Item = "VScan Enabled for all CIFS SVMs" Finding = "No CIFS SVMs Found" Topic = $Categories[$Items.VScan.Category] } } # FPolicy $Items.FPolicy.FullHeader = @" $Separator Recommendation: FPolicy should be configured Reference: System Manager insights "@ If ($Items.Fpolicy.Result.num_records -ne 0) { $Items.Fpolicy.Formatted = ForEach ($_ in $Items.Fpolicy.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() "Policy Name" = ($_.policy_name).ToString() Status = ($_.status).ToString() Engine = ($_.engine).ToString() } } $Items.FPolicy.FullData = $Items.Fpolicy.Formatted | Format-Table VServer, "Policy Name", Status, Engine | Out-String -Stream | Add-Indentation } Else { $Items.FPolicy.FullData = "`n$Spacer No Results Returned.`n" } $Items.FPolicy.Summary = New-Object -TypeName psobject -Property @{ Item = "FPolicy Configured" Finding = ($Items.Fpolicy.Result.num_records -ne 0) Topic = $Categories[$Items.Fpolicy.Category] } # NAS Auditing $Items.NASAuditing.FullHeader = @" $Separator Recommendation: NAS auditing should be enabled Reference: TR-4569 section "NAS file system auditing" "@ If ($Items.NASAuditing.Result.num_records -ne 0) { $Items.NASAuditing.Formatted = ForEach ($_ in $Items.NASAuditing.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Enabled = ($_.state).ToString() } } $Items.NASAuditing.FullData = $Items.NASAuditing.Formatted | Format-Table VServer, Enabled | Out-String -Stream | Add-Indentation } Else { $Items.NASAuditing.FullData = "`n$Spacer No NAS Auditing Configuration Found.`n" } $Items.NASAuditing.Summary = New-Object -TypeName psobject -Property @{ Item = "NAS Auditing Configured" Finding = ($Items.NASAuditing.Result.num_records -ne 0) Topic = $Categories[$Items.NASAuditing.Category] } # NIS $Items.NISServers.FullHeader = @" $Separator Recommendation: NIS should not be configured Reference: TR-4569 section "Authentication methods" "@ If ($Items.NISServers.Result.num_records -ne 0) { $Items.NISServers.Formatted = ForEach ($_ in $Items.NISServers.Result.records) { New-Object psobject -Property @{ VServer = ($_.name).ToString() NISDomain = ($_.nis.domain).ToString() } } $Items.NISServers.FullData = $Items.NISServers.Formatted | Format-Table vserver, nisdomain | Out-String -Stream | Add-Indentation } Else { $Items.NISServers.FullData = "`n$Spacer No NIS Configuration Found.`n" } $Items.NISServers.Summary = New-Object -TypeName psobject -Property @{ Item = "NIS not Configured" Finding = ($Items.NISServers.Result.num_records -eq 0) Topic = $Categories[$Items.NISServers.Category] } ### End - File Access - Category 5 ### Begin - Data Protection - Category 6 # Snapshot Autodeletion $Items.SnapShotAutoDelete.FullHeader = @" $Separator Recommendation: Snapshot auto-deletion should not be enabled for data volumes Reference: System Manager insights "@ If ($Items.SnapShotAutoDelete.Result.num_records -ne 0) { $Items.SnapShotAutoDelete.Formatted = ForEach ($_ in $Items.SnapShotAutoDelete.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Enabled = ($_.enabled).ToString() Volume = ($_.volume).ToString() } } $Items.SnapShotAutoDelete.FullData = $Items.SnapShotAutoDelete.Formatted | Format-Table VServer, Volume, Enabled | Out-String -Stream | Add-Indentation } Else { $Items.SnapShotAutoDelete.FullData = "`n$Spacer No Results Returned.`n" } $Items.SnapShotAutoDelete.Summary = New-Object -TypeName psobject -Property @{ Item = "No Volumes with Snapshot Autodeletion Enabled" Finding = ($Items.SnapShotAutoDelete.Result.num_records -eq 0) Topic = $Categories[$Items.SnapShotAutoDelete.Category] } # Snapshot Policy $Items.NullSnapShotPolicy.FullHeader = @" $Separator Recommendation: All volumes should have Snapshot policies Reference: System Manager insights "@ If ($Items.NullSnapShotPolicy.Result.num_records -ne 0) { $Items.NullSnapShotPolicy.Formatted = ForEach ($_ in $Items.NullSnapShotPolicy.Result.records) { New-Object psobject -Property @{ Volume = ($_.volume).ToString() "Snapshot Policy" = "-" VServer = ($_.vserver).ToString() } } $Items.NullSnapShotPolicy.FullData = $Items.NullSnapShotPolicy.Formatted | Format-Table volume, "Snapshot Policy", VServer | Out-String -Stream | Add-Indentation } Else { $Items.NullSnapShotPolicy.FullData = "`n$Spacer No Volumes with a Snapshot Policy of NULL." } If ($Items.NoneSnapShotPolicy.Result.num_records -ne 0) { $Items.NoneSS.Formatted = ForEach ($_ in $Items.NoneSnapShotPolicy.Result.records) { New-Object psobject -Property @{ Volume = ($_.volume).ToString() "Snapshot Policy" = ($_.snapshot_policy).ToString() VServer = ($_.vserver).ToString() } } $Items.NoneSnapShotPolicy.FullData = $Items.NoneSS.Formatted | Format-Table volume, "Snapshot Policy", VServer | Out-String -Stream | Add-Indentation } Else { $Items.NoneSnapShotPolicy.FullData = "`n$Spacer No Volumes with a Snapshot Policy of None.`n" } $Items.NullSnapShotPolicy.Summary = New-Object -TypeName psobject -Property @{ Item = "No Volumes with Snapshot Policy of NULL" Finding = ($Items.NullSnapShotPolicy.Result.num_records -eq 0) Topic = $Categories[$Items.NullSnapShotPolicy.Category] } $Items.NoneSnapShotPolicy.Summary = New-Object -TypeName psobject -Property @{ Item = "No Volumes with Snapshot Policy of none" Finding = ($Items.NoneSnapShotPolicy.Result.num_records -eq 0) Topic = $Categories[$Items.NoneSnapShotPolicy.Category] } # Snapshot Locking $Items.SnapShotLocking.FullHeader = @" $Separator Recommendation: snapshot-locking-enabled should be true for all volumes with snapshots Reference: TR-4569 section "Snapshot copy locking" "@ If ($Items.SnapShotLocking.Supported) { If ($Items.SnapShotLocking.Result.num_records -ne 0) { $Items.SnapShotLocking.Formatted = ForEach ($_ in $Items.SnapShotLocking.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Volume = ($_.volume).ToString() "Snapshot Locking Enabled" = ($_.snapshot_locking_enabled).ToString() } } $Items.SnapShotLocking.FullData = $Items.SnapShotLocking.Formatted | Format-Table VServer, Volume, "Snapshot Locking Enabled" | Out-String -Stream | Add-Indentation $Items.SnapShotLocking.Summary = New-Object -TypeName psobject -Property @{ Item = "Snapshot Locking Enabled for all Volumes" Finding = (!$Items.SnapShotLocking.Formatted."Snapshot Locking Enabled".contains("False")) Topic = $Categories[$Items.SnapShotLocking.Category] } } Else { } } Else { $Items.SnapShotLocking.FullData = "`n$Spacer Snapshot Copy Locking is not supported on this release. Consider upgrading to 9.12.1 or later.`n" $Items.SnapShotLocking.Summary = New-Object -TypeName psobject -Property @{ Item = "Snapshot Locking Enabled for all Volumes" Finding = "Not available in this release" Topic = $Categories[$Items.SnapShotLocking.Category] } } ### End - Data Protection - Category 6 ### Begin - Anti-Ransomware - Category 7 # SVM Anti-Ransomware $Items.SVMAntiRansomware.FullHeader = @" $Separator Recommendation: SVMs should be configured for anti-ransomware Reference: System Manager insights "@ If ($Items.SVMAntiRansomware.Supported) { If ($Items.SVMAntiRansomware.Result.num_records -ne 0) { $Items.SVMAntiRansomware.Formatted = ForEach ($_ in $Items.SVMAntiRansomware.Result.records) { New-Object psobject -Property @{ VServer = ($_.name).ToString() "Default Volume State" = ($_.anti_ransomware_default_volume_state).ToString() } } $Items.SVMAntiRansomware.FullData = $Items.SVMAntiRansomware.Formatted | Format-Table VServer, "Default Volume State" | Out-String -Stream | Add-Indentation $Items.SVMAntiRansomware.Summary = New-Object -TypeName psobject -Property @{ Item = "Ransomware Protection Enabled for all SVMs" Finding = (!$Items.SVMAntiRansomware.Formatted."Default Volume State".contains("disabled")) Topic = $Categories[$Items.SVMAntiRansomware.Category] } } } Else { $Items.SVMAntiRansomware.FullData = "`n$Spacer Ransomware Protection is not supported on this release. Consider upgrading to 9.10 or later.`n" $Items.SVMAntiRansomware.Summary = New-Object -TypeName psobject -Property @{ Item = "Ransomware Protection Enabled for all SVMs" Finding = "Not available in this release" Topic = $Categories[$Items.SVMAntiRansomware.Category] } } # Volume Anti-Ransomware $Items.VolumeAntiRansomware.FullHeader = @" $Separator Recommendation: Volume anti-ransomware-state should be enabled Reference: System Manager insights "@ If ($Items.VolumeAntiRansomware.Supported) { If ($Items.VolumeAntiRansomware.Result.num_records -ne 0) { $Items.VolumeAntiRansomware.Formatted = ForEach ($_ in $Items.VolumeAntiRansomware.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Volume = ($_.volume).ToString() "Anti Ransomware State" = ($_.anti_ransomware_state).ToString() } } } $Items.VolumeAntiRansomware.FullData = $Items.VolumeAntiRansomware.Formatted | Format-Table VServer, Volume, "Anti Ransomware State" | Out-String -Stream | Add-Indentation $Items.VolumeAntiRansomware.Summary = New-Object -TypeName psobject -Property @{ Item = "Ransomware Protection Enabled for all Volumes" Finding = (!$Items.VolumeAntiRansomware.Formatted."Anti Ransomware State".contains("disabled")) Topic = $Categories[$Items.VolumeAntiRansomware.Category] } } Else { $Items.VolumeAntiRansomware.FullData = "`n$Spacer Ransomware Protection is not supported on this release. Consider upgrading to 9.10 or later.`n" $Items.VolumeAntiRansomware.Summary = New-Object -TypeName psobject -Property @{ Item = "Ransomware Protection Enabled for all Volumes" Finding = "Not available in this release" Topic = $Categories[$Items.VolumeAntiRansomware.Category] } } ### End - Anti-Ransomware - Category 7 ### - Begin - Encryption - Category 8 # Key Manager $Items.KeyManager.FullHeader = @" $Separator Recommendation: A key-manager should be configured and encryption should be enabled at either the disk, aggregate, or volume layer Reference: TR-4569 section "Storage encryption" "@ If ($Items.KeyManager.Result.num_records -ne 0) { $Items.KeyManager.FullData = "`n$Spacer Key-manager is configured." } Else { $Items.KeyManager.FullData = "`n$Spacer No Key-manager Found." } $Items.KeyManager.Summary = New-Object -TypeName psobject -Property @{Item = "Key-Manager Configured" Finding = ($Items.KeyManager.Result.num_records -ne 0) Topic = $Categories[$Items.KeyManager.Category] } # Drive Protection If ($Items.DriveProtection.Result.num_records -ne 0) { $Items.DriveProtection.Formatted = ForEach ($_ in $Items.DriveProtection.Result.records) { New-Object psobject -Property @{ Aggregate = ($_.aggregate).ToString() Node = ($_.node).ToString() "Drive Protection Enabled" = ($_.drive_protection_enabled).ToString() } } $Items.DriveProtection.FullData = $Items.DriveProtection.Formatted | Format-Table Aggregate, Node, "Drive Protection Enabled" | Out-String -Stream | Add-Indentation } Else { $Items.DriveProtection.FullData = "`n$Spacer No Results Returned.`n" } $Items.DriveProtection.Summary = New-Object -TypeName psobject -Property @{ Item = "Drive Encryption Enabled for all Aggregates" Finding = (!$Items.DriveProtection.Formatted."Drive Protection Enabled".contains("False")) Topic = $Categories[$Items.DriveProtection.Category] } # Volume Encryption If ($Items.VolumeEncryption.Result.num_records -ne 0) { $Items.VolumeEncryption.Formatted = ForEach ($_ in $Items.VolumeEncryption.Result.records) { New-Object psobject -Property @{ VServer = ($_.vserver).ToString() Volume = ($_.volume).ToString() "Encryption Type" = ($_.encryption_type).ToString() "Is Encrypted" = ($_.is_encrypted).ToString() } } $Items.VolumeEncryption.FullData = $Items.VolumeEncryption.Formatted | Format-Table VServer, Volume, "Encryption Type", "Is Encrypted" | Out-String -Stream | Add-Indentation } Else { $Items.VolumeEncryption.FullData = "`n$Spacer No Results Returned.`n" } $Items.VolumeEncryption.Summary = New-Object -TypeName psobject -Property @{ Item = "Volume Encryption Enabled for all Volumes" Finding = (!$Items.VolumeEncryption.Formatted."Is Encrypted".contains("False")) Topic = $Categories[$Items.VolumeEncryption.Category] } ### - End - Encryption - Category 8 } # Table Formatting function Add-Indentation { process { $_ | ForEach-Object { ' ' * 8 + $_ } } } # Output to Text File function Write-Data { process{ $_ | Tee-Object ".\$Now.txt" -Append } } # Output Header function Header { Write-Output $Header | Write-Data } # Output Summary function SummaryOutput { $SummaryData = @() foreach ($key in $Items.Keys) { if ($($Items[$key].Summary)){ $SummaryData += $Items[$key].Summary } } Write-Output "Summary`n$Separator" | Write-Data Write-Output $SummaryData | Format-Table Item, Finding, Topic -HideTableHeaders | Out-String -Stream | Add-Indentation | Write-Data Write-Output $Separator | Write-Data } # Output Full Data function FullOutput{ Write-Output "Full Details" | Write-Data foreach ($Index in $Categories.Keys){ Write-Output "$Separator`n-- $($Categories.$Index) --" | Write-Data foreach ($key in $Items.Keys) { if ($($Items[$key].Category) -eq $Index){ Write-Output $Items[$key].FullHeader | Write-Data Write-Output $Items[$key].FullData | Write-Data } } } } # Start Collection and Processing CollectData ProcessData # Choices for output type $Title = "Would you like full or summary output?" $Choices = [System.Management.Automation.Host.ChoiceDescription[]] @("&Summary", "&Full", "&All") $Default = 0 $Choice = $host.UI.PromptForChoice($Title, $Prompt, $Choices, $Default) switch ($Choice) { 0 { Header SummaryOutput } 1 { Header FullOutput } 2 { Header SummaryOutput FullOutput } } |