By Keren Pollack, on October 7th, 2019

IIS is a popular choice of a web server. Hosted on Windows Server, IIS allows organizations to host serve up websites and services of all kinds. But due to its popularity also puts it in the crosshairs of attackers. It’s critical to not simply throw out a default installation of IIS without some well thought out hardening.

The Center for Internet Security (CIS) provides a set of benchmarks they recommend that all IIS servers adhere to. The benchmarks are categorized into seven different groups:

  1. Basic configuration
  2. Authentication and authorization
  3. NET
  4. Request filtering and other restriction modules
  5. IIS logging
  6. FTP requests
  7. Transport encryption

Knowing these benchmarks is great but knowing is only half the battle! You must ultimately apply them but first, you must check to see compliance levels. One way to do this is with PowerShell. By writing the code to check for compliance for each benchmark in a script, you can quickly confirm these CIS benchmarks across hundreds of IIS servers at once.

For more information on these settings, check out our IIS Hardening Guide.

Hardening Configurations using CIS Benchmarks

Checking Benchmarks with PowerShell

In this article, you’re going to learn how to perform checks against each CIS benchmark with PowerShell. You’ll see many different code snippets each uniquely tailored to find each CIS benchmark-setting on an IIS 10 server.

Most of the code to follow was also tested with IIS 7.5 but is not guaranteed to be 100% correct. Subtle differences in IIS 7.5 and IIS 10 may affect the code.

Each code snippet below can be run individually or put together in a large script to provide comprehensive reporting capabilities.

 

Basic Configuration Benchmark Checks

Ensure Web content is on a Non-System Partition

$test = Get-Content (Join-Path -Path $Env:SystemRoot -ChildPath 'System32\inetsrv\config\applicationHost.config')

If (
    (Test-Path -Path (Join-Path -Path $Env:SystemDrive -ChildPath 'inetpub')) -And
    $test -Match [RegEx]::Escape((Join-Path -Path $Env:SystemDrive -ChildPath 'inetpub'))
) {
    $true
} Else {
    $false
}

Ensure ‘Directory Browsing’ is Set to Disable

Get-Website | Foreach-Object {
  [PSCustomObject]@{
    "Name" = $_.Name
    "DirectoryBrowsing"  = (Get-WebConfigurationProperty -Filter "/system.webServer/directoryBrowse" -PSPath "IIS:\Sites\$($_.Name)" -Name "enabled").Value
}

Ensure ‘Application pool identity’ is configured for all application pools

$AppPools = Get-ChildItem 'IIS:\AppPools'

$AppPools | Foreach-Object {
  $processModels = Get-ItemProperty "IIS:\AppPools\$($_.Name)" | Select-Object -ExpandProperty 'processModel'

  If ( $processModels.identityType -NE 'ApplicationPoolIdentity' ) {
    $false
  } Else {
    $true
  }
}

Ensure ‘unique application pools’ is set for sites

[Bool](Get-WebApplication | Group-Object -Property 'applicationPool' | Where-Object 'count' -GT 1)

#6 - Ensure ‘application pool identity’ is configured for anonymous user identity
Get-ChildItem 'IIS:\Sites' | Foreach-Object {
  $anonAuth = (Get-WebConfigurationProperty -Filter '/system.webServer/security/authentication/anonymousAuthentication' -PSPath "IIS:\Sites\$($_.Name)" -Name "userName").Value

  [PSCustomObject]@{
    "Name" = $_.Name
    "AnonAuth" = $(If($anonAuth -EQ '') {$false}Else{$true})
  }
}

Ensure WebDav feature is disabled

[Bool](Get-WindowsFeature -Name 'Web-DAV-Publishing' | Where-Object Installed -EQ $true)

Hardening IIS server guide

Configuration and Authorization Benchmark Checks

Ensure ‘global authorization rule’ is set to restrict access

if ((Get-WindowsFeature Web-Url-Auth).Installed -EQ $true) {
  Get-WebSite | ForEach-Object {
    $site = $_.Name
    $config = Get-WebConfiguration -Filter "system.webServer/security/authorization" -PSPath "IIS:\Sites\$($_.Name)"

    $config.GetCollection() | ForEach-Object {
        $accessType = ($_.Attributes | Where-Object Name -EQ 'accessType').Value
        $users = ($_.Attributes | Where-Object Name -EQ 'users').Value
        $roles = ($_.Attributes | Where-Object Name -EQ 'roles').Value

        If (($accessType -EQ "Allow" -Or $accessType -EQ 0) -And ($users -eq "*" -or $roles -eq "?")) {
            [PSCustomObject]@{
              "Name" = $site
              "AccessType" = $accessType
              "Users" = $users
              "Roles" = $roles
              "Pass" = $false
            }
        } Else {
            [PSCustomObject]@{
              "Name" = $site
              "AccessType" = $accessType
              "Users" = $users
              "Roles" = $roles
              "Pass" = $true
            }
        }
    }
  }
}

Ensure access to sensitive site features is restricted to authenticated principals only

Get-Website | Foreach-Object {
  $mode = (Get-WebConfiguration -Filter 'system.web/authentication' -PSPath "IIS:\sites\$($_.Name)").mode

  If (($mode -NE 'forms') -And ($mode -NE 'Windows')) {
    [PSCustomObject]@{
      "Name" = $_.Name
      "Principals" = $false
    }
  } Else {
    [PSCustomObject]@{
      "Name" = $_.Name
      "Principals" = $true
    }
  }
}

Ensure ‘forms authentication’ requires SSL

Get-Website | Foreach-Object {
  $config = (Get-WebConfiguration -Filter 'system.web/authentication' -PSPath "IIS:\sites\$($_.Name)")

  If ($config.mode -EQ 'forms') {
      [PSCustomObject]@{
          "Name" = $_.Name
          "SSL"  = $config.Forms.RequireSSL
      }
  }
}

Ensure ‘forms authentication’ is set to use cookies

Get-Website | Foreach-Object {
  $config = (Get-WebConfiguration -Filter '/system.web/authentication' -PSPath "IIS:\sites\$($_.Name)")

  If ($config.mode -EQ 'forms') {
      [PSCustomObject]@{
          "Name"       = $_.Name
          "CookieMode" = $(If($config.Forms.Cookieless -NE 'UseCookie') { $false } Else { $true })
      }
  }
}

Ensure ‘cookie protection mode’ is configured for forms authentication

Get-Website | Foreach-Object {
  $config = (Get-WebConfiguration -Filter '/system.web/authentication' -PSPath "IIS:\sites\$($_.Name)")

  If ($config.mode -EQ 'forms') {
      [PSCustomObject]@{
          "Name" = $_.Name
          "CookieProtection" = $(If($config.Forms.protection -NE 'All') { $false } Else { $true })
      }
  }
}

Ensure transport layer security for ‘basic authentication’ is configured

Get-Website | Foreach-Object {
  $ssl   = (Get-WebConfiguration -Filter "/system.webServer/security/access" -PSPath "IIS:\sites\$($_.Name)").SSLFlags
  $basic = (Get-WebConfigurationProperty -filter "/system.WebServer/security/authentication/basicAuthentication" -name Enabled -PSPath "IIS:\sites\$($_.Name)").Value

  If ($basic) {
      [PSCustomObject]@{
          "Name" = $_.Name
          "SSL"  = $(If($ssl -EQ 'Ssl') { $true } Else { $false })
      }
  }
}

Ensure ‘passwordFormat’ is not set to clear

# Individual site config
Get-Website | Foreach-Object {
  $config = (Get-WebConfiguration -Filter '/system.web/authentication' -PSPath "IIS:\sites\$($_.Name)")
  $format = (Get-WebConfiguration -Filter '/system.web/authentication/forms/credentials' -PSPath "IIS:\sites\$($_.Name)").passwordFormat

  If ($config.mode -EQ 'forms') {
      [PSCustomObject]@{
          "Name" = $_.Name
          "Format" = $(If($format -EQ 'clear'){ $false } Else { $true })
      }
  }
}

# Machine Config
$machineConfig = [System.Configuration.ConfigurationManager]::OpenMachineConfiguration()
$passwordFormat = $machineConfig.GetSection("system.web/authentication").forms.credentials.passwordFormat
If ($passwordFormat -EQ 'clear') {
  $false
} Else {
  $true
}

Ensure ‘credentials’ are not stored in configuration files

Get-Website | Foreach-Object {
  $config = (Get-WebConfiguration -Filter '/system.web/authentication' -PSPath "IIS:\sites\$($_.Name)")
  $stored = (Get-WebConfiguration -filter '/system.web/authentication/forms/credentials' -PSPath "IIS:\sites\$($_.Name)").IsLocallyStored

  If ($config.mode -EQ 'forms') {
      [PSCustomObject]@{
          "Name" = $_.Name
          "LocalStored" = $stored
      }
  }
}

ASP.NET Benchmark Checks

Ensure ‘deployment method retail’ is set

$machineConfig = [System.Configuration.ConfigurationManager]::OpenMachineConfiguration()
$deployment = $machineConfig.GetSection("system.web/deployment")
$deployment.Retail

Ensure ‘debug’ is turned off

Get-Website | Foreach-Object {
  [PSCustomObject]@{
    "Site"  = $_.Name
    "Debug" = (Get-WebConfiguration -Filter '/system.web/compilation' -PSPath "IIS:\sites\$($_.Name)").Debug
  }
}

Ensure custom error messages are not off

Get-Website | Foreach-Object {
  $mode = (Get-WebConfiguration -Filter '/system.web/customErrors' -PSPath "IIS:\sites\$($_.Name)").Mode

  [PSCustomObject]@{
    "Site"  = $_.Name
    "Mode"  = $mode
    "CustomErrors" = $(If($mode -EQ 'off'){$false}Else{$true})
  }
}

Ensure IIS HTTP detailed errors are hidden from displaying remotely

Get-Website | Foreach-Object {
  $errorMode = (Get-WebConfiguration -Filter '/system.webServer/httpErrors' -PSPath "IIS:\sites\$($_.Name)").errorMode

  [PSCustomObject]@{
    "Site"  = $_.Name
    "ErrorMode" = $errorMode
    "Errors" = $(If(($errorMode -NE 'Custom') -And ($errorMode -NE 'DetailedLocalOnly') ){ $False } Else { $True })
  }
}

Ensure ASP.NET stack tracing is not enabled

# Individual Site Config
Get-Website | Foreach-Object {
  [PSCustomObject]@{
    "Site"  = $_.Name
    "Trace" = (Get-WebConfiguration -Filter '/system.web/trace' -PSPath "IIS:\sites\$($_.Name)").enabled
  }
}

# Machine Config
$machineConfig = [System.Configuration.ConfigurationManager]::OpenMachineConfiguration()
$deployment = $machineConfig.GetSection("system.web/trace")
$deployment.enabled

Ensure ‘httpcookie’ mode is configured for session state

Get-Website | Foreach-Object {
  $sessionState = (Get-WebConfiguration -Filter '/system.web/sessionState' -PSPath "IIS:\sites\$($_.Name)").cookieless

  [PSCustomObject]@{
    "Site"  = $_.Name
    "SessionState" = $sessionState
    "CookieLess" = $(If(($sessionState -NE "UseCookies") -And ($sessionState -NE "False")) { $false } Else { $true })
  }
}

Ensure ‘cookies’ are set with HttpOnly attribute

Get-Website | Foreach-Object {
  [PSCustomObject]@{
    "Site"  = $_.Name
    "httpCookies" = (Get-WebConfiguration -Filter '/system.web/httpCookies' -PSPath "IIS:\sites\$($_.Name)").httpOnlyCookies
  }
}

Ensure ‘MachineKey validation method – .Net 3.5’ is configured

Get-Website | Foreach-Object {
  $site = $_
  $applicationPool = $_.applicationPool
  If ($applicationPool) {
      $pools = Get-WebApplication -Site $_.Name

      $pools | ForEach-Object {
          $appPool    = ($_.Attributes | Where-Object Name -EQ 'applicationPool').Value
          $properties = Get-ItemProperty -Path "IIS:\AppPools\$appPool" | Select-Object *
          $version    = $properties.managedRuntimeVersion

          If ($version -Like "v2.*") {
              $validation = (Get-WebConfiguration -Filter '/system.web/machineKey' -PSPath "IIS:\sites\$($site.Name)").Validation

              [PSCustomObject]@{
                  "Site"       = $site.Name
                  "AppPool"    = $appPool
                  "Version"    = $properties.managedRuntimeVersion
                  "Validation" = $validation
              }
          }
      }
  }
}

Ensure ‘MachineKey validation method – .Net 4.5’ is configured

Get-Website | Foreach-Object {
  $site = $_
  $applicationPool = $_.applicationPool
  If ($applicationPool) {
      $pools = Get-WebApplication -Site $_.Name

      $pools | ForEach-Object {
          $appPool    = ($_.Attributes | Where-Object Name -EQ 'applicationPool').Value
          $properties = Get-ItemProperty -Path "IIS:\AppPools\$appPool" | Select-Object *
          $version    = $properties.managedRuntimeVersion

          If ($version -Like "v4.*") {
              $validation = (Get-WebConfiguration -Filter '/system.web/machineKey' -PSPath "IIS:\sites\$($site.Name)").Validation

              [PSCustomObject]@{
                  "Site"       = $site.Name
                  "AppPool"    = $appPool
                  "Version"    = $version
                  "Validation" = $validation
              }
          }
      }
  }
}

Ensure global .NET trust level is configured

Get-Website | Foreach-Object {
  $site = $_
  $applicationPool = $_.applicationPool
  If ($applicationPool) {
      $pools = Get-WebApplication -Site $_.Name

      $pools | ForEach-Object {
          $appPool    = ($_.Attributes | Where-Object Name -EQ 'applicationPool').Value
          $properties = Get-ItemProperty -Path "IIS:\AppPools\$appPool" | Select-Object *
          $version    = $properties.managedRuntimeVersion

          $level = (Get-WebConfiguration -Filter '/system.web/trust' -PSPath "IIS:\sites\$($site.Name)").level

          [PSCustomObject]@{
              "Site"    = $site.Name
              "AppPool" = $appPool
              "Version" = $version
              "Level"   = $Level
          }
      }
  }
}

Ensure X-Powered-By Header is removed

Get-Website | Foreach-Object {
  $site = $_
  $config = Get-WebConfiguration -Filter '/system.webServer/httpProtocol/customHeaders' -PSPath "IIS:\sites\$($site.Name)"

  $customHeaders = $config.GetCollection()

  If ($customHeaders) {
      $customHeaders | ForEach-Object {
          [PSCustomObject]@{
              "Site" = $site.Name
              "X-Powered-By" = ($_.Attributes | Where-Object Name -EQ name).Value -match 'x-powered-by'
          }
      }
  }
}

Ensure Server Header is removed

Get-Website | Foreach-Object {
  $site = $_
  $config = Get-WebConfiguration -Filter '/system.webServer/httpProtocol/customHeaders' -PSPath "IIS:\sites\$($site.Name)"

  $customHeaders = $config.GetCollection()

  If ($customHeaders) {
      $customHeaders | ForEach-Object {
          [PSCustomObject]@{
              "Site" = $site.Name
              "Server" = ($_.Attributes | Where-Object Name -EQ name).Value -match 'server'
          }
      }
  }
}

Request Filtering and other Restriction Modules Benchmark Checks

Ensure ‘maxAllowedContentLength’ is configured

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_
      [PSCustomObject]@{
          "Site" = $site.Name
          "maxAllowedContentLength" = (((Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)").requestLimits).Attributes | Where-Object Name -EQ 'maxAllowedContentLength').Value
      }
  }
}

Ensure ‘maxURL request filter’ is configured

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_
      [PSCustomObject]@{
          "Site" = $site.Name
          "maxURL" = (((Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)").requestLimits).Attributes | Where-Object Name -EQ 'maxURL').Value
      }
  }
}

Ensure ‘MaxQueryString request filter’ is configured

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_
      [PSCustomObject]@{
          "Site" = $site.Name
          "MaxQueryString" = (((Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)").requestLimits).Attributes | Where-Object Name -EQ 'maxQueryString').Value
      }
  }
}

Ensure non-ASCII characters in URLs are not allowed

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_
      [PSCustomObject]@{
          "Site" = $site.Name
          "allowHighBitCharacters" = (Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)").allowHighBitCharacters
      }
  }
}

Ensure Double-Encoded requests will be rejected

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_
      [PSCustomObject]@{
          "Site" = $site.Name
          "allowDoubleEscaping" = (Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)").allowDoubleEscaping
      }
  }
}

Ensure ‘HTTP Trace Method’ is disabled

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_

      $config = (Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)")

      $config.verbs.Attributes | Where-Object {
        $_.Name -EQ 'trace'
      }
  }
}

Ensure Unlisted File Extensions are not allowed

If ((Get-WindowsFeature Web-Filtering).Installed -EQ $true) {
  Get-Website | Foreach-Object {
      $site = $_
      [PSCustomObject]@{
          "Site" = $site.Name
          "allowUnlisted" = (((Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath "IIS:\sites\$($site.Name)").fileExtensions).Attributes | Where-Object Name -EQ 'allowUnlisted').Value
      }
  }
}

Ensure Handler is not granted Write and Script/Execute

Get-Website | Foreach-Object {
    $site = $_

    [PSCustomObject]@{
      "Site" = $site.Name
      "accessPolicy" = (Get-WebConfiguration -Filter 'system.webServer/handlers' -PSPath "IIS:\sites\$($site.Name)").accessPolicy
    }
}

Ensure ‘notListedIsapisAllowed’ is set to false

Get-Website | Foreach-Object {
  $site = $_

  [PSCustomObject]@{
    "Site" = $site.Name
    "notListedIsapisAllowed" = (Get-WebConfiguration -Filter 'system.webServer/security/isapiCgiRestriction' -PSPath "IIS:\sites\$($site.Name)").notListedIsapisAllowed
  }
}

Ensure ‘notListedCgisAllowed’ is set to false

Get-Website | Foreach-Object {
  $site = $_

  [PSCustomObject]@{
    "Site" = $site.Name
    "notListedIsapisAllowed" = (Get-WebConfiguration -Filter 'system.webServer/security/isapiCgiRestriction' -PSPath "IIS:\sites\$($site.Name)").notListedCgisAllowed
  }
}

Ensure ‘Dynamic IP Address Restrictions’ is enabled

If ((Get-WindowsFeature Web-Ip-Security).Installed -EQ $true) {
  Get-Website | Foreach-Object {
    $site = $_
    $config = Get-WebConfiguration -Filter '/system.webServer/security/dynamicIpSecurity' -PSPath "IIS:\sites\$($site.Name)"

    [PSCustomObject]@{
      "Site" = $site.Name
      "denyByConcurrentRequests" = $config.denyByConcurrentRequests.enabled
      "denyByRequestRate" = $config.denyByRequestRate.enabled
    }
  }
}

IIS Logging Benchmark Checks

Ensure Default IIS weblog location is moved

Get-Website | Foreach-Object {
  $site = $_

  [PSCustomObject]@{
    "Site" = $site.Name
    "Location" = $Site.logFile.Directory
  }
}

Ensure ‘ETW Logging’ is enabled

Get-Website | Foreach-Object {
  $site = $_

  [PSCustomObject]@{
    "Site" = $site.Name
    "logTargetW3C" = $Site.logFile.logTargetW3C
  }
}

FTP Request Benchmark Checks

Ensure FTP requests are encrypted

Get-Website | Foreach-Object {
  $site = $_
  $FTPBindings = $site.bindings.collection | Where-Object -Property Protocol -eq FTP
  If ($FTPBindings) {
    $config = (Get-WebConfiguration -Filter 'system.applicationHost/sites' -PSPath "IIS:\sites\$($site.Name)").siteDefaults.ftpServer.security.ssl

    ($config.Attributes | Where-Object Name -EQ 'controlChannelPolicy').Value
    ($config.Attributes | Where-Object Name -EQ 'dataChannelPolicy').Value
  }
}

Ensure FTP Logon attempt restrictions is enabled

Get-Website | Foreach-Object {
  $site = $_
  $FTPBindings = $site.bindings.collection | Where-Object -Property 'Protocol' -eq 'FTP'
  If ($FTPBindings) {
    $config = (Get-WebConfiguration -Filter 'system.ftpServer/security/authentication' -PSPath "IIS:\sites\$($site.Name)").denyByFailure
    [PSCustomObject]@{
        "Site"        = $site.Name
        "Enabled"     = $config.enabled
        "MaxFailures" = $config.maxFailure
        "EntryExp"    = ($config.entryExpiration).ToString()
        "Logging"     = $config.loggingOnlyMode
    }
  }
}

Transport Encryption Benchmark Checks

Ensure HSTS Header is set

Get-Website | Foreach-Object {
  $site   = $_
  $config = (Get-WebConfiguration -Filter '/system.webServer/httpProtocol' -PSPath "IIS:\sites\$($site.Name)").customHeaders
  $value  = ($config.Attributes | Where-Object Name -EQ 'Strict-Transport-Security').Value

  $value | Where-Object { $_ -Match "max-age" }
}

Ensure SSLv2 is Disabled

$path = "HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0"

If ((Test-Path -Path $path) -and (Test-Path -Path "$path\Server")) {
      $Key = Get-Item "$path\Server"

      if ($null -ne $Key.GetValue("Enabled", $null)) {
          $value = Get-ItemProperty "$path\Server" | Select-Object -ExpandProperty "Enabled"
          # Ensure it is set to 0
          if ($value -ne 0) {
            $false
          } Else {
            $true
          }
      }
}

Ensure SSLv3 is Disabled

$path = "HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0"

If ((Test-Path -Path $path) -and (Test-Path -Path "$path\Server")) {
      $Key = Get-Item "$path\Server"

      if ($null -ne $Key.GetValue("Enabled", $null)) {
          $value = Get-ItemProperty "$path\Server" | Select-Object -ExpandProperty "Enabled"
          # Ensure it is set to 0
          if ($value -ne 0) {
            $false
          } Else {
            $true
          }
      }
}


Ensure TLS 1.0 is Disabled

$path = "HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server"

If ((Test-Path -Path $path)) {
      $Key = Get-Item "$path"

      if ($null -ne $Key.GetValue("Enabled", $null)) {
          $value = Get-ItemProperty "$path\Server" | Select-Object -ExpandProperty "Enabled"
          # Ensure it is set to 0
          if ($value -ne 0) {
            $false
          } Else {
            $true
          }
      }
}

Ensure TLS 1.1 is Disabled

$path = “HKLM:\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server”

If ((Test-Path -Path $path)) {
      $Key = Get-Item "$path"

      if ($null -ne $Key.GetValue("Enabled", $null)) {
          $value = Get-ItemProperty "$path\Server" | Select-Object -ExpandProperty "Enabled"
          # Ensure it is set to 0
          if ($value -ne 0) {
            $false
          } Else {
            $true
          }
      }
}

Leaving TLS 1.2 and moving to TLS 1.3

 

AUTOMATE YOUR SERVER HARDENING:

Server hardening can be a painful procedure. If you’re reading this article, you probably already know it. Endless hours, labor and money are invested in this process, which can often result in production breakdown despite the effort to prevent it. CSH by CalCom is automating the entire server hardening process. CHS’s unique ability to ‘learn’ your network abolishes the need to perform lab testing while ensuring zero outages to your production environment. CHS will allow you to implement your policy directly on your production hassle-free. want to know more?

Click here and get the datasheet. 

 

Wrap Up

That’s it! You now have PowerShell code snippets for all CIS-recommended IIS server benchmarks. Creating a new PowerShell script or integrating this code into existing scripts will now allow you to easily confirm if your IIS server is properly hardened.

 

Hardening IIS server guide