Functions/Set-OSServerPerformanceTunning2.ps1
function Set-OSServerPerformanceTunning2 { <# .SYNOPSIS Configures Windows and IIS with the recommended performance settings for OutSystems. .DESCRIPTION This will configure Windows and IIS with the recommended performance settings for the OutSystems platform. An advanced configuration object can be used to control which sections are and are not done. Also, some values (namely, .NET and IIS upload size limits) can be set that will used to fine tune the respective settings. .PARAMETER IISNetCompilationPath Sets the IIS compilation folder. .PARAMETER IISHttpCompressionPath Sets the IIS compression folder. .PARAMETER AdvancedConfigurations Sets which of the sections should be completed, also allowing more specific configurations for some of these sections. This parameter is represent by an object with the following structure type (semi-JSONfied with the expected types enclosed in <>): { "SkipPlatformCheck" : <BOOL>, "Sections" : { "ProcessSchedulingConfig" : { "ShouldBeSkipped" : <BOOL> }, "NETConfig" : { "ShouldBeSkipped" : <BOOL>, "NewMaxRequestLength" : <INT> }, "IISUploadSizeLimitsConfig" : { "ShouldBeSkipped" : <BOOL>, "NewMaxAllowedContentLength" : <INT> }, "IISConnectionsConfig" : { "ShouldBeSkipped" : <BOOL> }, "AppPoolsConfig" : { "ShouldBeSkipped" : <BOOL>, "SkipMoveAppsToOSAppPools" : <BOOL> "AppPoolsToForciblyCreateAndConfig" : <STRING[]>, } } } The aboved properties have the following semantic: > SkipPlatformCheck If true, proceeds even if the platform is not yet installed. > ProcessSchedulingConfig > ShouldBeSkipped If true, skips the section where Windows processor scheduling priority is set to 'background services'. > NETConfig > ShouldBeSkipped If true, skips the section where .NET upload size limits and execution timeout are configured. > NewMaxRequestLength The value in KBytes that applied to the .NET Framework "MaxRequestLength" property. > IISUploadSizeLimitsConfig > ShouldBeSkipped If true, skips the section where IIS upload size limits are configured. > NewMaxAllowedContentLength The value in Bytes that applied to the .NET Framework "MaxRequestLength" property. > IISConnectionsConfig > ShouldBeSkipped If true, skips the section where IIS is configured for unlimited connections. > AppPoolsConfig > ShouldBeSkipped If true, skips the section where OutSystems apps are moved to the respective OutSystems app pool. > SkipMoveAppsToOSAppPools If true, will not move OutSytems apps to the corresponding IIS app pools created by OutSystems (e.g. 'ServiceCenter' to 'ServiceCenterAppPool'). > AppPoolsToForciblyCreateAndConfig If this list is not empty and has valid app pool names, will force the creation and configuration of the app pools. Valid app pool names: "OutSystemsApplications", "ServiceCenterAppPool", "LifeTimeAppPool". .EXAMPLE Set-OSServerPerformanceTunning .EXAMPLE Set-OSServerPerformanceTunning -IISNetCompilationPath d:\IISTemp\Compilation -IISHttpCompressionPath d:\IISTemp\Compression .EXAMPLE Set-OSServerPerformanceTunning -AdvancedConfigurations @{ "Sections" = @{ "NETConfig" = @{ "ShouldBeSkipped" = $True } ; "IISConnectionsConfig" = @{ "ShouldBeSkipped" = $True } ; "ProcessSchedulingConfig" = @{ "ShouldBeSkipped" = $True } ; "IISUploadSizeLimitsConfig" = @{ "NewMaxAllowedContentLength" = 10000000 ; "ShouldBeSkipped" = $True } ; "AppPoolsConfig" = @{ "ShouldBeSkipped" = $True } } ; "SkipPlatformCheck" = $True ; "SkipMoveAppsToOSAppPools" = $True } #> [CmdletBinding()] Param( [Parameter()] [ValidateNotNullOrEmpty()] [string]$IISNetCompilationPath, [Parameter()] [ValidateNotNullOrEmpty()] [string]$IISHttpCompressionPath, [Parameter()] [ValidateNotNullOrEmpty()] [object]$AdvancedConfigurations ) begin { LogMessage -Function $($MyInvocation.Mycommand) -Phase 0 -Stream 0 -Message "Starting" SendFunctionStartEvent -InvocationInfo $MyInvocation $osVersion = GetServerVersion } process { if (-not $(IsAdmin)) { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 3 -Message "The current user is not Administrator or not running this script in an elevated session" WriteNonTerminalError -Message "The current user is not Administrator or not running this script in an elevated session" return } $SkipPlatformCheck = $AdvancedConfigurations.SkipPlatformCheck $SkipProcessSchedulingConfig = $($AdvancedConfigurations.Sections.ProcessSchedulingConfig.ShouldBeSkipped) $SkipNETConfig = $($AdvancedConfigurations.Sections.NETConfig.ShouldBeSkipped) $SkipIISUploadSizeLimitsConfig = $($AdvancedConfigurations.Sections.IISUploadSizeLimitsConfig.ShouldBeSkipped) $SkipIISConnectionsConfig = $($AdvancedConfigurations.Sections.IISConnectionsConfig.ShouldBeSkipped) $SkipAppPoolsConfig = $($AdvancedConfigurations.Sections.AppPoolsConfig.ShouldBeSkipped) $SkipMoveAppsToOSAppPools = $($AdvancedConfigurations.Sections.AppPoolsConfig.SkipMoveAppsToOSAppPools) if ($(-not $SkipPlatformCheck) -and ($(-not $osVersion) -or $(-not $(GetServerInstallDir)))) { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 3 -Message "Outsystems platform is not installed" WriteNonTerminalError -Message "Outsystems platform is not installed" return } if (-not $SkipProcessSchedulingConfig) { # Configure process scheduling -- http://technet.microsoft.com/library/Cc976120 LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Configuring Windows processor scheduling priority to background services" try { RegWrite -Path "HKLM:\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PriorityControl" -Name "Win32PrioritySeparation" -Type "Dword" -Value 24 } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error configuring processor scheduling priority" WriteNonTerminalError -Message "Error configuring processor scheduling priority" return } } if (-not $SkipNETConfig) { $MaxRequestLength = $AdvancedConfigurations.Sections.NETConfig.NewMaxRequestLength if (-not $MaxRequestLength) { $MaxRequestLength = $OSPerfTuningMaxRequestLength } # Configure .NET LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Configuring .NET upload size limits and execution timeout (maxRequestLength = $MaxRequestLength, executionTimeout = $($OSPerfTuningExecutionTimeout.TotalSeconds) seconds)" try { SetDotNetLimits -UploadLimit $MaxRequestLength -ExecutionTimeout $OSPerfTuningExecutionTimeout } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error configuring .NET settings" WriteNonTerminalError -Message "Error configuring .NET settings" return } } if (-not $SkipIISUploadSizeLimitsConfig) { $MaxAllowedContentLength = $AdvancedConfigurations.Sections.IISUploadSizeLimitsConfig.NewMaxAllowedContentLength if (-not $MaxAllowedContentLength) { $MaxAllowedContentLength = $OSPerfTuningMaxAllowedContentLength } # Configure IIS requests limits (Server Level) LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Configuring IIS upload size limits (maxAllowedContentLength = $MaxAllowedContentLength)" try { SetWebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/security/requestFiltering/requestLimits" -Name "maxAllowedContentLength" -Value $MaxAllowedContentLength } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error configuring IIS upload size limits" WriteNonTerminalError -Message "Error configuring IIS upload size limits" return } } if (-not $SkipIISConnectionsConfig) { # Configure IIS for unlimited connections. (Default Web Site) - This should not be needed cause IIS defaults to maximum. LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Configuring IIS for unlimited connections (MaxConnections = $OSPerfTuningMaxConnections)" try { SetWebConfigurationProperty -PSPath "IIS:\" -Filter "system.applicationHost" -Name "sections['webLimits'].OverrideModeDefault" -Value "Allow" SetWebConfigurationProperty -PSPath "IIS:\" -Filter "system.applicationHost" -Name "sections['webLimits'].allowDefinition" -Value "Everywhere" SetWebConfigurationProperty -PSPath "IIS:\" -Filter "system.applicationHost/sites/site[@name='Default Web Site']" -Name "Limits" -Value @{MaxConnections = $OSPerfTuningMaxConnections } } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error configuring IIS for unlimited connections" WriteNonTerminalError -Message "Error configuring IIS for unlimited connections" return } } if (-not $SkipAppPoolsConfig) { # Configure IIS Application Pools $DefaultWebSiteApps = $(Get-WebApplication -Site "Default Web Site").Path foreach ($Config in $OSIISConfig) { # Reset array at each loop $interestingApps = @() if (-not $SkipMoveAppsToOSAppPools) { # Build an array with all matching Apps. foreach ($appMatchPattern in $($Config.Match)) { $interestingApps += $DefaultWebSiteApps | Where-Object -FilterScript { ($_ -like $appMatchPattern) -and ($_ -notin $OSIISConfigExcludedApps) } } } # if an app was found $HasAppsToMove = ($interestingApps.Count -gt 0) # if the app pool was set to be forcibly configured $AppPoolsToForciblyCreateAndConfig = $($AdvancedConfigurations.Sections.AppPoolsConfig.AppPoolsToForciblyCreateAndConfig) $ForceCreateAndConfigAppPool = ($AppPoolsToForciblyCreateAndConfig -and $AppPoolsToForciblyCreateAndConfig.Contains($Config.PoolName)) # if we should try to configure app pool if ($HasAppsToMove -or $ForceCreateAndConfigAppPool) { # Check if AppPool exists. if not, create a new one. if (-not $(Get-ChildItem -Path "IIS:\AppPools\$($Config.PoolName)" -ErrorAction SilentlyContinue)) { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Creating IIS Application Pool $($Config.PoolName)" try { New-Item -Path "IIS:\AppPools\$($Config.PoolName)" -ErrorAction Stop | Out-Null } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error creating Application Pool $($Config.PoolName)" WriteNonTerminalError -Message "Error creating AppPool $($Config.PoolName)" return } } # Configure the AppPool LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Configuring IIS Application Pool $($Config.PoolName)" $AppPoolItem = Get-Item "IIS:\AppPools\$($Config.PoolName)" # Commit everything on one shot Start-WebCommitDelay $AppPoolItem.managedRuntimeVersion = "v4.0" $AppPoolItem.recycling.periodicRestart.time = [TimeSpan]::FromMinutes(0) $AppPoolItem.recycling.periodicRestart.requests = 0 $AppPoolItem.recycling.logEventOnRecycle = "Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory" $AppPoolItem.processModel.idleTimeout = [TimeSpan]::FromMinutes(0) $AppPoolItem.failure.rapidFailProtection = $false $AppPoolItem.recycling.periodicRestart.privateMemory = [int]($(GetInstalledRAM) * 1MB * ($($Config.MemoryPercentage) / 100)) # Version specific config switch ("$(([version]$osVersion).Major)") { '10' { $AppPoolItem.managedPipelineMode = "Classic" } default { $AppPoolItem.managedPipelineMode = "Integrated" } } $AppPoolItem | Set-Item # Clear periodic restarts schedule $AppPoolItem | Clear-ItemProperty -Name recycling.periodicRestart.schedule # Explicit cher here for clarity, the foreach implicity ensures this if ($HasAppsToMove) { # Move the InterestingApp to the AppPool foreach ($InterestingApp In $interestingApps) { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Moving Application $InterestingApp to Application Pool $($Config.PoolName)" Set-ItemProperty -Path "IIS:\Sites\Default Web Site$InterestingApp" -Name applicationPool -Value $($Config.PoolName) } } # Commit everything in one shot try { Stop-WebCommitDelay } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error applying setting to Application Pool $($Config.PoolName)" WriteNonTerminalError -Message "Error applying setting to Application Pool $($Config.PoolName)" return } LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Application Pool $($Config.PoolName) configuration done" } } } # Configure .NET compilation folder (Server Level) if ($IISNetCompilationPath) { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "IISNetCompilationPath specified on the command line" if (-not (Test-Path -Path $IISNetCompilationPath)) { try { New-Item -Path $IISNetCompilationPath -ItemType directory -Force -ErrorAction Stop | Out-Null } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error creating the IIS Net compilation folder" WriteNonTerminalError -Message "Error creating the IIS Net compilation folder" return } } LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Changing IIS compilation folder to $IISNetCompilationPath" try { SetWebConfigurationProperty -PSPath "MACHINE/WEBROOT" -Filter "system.web/compilation" -Name 'tempDirectory' -Value $IISNetCompilationPath } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error setting the IIS compilation folder" WriteNonTerminalError -Message "Error setting the IIS compilation folder" return } } # Configure HTTP Compression folder (Server Level) if ($IISHttpCompressionPath) { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "IISHttpCompressionPath specified on the command line" if (-not (Test-Path -Path $IISHttpCompressionPath)) { try { New-Item -Path $IISHttpCompressionPath -ItemType directory -Force -ErrorAction Stop | Out-Null } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error creating the IIS HTTP compression folder" WriteNonTerminalError -Message "Error creating the IIS HTTP compression folder" return } } LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Stream 0 -Message "Changing IIS HTTP compression folder to $IISHttpCompressionPath" try { SetWebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/httpCompression" -Name "directory" -Value $IISHttpCompressionPath } catch { LogMessage -Function $($MyInvocation.Mycommand) -Phase 1 -Exception $_.Exception -Stream 3 -Message "Error setting the IIS HTTP compression folder" WriteNonTerminalError -Message "Error setting the IIS HTTP compression folder" return } } } end { SendFunctionEndEvent -InvocationInfo $MyInvocation LogMessage -Function $($MyInvocation.Mycommand) -Phase 2 -Stream 0 -Message "Ending" } } |