From 42a28d19c3f4496e6ce5e7c49be0278d61a841b0 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 00:04:43 +0300 Subject: [PATCH 01/22] added missing application pool default settings --- .../MSFT_xWebAppPoolDefaults.psm1 | 828 +++++++++++++++--- .../MSFT_xWebAppPoolDefaults.schema.mof | 54 +- 2 files changed, 749 insertions(+), 133 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 6def1b06a..102f51ed2 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -2,19 +2,90 @@ Import-Module -Name "$PSScriptRoot\..\Helper.psm1" # Localized messages -data LocalizedData -{ +data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' - NoWebAdministrationModule = Please ensure that WebAdministration module is installed. - SettingValue = Changing default value '{0}' to '{1}' - ValueOk = Default value '{0}' is already '{1}' VerboseGetTargetResource = Get-TargetResource has been run. + + ErrorAppPoolDefaultsNotFound = Application pool defaults element could not be located. + VerboseAppPoolDefaultsFound = Application pool defaults was found. + VerbosePropertyNotInDesiredState = The "{0}" property of application pool defaults does not match the desired state. + VerboseCredentialToBeCleared = Custom account credentials of application pool defaults need to be cleared because the "identityType" property is not set to "SpecificUser". + VerboseCredentialToBeIgnored = The "Credential" property is only valid when the "identityType" property is set to "SpecificUser". + VerboseResourceInDesiredState = The target resource is already in the desired state. No action is required. + VerboseResourceNotInDesiredState = The target resource is not in the desired state. + VerboseSetProperty = Setting the "{0}" property of application pool defaults". + VerboseClearCredential = Clearing custom account credentials of application pool defaults because the "identityType" property is not set to "SpecificUser". + VerboseRestartScheduleValueAdd = Adding value "{0}" to the "restartSchedule" collection of application pool defaults. + VerboseRestartScheduleValueRemove = Removing value "{0}" from the "restartSchedule" collection of application pool defaults. '@ } -function Get-TargetResource -{ +# Writable properties except Credential. +data PropertyData { + @( + # General + @{Name = 'autoStart'; Path = 'autoStart'} + @{Name = 'CLRConfigFile'; Path = 'CLRConfigFile'} + @{Name = 'enable32BitAppOnWin64'; Path = 'enable32BitAppOnWin64'} + @{Name = 'enableConfigurationOverride'; Path = 'enableConfigurationOverride'} + @{Name = 'managedPipelineMode'; Path = 'managedPipelineMode'} + @{Name = 'managedRuntimeLoader'; Path = 'managedRuntimeLoader'} + @{Name = 'managedRuntimeVersion'; Path = 'managedRuntimeVersion'} + @{Name = 'passAnonymousToken'; Path = 'passAnonymousToken'} + @{Name = 'startMode'; Path = 'startMode'} + @{Name = 'queueLength'; Path = 'queueLength'} + + # CPU + @{Name = 'cpuAction'; Path = 'cpu.action'} + @{Name = 'cpuLimit'; Path = 'cpu.limit'} + @{Name = 'cpuResetInterval'; Path = 'cpu.resetInterval'} + @{Name = 'cpuSmpAffinitized'; Path = 'cpu.smpAffinitized'} + @{Name = 'cpuSmpProcessorAffinityMask'; Path = 'cpu.smpProcessorAffinityMask'} + @{Name = 'cpuSmpProcessorAffinityMask2'; Path = 'cpu.smpProcessorAffinityMask2'} + + # Process Model + @{Name = 'identityType'; Path = 'processModel.identityType'} + @{Name = 'idleTimeout'; Path = 'processModel.idleTimeout'} + @{Name = 'idleTimeoutAction'; Path = 'processModel.idleTimeoutAction'} + @{Name = 'loadUserProfile'; Path = 'processModel.loadUserProfile'} + @{Name = 'logEventOnProcessModel'; Path = 'processModel.logEventOnProcessModel'} + @{Name = 'logonType'; Path = 'processModel.logonType'} + @{Name = 'manualGroupMembership'; Path = 'processModel.manualGroupMembership'} + @{Name = 'maxProcesses'; Path = 'processModel.maxProcesses'} + @{Name = 'pingingEnabled'; Path = 'processModel.pingingEnabled'} + @{Name = 'pingInterval'; Path = 'processModel.pingInterval'} + @{Name = 'pingResponseTime'; Path = 'processModel.pingResponseTime'} + @{Name = 'setProfileEnvironment'; Path = 'processModel.setProfileEnvironment'} + @{Name = 'shutdownTimeLimit'; Path = 'processModel.shutdownTimeLimit'} + @{Name = 'startupTimeLimit'; Path = 'processModel.startupTimeLimit'} + + # Process Orphaning + @{Name = 'orphanActionExe'; Path = 'failure.orphanActionExe'} + @{Name = 'orphanActionParams'; Path = 'failure.orphanActionParams'} + @{Name = 'orphanWorkerProcess'; Path = 'failure.orphanWorkerProcess'} + + # Rapid-Fail Protection + @{Name = 'loadBalancerCapabilities'; Path = 'failure.loadBalancerCapabilities'} + @{Name = 'rapidFailProtection'; Path = 'failure.rapidFailProtection'} + @{Name = 'rapidFailProtectionInterval'; Path = 'failure.rapidFailProtectionInterval'} + @{Name = 'rapidFailProtectionMaxCrashes'; Path = 'failure.rapidFailProtectionMaxCrashes'} + @{Name = 'autoShutdownExe'; Path = 'failure.autoShutdownExe'} + @{Name = 'autoShutdownParams'; Path = 'failure.autoShutdownParams'} + + # Recycling + @{Name = 'disallowOverlappingRotation'; Path = 'recycling.disallowOverlappingRotation'} + @{Name = 'disallowRotationOnConfigChange'; Path = 'recycling.disallowRotationOnConfigChange'} + @{Name = 'logEventOnRecycle'; Path = 'recycling.logEventOnRecycle'} + @{Name = 'restartMemoryLimit'; Path = 'recycling.periodicRestart.memory'} + @{Name = 'restartPrivateMemoryLimit'; Path = 'recycling.periodicRestart.privateMemory'} + @{Name = 'restartRequestsLimit'; Path = 'recycling.periodicRestart.requests'} + @{Name = 'restartTimeLimit'; Path = 'recycling.periodicRestart.time'} + @{Name = 'restartSchedule'; Path = 'recycling.periodicRestart.schedule'} + ) +} + +function Get-TargetResource { <# .SYNOPSIS This will return a hashtable of results @@ -34,14 +105,46 @@ function Get-TargetResource Write-Verbose -Message $LocalizedData.VerboseGetTargetResource - return @{ - ManagedRuntimeVersion = (Get-Value -Path '' -Name 'managedRuntimeVersion') - IdentityType = (Get-Value -Path 'processModel' -Name 'identityType') + # XPath -Filter is case-sensitive. Use Where-Object to get the target application pool by name. + $appPool = Get-AppPoolDefault + + $cimCredential = $null + if ($appPool.processModel.identityType -eq 'SpecificUser') { + $cimCredential = New-CimInstance -ClientOnly ` + -ClassName MSFT_Credential ` + -Namespace root/microsoft/windows/DesiredStateConfiguration ` + -Property @{ + UserName = [String]$appPool.processModel.userName + Password = [String]$appPool.processModel.password + } } + + + $returnValue = @{ + Credential = $cimCredential + } + + $PropertyData.Where( + { + $_.Name -ne 'restartSchedule' + } + ).ForEach( + { + $property = Get-Property -Object $appPool -PropertyName $_.Path + $returnValue.Add($_.Name, $property) + } + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $returnValue.Add('restartSchedule', $restartScheduleCurrent) + + return $returnValue } -function Set-TargetResource -{ +function Set-TargetResource { <# .SYNOPSIS This will set the desired state @@ -57,24 +160,288 @@ function Set-TargetResource $ApplyTo, [Parameter()] - [ValidateSet('','v2.0','v4.0')] + [ValidateSet('', 'v2.0', 'v4.0')] [System.String] $ManagedRuntimeVersion, - [Parameter()] - [ValidateSet('ApplicationPoolIdentity','LocalService','LocalSystem','NetworkService')] - [System.String] - $IdentityType + + [Boolean] $autoStart, + + [String] $CLRConfigFile, + + [Boolean] $enable32BitAppOnWin64, + + [Boolean] $enableConfigurationOverride, + + [ValidateSet('Integrated', 'Classic')] + [String] $managedPipelineMode, + + [String] $managedRuntimeLoader, + + [Boolean] $passAnonymousToken, + + [ValidateSet('OnDemand', 'AlwaysRunning')] + [String] $startMode, + + [ValidateRange(10, 65535)] + [UInt32] $queueLength, + + [ValidateSet('NoAction', 'KillW3wp', 'Throttle', 'ThrottleUnderLoad')] + [String] $cpuAction, + + [ValidateRange(0, 100000)] + [UInt32] $cpuLimit, + + [ValidateScript( { + ([ValidateRange(0, 1440)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $cpuResetInterval, + + [Boolean] $cpuSmpAffinitized, + + [UInt32] $cpuSmpProcessorAffinityMask, + + [UInt32] $cpuSmpProcessorAffinityMask2, + + [ValidateSet( + 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', + 'NetworkService', 'SpecificUser' + )] + [String] $identityType, + + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential, + + [ValidateScript( { + ([ValidateRange(0, 43200)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $idleTimeout, + + [ValidateSet('Terminate', 'Suspend')] + [String] $idleTimeoutAction, + + [Boolean] $loadUserProfile, + + [String] $logEventOnProcessModel, + + [ValidateSet('LogonBatch', 'LogonService')] + [String] $logonType, + + [Boolean] $manualGroupMembership, + + [ValidateRange(0, 2147483647)] + [UInt32] $maxProcesses, + + [Boolean] $pingingEnabled, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingInterval, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingResponseTime, + + [Boolean] $setProfileEnvironment, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $shutdownTimeLimit, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $startupTimeLimit, + + [String] $orphanActionExe, + + [String] $orphanActionParams, + + [Boolean] $orphanWorkerProcess, + + [ValidateSet('HttpLevel', 'TcpLevel')] + [String] $loadBalancerCapabilities, + + [Boolean] $rapidFailProtection, + + [ValidateScript( { + ([ValidateRange(1, 144000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $rapidFailProtectionInterval, + + [ValidateRange(0, 2147483647)] + [UInt32] $rapidFailProtectionMaxCrashes, + + [String] $autoShutdownExe, + + [String] $autoShutdownParams, + + [Boolean] $disallowOverlappingRotation, + + [Boolean] $disallowRotationOnConfigChange, + + [String] $logEventOnRecycle, + + [UInt32] $restartMemoryLimit, + + [UInt32] $restartPrivateMemoryLimit, + + [UInt32] $restartRequestsLimit, + + [ValidateScript( { + ([ValidateRange(0, 432000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $restartTimeLimit, + + [ValidateScript( { + ($_ -eq '') -or + (& { + ([ValidateRange(0, 86399)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + }) + })] + [String[]] $restartSchedule ) Assert-Module + + $appPool = Get-AppPoolDefault + + # Set Application Pool Properties + + Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) + + $PropertyData.Where( + { + ($_.Name -in $PSBoundParameters.Keys) -and + ($_.Name -notin @('restartSchedule')) + } + ).ForEach( + { + $propertyName = $_.Name + $propertyPath = $_.Path + $property = Get-Property -Object $appPool -PropertyName $propertyPath + + if ( + $PSBoundParameters[$propertyName] -ne $property + ) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f $propertyName + ) + Invoke-AppCmd -ArgumentList ( + '/{0}:{1}' -f $propertyPath, $PSBoundParameters[$propertyName] + ) + } + } + ) + + if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters['identityType'] -eq 'SpecificUser') { + if ($appPool.processModel.userName -ne $Credential.UserName) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f 'Credential (userName)' + ) + + Invoke-AppCmd -ArgumentList ( + '/processModel.userName:{0}' -f $Credential.UserName + ) + } + + $clearTextPassword = $Credential.GetNetworkCredential().Password + + if ($appPool.processModel.password -cne $clearTextPassword) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f 'Credential (password)' + ) + + Invoke-AppCmd -ArgumentList ( + '/processModel.password:{0}' -f $clearTextPassword + ) + } + } + else { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeIgnored']) + } + } + + # Ensure userName and password are cleared if identityType isn't set to SpecificUser. + if ( + ( + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $true) -and + ($PSBoundParameters['identityType'] -ne 'SpecificUser') + ) -or + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $false) -and + ($appPool.processModel.identityType -ne 'SpecificUser') + ) + ) -and + ( + ([String]::IsNullOrEmpty($appPool.processModel.userName) -eq $false) -or + ([String]::IsNullOrEmpty($appPool.processModel.password) -eq $false) + ) + ) { + Write-Verbose -Message ($LocalizedData['VerboseClearCredential']) + + Invoke-AppCmd -ArgumentList '/processModel.userName:' + Invoke-AppCmd -ArgumentList '/processModel.password:' + } - Set-Value -Path '' -Name 'managedRuntimeVersion' -NewValue $ManagedRuntimeVersion - Set-Value -Path 'processModel' -Name 'identityType' -NewValue $IdentityType + if ($PSBoundParameters.ContainsKey('restartSchedule')) { + # Normalize the restartSchedule array values. + $restartScheduleDesired = [String[]]@( + $restartSchedule.Where( + { + $_ -ne '' + } + ).ForEach( + { + [TimeSpan]::Parse($_).ToString('hh\:mm\:ss') + } + ) | + Select-Object -Unique + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + Compare-Object -ReferenceObject $restartScheduleDesired ` + -DifferenceObject $restartScheduleCurrent | + ForEach-Object -Process { + + # Add value + if ($_.SideIndicator -eq '<=') { + Write-Verbose -Message ( + $LocalizedData['VerboseRestartScheduleValueAdd'] -f + $_.InputObject + ) + + Invoke-AppCmd -ArgumentList ( + "/+recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + ) + } + # Remove value + else { + Write-Verbose -Message ( + $LocalizedData['VerboseRestartScheduleValueRemove'] -f + $_.InputObject + ) + + Invoke-AppCmd -ArgumentList ( + "/-recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + ) + } + + } + } + } -function Test-TargetResource -{ +function Test-TargetResource { <# .SYNOPSIS This tests the desired state. If the state is not correct it will return $false. @@ -92,153 +459,354 @@ function Test-TargetResource $ApplyTo, [Parameter()] - [ValidateSet('','v2.0','v4.0')] + [ValidateSet('', 'v2.0', 'v4.0')] [System.String] $ManagedRuntimeVersion, - [Parameter()] - [ValidateSet('ApplicationPoolIdentity','LocalService','LocalSystem','NetworkService')] - [System.String] - $IdentityType + [Boolean] $autoStart, + + [String] $CLRConfigFile, + + [Boolean] $enable32BitAppOnWin64, + + [Boolean] $enableConfigurationOverride, + + [ValidateSet('Integrated', 'Classic')] + [String] $managedPipelineMode, + + [String] $managedRuntimeLoader, + + [Boolean] $passAnonymousToken, + + [ValidateSet('OnDemand', 'AlwaysRunning')] + [String] $startMode, + + [ValidateRange(10, 65535)] + [UInt32] $queueLength, + + [ValidateSet('NoAction', 'KillW3wp', 'Throttle', 'ThrottleUnderLoad')] + [String] $cpuAction, + + [ValidateRange(0, 100000)] + [UInt32] $cpuLimit, + + [ValidateScript( { + ([ValidateRange(0, 1440)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $cpuResetInterval, + + [Boolean] $cpuSmpAffinitized, + + [UInt32] $cpuSmpProcessorAffinityMask, + + [UInt32] $cpuSmpProcessorAffinityMask2, + + [ValidateSet( + 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', + 'NetworkService', 'SpecificUser' + )] + [String] $identityType, + + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential, + + [ValidateScript( { + ([ValidateRange(0, 43200)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $idleTimeout, + + [ValidateSet('Terminate', 'Suspend')] + [String] $idleTimeoutAction, + + [Boolean] $loadUserProfile, + + [String] $logEventOnProcessModel, + + [ValidateSet('LogonBatch', 'LogonService')] + [String] $logonType, + + [Boolean] $manualGroupMembership, + + [ValidateRange(0, 2147483647)] + [UInt32] $maxProcesses, + + [Boolean] $pingingEnabled, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingInterval, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingResponseTime, + + [Boolean] $setProfileEnvironment, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $shutdownTimeLimit, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $startupTimeLimit, + + [String] $orphanActionExe, + + [String] $orphanActionParams, + + [Boolean] $orphanWorkerProcess, + + [ValidateSet('HttpLevel', 'TcpLevel')] + [String] $loadBalancerCapabilities, + + [Boolean] $rapidFailProtection, + + [ValidateScript( { + ([ValidateRange(1, 144000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $rapidFailProtectionInterval, + + [ValidateRange(0, 2147483647)] + [UInt32] $rapidFailProtectionMaxCrashes, + + [String] $autoShutdownExe, + + [String] $autoShutdownParams, + + [Boolean] $disallowOverlappingRotation, + + [Boolean] $disallowRotationOnConfigChange, + + [String] $logEventOnRecycle, + + [UInt32] $restartMemoryLimit, + + [UInt32] $restartPrivateMemoryLimit, + + [UInt32] $restartRequestsLimit, + + [ValidateScript( { + ([ValidateRange(0, 432000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $restartTimeLimit, + + [ValidateScript( { + ($_ -eq '') -or + (& { + ([ValidateRange(0, 86399)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + }) + })] + [String[]] $restartSchedule ) Assert-Module - if (-not((Confirm-Value -Path '' ` - -Name 'managedRuntimeVersion' ` - -NewValue $ManagedRuntimeVersion))) - { - return $false + $inDesiredState = $true + + $appPool = Get-AppPoolDefault + + $PropertyData.Where( + { + ($_.Name -in $PSBoundParameters.Keys) -and + ($_.Name -ne 'restartSchedule') + } + ).ForEach( + { + $propertyName = $_.Name + $propertyPath = $_.Path + $property = Get-Property -Object $appPool -PropertyName $propertyPath + + if ( + $PSBoundParameters[$propertyName] -ne $property + ) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f $propertyName + ) + + $inDesiredState = $false + } + } + ) + + + if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters['identityType'] -eq 'SpecificUser') { + if ($appPool.processModel.userName -ne $Credential.UserName) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f + 'Credential (userName)' + ) + + $inDesiredState = $false + } + + $clearTextPassword = $Credential.GetNetworkCredential().Password + + if ($appPool.processModel.password -cne $clearTextPassword) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f + 'Credential (password)' + ) + + $inDesiredState = $false + } + } + else { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeIgnored']) + } } - if (-not((Confirm-Value -Path 'processModel' ` - -Name 'identityType' ` - -NewValue $IdentityType))) - { - return $false + # Ensure userName and password are cleared if identityType isn't set to SpecificUser. + if ( + ( + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $true) -and + ($PSBoundParameters['identityType'] -ne 'SpecificUser') + ) -or + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $false) -and + ($appPool.processModel.identityType -ne 'SpecificUser') + ) + ) -and + ( + ([String]::IsNullOrEmpty($appPool.processModel.userName) -eq $false) -or + ([String]::IsNullOrEmpty($appPool.processModel.password) -eq $false) + ) + ) { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeCleared']) + + $inDesiredState = $false + } + + if ($PSBoundParameters.ContainsKey('restartSchedule')) { + # Normalize the restartSchedule array values. + $restartScheduleDesired = [String[]]@( + $restartSchedule.Where( + { + $_ -ne '' + } + ).ForEach( + { + [TimeSpan]::Parse($_).ToString('hh\:mm\:ss') + } + ) | + Select-Object -Unique + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + if ( + Compare-Object -ReferenceObject $restartScheduleDesired ` + -DifferenceObject $restartScheduleCurrent + ) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f 'restartSchedule' + ) + + $inDesiredState = $false + } } - return $true + + if ($inDesiredState -eq $true) { + Write-Verbose -Message ($LocalizedData['VerboseResourceInDesiredState']) + } + else { + Write-Verbose -Message ($LocalizedData['VerboseResourceNotInDesiredState']) + } + + return $inDesiredState } #region Helper Functions -function Confirm-Value -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param + +function Get-Property { + param ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, + [object] $Object, + [string] $PropertyName) - [Parameter(Mandatory = $true)] - [System.String] - $Name, + $parts = $PropertyName.Split('.') + $firstPart = $parts[0] - [Parameter()] - [System.String] - $NewValue - ) - - if (-not($NewValue)) - { - # if no new value was specified, we assume this value is okay. - return $true - } + $value = $Object.$firstPart + if ($parts.Count -gt 1) { + $newParts = @() + 1..($parts.Count - 1) | ForEach-Object { + $newParts += $parts[$_] + } - $existingValue = Get-Value -Path $Path -Name $Name - if ($existingValue -ne $NewValue) - { - return $false + $newName = ($newParts -join '.') + return Get-Property -Object $value -PropertyName $newName } - else - { - $relPath = $Path + '/' + $Name - Write-Verbose($LocalizedData.ValueOk -f $relPath,$NewValue); - return $true + else { + return $value } -} +} + +<# + .SYNOPSIS + Runs appcmd.exe - if there's an error then the application will terminate + + .PARAMETER ArgumentList + Optional list of string arguments to be passed into appcmd.exe -function Set-Value -{ +#> +function Invoke-AppCmd { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $NewValue + [String[]] $ArgumentList ) - # if the variable doesn't exist, the user doesn't want to change this value - if (-not($NewValue)) - { - return - } + <# + This is a local preference for the function which will terminate + the program if there's an error invoking appcmd.exe + #> + $ErrorActionPreference = 'Stop' - $existingValue = Get-Value -Path $Path -Name $Name - if ($existingValue -ne $NewValue) - { - if ($Path -ne '') - { - $Path = '/' + $Path - } + $appcmdFilePath = "$env:SystemRoot\System32\inetsrv\appcmd.exe" + $allArguments = @("set", "config", "-section:applicationPools") + $ArgumentList + + $appcmdResult = $(& $appcmdFilePath $allArguments) + Write-Verbose -Message $($appcmdResult).ToString() - Set-WebConfigurationProperty ` - -PSPath 'MACHINE/WEBROOT/APPHOST' ` - -Filter "system.applicationHost/applicationPools/applicationPoolDefaults$Path" ` - -Name $Name ` - -Value "$NewValue" - - $relPath = $Path + '/' + $Name - Write-Verbose($LocalizedData.SettingValue -f $relPath,$NewValue); + if ($LASTEXITCODE -ne 0) { + $errorMessage = $LocalizedData['ErrorAppCmdNonZeroExitCode'] -f $LASTEXITCODE + + New-TerminatingError -ErrorId 'ErrorAppCmdNonZeroExitCode' ` + -ErrorMessage $errorMessage ` + -ErrorCategory 'InvalidResult' } } -function Get-Value -{ - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, - [Parameter(Mandatory = $true)] - [System.String] - $Name - ) +function Get-AppPoolDefault { + # XPath -Filter is case-sensitive. Use Where-Object to get the target application pool by name. + $appPool = Get-WebConfiguration ` + -PSPath 'MACHINE/WEBROOT/APPHOST' ` + -Filter '/system.applicationHost/applicationPools/applicationPoolDefaults' + - if ($Path -ne '') - { - $Path = '/' + $Path + if ($null -eq $appPool) { + New-TerminatingError -ErrorId 'ErrorAppPoolDefaultsNotFound' ` + -ErrorMessage $LocalizedData['ErrorAppPoolDefaultsNotFound'] ` + -ErrorCategory 'InvalidResult' } - $result = Get-WebConfigurationProperty ` - -PSPath 'MACHINE/WEBROOT/APPHOST' ` - -Filter "system.applicationHost/applicationPools/applicationPoolDefaults$Path" ` - -Name $Name + Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) - if ($result -is [Microsoft.IIs.PowerShell.Framework.ConfigurationAttribute]) - { - return $result.Value - } else { - return $result - } + return $appPool } #endregion -Export-ModuleMember -Function *-TargetResource +Export-ModuleMember -Function *-TargetResource \ No newline at end of file diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof index 99b2f22c9..6b4991147 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof @@ -3,6 +3,54 @@ class MSFT_xWebAppPoolDefaults : OMI_BaseResource { [Key, Description("Dummy value because we need a key, always 'Machine'"), ValueMap{"Machine"}, Values{"Machine"}] string ApplyTo; - [write, Description("applicationPools/applicationPoolDefaults/managedRuntimeVersion"), ValueMap{"","v2.0","v4.0"}, Values{"","v2.0","v4.0"}] string ManagedRuntimeVersion; - [write, Description("applicationPools/applicationPoolDefaults/processModel/identityType"), ValueMap{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService"}, Values{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService"}] string IdentityType; -}; + + [Write, Description("When set to true, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started.")] Boolean autoStart; + [Write, Description("Indicates the .NET configuration file for the application pool.")] String CLRConfigFile; + [Write, Description("When set to true, enables a 32-bit application to run on a computer that runs a 64-bit version of Windows.")] Boolean enable32BitAppOnWin64; + [Write, Description("When set to true, indicates that delegated settings in Web.config files will processed for applications within this application pool. When set to false, all settings in Web.config files will be ignored for this application pool.")] Boolean enableConfigurationOverride; + [Write, Description("Indicates the request-processing mode that is used to process requests for managed content. The values that are allowed for this property are: Integrated, Classic."), ValueMap{"Integrated","Classic"},Values{"Integrated","Classic"}] String managedPipelineMode; + [Write, Description("Indicates the managed loader to use for pre-loading the application pool.")] String managedRuntimeLoader; + [Write, Description("Indicates the CLR version to be used by the application pool. The values that are allowed for this property are: v4.0, v2.0, and ''."), ValueMap{"v4.0","v2.0",""},Values{"v4.0","v2.0",""}] String managedRuntimeVersion; + [Write, Description("When set to true, the Windows Process Activation Service (WAS) creates and passes a token for the built-in IUSR anonymous user account to the Anonymous authentication module. The Anonymous authentication module uses the token to impersonate the built-in account. When this property is set to false, the token will not be passed.")] Boolean passAnonymousToken; + [Write, Description("Indicates the startup type for the application pool. The values that are allowed for this property are: OnDemand, AlwaysRunning."), ValueMap{"OnDemand","AlwaysRunning"},Values{"OnDemand","AlwaysRunning"}] String startMode; + [Write, Description("Indicates the maximum number of requests that HTTP.sys will queue for the application pool. The value must be a valid integer between 10 and 65535.")] UInt32 queueLength; + [Write, Description("Configures the action that IIS takes when a worker process exceeds its configured CPU limit. The values that are allowed for this property are: NoAction, KillW3wp, Throttle, and ThrottleUnderLoad."), ValueMap{"NoAction","KillW3wp","Throttle","ThrottleUnderLoad"},Values{"NoAction","KillW3wp","Throttle","ThrottleUnderLoad"}] String cpuAction; + [Write, Description("Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in the application pool are allowed to consume over a period of time as indicated by the cpuResetInterval property. The value must be a valid integer between 0 and 100000.")] UInt32 cpuLimit; + [Write, Description("Indicates the reset period (in minutes) for CPU monitoring and throttling limits on the application pool. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 1440. Setting the value of this property to 0 disables CPU monitoring.")] String cpuResetInterval; + [Write, Description("Indicates whether a particular worker process assigned to the application pool should also be assigned to a given CPU.")] Boolean cpuSmpAffinitized; + [Write, Description("Indicates the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. Before this property takes effect, the cpuSmpAffinitized property must be set to true for the application pool. The value must be a valid integer between 0 and 4294967295.")] UInt32 cpuSmpProcessorAffinityMask; + [Write, Description("Indicates the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. Before this property takes effect, the cpuSmpAffinitized property must be set to true for the application pool. The value must be a valid integer between 0 and 4294967295.")] UInt32 cpuSmpProcessorAffinityMask2; + [Write, Description("Indicates the account identity under which the application pool runs. The values that are allowed for this property are: ApplicationPoolIdentity, LocalService, LocalSystem, NetworkService, and SpecificUser."), ValueMap{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"}, Values{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"}] String identityType; + [Write, Description("Indicates the custom account crededentials. This property is only valid when the identityType property is set to SpecificUser."), EmbeddedInstance("MSFT_Credential")] String Credential; + [Write, Description("Indicates the amount of time (in minutes) a worker process will remain idle before it shuts down. The value must be a string representation of a TimeSpan value and must be less than the restartTimeLimit property value. The valid range (in minutes) is 0 to 43200.")] String idleTimeout; + [Write, Description("Indicates the action to perform when the idle timeout duration has been reached. The values that are allowed for this property are: Terminate, Suspend."), ValueMap{"Terminate","Suspend"}, Values{"Terminate","Suspend"}] String idleTimeoutAction; + [Write, Description("Indicates whether IIS loads the user profile for the application pool identity.")] Boolean loadUserProfile; + [Write, Description("Indicates that IIS should generate an event log entry for each occurrence of the specified process model events.")] String logEventOnProcessModel; + [Write, Description("Indicates the logon type for the process identity. The values that are allowed for this property are: LogonBatch, LogonService."), ValueMap{"LogonBatch","LogonService"},Values{"LogonBatch","LogonService"}] String logonType; + [Write, Description("Indicates whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token.")] Boolean manualGroupMembership; + [Write, Description("Indicates the maximum number of worker processes that would be used for the application pool. The value must be a valid integer between 0 and 2147483647.")] UInt32 maxProcesses; + [Write, Description("Indicates whether pinging (health monitoring) is enabled for the worker process(es) serving this application pool.")] Boolean pingingEnabled; + [Write, Description("Indicates the period of time (in seconds) between health monitoring pings sent to the worker process(es) serving this application pool. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String pingInterval; + [Write, Description("Indicates the maximum time (in seconds) that a worker process is given to respond to a health monitoring ping. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String pingResponseTime; + [Write, Description("Indicates the environment to be set based on the user profile for the new process.")] Boolean setProfileEnvironment; + [Write, Description("Indicates the period of time (in seconds) a worker process is given to finish processing requests and shut down. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String shutdownTimeLimit; + [Write, Description("Indicates the period of time (in seconds) a worker process is given to start up and initialize. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String startupTimeLimit; + [Write, Description("Indicates an executable to run when a worker process is orphaned.")] String orphanActionExe; + [Write, Description("Indicates parameters for the executable that is specified in the orphanActionExe property.")] String orphanActionParams; + [Write, Description("Indicates whether to assign a worker process to an orphan state instead of terminating it when the application pool fails. If true, an unresponsive worker process will be orphaned instead of terminated.")] Boolean orphanWorkerProcess; + [Write, Description("Indicates the response behavior of a service when it is unavailable. The values that are allowed for this property are: HttpLevel, TcpLevel. If set to HttpLevel and the application pool is stopped, HTTP.sys will return HTTP 503 error. If set to TcpLevel, HTTP.sys will reset the connection."), ValueMap{"HttpLevel","TcpLevel"},Values{"HttpLevel","TcpLevel"}] String loadBalancerCapabilities; + [Write, Description("Indicates whether rapid-fail protection is enabled. If true, the application pool is shut down if there are a specified number of worker process crashes within a specified time period.")] Boolean rapidFailProtection; + [Write, Description("Indicates the time interval (in minutes) during which the specified number of worker process crashes must occur before the application pool is shut down by rapid-fail protection. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 1 to 144000.")] String rapidFailProtectionInterval; + [Write, Description("Indicates the maximum number of worker process crashes permitted before the application pool is shut down by rapid-fail protection. The value must be a valid integer between 0 and 2147483647.")] UInt32 rapidFailProtectionMaxCrashes; + [Write, Description("Indicates an executable to run when the application pool is shut down by rapid-fail protection.")] String autoShutdownExe; + [Write, Description("Indicates parameters for the executable that is specified in the autoShutdownExe property.")] String autoShutdownParams; + [Write, Description("Indicates whether the W3SVC service should start another worker process to replace the existing worker process while that process is shutting down. If true, the application pool recycle will happen such that the existing worker process exits before another worker process is created.")] Boolean disallowOverlappingRotation; + [Write, Description("Indicates whether the W3SVC service should rotate worker processes in the application pool when the configuration has changed. If true, the application pool will not recycle when its configuration is changed.")] Boolean disallowRotationOnConfigChange; + [Write, Description("Indicates that IIS should generate an event log entry for each occurrence of the specified recycling events.")] String logEventOnRecycle; + [Write, Description("Indicates the maximum amount of virtual memory (in KB) a worker process can consume before causing the application pool to recycle. The value must be a valid integer between 0 and 4294967295. A value of 0 means there is no limit.")] UInt32 restartMemoryLimit; + [Write, Description("Indicates the maximum amount of private memory (in KB) a worker process can consume before causing the application pool to recycle. The value must be a valid integer between 0 and 4294967295. A value of 0 means there is no limit.")] UInt32 restartPrivateMemoryLimit; + [Write, Description("Indicates the maximum number of requests the application pool can process before it is recycled. The value must be a valid integer between 0 and 4294967295. A value of 0 means the application pool can process an unlimited number of requests.")] UInt32 restartRequestsLimit; + [Write, Description("Indicates the period of time (in minutes) after which the application pool will recycle. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 432000. A value of 0 means the application pool does not recycle on a regular interval.")] String restartTimeLimit; + [Write, Description("Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. The value must be an array of string representations of TimeSpan values. TimeSpan values must be between 00:00:00 and 23:59:59 seconds inclusive, with a granularity of 60 seconds. Setting the value of this property to '' disables the schedule.")] String restartSchedule[]; + +}; \ No newline at end of file From bdf9689128408951a881b0a03cf272cd92f81b76 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:36:08 +0300 Subject: [PATCH 02/22] Unit tests for application pool defaults with all attributes --- Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 | 2856 ++++++++++++++++- 1 file changed, 2749 insertions(+), 107 deletions(-) diff --git a/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 b/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 index c6161a95f..e39504357 100644 --- a/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 +++ b/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 @@ -1,194 +1,2836 @@ -#region HEADER +#requires -Version 4.0 + +# Suppressing this rule because IIS requires PlainText for one of the functions used in this test +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param () $script:DSCModuleName = 'xWebAdministration' $script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' -# Unit Test Template Version: 1.2.1 +#region HEADER $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone','https://github.com/PowerShell/DscResource.Tests.git', ` - (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests')) + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } -Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path ` - -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'Tests\MockWebAdministrationWindowsFeature.psm1') $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` -TestType Unit - -#endregion HEADER - -function Invoke-TestSetup { -} - -function Invoke-TestCleanup { - Restore-TestEnvironment -TestEnvironment $TestEnvironment -} +#endregion # Begin Testing try { - Invoke-TestSetup + #region Pester Tests InModuleScope $script:DSCResourceName { Describe "$($script:DSCResourceName)\Get-TargetResource" { - Context 'Get application pool defaults' { + Mock Assert-Module + + Context 'Application pool defaults' { + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } processModel = @{ identityType = 'SpecificUser' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = 'P@$$w0rd' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = 'CONTOSO\JDoe' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } } } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] - } + $result = Get-TargetResource -ApplyTo 'Machine' + + It 'Should return the autoStart property' { + $result.autoStart | Should Be $mockAppPoolDefaults.autoStart } - $result = Get-TargetResource -ApplyTo 'Machine' + It 'Should return the CLRConfigFile property' { + $result.CLRConfigFile | Should Be $mockAppPoolDefaults.CLRConfigFile + } + + It 'Should return the enable32BitAppOnWin64 property' { + $result.enable32BitAppOnWin64 | Should Be $mockAppPoolDefaults.enable32BitAppOnWin64 + } + + It 'Should return the enableConfigurationOverride property' { + $result.enableConfigurationOverride | Should Be $mockAppPoolDefaults.enableConfigurationOverride + } + + It 'Should return the managedPipelineMode property' { + $result.managedPipelineMode | Should Be $mockAppPoolDefaults.managedPipelineMode + } + + It 'Should return the managedRuntimeLoader property' { + $result.managedRuntimeLoader | Should Be $mockAppPoolDefaults.managedRuntimeLoader + } + + It 'Should return the managedRuntimeVersion property' { + $result.managedRuntimeVersion | Should Be $mockAppPoolDefaults.managedRuntimeVersion + } + + It 'Should return the passAnonymousToken property' { + $result.passAnonymousToken | Should Be $mockAppPoolDefaults.passAnonymousToken + } + + It 'Should return the startMode property' { + $result.startMode | Should Be $mockAppPoolDefaults.startMode + } + + It 'Should return the queueLength property' { + $result.queueLength | Should Be $mockAppPoolDefaults.queueLength + } + + It 'Should return the cpuAction property' { + $result.cpuAction | Should Be $mockAppPoolDefaults.cpu.action + } + + It 'Should return the cpuLimit property' { + $result.cpuLimit | Should Be $mockAppPoolDefaults.cpu.limit + } + + It 'Should return the cpuResetInterval property' { + $result.cpuResetInterval | Should Be $mockAppPoolDefaults.cpu.resetInterval + } + + It 'Should return the cpuSmpAffinitized property' { + $result.cpuSmpAffinitized | Should Be $mockAppPoolDefaults.cpu.smpAffinitized + } + + It 'Should return the cpuSmpProcessorAffinityMask property' { + $result.cpuSmpProcessorAffinityMask | Should Be $mockAppPoolDefaults.cpu.smpProcessorAffinityMask + } + + It 'Should return the cpuSmpProcessorAffinityMask2 property' { + $result.cpuSmpProcessorAffinityMask2 | Should Be $mockAppPoolDefaults.cpu.smpProcessorAffinityMask2 + } + + It 'Should return the identityType property' { + $result.identityType | Should Be $mockAppPoolDefaults.processModel.identityType + } + + It 'Should return the Credential (userName) property' { + # Get-DscConfiguration returns MSFT_Credential with empty UserName + $result.Credential.userName | Should Be $mockAppPoolDefaults.processModel.userName + } + + It 'Should return the Credential (password) property' { + # Get-DscConfiguration returns MSFT_Credential with empty Password + $result.Credential.Password | Should Be $mockAppPoolDefaults.processModel.password + } + + It 'Should return the idleTimeout property' { + $result.idleTimeout | Should Be $mockAppPoolDefaults.processModel.idleTimeout + } + + It 'Should return the idleTimeoutAction property' { + $result.idleTimeoutAction | Should Be $mockAppPoolDefaults.processModel.idleTimeoutAction + } + + It 'Should return the loadUserProfile property' { + $result.loadUserProfile | Should Be $mockAppPoolDefaults.processModel.loadUserProfile + } + + It 'Should return the logonType property' { + $result.logonType | Should Be $mockAppPoolDefaults.processModel.logonType + } + + It 'Should return the logEventOnProcessModel property' { + $result.logEventOnProcessModel | Should Be $mockAppPoolDefaults.processModel.logEventOnProcessModel + } + + It 'Should return the manualGroupMembership property' { + $result.manualGroupMembership | Should Be $mockAppPoolDefaults.processModel.manualGroupMembership + } + + It 'Should return the maxProcesses property' { + $result.maxProcesses | Should Be $mockAppPoolDefaults.processModel.maxProcesses + } + + It 'Should return the pingingEnabled property' { + $result.pingingEnabled | Should Be $mockAppPoolDefaults.processModel.pingingEnabled + } + + It 'Should return the pingInterval property' { + $result.pingInterval | Should Be $mockAppPoolDefaults.processModel.pingInterval + } + + It 'Should return the pingResponseTime property' { + $result.pingResponseTime | Should Be $mockAppPoolDefaults.processModel.pingResponseTime + } + + It 'Should return the setProfileEnvironment property' { + $result.setProfileEnvironment | Should Be $mockAppPoolDefaults.processModel.setProfileEnvironment + } + + It 'Should return the shutdownTimeLimit property' { + $result.shutdownTimeLimit | Should Be $mockAppPoolDefaults.processModel.shutdownTimeLimit + } + + It 'Should return the startupTimeLimit property' { + $result.startupTimeLimit | Should Be $mockAppPoolDefaults.processModel.startupTimeLimit + } + + It 'Should return the orphanActionExe property' { + $result.orphanActionExe | Should Be $mockAppPoolDefaults.failure.orphanActionExe + } + + It 'Should return the orphanActionParams property' { + $result.orphanActionParams | Should Be $mockAppPoolDefaults.failure.orphanActionParams + } + + It 'Should return the orphanWorkerProcess property' { + $result.orphanWorkerProcess | Should Be $mockAppPoolDefaults.failure.orphanWorkerProcess + } + + It 'Should return the loadBalancerCapabilities property' { + $result.loadBalancerCapabilities | Should Be $mockAppPoolDefaults.failure.loadBalancerCapabilities + } + + It 'Should return the rapidFailProtection property' { + $result.rapidFailProtection | Should Be $mockAppPoolDefaults.failure.rapidFailProtection + } + + It 'Should return the rapidFailProtectionInterval property' { + $result.rapidFailProtectionInterval | Should Be $mockAppPoolDefaults.failure.rapidFailProtectionInterval + } + + It 'Should return the rapidFailProtectionMaxCrashes property' { + $result.rapidFailProtectionMaxCrashes | Should Be $mockAppPoolDefaults.failure.rapidFailProtectionMaxCrashes + } + + It 'Should return the autoShutdownExe property' { + $result.autoShutdownExe | Should Be $mockAppPoolDefaults.failure.autoShutdownExe + } + + It 'Should return the autoShutdownParams property' { + $result.autoShutdownParams | Should Be $mockAppPoolDefaults.failure.autoShutdownParams + } + + It 'Should return the disallowOverlappingRotation property' { + $result.disallowOverlappingRotation | Should Be $mockAppPoolDefaults.recycling.disallowOverlappingRotation + } + + It 'Should return the disallowRotationOnConfigChange property' { + $result.disallowRotationOnConfigChange | Should Be $mockAppPoolDefaults.recycling.disallowRotationOnConfigChange + } + + It 'Should return the logEventOnRecycle property' { + $result.logEventOnRecycle | Should Be $mockAppPoolDefaults.recycling.logEventOnRecycle + } + + It 'Should return the restartMemoryLimit property' { + $result.restartMemoryLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.memory + } + + It 'Should return the restartPrivateMemoryLimit property' { + $result.restartPrivateMemoryLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.privateMemory + } + + It 'Should return the restartRequestsLimit property' { + $result.restartRequestsLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.requests + } - It 'Should return managedRuntimeVersion' { - $result.managedRuntimeVersion | ` - Should Be $mockAppPoolDefaults.managedRuntimeVersion + It 'Should return the restartTimeLimit property' { + $result.restartTimeLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.time } - It 'Should return processModel\identityType' { - $result.identityType | ` - Should Be $mockAppPoolDefaults.processModel.identityType + It 'Should return the restartSchedule property' { + + $restartScheduleValues = [String[]]@( + @($mockAppPoolDefaults.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $compareSplat = @{ + ReferenceObject = [String[]]@($result.restartSchedule) + DifferenceObject = $restartScheduleValues + ExcludeDifferent = $true + IncludeEqual = $true + } + + $compareResult = Compare-Object @compareSplat + + $compareResult.Count -eq $restartScheduleValues.Count | Should Be $true + } + } + } - Describe "$($script:DSCResourceName)\Test-TargetResource" { + Describe "how '$($script:DSCResourceName)\Test-TargetResource' responds" { + + Mock Assert-Module + + Context 'Test target resource with no property specified' { - $mockAppPoolDefaults = @{ - managedRuntimeVersion = 'v4.0' - processModel = @{ - identityType = 'NetworkService' + $mockAppPoolDefaults = @{ } - } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] + It 'Should return True' { + Test-TargetResource -ApplyTo 'Machine' | + Should Be $true } + } - Context 'Application pool defaults correct' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'NetworkService' + Context 'All the properties match the desired state' { + + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } + processModel = @{ + identityType = 'SpecificUser' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = 'P@$$w0rD' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = 'CONTOSO\JDoe' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + $mockRestartSchedule = [String[]]@( + @($mockAppPoolDefaults.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $testParamsSplat = @{ + autoStart = $mockAppPoolDefaults.autoStart + CLRConfigFile = $mockAppPoolDefaults.CLRConfigFile + enable32BitAppOnWin64 = $mockAppPoolDefaults.enable32BitAppOnWin64 + enableConfigurationOverride = $mockAppPoolDefaults.enableConfigurationOverride + managedPipelineMode = $mockAppPoolDefaults.managedPipelineMode + managedRuntimeLoader = $mockAppPoolDefaults.managedRuntimeLoader + managedRuntimeVersion = $mockAppPoolDefaults.managedRuntimeVersion + passAnonymousToken = $mockAppPoolDefaults.passAnonymousToken + startMode = $mockAppPoolDefaults.startMode + queueLength = $mockAppPoolDefaults.queueLength + cpuAction = $mockAppPoolDefaults.cpu.action + cpuLimit = $mockAppPoolDefaults.cpu.limit + cpuResetInterval = $mockAppPoolDefaults.cpu.resetInterval + cpuSmpAffinitized = $mockAppPoolDefaults.cpu.smpAffinitized + cpuSmpProcessorAffinityMask = $mockAppPoolDefaults.cpu.smpProcessorAffinityMask + cpuSmpProcessorAffinityMask2 = $mockAppPoolDefaults.cpu.smpProcessorAffinityMask2 + identityType = $mockAppPoolDefaults.processModel.identityType + Credential = $mockCredential + idleTimeout = $mockAppPoolDefaults.processModel.idleTimeout + idleTimeoutAction = $mockAppPoolDefaults.processModel.idleTimeoutAction + loadUserProfile = $mockAppPoolDefaults.processModel.loadUserProfile + logEventOnProcessModel = $mockAppPoolDefaults.processModel.logEventOnProcessModel + logonType = $mockAppPoolDefaults.processModel.logonType + manualGroupMembership = $mockAppPoolDefaults.processModel.manualGroupMembership + maxProcesses = $mockAppPoolDefaults.processModel.maxProcesses + pingingEnabled = $mockAppPoolDefaults.processModel.pingingEnabled + pingInterval = $mockAppPoolDefaults.processModel.pingInterval + pingResponseTime = $mockAppPoolDefaults.processModel.pingResponseTime + setProfileEnvironment = $mockAppPoolDefaults.processModel.setProfileEnvironment + shutdownTimeLimit = $mockAppPoolDefaults.processModel.shutdownTimeLimit + startupTimeLimit = $mockAppPoolDefaults.processModel.startupTimeLimit + orphanActionExe = $mockAppPoolDefaults.failure.orphanActionExe + orphanActionParams = $mockAppPoolDefaults.failure.orphanActionParams + orphanWorkerProcess = $mockAppPoolDefaults.failure.orphanWorkerProcess + loadBalancerCapabilities = $mockAppPoolDefaults.failure.loadBalancerCapabilities + rapidFailProtection = $mockAppPoolDefaults.failure.rapidFailProtection + rapidFailProtectionInterval = $mockAppPoolDefaults.failure.rapidFailProtectionInterval + rapidFailProtectionMaxCrashes = $mockAppPoolDefaults.failure.rapidFailProtectionMaxCrashes + autoShutdownExe = $mockAppPoolDefaults.failure.autoShutdownExe + autoShutdownParams = $mockAppPoolDefaults.failure.autoShutdownParams + disallowOverlappingRotation = $mockAppPoolDefaults.recycling.disallowOverlappingRotation + disallowRotationOnConfigChange = $mockAppPoolDefaults.recycling.disallowRotationOnConfigChange + logEventOnRecycle = $mockAppPoolDefaults.recycling.logEventOnRecycle + restartMemoryLimit = $mockAppPoolDefaults.recycling.periodicRestart.memory + restartPrivateMemoryLimit = $mockAppPoolDefaults.recycling.periodicRestart.privateMemory + restartRequestsLimit = $mockAppPoolDefaults.recycling.periodicRestart.requests + restartTimeLimit = $mockAppPoolDefaults.recycling.periodicRestart.time + restartSchedule = $mockRestartSchedule + } It 'Should return True' { - $result | Should Be $true + Test-TargetResource -ApplyTo Machine @testParamsSplat | + Should Be $true } + } - Context 'Application pool different managedRuntimeVersion' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v2.0' ` - -IdentityType 'NetworkService' + Context 'Test the autoStart property' { + + $mockAppPoolDefaults = @{ + autoStart = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoStart $true | + Should Be $true + } - It 'Should return False' { - $result | Should Be $false + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoStart $false | + Should Be $false } + } - Context 'Application pool different processModel/@identityType' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'LocalSystem' + Context 'Test the CLRConfigFile property' { + + $mockAppPoolDefaults = @{ + CLRConfigFile = '' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -CLRConfigFile '' | + Should Be $true + } - It 'Should return False' { - $result | Should Be $false + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -CLRConfigFile 'C:\inetpub\temp\aspnet.config' | + Should Be $false } + } - Context 'Application pool no value for managedRuntimeVersion' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -IdentityType 'NetworkService' + Context 'Test the enable32BitAppOnWin64 property' { - It 'Should return True' { - $result | Should Be $true + $mockAppPoolDefaults = @{ + enable32BitAppOnWin64 = $false + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -enable32BitAppOnWin64 $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -enable32BitAppOnWin64 $true | + Should Be $false + } + + } + + Context 'Test the enableConfigurationOverride property' { + + $mockAppPoolDefaults = @{ + enableConfigurationOverride = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -enableConfigurationOverride $true | + Should Be $true } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -enableConfigurationOverride $false | + Should Be $false + } + } - } - Describe "$($script:DSCResourceName)\Set-TargetResource" { + Context 'Test the managedPipelineMode property' { + + $mockAppPoolDefaults = @{ + managedPipelineMode = 'Integrated' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedPipelineMode 'Integrated' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedPipelineMode 'Classic' | + Should Be $false + } + + } + + Context 'Test the managedRuntimeLoader property' { + + $mockAppPoolDefaults = @{ + managedRuntimeLoader = 'webengine4.dll' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeLoader 'webengine4.dll' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeLoader '' | + Should Be $false + } + + } + + Context 'Test the managedRuntimeVersion property' { + + $mockAppPoolDefaults = @{ + managedRuntimeVersion = 'v4.0' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeVersion 'v4.0' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeVersion 'v2.0' | + Should Be $false + } + + } + + Context 'Test the passAnonymousToken property' { + + $mockAppPoolDefaults = @{ + passAnonymousToken = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -passAnonymousToken $true | + Should Be $true + } - $mockAppPoolDefaults = @{ - managedRuntimeVersion = 'v4.0' - processModel = @{ - identityType = 'NetworkService' + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -passAnonymousToken $false | + Should Be $false } + } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Context 'Test the startMode property' { + + $mockAppPoolDefaults = @{ + startMode = 'OnDemand' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -startMode 'OnDemand' | + Should Be $true + } - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -startMode 'AlwaysRunning' | + Should Be $false } + } - Mock Set-WebConfigurationProperty -MockWith { } + Context 'Test the queueLength property' { + + $mockAppPoolDefaults = @{ + queueLength = 1000 + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - Context 'Application pool defaults correct' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'NetworkService' + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -queueLength 1000 | + Should Be $true + } - It 'Should not call Set-WebConfigurationProperty' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 0 + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -queueLength 2000 | + Should Be $false } + } - Context 'Application pool different managedRuntimeVersion' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v2.0' ` - -IdentityType 'NetworkService' + Context 'Test the cpuAction property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + action = 'NoAction' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuAction 'NoAction' | + Should Be $true + } - It 'Should call Set-WebConfigurationProperty once' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 1 ` - -ParameterFilter { $Name -eq 'managedRuntimeVersion' } + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuAction 'KillW3wp' | + Should Be $false } + } - Context 'Application pool different processModel/@identityType' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'LocalSystem' + Context 'Test the cpuLimit property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + limit = 0 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuLimit 0 | + Should Be $true + } - It 'Should call Set-WebConfigurationProperty once' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 1 ` - -ParameterFilter { $Name -eq 'identityType' } + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuLimit 90000 | + Should Be $false } + } - } - } -} -finally -{ - Invoke-TestCleanup + + Context 'Test the cpuResetInterval property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + resetInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuResetInterval '00:05:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuResetInterval '00:10:00' | + Should Be $false + } + + } + + Context 'Test the cpuSmpAffinitized property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpAffinitized = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpAffinitized $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpAffinitized $true | + Should Be $false + } + + } + + Context 'Test the cpuSmpProcessorAffinityMask property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask 4294967295 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask 1 | + Should Be $false + } + + } + + Context 'Test the cpuSmpProcessorAffinityMask2 property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask2 = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask2 4294967295 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask2 1 | + Should Be $false + } + + } + + Context 'Test the identityType property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'ApplicationPoolIdentity' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -identityType 'ApplicationPoolIdentity' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -identityType 'NetworkService' | + Should Be $false + } + + } + + Context 'Test the Credential property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'SpecificUser' + password = '1q2w3e4r' + userName = 'CONTOSO\JDoe' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when both the userName and the password properties match the desired state' { + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $true + + } + + It 'Should return False when the userName property does not match the desired state' { + + $mockUserName = 'CONTOSO\GFawkes' + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $false + + } + + It 'Should return False when the password property does not match the desired state' { + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = '5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $false + + } + + } + + Context 'Test the idleTimeout property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeout = '00:20:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeout '00:20:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeout '00:15:00' | + Should Be $false + } + + } + + Context 'Test the idleTimeoutAction property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeoutAction = 'Terminate' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeoutAction 'Terminate' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeoutAction 'Suspend' | + Should Be $false + } + + } + + Context 'Test the loadUserProfile property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + loadUserProfile = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -loadUserProfile $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -loadUserProfile $false | + Should Be $false + } + + } + + Context 'Test the logEventOnProcessModel property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logEventOnProcessModel = 'IdleTimeout' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnProcessModel 'IdleTimeout' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnProcessModel '' | + Should Be $false + } + + } + + Context 'Test the logonType property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logonType = 'LogonBatch' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logonType 'LogonBatch' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logonType 'LogonService' | + Should Be $false + } + + } + + Context 'Test the manualGroupMembership property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + manualGroupMembership = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -manualGroupMembership $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -manualGroupMembership $true | + Should Be $false + } + + } + + Context 'Test the maxProcesses property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + maxProcesses = 1 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -maxProcesses 1 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -maxProcesses 2 | + Should Be $false + } + + } + + Context 'Test the pingingEnabled property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingingEnabled = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingingEnabled $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingingEnabled $false | + Should Be $false + } + + } + + Context 'Test the pingInterval property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingInterval = '00:00:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingInterval '00:00:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingInterval '00:01:00' | + Should Be $false + } + + } + + Context 'Test the pingResponseTime property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingResponseTime = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingResponseTime '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingResponseTime '00:02:00' | + Should Be $false + } + + } + + Context 'Test the setProfileEnvironment property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + setProfileEnvironment = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -setProfileEnvironment $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -setProfileEnvironment $true | + Should Be $false + } + + } + + Context 'Test the shutdownTimeLimit property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + shutdownTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -shutdownTimeLimit '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -shutdownTimeLimit '00:02:00' | + Should Be $false + } + + } + + Context 'Test the startupTimeLimit property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + startupTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -startupTimeLimit '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -startupTimeLimit '00:02:00' | + Should Be $false + } + + } + + Context 'Test the orphanActionExe property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionExe '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionExe 'C:\inetpub\temp\orphanAction.exe' | + Should Be $false + } + + } + + Context 'Test the orphanActionParams property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionParams '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionParams '/orphanActionParam1' | + Should Be $false + } + + } + + Context 'Test the orphanWorkerProcess property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanWorkerProcess = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanWorkerProcess $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanWorkerProcess $true | + Should Be $false + } + + } + + Context 'Test the loadBalancerCapabilities property' { + + $mockAppPoolDefaults = @{ + failure = @{ + loadBalancerCapabilities = 'HttpLevel' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -loadBalancerCapabilities 'HttpLevel' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -loadBalancerCapabilities 'TcpLevel' | + Should Be $false + } + + } + + Context 'Test the rapidFailProtection property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtection = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtection $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtection $false | + Should Be $false + } + + } + + Context 'Test the rapidFailProtectionInterval property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionInterval '00:05:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionInterval '00:10:00' | + Should Be $false + } + + } + + Context 'Test the rapidFailProtectionMaxCrashes property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionMaxCrashes = 5 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionMaxCrashes 5 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionMaxCrashes 10 | + Should Be $false + } + + } + + Context 'Test the autoShutdownExe property' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownExe '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownExe 'C:\inetpub\temp\autoShutdown.exe' | + Should Be $false + } + + } + + Context 'Test the autoShutdownParams property' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownParams '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownParams '/autoShutdownParam1' | + Should Be $false + } + + } + + Context 'Test the disallowOverlappingRotation property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowOverlappingRotation = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -disallowOverlappingRotation $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -disallowOverlappingRotation $true | + Should Be $false + } + + } + + Context 'Test the disallowRotationOnConfigChange property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowRotationOnConfigChange = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -disallowRotationOnConfigChange $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -disallowRotationOnConfigChange $true | + Should Be $false + } + + } + + Context 'Test the logEventOnRecycle property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnRecycle 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnRecycle 'Time,Memory,PrivateMemory' | + Should Be $false + } + + } + + Context 'Test the restartMemoryLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + memory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartMemoryLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartMemoryLimit 1048576 | + Should Be $false + } + + } + + Context 'Test the restartPrivateMemoryLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + privateMemory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartPrivateMemoryLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartPrivateMemoryLimit 1048576 | + Should Be $false + } + + } + + Context 'Test the restartRequestsLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + requests = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartRequestsLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartRequestsLimit 1000 | + Should Be $false + } + + } + + Context 'Test the restartTimeLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + time = '1.05:00:00' + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartTimeLimit '1.05:00:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartTimeLimit '2.10:00:00' | + Should Be $false + } + + } + + Context 'Test the restartSchedule property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartSchedule @('04:00:00', '08:00:00') | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartSchedule @('') | + Should Be $false + } + + } + + } + + Describe "how '$($script:DSCResourceName)\Set-TargetResource' responds" { + + Mock -CommandName Assert-Module -MockWith {} + + Context 'All the properties need to be set' { + + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } + processModel = @{ + identityType = 'ApplicationPoolIdentity' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = '' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = '' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '02:00:00'} + @{value = '04:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $mockUserName = 'CONTOSO\GFawkes' + $mockPassword = '5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + $setParamsSplat = @{ + autoStart = $false + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + enable32BitAppOnWin64 = $true + enableConfigurationOverride = $false + managedPipelineMode = 'Classic' + managedRuntimeLoader = '' + managedRuntimeVersion = 'v2.0' + passAnonymousToken = $false + startMode = 'AlwaysRunning' + queueLength = 2000 + cpuAction = 'KillW3wp' + cpuLimit = 90000 + cpuResetInterval = '00:10:00' + cpuSmpAffinitized = $true + cpuSmpProcessorAffinityMask = 1 + cpuSmpProcessorAffinityMask2 = 1 + identityType = 'SpecificUser' + Credential = $mockCredential + idleTimeout = '00:15:00' + idleTimeoutAction = 'Suspend' + loadUserProfile = $false + logEventOnProcessModel = '' + logonType = 'LogonService' + manualGroupMembership = $true + maxProcesses = 2 + pingingEnabled = $false + pingInterval = '00:01:00' + pingResponseTime = '00:02:00' + setProfileEnvironment = $true + shutdownTimeLimit = '00:02:00' + startupTimeLimit = '00:02:00' + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + orphanActionParams = '/orphanActionParam1' + orphanWorkerProcess = $true + loadBalancerCapabilities = 'TcpLevel' + rapidFailProtection = $false + rapidFailProtectionInterval = '00:10:00' + rapidFailProtectionMaxCrashes = 10 + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + autoShutdownParams = '/autoShutdownParam1' + disallowOverlappingRotation = $true + disallowRotationOnConfigChange = $true + logEventOnRecycle = 'Time,Memory,PrivateMemory' + restartMemoryLimit = 1048576 + restartPrivateMemoryLimit = 1048576 + restartRequestsLimit = 1000 + restartTimeLimit = '2.10:00:00' + restartSchedule = @('06:00:00', '08:00:00') + } + + Mock Invoke-AppCmd + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call all the mocks' { + Assert-MockCalled Invoke-AppCmd -Exactly 52 + } + + } + + Context 'The autoStart property needs to be set' { + + $mockAppPoolDefaults = @{ + autoStart = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoStart = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/autoStart:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The CLRConfigFile property needs to be set' { + + $mockAppPoolDefaults = @{ + CLRConfigFile = '' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/CLRConfigFile:C:\inetpub\temp\aspnet.config'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The enable32BitAppOnWin64 property needs to be set' { + + $mockAppPoolDefaults = @{ + enable32BitAppOnWin64 = $false + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + enable32BitAppOnWin64 = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enable32BitAppOnWin64:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The enableConfigurationOverride property needs to be set' { + + $mockAppPoolDefaults = @{ + enableConfigurationOverride = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + enableConfigurationOverride = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enableConfigurationOverride:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedPipelineMode property needs to be set' { + + $mockAppPoolDefaults = @{ + managedPipelineMode = 'Integrated' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedPipelineMode = 'Classic' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedPipelineMode:Classic'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedRuntimeLoader property needs to be set' { + + $mockAppPoolDefaults = @{ + managedRuntimeLoader = 'webengine4.dll' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedRuntimeLoader = '' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeLoader:'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedRuntimeVersion property needs to be set' { + + $mockAppPoolDefaults = @{ + managedRuntimeVersion = 'v4.0' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedRuntimeVersion = 'v2.0' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeVersion:v2.0'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The passAnonymousToken property needs to be set' { + + $mockAppPoolDefaults = @{ + passAnonymousToken = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + passAnonymousToken = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/passAnonymousToken:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The startMode property needs to be set' { + + $mockAppPoolDefaults = @{ + startMode = 'OnDemand' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + startMode = 'AlwaysRunning' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/startMode:AlwaysRunning'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The queueLength property needs to be set' { + + $mockAppPoolDefaults = @{ + queueLength = 1000 + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + queueLength = 2000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/queueLength:2000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuAction property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + action = 'NoAction' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuAction = 'KillW3wp' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.action:KillW3wp'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + limit = 0 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuLimit = 90000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.limit:90000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuResetInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + resetInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuResetInterval = '00:10:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.resetInterval:00:10:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpAffinitized property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpAffinitized = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpAffinitized = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpAffinitized:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpProcessorAffinityMask property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpProcessorAffinityMask = 1 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask:1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpProcessorAffinityMask2 property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask2 = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpProcessorAffinityMask2 = 1 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask2:1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The identityType property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'ApplicationPoolIdentity' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + identityType = 'SpecificUser' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.identityType:SpecificUser'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The idleTimeout property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeout = '00:20:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + idleTimeout = '00:15:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeout:00:15:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The idleTimeoutAction property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeoutAction = 'Terminate' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + idleTimeoutAction = 'Suspend' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeoutAction:Suspend'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The loadUserProfile property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + loadUserProfile = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + loadUserProfile = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.loadUserProfile:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logEventOnProcessModel property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logEventOnProcessModel = 'IdleTimeout' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logEventOnProcessModel = '' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logEventOnProcessModel:'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logonType property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logonType = 'LogonBatch' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logonType = 'LogonService' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logonType:LogonService'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The manualGroupMembership property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + manualGroupMembership = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + manualGroupMembership = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.manualGroupMembership:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The maxProcesses property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + maxProcesses = 1 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + maxProcesses = 2 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.maxProcesses:2'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingingEnabled property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingingEnabled = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingingEnabled = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingingEnabled:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingInterval = '00:00:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingInterval = '00:01:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingInterval:00:01:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingResponseTime property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingResponseTime = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingResponseTime = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingResponseTime:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The setProfileEnvironment property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + setProfileEnvironment = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + setProfileEnvironment = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.setProfileEnvironment:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The shutdownTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + shutdownTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + shutdownTimeLimit = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.shutdownTimeLimit:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The startupTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + startupTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + startupTimeLimit = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.startupTimeLimit:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanActionExe property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanActionParams property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanActionParams = '/orphanActionParam1' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionParams:/orphanActionParam1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanWorkerProcess property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanWorkerProcess = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanWorkerProcess = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanWorkerProcess:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The loadBalancerCapabilities property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + loadBalancerCapabilities = 'HttpLevel' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + loadBalancerCapabilities = 'TcpLevel' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.loadBalancerCapabilities:TcpLevel'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtection property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtection = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtection = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtection:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtectionInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtectionInterval = '00:10:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionInterval:00:10:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtectionMaxCrashes property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionMaxCrashes = 5 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtectionMaxCrashes = 10 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionMaxCrashes:10'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The autoShutdownExe property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The autoShutdownParams property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownParams = '' + } + + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoShutdownParams = '/autoShutdownParam1' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownParams:/autoShutdownParam1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The disallowOverlappingRotation property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowOverlappingRotation = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + disallowOverlappingRotation = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowOverlappingRotation:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The disallowRotationOnConfigChange property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowRotationOnConfigChange = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + disallowRotationOnConfigChange = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowRotationOnConfigChange:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logEventOnRecycle property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logEventOnRecycle = 'Time,Memory,PrivateMemory' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartMemoryLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + memory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartMemoryLimit = 1048576 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.memory:1048576'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartPrivateMemoryLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + privateMemory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartPrivateMemoryLimit = 1048576 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.privateMemory:1048576'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartRequestsLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + requests = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartRequestsLimit = 1000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.requests:1000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + time = '1.05:00:00' + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartTimeLimit = '2.10:00:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.time:2.10:00:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartSchedule property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + schedule = @{ + Collection = @( + @{value = '04:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartSchedule = @('08:00:00') + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 + } + + } + + } + + } + + #endregion +} +finally +{ + Restore-TestEnvironment -TestEnvironment $TestEnvironment } From c6c3788613432f0d2d20db237d5838fb8a4df392 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:41:30 +0300 Subject: [PATCH 03/22] updated release notes --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 05d0480fe..50d4fdd24 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,8 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### Unreleased +* Added missing settings for **xWebAppPoolDefaults**. Fixes #105. + ### 1.19.0.0 * **xWebAppPoolDefaults** now returns values. Fixes #311. From 333190da373136bf4979bbd2428ede3b39619fe0 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:55:46 +0300 Subject: [PATCH 04/22] Updated sample usage in readme and in sample file --- Examples/Sample_xWebAppPoolDefaults.ps1 | 53 ++++++++- README.md | 137 +++++++++++++++++++++++- 2 files changed, 182 insertions(+), 8 deletions(-) diff --git a/Examples/Sample_xWebAppPoolDefaults.ps1 b/Examples/Sample_xWebAppPoolDefaults.ps1 index 6eca34e0b..b1b67dfc1 100644 --- a/Examples/Sample_xWebAppPoolDefaults.ps1 +++ b/Examples/Sample_xWebAppPoolDefaults.ps1 @@ -21,9 +21,56 @@ Configuration Sample_xWebAppPoolDefaults # Configures the application pool defaults. xWebAppPoolDefaults PoolDefaults { - ApplyTo = 'Machine' - ManagedRuntimeVersion = 'v4.0' - IdentityType = 'ApplicationPoolIdentity' + ApplyTo = 'Machine' + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpuAction = 'NoAction' + cpuLimit = 90000 + cpuResetInterval = (New-TimeSpan -Minutes 5).ToString() + cpuSmpAffinitized = $false + cpuSmpProcessorAffinityMask = 4294967295 + cpuSmpProcessorAffinityMask2 = 4294967295 + identityType = 'ApplicationPoolIdentity' + idleTimeout = (New-TimeSpan -Minutes 20).ToString() + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + pingingEnabled = $true + pingInterval = (New-TimeSpan -Seconds 30).ToString() + pingResponseTime = (New-TimeSpan -Seconds 90).ToString() + setProfileEnvironment = $false + shutdownTimeLimit = (New-TimeSpan -Seconds 90).ToString() + startupTimeLimit = (New-TimeSpan -Seconds 90).ToString() + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = (New-TimeSpan -Minutes 5).ToString() + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + restartMemoryLimit = 0 + restartPrivateMemoryLimit = 0 + restartRequestsLimit = 0 + restartTimeLimit = (New-TimeSpan -Minutes 1440).ToString() + restartSchedule = @('00:00:00', '08:00:00', '16:00:00') } + + } } diff --git a/README.md b/README.md index 50d4fdd24..2a36466e0 100644 --- a/README.md +++ b/README.md @@ -224,8 +224,90 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### xWebAppPoolDefaults * **ApplyTo**: Required Key value, always **Machine** -* **ManagedRuntimeVersion**: CLR Version {v2.0|v4.0|} empty string for unmanaged. -* **ApplicationPoolIdentity**: {ApplicationPoolIdentity | LocalService | LocalSystem | NetworkService} +* **autoStart** : When set to `$true`, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started. +* **CLRConfigFile** : Indicates the .NET configuration file for the application pool. +* **enable32BitAppOnWin64** : When set to `$true`, enables a 32-bit application to run on a computer that runs a 64-bit version of Windows. +* **enableConfigurationOverride** : When set to `$true`, indicates that delegated settings in Web.config files will be processed for applications within this application pool. + When set to `$false`, all settings in Web.config files will be ignored for this application pool. +* **managedPipelineMode** : Indicates the request-processing mode that is used to process requests for managed content. The values that are allowed for this property are: `Integrated`, `Classic`. +* **managedRuntimeLoader** : Indicates the managed loader to use for pre-loading the application pool. +* **managedRuntimeVersion** : Indicates the CLR version to be used by the application pool. The values that are allowed for this property are: `v4.0`, `v2.0`, and `""`. +* **passAnonymousToken** : When set to `$true`, the Windows Process Activation Service (WAS) creates and passes a token for the built-in IUSR anonymous user account to the Anonymous authentication module. + The Anonymous authentication module uses the token to impersonate the built-in account. When this property is set to `$false`, the token will not be passed. +* **startMode** : Indicates the startup type for the application pool. The values that are allowed for this property are: `OnDemand`, `AlwaysRunning`. +* **queueLength** : Indicates the maximum number of requests that HTTP.sys will queue for the application pool. The value must be a valid integer between `10` and `65535`. +* **cpuAction** : Configures the action that IIS takes when a worker process exceeds its configured CPU limit. + The values that are allowed for this property are: `NoAction`, `KillW3wp`, `Throttle`, and `ThrottleUnderLoad`. +* **cpuLimit** : Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in the application pool are allowed to consume over a period of time as indicated by the **cpuResetInterval** property. + The value must be a valid integer between `0` and `100000`. +* **cpuResetInterval** : Indicates the reset period (in minutes) for CPU monitoring and throttling limits on the application pool. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `0` to `1440`. + Setting the value of this property to `00:00:00` disables CPU monitoring. +* **cpuSmpAffinitized** : Indicates whether a particular worker process assigned to the application pool should also be assigned to a given CPU. +* **cpuSmpProcessorAffinityMask** : Indicates the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. + Before this property takes effect, the **cpuSmpAffinitized** property must be set to `$true` for the application pool. + The value must be a valid integer between `0` and `4294967295`. +* **cpuSmpProcessorAffinityMask2** : Indicates the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. + Before this property takes effect, the **cpuSmpAffinitized** property must be set to `$true` for the application pool. + The value must be a valid integer between `0` and `4294967295`. +* **identityType** : Indicates the account identity under which the application pool runs. + The values that are allowed for this property are: `ApplicationPoolIdentity`, `LocalService`, `LocalSystem`, `NetworkService`, and `SpecificUser`. +* **Credential** : Indicates the custom account crededentials. This property is only valid when the **identityType** property is set to `SpecificUser`. +* **idleTimeout** : Indicates the amount of time (in minutes) a worker process will remain idle before it shuts down. + The value must be a string representation of a TimeSpan value and must be less than the **restartTimeLimit** property value. The valid range (in minutes) is `0` to `43200`. +* **idleTimeoutAction** : Indicates the action to perform when the idle timeout duration has been reached. + The values that are allowed for this property are: `Terminate`, `Suspend`. +* **loadUserProfile** : Indicates whether IIS loads the user profile for the application pool identity. +* **logEventOnProcessModel** : Indicates that IIS should generate an event log entry for each occurrence of the specified process model events. +* **logonType** : Indicates the logon type for the process identity. The values that are allowed for this property are: `LogonBatch`, `LogonService`. +* **manualGroupMembership** : Indicates whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token. +* **maxProcesses** : Indicates the maximum number of worker processes that would be used for the application pool. + The value must be a valid integer between `0` and `2147483647`. +* **pingingEnabled** : Indicates whether pinging (health monitoring) is enabled for the worker process(es) serving this application pool. +* **pingInterval** : Indicates the period of time (in seconds) between health monitoring pings sent to the worker process(es) serving this application pool. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **pingResponseTime** : Indicates the maximum time (in seconds) that a worker process is given to respond to a health monitoring ping. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **setProfileEnvironment** : Indicates the environment to be set based on the user profile for the new process. +* **shutdownTimeLimit** : Indicates the period of time (in seconds) a worker process is given to finish processing requests and shut down. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **startupTimeLimit** : Indicates the period of time (in seconds) a worker process is given to start up and initialize. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **orphanActionExe** : Indicates an executable to run when a worker process is orphaned. +* **orphanActionParams** : Indicates parameters for the executable that is specified in the **orphanActionExe** property. +* **orphanWorkerProcess** : Indicates whether to assign a worker process to an orphan state instead of terminating it when the application pool fails. + If `$true`, an unresponsive worker process will be orphaned instead of terminated. +* **loadBalancerCapabilities** : Indicates the response behavior of a service when it is unavailable. The values that are allowed for this property are: `HttpLevel`, `TcpLevel`. + If set to `HttpLevel` and the application pool is stopped, HTTP.sys will return HTTP 503 error. If set to `TcpLevel`, HTTP.sys will reset the connection. +* **rapidFailProtection** : Indicates whether rapid-fail protection is enabled. + If `$true`, the application pool is shut down if there are a specified number of worker process crashes within a specified time period. +* **rapidFailProtectionInterval** : Indicates the time interval (in minutes) during which the specified number of worker process crashes must occur before the application pool is shut down by rapid-fail protection. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `1` to `144000`. +* **rapidFailProtectionMaxCrashes** : Indicates the maximum number of worker process crashes permitted before the application pool is shut down by rapid-fail protection. + The value must be a valid integer between `0` and `2147483647`. +* **autoShutdownExe** : Indicates an executable to run when the application pool is shut down by rapid-fail protection. +* **autoShutdownParams** : Indicates parameters for the executable that is specified in the **autoShutdownExe** property. +* **disallowOverlappingRotation** : Indicates whether the W3SVC service should start another worker process to replace the existing worker process while that process is shutting down. + If `$true`, the application pool recycle will happen such that the existing worker process exits before another worker process is created. +* **disallowRotationOnConfigChange** : Indicates whether the W3SVC service should rotate worker processes in the application pool when the configuration has changed. + If `$true`, the application pool will not recycle when its configuration is changed. +* **logEventOnRecycle** : Indicates that IIS should generate an event log entry for each occurrence of the specified recycling events. +* **restartMemoryLimit** : Indicates the maximum amount of virtual memory (in KB) a worker process can consume before causing the application pool to recycle. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means there is no limit. +* **restartPrivateMemoryLimit** : Indicates the maximum amount of private memory (in KB) a worker process can consume before causing the application pool to recycle. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means there is no limit. +* **restartRequestsLimit** : Indicates the maximum number of requests the application pool can process before it is recycled. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means the application pool can process an unlimited number of requests. +* **restartTimeLimit** : Indicates the period of time (in minutes) after which the application pool will recycle. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `0` to `432000`. + A value of `00:00:00` means the application pool does not recycle on a regular interval. +* **restartSchedule** : Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. + The value must be an array of string representations of TimeSpan values. + TimeSpan values must be between `00:00:00` and `23:59:59` seconds inclusive, with a granularity of 60 seconds. + Setting the value of this property to `""` disables the schedule. ### xWebSiteDefaults @@ -1051,9 +1133,54 @@ configuration Sample_IISServerDefaults xWebAppPoolDefaults PoolDefaults { - ApplyTo = 'Machine' - ManagedRuntimeVersion = 'v4.0' - IdentityType = 'ApplicationPoolIdentity' + ApplyTo = 'Machine' + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpuAction = 'NoAction' + cpuLimit = 90000 + cpuResetInterval = (New-TimeSpan -Minutes 5).ToString() + cpuSmpAffinitized = $false + cpuSmpProcessorAffinityMask = 4294967295 + cpuSmpProcessorAffinityMask2 = 4294967295 + identityType = 'ApplicationPoolIdentity' + idleTimeout = (New-TimeSpan -Minutes 20).ToString() + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + pingingEnabled = $true + pingInterval = (New-TimeSpan -Seconds 30).ToString() + pingResponseTime = (New-TimeSpan -Seconds 90).ToString() + setProfileEnvironment = $false + shutdownTimeLimit = (New-TimeSpan -Seconds 90).ToString() + startupTimeLimit = (New-TimeSpan -Seconds 90).ToString() + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = (New-TimeSpan -Minutes 5).ToString() + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + restartMemoryLimit = 0 + restartPrivateMemoryLimit = 0 + restartRequestsLimit = 0 + restartTimeLimit = (New-TimeSpan -Minutes 1440).ToString() + restartSchedule = @('00:00:00', '08:00:00', '16:00:00') } } } From 48ab094112d5269fd959e7f7d79c5ebe3ecb9f69 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 23:33:51 +0300 Subject: [PATCH 05/22] Added required new lines at the end of files --- .../MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 | 2 +- .../MSFT_xWebAppPoolDefaults.schema.mof | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 102f51ed2..f5da96ef2 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -809,4 +809,4 @@ function Get-AppPoolDefault { #endregion -Export-ModuleMember -Function *-TargetResource \ No newline at end of file +Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof index 6b4991147..47e1a9d79 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof @@ -53,4 +53,4 @@ class MSFT_xWebAppPoolDefaults : OMI_BaseResource [Write, Description("Indicates the period of time (in minutes) after which the application pool will recycle. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 432000. A value of 0 means the application pool does not recycle on a regular interval.")] String restartTimeLimit; [Write, Description("Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. The value must be an array of string representations of TimeSpan values. TimeSpan values must be between 00:00:00 and 23:59:59 seconds inclusive, with a granularity of 60 seconds. Setting the value of this property to '' disables the schedule.")] String restartSchedule[]; -}; \ No newline at end of file +}; From 5a6860fcba50406fdddc36e4b699b88a0d773657 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Thu, 21 Dec 2017 22:56:28 +0300 Subject: [PATCH 06/22] Integration tests --- .../MSFT_xWebAppPoolDefaults.psm1 | 23 +-- ..._xWebAppPoolDefaults.Integration.Tests.ps1 | 159 ++++++----------- .../MSFT_xWebAppPoolDefaults.config.ps1 | 167 +++++++++++++----- 3 files changed, 189 insertions(+), 160 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index f5da96ef2..982b5fcfa 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -5,7 +5,8 @@ Import-Module -Name "$PSScriptRoot\..\Helper.psm1" data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' - VerboseGetTargetResource = Get-TargetResource has been run. + ErrorAppCmdNonZeroExitCode = AppCmd.exe has exited with error code "{0}". + VerboseGetTargetResource = Get-TargetResource has been run. ErrorAppPoolDefaultsNotFound = Application pool defaults element could not be located. VerboseAppPoolDefaultsFound = Application pool defaults was found. @@ -312,8 +313,6 @@ function Set-TargetResource { # Set Application Pool Properties - Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) - $PropertyData.Where( { ($_.Name -in $PSBoundParameters.Keys) -and @@ -331,8 +330,9 @@ function Set-TargetResource { Write-Verbose -Message ( $LocalizedData['VerboseSetProperty'] -f $propertyName ) + Invoke-AppCmd -ArgumentList ( - '/{0}:{1}' -f $propertyPath, $PSBoundParameters[$propertyName] + '/{0}:{1}' -f "applicationPoolDefaults.$($propertyPath)", $PSBoundParameters[$propertyName] ) } } @@ -346,7 +346,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - '/processModel.userName:{0}' -f $Credential.UserName + '/applicationPoolDefaults.processModel.userName:{0}' -f $Credential.UserName ) } @@ -358,7 +358,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - '/processModel.password:{0}' -f $clearTextPassword + '/applicationPoolDefaults.processModel.password:{0}' -f $clearTextPassword ) } } @@ -386,8 +386,8 @@ function Set-TargetResource { ) { Write-Verbose -Message ($LocalizedData['VerboseClearCredential']) - Invoke-AppCmd -ArgumentList '/processModel.userName:' - Invoke-AppCmd -ArgumentList '/processModel.password:' + Invoke-AppCmd -ArgumentList '/applicationPoolDefaults.processModel.userName:' + Invoke-AppCmd -ArgumentList '/applicationPoolDefaults.processModel.password:' } if ($PSBoundParameters.ContainsKey('restartSchedule')) { @@ -421,7 +421,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - "/+recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject ) } # Remove value @@ -432,7 +432,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - "/-recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject ) } @@ -774,8 +774,9 @@ function Invoke-AppCmd { $ErrorActionPreference = 'Stop' $appcmdFilePath = "$env:SystemRoot\System32\inetsrv\appcmd.exe" - $allArguments = @("set", "config", "-section:applicationPools") + $ArgumentList + $allArguments = @("set", "config", "-section:system.applicationHost/applicationPools") + $ArgumentList + ("/commit:apphost") + # Write-Verbose -Message "calling $($appcmdFilePath) $($allArguments)" $appcmdResult = $(& $appcmdFilePath $allArguments) Write-Verbose -Message $($appcmdResult).ToString() diff --git a/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 b/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 index 3b6e4d551..cee617cc1 100644 --- a/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 @@ -1,6 +1,7 @@ +#requires -Version 4.0 -$script:DSCModuleName = 'xWebAdministration' -$script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' +$script:DSCModuleName = 'xWebAdministration' +$script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' #region HEADER @@ -16,148 +17,98 @@ Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\ $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` - -TestType Integration + -TestType Integration + #endregion -[string] $tempName = "$($script:DSCResourceName)_" + (Get-Date).ToString("yyyyMMdd_HHmmss") +# Test Setup +if ((Get-Service -Name 'W3SVC').Status -ne 'Running') +{ + Start-Service -Name 'W3SVC' +} + +$tempBackupName = "$($script:DSCResourceName)_$(Get-Date -Format 'yyyyMMdd_HHmmss')" # Using try/finally to always cleanup even if something awful happens. + try { - #region Integration Tests + # Create configuration backup + + Backup-WebConfiguration -Name $tempBackupName | Out-Null - # some constants - [string]$constPsPath = 'MACHINE/WEBROOT/APPHOST' - [string]$constAPDFilter = 'system.applicationHost/applicationPools/applicationPoolDefaults' - [string]$constSiteFilter = 'system.applicationHost/sites/' + #region Integration Tests $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" . $ConfigFile - $null = Backup-WebConfiguration -Name $tempName + Describe "$($script:DSCResourceName)_Integration" { - function Get-SiteValue([string]$path,[string]$name) - { - return (Get-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/$path" -name $name).value - } + #region Default Tests - Describe "$($script:DSCResourceName)_Integration" { - #region DEFAULT TESTS - It 'Should compile without throwing' { + It 'Should be able to compile and apply without throwing' { { - Invoke-Expression -Command "$($script:DSCResourceName)_Config -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw + Invoke-Expression -Command ( + '{0}_Config -OutputPath $TestDrive -ConfigurationData $ConfigData -ErrorAction Stop' -f + $script:DSCResourceName + ) + + Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Force -Wait -Verbose + } | Should Not Throw } It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should Not throw + { + Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should Not Throw } + #endregion - It 'Changing ManagedRuntimeVersion' { + It 'Should have set the resource and all the parameters should match' { + + $currentConfiguration = Get-DscConfiguration + + foreach ($parameter in $TestParameters.GetEnumerator()) { - # get the current value - [string] $originalValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion) + Write-Verbose -Message "The $($parameter.Name) property should be set." - # We are using environment variables here, because a inline PowerShell variable was empty after executing Start-DscConfiguration + if ($parameter.Name -eq 'Credential') + { + $appPoolDefaults = Get-WebConfiguration -Filter '/system.applicationHost/applicationPools/applicationPoolDefaults' + + $appPoolDefaults.processModel.userName | + Should Be $TestParameters['Credential'].UserName - # change the value to something else - if ($originalValue -eq 'v4.0') + $appPoolDefaults.processModel.password | + Should Be $TestParameters['Credential'].GetNetworkCredential().Password + } + elseif ($parameter.Name -eq 'ApplyTo') { - $env:PesterManagedRuntimeVersion = 'v2.0' + # ignored. } else { - $env:PesterManagedRuntimeVersion = 'v4.0' + $currentConfiguration."$($parameter.Name)" | + Should Be $TestParameters[$parameter.Name] } - - Invoke-Expression -Command "$($script:DSCResourceName)_ManagedRuntimeVersion -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | should not throw - - # get the configured value again - $changedValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion).Value - - # compare it to the one we just tried to set. - $changedValue | should be $env:PesterManagedRuntimeVersion - } - - It 'Changing IdentityType' { - # get the current value - [string] $originalValue = (Get-WebConfigurationProperty ` - -PSPath $constPsPath ` - -Filter $constAPDFilter/processModel ` - -Name identityType) - - if ($originalValue -eq 'ApplicationPoolIdentity') - { - $env:PesterApplicationPoolIdentity = 'LocalService' - } - else - { - $env:PesterApplicationPoolIdentity = 'ApplicationPoolIdentity' } - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_AppPoolIdentityType -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = (Get-WebConfigurationProperty -PSPath $constPsPath -Filter $constAPDFilter/processModel -Name identityType) - - $changedValue | Should Be $env:PesterApplicationPoolIdentity } - - It 'Changing LogFormat' { - [string] $originalValue = Get-SiteValue 'logFile' 'logFormat' - - if ($originalValue -eq 'W3C') - { - $env:PesterLogFormat = 'IIS' - } - else - { - $env:PesterLogFormat = 'W3C' - } - - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_LogFormat -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = Get-SiteValue 'logFile' 'logFormat' - - $changedValue | Should Be $env:PesterALogFormat - } - - It 'Changing Default AppPool' { - # get the current value - - [string] $originalValue = Get-SiteValue 'applicationDefaults' 'applicationPool' - - $env:PesterDefaultPool = 'DefaultAppPool' - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_DefaultPool -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = Get-SiteValue 'applicationDefaults' 'applicationPool' - $changedValue | should be $env:PesterDefaultPool + It 'Actual configuration should match the desired configuration' { + Test-DscConfiguration -Verbose | Should Be $true } } + #endregion } finally { #region FOOTER - Restore-WebConfiguration -Name $tempName - Remove-WebConfigurationBackup -Name $tempName + Restore-WebConfiguration -Name $tempBackupName + Remove-WebConfigurationBackup -Name $tempBackupName Restore-TestEnvironment -TestEnvironment $TestEnvironment #endregion diff --git a/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 b/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 index c804256ae..32c1aaad2 100644 --- a/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 +++ b/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 @@ -1,60 +1,137 @@ -[string] $constPsPath = 'MACHINE/WEBROOT/APPHOST' -[string] $constAPDFilter = 'system.applicationHost/applicationPools/applicationPoolDefaults' -[string] $constSiteFilter = 'system.applicationHost/sites/' +#requires -Version 4.0 -[string] $originalValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion).Value +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] +param () -configuration MSFT_xWebAppPoolDefaults_Config -{ - Import-DscResource -ModuleName xWebAdministration - - xWebAppPoolDefaults PoolDefaults - { - ApplyTo = 'Machine' - ManagedRuntimeVersion = $originalValue - } +$ConfigData = @{ + AllNodes = @( + @{ + NodeName = '*' + PSDscAllowPlainTextPassword = $true + } + @{ + NodeName = 'localhost' + } + ) } -configuration MSFT_xWebAppPoolDefaults_ManagedRuntimeVersion -{ - Import-DscResource -ModuleName xWebAdministration +$TestCredential = New-Object -TypeName PSCredential -ArgumentList ( + 'CONTOSO\JDoe', + ('5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force) +) - xWebAppPoolDefaults PoolDefaults - { - ApplyTo = 'Machine' - ManagedRuntimeVersion = $env:PesterManagedRuntimeVersion - } +$TestParameters = [Ordered]@{ + applyTo = 'Machine' + autoStart = $false + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + enable32BitAppOnWin64 = $true + enableConfigurationOverride = $false + managedPipelineMode = 'Classic' + managedRuntimeLoader = '' + managedRuntimeVersion = 'v2.0' + passAnonymousToken = $false + startMode = 'AlwaysRunning' + queueLength = 2000 + cpuAction = 'KillW3wp' + cpuLimit = 90000 + cpuResetInterval = '00:10:00' + cpuSmpAffinitized = $true + cpuSmpProcessorAffinityMask = 1 + cpuSmpProcessorAffinityMask2 = 1 + identityType = 'SpecificUser' + Credential = $TestCredential + idleTimeout = '00:15:00' + idleTimeoutAction = 'Suspend' + loadUserProfile = $false + logEventOnProcessModel = '' + logonType = 'LogonService' + manualGroupMembership = $true + maxProcesses = 2 + pingingEnabled = $false + pingInterval = '00:01:00' + pingResponseTime = '00:02:00' + setProfileEnvironment = $true + shutdownTimeLimit = '00:02:00' + startupTimeLimit = '00:02:00' + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + orphanActionParams = '/orphanActionParam1' + orphanWorkerProcess = $true + loadBalancerCapabilities = 'TcpLevel' + rapidFailProtection = $false + rapidFailProtectionInterval = '00:10:00' + rapidFailProtectionMaxCrashes = 10 + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + autoShutdownParams = '/autoShutdownParam1' + disallowOverlappingRotation = $true + disallowRotationOnConfigChange = $true + logEventOnRecycle = 'Time,Memory,PrivateMemory' + restartMemoryLimit = 1048576 + restartPrivateMemoryLimit = 1048576 + restartRequestsLimit = 1000 + restartTimeLimit = '2.10:00:00' + restartSchedule = @('05:00:00', '21:00:00') } -configuration MSFT_xWebAppPoolDefaults_AppPoolIdentityType +Configuration MSFT_xWebAppPoolDefaults_Config { Import-DscResource -ModuleName xWebAdministration - xWebAppPoolDefaults PoolDefaults + Node $AllNodes.NodeName { - ApplyTo = 'Machine' - IdentityType = $env:PesterApplicationPoolIdentity + xWebAppPoolDefaults Defaults + { + ApplyTo = $TestParameters.applyTo + autoStart = $TestParameters.autoStart + CLRConfigFile = $TestParameters.CLRConfigFile + enable32BitAppOnWin64 = $TestParameters.enable32BitAppOnWin64 + enableConfigurationOverride = $TestParameters.enableConfigurationOverride + managedPipelineMode = $TestParameters.managedPipelineMode + managedRuntimeLoader = $TestParameters.managedRuntimeLoader + managedRuntimeVersion = $TestParameters.managedRuntimeVersion + passAnonymousToken = $TestParameters.passAnonymousToken + startMode = $TestParameters.startMode + queueLength = $TestParameters.queueLength + cpuAction = $TestParameters.cpuAction + cpuLimit = $TestParameters.cpuLimit + cpuResetInterval = $TestParameters.cpuResetInterval + cpuSmpAffinitized = $TestParameters.cpuSmpAffinitized + cpuSmpProcessorAffinityMask = $TestParameters.cpuSmpProcessorAffinityMask + cpuSmpProcessorAffinityMask2 = $TestParameters.cpuSmpProcessorAffinityMask2 + identityType = $TestParameters.identityType + Credential = $TestParameters.Credential + idleTimeout = $TestParameters.idleTimeout + idleTimeoutAction = $TestParameters.idleTimeoutAction + loadUserProfile = $TestParameters.loadUserProfile + logEventOnProcessModel = $TestParameters.logEventOnProcessModel + logonType = $TestParameters.logonType + manualGroupMembership = $TestParameters.manualGroupMembership + maxProcesses = $TestParameters.maxProcesses + pingingEnabled = $TestParameters.pingingEnabled + pingInterval = $TestParameters.pingInterval + pingResponseTime = $TestParameters.pingResponseTime + setProfileEnvironment = $TestParameters.setProfileEnvironment + shutdownTimeLimit = $TestParameters.shutdownTimeLimit + startupTimeLimit = $TestParameters.startupTimeLimit + orphanActionExe = $TestParameters.orphanActionExe + orphanActionParams = $TestParameters.orphanActionParams + orphanWorkerProcess = $TestParameters.orphanWorkerProcess + loadBalancerCapabilities = $TestParameters.loadBalancerCapabilities + rapidFailProtection = $TestParameters.rapidFailProtection + rapidFailProtectionInterval = $TestParameters.rapidFailProtectionInterval + rapidFailProtectionMaxCrashes = $TestParameters.rapidFailProtectionMaxCrashes + autoShutdownExe = $TestParameters.autoShutdownExe + autoShutdownParams = $TestParameters.autoShutdownParams + disallowOverlappingRotation = $TestParameters.disallowOverlappingRotation + disallowRotationOnConfigChange = $TestParameters.disallowRotationOnConfigChange + logEventOnRecycle = $TestParameters.logEventOnRecycle + restartMemoryLimit = $TestParameters.restartMemoryLimit + restartPrivateMemoryLimit = $TestParameters.restartPrivateMemoryLimit + restartRequestsLimit = $TestParameters.restartRequestsLimit + restartTimeLimit = $TestParameters.restartTimeLimit + restartSchedule = $TestParameters.restartSchedule + } } } -configuration MSFT_xWebAppPoolDefaults_LogFormat -{ - Import-DscResource -ModuleName xWebAdministration - xWebSiteDefaults LogFormat - { - ApplyTo = 'Machine' - LogFormat = $env:PesterLogFormat - } -} - -configuration MSFT_xWebAppPoolDefaults_DefaultPool -{ - Import-DscResource -ModuleName xWebAdministration - - xWebSiteDefaults DefaultPool - { - ApplyTo = 'Machine' - DefaultApplicationPool = $env:PesterDefaultPool - } -} From fa2b9388a0e039350e2cefb26408e26282679299 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Thu, 21 Dec 2017 23:27:40 +0300 Subject: [PATCH 07/22] changes in unit tests --- Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 b/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 index e39504357..5fe29e006 100644 --- a/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 +++ b/Tests/Unit/MSFT_xWebAppPoolDefaults.tests.ps1 @@ -1711,7 +1711,7 @@ try autoStart = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/autoStart:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.autoStart:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1733,7 +1733,7 @@ try CLRConfigFile = 'C:\inetpub\temp\aspnet.config' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/CLRConfigFile:C:\inetpub\temp\aspnet.config'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.CLRConfigFile:C:\inetpub\temp\aspnet.config'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1755,7 +1755,7 @@ try enable32BitAppOnWin64 = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enable32BitAppOnWin64:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.enable32BitAppOnWin64:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1777,7 +1777,7 @@ try enableConfigurationOverride = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enableConfigurationOverride:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.enableConfigurationOverride:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1799,7 +1799,7 @@ try managedPipelineMode = 'Classic' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedPipelineMode:Classic'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedPipelineMode:Classic'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1821,7 +1821,7 @@ try managedRuntimeLoader = '' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeLoader:'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedRuntimeLoader:'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1843,7 +1843,7 @@ try managedRuntimeVersion = 'v2.0' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeVersion:v2.0'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedRuntimeVersion:v2.0'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1865,7 +1865,7 @@ try passAnonymousToken = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/passAnonymousToken:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.passAnonymousToken:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1887,7 +1887,7 @@ try startMode = 'AlwaysRunning' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/startMode:AlwaysRunning'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.startMode:AlwaysRunning'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1909,7 +1909,7 @@ try queueLength = 2000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/queueLength:2000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.queueLength:2000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1933,7 +1933,7 @@ try cpuAction = 'KillW3wp' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.action:KillW3wp'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.action:KillW3wp'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1957,7 +1957,7 @@ try cpuLimit = 90000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.limit:90000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.limit:90000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1981,7 +1981,7 @@ try cpuResetInterval = '00:10:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.resetInterval:00:10:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.resetInterval:00:10:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2005,7 +2005,7 @@ try cpuSmpAffinitized = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpAffinitized:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpAffinitized:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2029,7 +2029,7 @@ try cpuSmpProcessorAffinityMask = 1 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask:1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpProcessorAffinityMask:1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2053,7 +2053,7 @@ try cpuSmpProcessorAffinityMask2 = 1 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask2:1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpProcessorAffinityMask2:1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2077,7 +2077,7 @@ try identityType = 'SpecificUser' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.identityType:SpecificUser'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.identityType:SpecificUser'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2101,7 +2101,7 @@ try idleTimeout = '00:15:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeout:00:15:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.idleTimeout:00:15:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2125,7 +2125,7 @@ try idleTimeoutAction = 'Suspend' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeoutAction:Suspend'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.idleTimeoutAction:Suspend'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2149,7 +2149,7 @@ try loadUserProfile = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.loadUserProfile:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.loadUserProfile:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2173,7 +2173,7 @@ try logEventOnProcessModel = '' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logEventOnProcessModel:'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.logEventOnProcessModel:'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2197,7 +2197,7 @@ try logonType = 'LogonService' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logonType:LogonService'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.logonType:LogonService'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2221,7 +2221,7 @@ try manualGroupMembership = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.manualGroupMembership:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.manualGroupMembership:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2245,7 +2245,7 @@ try maxProcesses = 2 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.maxProcesses:2'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.maxProcesses:2'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2269,7 +2269,7 @@ try pingingEnabled = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingingEnabled:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingingEnabled:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2293,7 +2293,7 @@ try pingInterval = '00:01:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingInterval:00:01:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingInterval:00:01:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2317,7 +2317,7 @@ try pingResponseTime = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingResponseTime:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingResponseTime:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2341,7 +2341,7 @@ try setProfileEnvironment = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.setProfileEnvironment:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.setProfileEnvironment:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2365,7 +2365,7 @@ try shutdownTimeLimit = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.shutdownTimeLimit:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.shutdownTimeLimit:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2389,7 +2389,7 @@ try startupTimeLimit = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.startupTimeLimit:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.startupTimeLimit:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2413,7 +2413,7 @@ try orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2437,7 +2437,7 @@ try orphanActionParams = '/orphanActionParam1' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionParams:/orphanActionParam1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanActionParams:/orphanActionParam1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2461,7 +2461,7 @@ try orphanWorkerProcess = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanWorkerProcess:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanWorkerProcess:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2485,7 +2485,7 @@ try loadBalancerCapabilities = 'TcpLevel' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.loadBalancerCapabilities:TcpLevel'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.loadBalancerCapabilities:TcpLevel'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2509,7 +2509,7 @@ try rapidFailProtection = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtection:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtection:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2533,7 +2533,7 @@ try rapidFailProtectionInterval = '00:10:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionInterval:00:10:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtectionInterval:00:10:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2557,7 +2557,7 @@ try rapidFailProtectionMaxCrashes = 10 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionMaxCrashes:10'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtectionMaxCrashes:10'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2581,7 +2581,7 @@ try autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2606,7 +2606,7 @@ try autoShutdownParams = '/autoShutdownParam1' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownParams:/autoShutdownParam1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.autoShutdownParams:/autoShutdownParam1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2630,7 +2630,7 @@ try disallowOverlappingRotation = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowOverlappingRotation:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.disallowOverlappingRotation:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2654,7 +2654,7 @@ try disallowRotationOnConfigChange = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowRotationOnConfigChange:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.disallowRotationOnConfigChange:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2678,7 +2678,7 @@ try logEventOnRecycle = 'Time,Memory,PrivateMemory' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2704,7 +2704,7 @@ try restartMemoryLimit = 1048576 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.memory:1048576'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.memory:1048576'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2730,7 +2730,7 @@ try restartPrivateMemoryLimit = 1048576 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.privateMemory:1048576'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.privateMemory:1048576'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2756,7 +2756,7 @@ try restartRequestsLimit = 1000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.requests:1000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.requests:1000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2782,7 +2782,7 @@ try restartTimeLimit = '2.10:00:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.time:2.10:00:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.time:2.10:00:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2812,14 +2812,14 @@ try restartSchedule = @('08:00:00') } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='04:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='08:00:00']"} Set-TargetResource -ApplyTo Machine @setParamsSplat It 'Should call Invoke-AppCmd' { - Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 - Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 } } From e5968549601f17ce67b74d0112a7e51ca89c6fd2 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 00:04:43 +0300 Subject: [PATCH 08/22] added missing application pool default settings --- .../MSFT_xWebAppPoolDefaults.psm1 | 828 +++++++++++++++--- .../MSFT_xWebAppPoolDefaults.schema.mof | 54 +- 2 files changed, 749 insertions(+), 133 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 6def1b06a..102f51ed2 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -2,19 +2,90 @@ Import-Module -Name "$PSScriptRoot\..\Helper.psm1" # Localized messages -data LocalizedData -{ +data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' - NoWebAdministrationModule = Please ensure that WebAdministration module is installed. - SettingValue = Changing default value '{0}' to '{1}' - ValueOk = Default value '{0}' is already '{1}' VerboseGetTargetResource = Get-TargetResource has been run. + + ErrorAppPoolDefaultsNotFound = Application pool defaults element could not be located. + VerboseAppPoolDefaultsFound = Application pool defaults was found. + VerbosePropertyNotInDesiredState = The "{0}" property of application pool defaults does not match the desired state. + VerboseCredentialToBeCleared = Custom account credentials of application pool defaults need to be cleared because the "identityType" property is not set to "SpecificUser". + VerboseCredentialToBeIgnored = The "Credential" property is only valid when the "identityType" property is set to "SpecificUser". + VerboseResourceInDesiredState = The target resource is already in the desired state. No action is required. + VerboseResourceNotInDesiredState = The target resource is not in the desired state. + VerboseSetProperty = Setting the "{0}" property of application pool defaults". + VerboseClearCredential = Clearing custom account credentials of application pool defaults because the "identityType" property is not set to "SpecificUser". + VerboseRestartScheduleValueAdd = Adding value "{0}" to the "restartSchedule" collection of application pool defaults. + VerboseRestartScheduleValueRemove = Removing value "{0}" from the "restartSchedule" collection of application pool defaults. '@ } -function Get-TargetResource -{ +# Writable properties except Credential. +data PropertyData { + @( + # General + @{Name = 'autoStart'; Path = 'autoStart'} + @{Name = 'CLRConfigFile'; Path = 'CLRConfigFile'} + @{Name = 'enable32BitAppOnWin64'; Path = 'enable32BitAppOnWin64'} + @{Name = 'enableConfigurationOverride'; Path = 'enableConfigurationOverride'} + @{Name = 'managedPipelineMode'; Path = 'managedPipelineMode'} + @{Name = 'managedRuntimeLoader'; Path = 'managedRuntimeLoader'} + @{Name = 'managedRuntimeVersion'; Path = 'managedRuntimeVersion'} + @{Name = 'passAnonymousToken'; Path = 'passAnonymousToken'} + @{Name = 'startMode'; Path = 'startMode'} + @{Name = 'queueLength'; Path = 'queueLength'} + + # CPU + @{Name = 'cpuAction'; Path = 'cpu.action'} + @{Name = 'cpuLimit'; Path = 'cpu.limit'} + @{Name = 'cpuResetInterval'; Path = 'cpu.resetInterval'} + @{Name = 'cpuSmpAffinitized'; Path = 'cpu.smpAffinitized'} + @{Name = 'cpuSmpProcessorAffinityMask'; Path = 'cpu.smpProcessorAffinityMask'} + @{Name = 'cpuSmpProcessorAffinityMask2'; Path = 'cpu.smpProcessorAffinityMask2'} + + # Process Model + @{Name = 'identityType'; Path = 'processModel.identityType'} + @{Name = 'idleTimeout'; Path = 'processModel.idleTimeout'} + @{Name = 'idleTimeoutAction'; Path = 'processModel.idleTimeoutAction'} + @{Name = 'loadUserProfile'; Path = 'processModel.loadUserProfile'} + @{Name = 'logEventOnProcessModel'; Path = 'processModel.logEventOnProcessModel'} + @{Name = 'logonType'; Path = 'processModel.logonType'} + @{Name = 'manualGroupMembership'; Path = 'processModel.manualGroupMembership'} + @{Name = 'maxProcesses'; Path = 'processModel.maxProcesses'} + @{Name = 'pingingEnabled'; Path = 'processModel.pingingEnabled'} + @{Name = 'pingInterval'; Path = 'processModel.pingInterval'} + @{Name = 'pingResponseTime'; Path = 'processModel.pingResponseTime'} + @{Name = 'setProfileEnvironment'; Path = 'processModel.setProfileEnvironment'} + @{Name = 'shutdownTimeLimit'; Path = 'processModel.shutdownTimeLimit'} + @{Name = 'startupTimeLimit'; Path = 'processModel.startupTimeLimit'} + + # Process Orphaning + @{Name = 'orphanActionExe'; Path = 'failure.orphanActionExe'} + @{Name = 'orphanActionParams'; Path = 'failure.orphanActionParams'} + @{Name = 'orphanWorkerProcess'; Path = 'failure.orphanWorkerProcess'} + + # Rapid-Fail Protection + @{Name = 'loadBalancerCapabilities'; Path = 'failure.loadBalancerCapabilities'} + @{Name = 'rapidFailProtection'; Path = 'failure.rapidFailProtection'} + @{Name = 'rapidFailProtectionInterval'; Path = 'failure.rapidFailProtectionInterval'} + @{Name = 'rapidFailProtectionMaxCrashes'; Path = 'failure.rapidFailProtectionMaxCrashes'} + @{Name = 'autoShutdownExe'; Path = 'failure.autoShutdownExe'} + @{Name = 'autoShutdownParams'; Path = 'failure.autoShutdownParams'} + + # Recycling + @{Name = 'disallowOverlappingRotation'; Path = 'recycling.disallowOverlappingRotation'} + @{Name = 'disallowRotationOnConfigChange'; Path = 'recycling.disallowRotationOnConfigChange'} + @{Name = 'logEventOnRecycle'; Path = 'recycling.logEventOnRecycle'} + @{Name = 'restartMemoryLimit'; Path = 'recycling.periodicRestart.memory'} + @{Name = 'restartPrivateMemoryLimit'; Path = 'recycling.periodicRestart.privateMemory'} + @{Name = 'restartRequestsLimit'; Path = 'recycling.periodicRestart.requests'} + @{Name = 'restartTimeLimit'; Path = 'recycling.periodicRestart.time'} + @{Name = 'restartSchedule'; Path = 'recycling.periodicRestart.schedule'} + ) +} + +function Get-TargetResource { <# .SYNOPSIS This will return a hashtable of results @@ -34,14 +105,46 @@ function Get-TargetResource Write-Verbose -Message $LocalizedData.VerboseGetTargetResource - return @{ - ManagedRuntimeVersion = (Get-Value -Path '' -Name 'managedRuntimeVersion') - IdentityType = (Get-Value -Path 'processModel' -Name 'identityType') + # XPath -Filter is case-sensitive. Use Where-Object to get the target application pool by name. + $appPool = Get-AppPoolDefault + + $cimCredential = $null + if ($appPool.processModel.identityType -eq 'SpecificUser') { + $cimCredential = New-CimInstance -ClientOnly ` + -ClassName MSFT_Credential ` + -Namespace root/microsoft/windows/DesiredStateConfiguration ` + -Property @{ + UserName = [String]$appPool.processModel.userName + Password = [String]$appPool.processModel.password + } } + + + $returnValue = @{ + Credential = $cimCredential + } + + $PropertyData.Where( + { + $_.Name -ne 'restartSchedule' + } + ).ForEach( + { + $property = Get-Property -Object $appPool -PropertyName $_.Path + $returnValue.Add($_.Name, $property) + } + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $returnValue.Add('restartSchedule', $restartScheduleCurrent) + + return $returnValue } -function Set-TargetResource -{ +function Set-TargetResource { <# .SYNOPSIS This will set the desired state @@ -57,24 +160,288 @@ function Set-TargetResource $ApplyTo, [Parameter()] - [ValidateSet('','v2.0','v4.0')] + [ValidateSet('', 'v2.0', 'v4.0')] [System.String] $ManagedRuntimeVersion, - [Parameter()] - [ValidateSet('ApplicationPoolIdentity','LocalService','LocalSystem','NetworkService')] - [System.String] - $IdentityType + + [Boolean] $autoStart, + + [String] $CLRConfigFile, + + [Boolean] $enable32BitAppOnWin64, + + [Boolean] $enableConfigurationOverride, + + [ValidateSet('Integrated', 'Classic')] + [String] $managedPipelineMode, + + [String] $managedRuntimeLoader, + + [Boolean] $passAnonymousToken, + + [ValidateSet('OnDemand', 'AlwaysRunning')] + [String] $startMode, + + [ValidateRange(10, 65535)] + [UInt32] $queueLength, + + [ValidateSet('NoAction', 'KillW3wp', 'Throttle', 'ThrottleUnderLoad')] + [String] $cpuAction, + + [ValidateRange(0, 100000)] + [UInt32] $cpuLimit, + + [ValidateScript( { + ([ValidateRange(0, 1440)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $cpuResetInterval, + + [Boolean] $cpuSmpAffinitized, + + [UInt32] $cpuSmpProcessorAffinityMask, + + [UInt32] $cpuSmpProcessorAffinityMask2, + + [ValidateSet( + 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', + 'NetworkService', 'SpecificUser' + )] + [String] $identityType, + + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential, + + [ValidateScript( { + ([ValidateRange(0, 43200)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $idleTimeout, + + [ValidateSet('Terminate', 'Suspend')] + [String] $idleTimeoutAction, + + [Boolean] $loadUserProfile, + + [String] $logEventOnProcessModel, + + [ValidateSet('LogonBatch', 'LogonService')] + [String] $logonType, + + [Boolean] $manualGroupMembership, + + [ValidateRange(0, 2147483647)] + [UInt32] $maxProcesses, + + [Boolean] $pingingEnabled, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingInterval, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingResponseTime, + + [Boolean] $setProfileEnvironment, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $shutdownTimeLimit, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $startupTimeLimit, + + [String] $orphanActionExe, + + [String] $orphanActionParams, + + [Boolean] $orphanWorkerProcess, + + [ValidateSet('HttpLevel', 'TcpLevel')] + [String] $loadBalancerCapabilities, + + [Boolean] $rapidFailProtection, + + [ValidateScript( { + ([ValidateRange(1, 144000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $rapidFailProtectionInterval, + + [ValidateRange(0, 2147483647)] + [UInt32] $rapidFailProtectionMaxCrashes, + + [String] $autoShutdownExe, + + [String] $autoShutdownParams, + + [Boolean] $disallowOverlappingRotation, + + [Boolean] $disallowRotationOnConfigChange, + + [String] $logEventOnRecycle, + + [UInt32] $restartMemoryLimit, + + [UInt32] $restartPrivateMemoryLimit, + + [UInt32] $restartRequestsLimit, + + [ValidateScript( { + ([ValidateRange(0, 432000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $restartTimeLimit, + + [ValidateScript( { + ($_ -eq '') -or + (& { + ([ValidateRange(0, 86399)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + }) + })] + [String[]] $restartSchedule ) Assert-Module + + $appPool = Get-AppPoolDefault + + # Set Application Pool Properties + + Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) + + $PropertyData.Where( + { + ($_.Name -in $PSBoundParameters.Keys) -and + ($_.Name -notin @('restartSchedule')) + } + ).ForEach( + { + $propertyName = $_.Name + $propertyPath = $_.Path + $property = Get-Property -Object $appPool -PropertyName $propertyPath + + if ( + $PSBoundParameters[$propertyName] -ne $property + ) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f $propertyName + ) + Invoke-AppCmd -ArgumentList ( + '/{0}:{1}' -f $propertyPath, $PSBoundParameters[$propertyName] + ) + } + } + ) + + if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters['identityType'] -eq 'SpecificUser') { + if ($appPool.processModel.userName -ne $Credential.UserName) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f 'Credential (userName)' + ) + + Invoke-AppCmd -ArgumentList ( + '/processModel.userName:{0}' -f $Credential.UserName + ) + } + + $clearTextPassword = $Credential.GetNetworkCredential().Password + + if ($appPool.processModel.password -cne $clearTextPassword) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f 'Credential (password)' + ) + + Invoke-AppCmd -ArgumentList ( + '/processModel.password:{0}' -f $clearTextPassword + ) + } + } + else { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeIgnored']) + } + } + + # Ensure userName and password are cleared if identityType isn't set to SpecificUser. + if ( + ( + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $true) -and + ($PSBoundParameters['identityType'] -ne 'SpecificUser') + ) -or + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $false) -and + ($appPool.processModel.identityType -ne 'SpecificUser') + ) + ) -and + ( + ([String]::IsNullOrEmpty($appPool.processModel.userName) -eq $false) -or + ([String]::IsNullOrEmpty($appPool.processModel.password) -eq $false) + ) + ) { + Write-Verbose -Message ($LocalizedData['VerboseClearCredential']) + + Invoke-AppCmd -ArgumentList '/processModel.userName:' + Invoke-AppCmd -ArgumentList '/processModel.password:' + } - Set-Value -Path '' -Name 'managedRuntimeVersion' -NewValue $ManagedRuntimeVersion - Set-Value -Path 'processModel' -Name 'identityType' -NewValue $IdentityType + if ($PSBoundParameters.ContainsKey('restartSchedule')) { + # Normalize the restartSchedule array values. + $restartScheduleDesired = [String[]]@( + $restartSchedule.Where( + { + $_ -ne '' + } + ).ForEach( + { + [TimeSpan]::Parse($_).ToString('hh\:mm\:ss') + } + ) | + Select-Object -Unique + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + Compare-Object -ReferenceObject $restartScheduleDesired ` + -DifferenceObject $restartScheduleCurrent | + ForEach-Object -Process { + + # Add value + if ($_.SideIndicator -eq '<=') { + Write-Verbose -Message ( + $LocalizedData['VerboseRestartScheduleValueAdd'] -f + $_.InputObject + ) + + Invoke-AppCmd -ArgumentList ( + "/+recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + ) + } + # Remove value + else { + Write-Verbose -Message ( + $LocalizedData['VerboseRestartScheduleValueRemove'] -f + $_.InputObject + ) + + Invoke-AppCmd -ArgumentList ( + "/-recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + ) + } + + } + } + } -function Test-TargetResource -{ +function Test-TargetResource { <# .SYNOPSIS This tests the desired state. If the state is not correct it will return $false. @@ -92,153 +459,354 @@ function Test-TargetResource $ApplyTo, [Parameter()] - [ValidateSet('','v2.0','v4.0')] + [ValidateSet('', 'v2.0', 'v4.0')] [System.String] $ManagedRuntimeVersion, - [Parameter()] - [ValidateSet('ApplicationPoolIdentity','LocalService','LocalSystem','NetworkService')] - [System.String] - $IdentityType + [Boolean] $autoStart, + + [String] $CLRConfigFile, + + [Boolean] $enable32BitAppOnWin64, + + [Boolean] $enableConfigurationOverride, + + [ValidateSet('Integrated', 'Classic')] + [String] $managedPipelineMode, + + [String] $managedRuntimeLoader, + + [Boolean] $passAnonymousToken, + + [ValidateSet('OnDemand', 'AlwaysRunning')] + [String] $startMode, + + [ValidateRange(10, 65535)] + [UInt32] $queueLength, + + [ValidateSet('NoAction', 'KillW3wp', 'Throttle', 'ThrottleUnderLoad')] + [String] $cpuAction, + + [ValidateRange(0, 100000)] + [UInt32] $cpuLimit, + + [ValidateScript( { + ([ValidateRange(0, 1440)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $cpuResetInterval, + + [Boolean] $cpuSmpAffinitized, + + [UInt32] $cpuSmpProcessorAffinityMask, + + [UInt32] $cpuSmpProcessorAffinityMask2, + + [ValidateSet( + 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', + 'NetworkService', 'SpecificUser' + )] + [String] $identityType, + + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential, + + [ValidateScript( { + ([ValidateRange(0, 43200)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $idleTimeout, + + [ValidateSet('Terminate', 'Suspend')] + [String] $idleTimeoutAction, + + [Boolean] $loadUserProfile, + + [String] $logEventOnProcessModel, + + [ValidateSet('LogonBatch', 'LogonService')] + [String] $logonType, + + [Boolean] $manualGroupMembership, + + [ValidateRange(0, 2147483647)] + [UInt32] $maxProcesses, + + [Boolean] $pingingEnabled, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingInterval, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingResponseTime, + + [Boolean] $setProfileEnvironment, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $shutdownTimeLimit, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $startupTimeLimit, + + [String] $orphanActionExe, + + [String] $orphanActionParams, + + [Boolean] $orphanWorkerProcess, + + [ValidateSet('HttpLevel', 'TcpLevel')] + [String] $loadBalancerCapabilities, + + [Boolean] $rapidFailProtection, + + [ValidateScript( { + ([ValidateRange(1, 144000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $rapidFailProtectionInterval, + + [ValidateRange(0, 2147483647)] + [UInt32] $rapidFailProtectionMaxCrashes, + + [String] $autoShutdownExe, + + [String] $autoShutdownParams, + + [Boolean] $disallowOverlappingRotation, + + [Boolean] $disallowRotationOnConfigChange, + + [String] $logEventOnRecycle, + + [UInt32] $restartMemoryLimit, + + [UInt32] $restartPrivateMemoryLimit, + + [UInt32] $restartRequestsLimit, + + [ValidateScript( { + ([ValidateRange(0, 432000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $restartTimeLimit, + + [ValidateScript( { + ($_ -eq '') -or + (& { + ([ValidateRange(0, 86399)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + }) + })] + [String[]] $restartSchedule ) Assert-Module - if (-not((Confirm-Value -Path '' ` - -Name 'managedRuntimeVersion' ` - -NewValue $ManagedRuntimeVersion))) - { - return $false + $inDesiredState = $true + + $appPool = Get-AppPoolDefault + + $PropertyData.Where( + { + ($_.Name -in $PSBoundParameters.Keys) -and + ($_.Name -ne 'restartSchedule') + } + ).ForEach( + { + $propertyName = $_.Name + $propertyPath = $_.Path + $property = Get-Property -Object $appPool -PropertyName $propertyPath + + if ( + $PSBoundParameters[$propertyName] -ne $property + ) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f $propertyName + ) + + $inDesiredState = $false + } + } + ) + + + if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters['identityType'] -eq 'SpecificUser') { + if ($appPool.processModel.userName -ne $Credential.UserName) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f + 'Credential (userName)' + ) + + $inDesiredState = $false + } + + $clearTextPassword = $Credential.GetNetworkCredential().Password + + if ($appPool.processModel.password -cne $clearTextPassword) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f + 'Credential (password)' + ) + + $inDesiredState = $false + } + } + else { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeIgnored']) + } } - if (-not((Confirm-Value -Path 'processModel' ` - -Name 'identityType' ` - -NewValue $IdentityType))) - { - return $false + # Ensure userName and password are cleared if identityType isn't set to SpecificUser. + if ( + ( + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $true) -and + ($PSBoundParameters['identityType'] -ne 'SpecificUser') + ) -or + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $false) -and + ($appPool.processModel.identityType -ne 'SpecificUser') + ) + ) -and + ( + ([String]::IsNullOrEmpty($appPool.processModel.userName) -eq $false) -or + ([String]::IsNullOrEmpty($appPool.processModel.password) -eq $false) + ) + ) { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeCleared']) + + $inDesiredState = $false + } + + if ($PSBoundParameters.ContainsKey('restartSchedule')) { + # Normalize the restartSchedule array values. + $restartScheduleDesired = [String[]]@( + $restartSchedule.Where( + { + $_ -ne '' + } + ).ForEach( + { + [TimeSpan]::Parse($_).ToString('hh\:mm\:ss') + } + ) | + Select-Object -Unique + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + if ( + Compare-Object -ReferenceObject $restartScheduleDesired ` + -DifferenceObject $restartScheduleCurrent + ) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f 'restartSchedule' + ) + + $inDesiredState = $false + } } - return $true + + if ($inDesiredState -eq $true) { + Write-Verbose -Message ($LocalizedData['VerboseResourceInDesiredState']) + } + else { + Write-Verbose -Message ($LocalizedData['VerboseResourceNotInDesiredState']) + } + + return $inDesiredState } #region Helper Functions -function Confirm-Value -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param + +function Get-Property { + param ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, + [object] $Object, + [string] $PropertyName) - [Parameter(Mandatory = $true)] - [System.String] - $Name, + $parts = $PropertyName.Split('.') + $firstPart = $parts[0] - [Parameter()] - [System.String] - $NewValue - ) - - if (-not($NewValue)) - { - # if no new value was specified, we assume this value is okay. - return $true - } + $value = $Object.$firstPart + if ($parts.Count -gt 1) { + $newParts = @() + 1..($parts.Count - 1) | ForEach-Object { + $newParts += $parts[$_] + } - $existingValue = Get-Value -Path $Path -Name $Name - if ($existingValue -ne $NewValue) - { - return $false + $newName = ($newParts -join '.') + return Get-Property -Object $value -PropertyName $newName } - else - { - $relPath = $Path + '/' + $Name - Write-Verbose($LocalizedData.ValueOk -f $relPath,$NewValue); - return $true + else { + return $value } -} +} + +<# + .SYNOPSIS + Runs appcmd.exe - if there's an error then the application will terminate + + .PARAMETER ArgumentList + Optional list of string arguments to be passed into appcmd.exe -function Set-Value -{ +#> +function Invoke-AppCmd { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $NewValue + [String[]] $ArgumentList ) - # if the variable doesn't exist, the user doesn't want to change this value - if (-not($NewValue)) - { - return - } + <# + This is a local preference for the function which will terminate + the program if there's an error invoking appcmd.exe + #> + $ErrorActionPreference = 'Stop' - $existingValue = Get-Value -Path $Path -Name $Name - if ($existingValue -ne $NewValue) - { - if ($Path -ne '') - { - $Path = '/' + $Path - } + $appcmdFilePath = "$env:SystemRoot\System32\inetsrv\appcmd.exe" + $allArguments = @("set", "config", "-section:applicationPools") + $ArgumentList + + $appcmdResult = $(& $appcmdFilePath $allArguments) + Write-Verbose -Message $($appcmdResult).ToString() - Set-WebConfigurationProperty ` - -PSPath 'MACHINE/WEBROOT/APPHOST' ` - -Filter "system.applicationHost/applicationPools/applicationPoolDefaults$Path" ` - -Name $Name ` - -Value "$NewValue" - - $relPath = $Path + '/' + $Name - Write-Verbose($LocalizedData.SettingValue -f $relPath,$NewValue); + if ($LASTEXITCODE -ne 0) { + $errorMessage = $LocalizedData['ErrorAppCmdNonZeroExitCode'] -f $LASTEXITCODE + + New-TerminatingError -ErrorId 'ErrorAppCmdNonZeroExitCode' ` + -ErrorMessage $errorMessage ` + -ErrorCategory 'InvalidResult' } } -function Get-Value -{ - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, - [Parameter(Mandatory = $true)] - [System.String] - $Name - ) +function Get-AppPoolDefault { + # XPath -Filter is case-sensitive. Use Where-Object to get the target application pool by name. + $appPool = Get-WebConfiguration ` + -PSPath 'MACHINE/WEBROOT/APPHOST' ` + -Filter '/system.applicationHost/applicationPools/applicationPoolDefaults' + - if ($Path -ne '') - { - $Path = '/' + $Path + if ($null -eq $appPool) { + New-TerminatingError -ErrorId 'ErrorAppPoolDefaultsNotFound' ` + -ErrorMessage $LocalizedData['ErrorAppPoolDefaultsNotFound'] ` + -ErrorCategory 'InvalidResult' } - $result = Get-WebConfigurationProperty ` - -PSPath 'MACHINE/WEBROOT/APPHOST' ` - -Filter "system.applicationHost/applicationPools/applicationPoolDefaults$Path" ` - -Name $Name + Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) - if ($result -is [Microsoft.IIs.PowerShell.Framework.ConfigurationAttribute]) - { - return $result.Value - } else { - return $result - } + return $appPool } #endregion -Export-ModuleMember -Function *-TargetResource +Export-ModuleMember -Function *-TargetResource \ No newline at end of file diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof index 99b2f22c9..6b4991147 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof @@ -3,6 +3,54 @@ class MSFT_xWebAppPoolDefaults : OMI_BaseResource { [Key, Description("Dummy value because we need a key, always 'Machine'"), ValueMap{"Machine"}, Values{"Machine"}] string ApplyTo; - [write, Description("applicationPools/applicationPoolDefaults/managedRuntimeVersion"), ValueMap{"","v2.0","v4.0"}, Values{"","v2.0","v4.0"}] string ManagedRuntimeVersion; - [write, Description("applicationPools/applicationPoolDefaults/processModel/identityType"), ValueMap{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService"}, Values{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService"}] string IdentityType; -}; + + [Write, Description("When set to true, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started.")] Boolean autoStart; + [Write, Description("Indicates the .NET configuration file for the application pool.")] String CLRConfigFile; + [Write, Description("When set to true, enables a 32-bit application to run on a computer that runs a 64-bit version of Windows.")] Boolean enable32BitAppOnWin64; + [Write, Description("When set to true, indicates that delegated settings in Web.config files will processed for applications within this application pool. When set to false, all settings in Web.config files will be ignored for this application pool.")] Boolean enableConfigurationOverride; + [Write, Description("Indicates the request-processing mode that is used to process requests for managed content. The values that are allowed for this property are: Integrated, Classic."), ValueMap{"Integrated","Classic"},Values{"Integrated","Classic"}] String managedPipelineMode; + [Write, Description("Indicates the managed loader to use for pre-loading the application pool.")] String managedRuntimeLoader; + [Write, Description("Indicates the CLR version to be used by the application pool. The values that are allowed for this property are: v4.0, v2.0, and ''."), ValueMap{"v4.0","v2.0",""},Values{"v4.0","v2.0",""}] String managedRuntimeVersion; + [Write, Description("When set to true, the Windows Process Activation Service (WAS) creates and passes a token for the built-in IUSR anonymous user account to the Anonymous authentication module. The Anonymous authentication module uses the token to impersonate the built-in account. When this property is set to false, the token will not be passed.")] Boolean passAnonymousToken; + [Write, Description("Indicates the startup type for the application pool. The values that are allowed for this property are: OnDemand, AlwaysRunning."), ValueMap{"OnDemand","AlwaysRunning"},Values{"OnDemand","AlwaysRunning"}] String startMode; + [Write, Description("Indicates the maximum number of requests that HTTP.sys will queue for the application pool. The value must be a valid integer between 10 and 65535.")] UInt32 queueLength; + [Write, Description("Configures the action that IIS takes when a worker process exceeds its configured CPU limit. The values that are allowed for this property are: NoAction, KillW3wp, Throttle, and ThrottleUnderLoad."), ValueMap{"NoAction","KillW3wp","Throttle","ThrottleUnderLoad"},Values{"NoAction","KillW3wp","Throttle","ThrottleUnderLoad"}] String cpuAction; + [Write, Description("Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in the application pool are allowed to consume over a period of time as indicated by the cpuResetInterval property. The value must be a valid integer between 0 and 100000.")] UInt32 cpuLimit; + [Write, Description("Indicates the reset period (in minutes) for CPU monitoring and throttling limits on the application pool. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 1440. Setting the value of this property to 0 disables CPU monitoring.")] String cpuResetInterval; + [Write, Description("Indicates whether a particular worker process assigned to the application pool should also be assigned to a given CPU.")] Boolean cpuSmpAffinitized; + [Write, Description("Indicates the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. Before this property takes effect, the cpuSmpAffinitized property must be set to true for the application pool. The value must be a valid integer between 0 and 4294967295.")] UInt32 cpuSmpProcessorAffinityMask; + [Write, Description("Indicates the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. Before this property takes effect, the cpuSmpAffinitized property must be set to true for the application pool. The value must be a valid integer between 0 and 4294967295.")] UInt32 cpuSmpProcessorAffinityMask2; + [Write, Description("Indicates the account identity under which the application pool runs. The values that are allowed for this property are: ApplicationPoolIdentity, LocalService, LocalSystem, NetworkService, and SpecificUser."), ValueMap{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"}, Values{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"}] String identityType; + [Write, Description("Indicates the custom account crededentials. This property is only valid when the identityType property is set to SpecificUser."), EmbeddedInstance("MSFT_Credential")] String Credential; + [Write, Description("Indicates the amount of time (in minutes) a worker process will remain idle before it shuts down. The value must be a string representation of a TimeSpan value and must be less than the restartTimeLimit property value. The valid range (in minutes) is 0 to 43200.")] String idleTimeout; + [Write, Description("Indicates the action to perform when the idle timeout duration has been reached. The values that are allowed for this property are: Terminate, Suspend."), ValueMap{"Terminate","Suspend"}, Values{"Terminate","Suspend"}] String idleTimeoutAction; + [Write, Description("Indicates whether IIS loads the user profile for the application pool identity.")] Boolean loadUserProfile; + [Write, Description("Indicates that IIS should generate an event log entry for each occurrence of the specified process model events.")] String logEventOnProcessModel; + [Write, Description("Indicates the logon type for the process identity. The values that are allowed for this property are: LogonBatch, LogonService."), ValueMap{"LogonBatch","LogonService"},Values{"LogonBatch","LogonService"}] String logonType; + [Write, Description("Indicates whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token.")] Boolean manualGroupMembership; + [Write, Description("Indicates the maximum number of worker processes that would be used for the application pool. The value must be a valid integer between 0 and 2147483647.")] UInt32 maxProcesses; + [Write, Description("Indicates whether pinging (health monitoring) is enabled for the worker process(es) serving this application pool.")] Boolean pingingEnabled; + [Write, Description("Indicates the period of time (in seconds) between health monitoring pings sent to the worker process(es) serving this application pool. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String pingInterval; + [Write, Description("Indicates the maximum time (in seconds) that a worker process is given to respond to a health monitoring ping. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String pingResponseTime; + [Write, Description("Indicates the environment to be set based on the user profile for the new process.")] Boolean setProfileEnvironment; + [Write, Description("Indicates the period of time (in seconds) a worker process is given to finish processing requests and shut down. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String shutdownTimeLimit; + [Write, Description("Indicates the period of time (in seconds) a worker process is given to start up and initialize. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String startupTimeLimit; + [Write, Description("Indicates an executable to run when a worker process is orphaned.")] String orphanActionExe; + [Write, Description("Indicates parameters for the executable that is specified in the orphanActionExe property.")] String orphanActionParams; + [Write, Description("Indicates whether to assign a worker process to an orphan state instead of terminating it when the application pool fails. If true, an unresponsive worker process will be orphaned instead of terminated.")] Boolean orphanWorkerProcess; + [Write, Description("Indicates the response behavior of a service when it is unavailable. The values that are allowed for this property are: HttpLevel, TcpLevel. If set to HttpLevel and the application pool is stopped, HTTP.sys will return HTTP 503 error. If set to TcpLevel, HTTP.sys will reset the connection."), ValueMap{"HttpLevel","TcpLevel"},Values{"HttpLevel","TcpLevel"}] String loadBalancerCapabilities; + [Write, Description("Indicates whether rapid-fail protection is enabled. If true, the application pool is shut down if there are a specified number of worker process crashes within a specified time period.")] Boolean rapidFailProtection; + [Write, Description("Indicates the time interval (in minutes) during which the specified number of worker process crashes must occur before the application pool is shut down by rapid-fail protection. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 1 to 144000.")] String rapidFailProtectionInterval; + [Write, Description("Indicates the maximum number of worker process crashes permitted before the application pool is shut down by rapid-fail protection. The value must be a valid integer between 0 and 2147483647.")] UInt32 rapidFailProtectionMaxCrashes; + [Write, Description("Indicates an executable to run when the application pool is shut down by rapid-fail protection.")] String autoShutdownExe; + [Write, Description("Indicates parameters for the executable that is specified in the autoShutdownExe property.")] String autoShutdownParams; + [Write, Description("Indicates whether the W3SVC service should start another worker process to replace the existing worker process while that process is shutting down. If true, the application pool recycle will happen such that the existing worker process exits before another worker process is created.")] Boolean disallowOverlappingRotation; + [Write, Description("Indicates whether the W3SVC service should rotate worker processes in the application pool when the configuration has changed. If true, the application pool will not recycle when its configuration is changed.")] Boolean disallowRotationOnConfigChange; + [Write, Description("Indicates that IIS should generate an event log entry for each occurrence of the specified recycling events.")] String logEventOnRecycle; + [Write, Description("Indicates the maximum amount of virtual memory (in KB) a worker process can consume before causing the application pool to recycle. The value must be a valid integer between 0 and 4294967295. A value of 0 means there is no limit.")] UInt32 restartMemoryLimit; + [Write, Description("Indicates the maximum amount of private memory (in KB) a worker process can consume before causing the application pool to recycle. The value must be a valid integer between 0 and 4294967295. A value of 0 means there is no limit.")] UInt32 restartPrivateMemoryLimit; + [Write, Description("Indicates the maximum number of requests the application pool can process before it is recycled. The value must be a valid integer between 0 and 4294967295. A value of 0 means the application pool can process an unlimited number of requests.")] UInt32 restartRequestsLimit; + [Write, Description("Indicates the period of time (in minutes) after which the application pool will recycle. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 432000. A value of 0 means the application pool does not recycle on a regular interval.")] String restartTimeLimit; + [Write, Description("Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. The value must be an array of string representations of TimeSpan values. TimeSpan values must be between 00:00:00 and 23:59:59 seconds inclusive, with a granularity of 60 seconds. Setting the value of this property to '' disables the schedule.")] String restartSchedule[]; + +}; \ No newline at end of file From bfcd8b3b3297e8d9307808cf2fbc3fd1e36d9179 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:36:08 +0300 Subject: [PATCH 09/22] Unit tests for application pool defaults with all attributes --- Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 | 2856 ++++++++++++++++- 1 file changed, 2749 insertions(+), 107 deletions(-) diff --git a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 index c6161a95f..e39504357 100644 --- a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 +++ b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 @@ -1,194 +1,2836 @@ -#region HEADER +#requires -Version 4.0 + +# Suppressing this rule because IIS requires PlainText for one of the functions used in this test +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param () $script:DSCModuleName = 'xWebAdministration' $script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' -# Unit Test Template Version: 1.2.1 +#region HEADER $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone','https://github.com/PowerShell/DscResource.Tests.git', ` - (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests')) + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } -Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path ` - -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'Tests\MockWebAdministrationWindowsFeature.psm1') $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` -TestType Unit - -#endregion HEADER - -function Invoke-TestSetup { -} - -function Invoke-TestCleanup { - Restore-TestEnvironment -TestEnvironment $TestEnvironment -} +#endregion # Begin Testing try { - Invoke-TestSetup + #region Pester Tests InModuleScope $script:DSCResourceName { Describe "$($script:DSCResourceName)\Get-TargetResource" { - Context 'Get application pool defaults' { + Mock Assert-Module + + Context 'Application pool defaults' { + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } processModel = @{ identityType = 'SpecificUser' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = 'P@$$w0rd' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = 'CONTOSO\JDoe' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } } } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] - } + $result = Get-TargetResource -ApplyTo 'Machine' + + It 'Should return the autoStart property' { + $result.autoStart | Should Be $mockAppPoolDefaults.autoStart } - $result = Get-TargetResource -ApplyTo 'Machine' + It 'Should return the CLRConfigFile property' { + $result.CLRConfigFile | Should Be $mockAppPoolDefaults.CLRConfigFile + } + + It 'Should return the enable32BitAppOnWin64 property' { + $result.enable32BitAppOnWin64 | Should Be $mockAppPoolDefaults.enable32BitAppOnWin64 + } + + It 'Should return the enableConfigurationOverride property' { + $result.enableConfigurationOverride | Should Be $mockAppPoolDefaults.enableConfigurationOverride + } + + It 'Should return the managedPipelineMode property' { + $result.managedPipelineMode | Should Be $mockAppPoolDefaults.managedPipelineMode + } + + It 'Should return the managedRuntimeLoader property' { + $result.managedRuntimeLoader | Should Be $mockAppPoolDefaults.managedRuntimeLoader + } + + It 'Should return the managedRuntimeVersion property' { + $result.managedRuntimeVersion | Should Be $mockAppPoolDefaults.managedRuntimeVersion + } + + It 'Should return the passAnonymousToken property' { + $result.passAnonymousToken | Should Be $mockAppPoolDefaults.passAnonymousToken + } + + It 'Should return the startMode property' { + $result.startMode | Should Be $mockAppPoolDefaults.startMode + } + + It 'Should return the queueLength property' { + $result.queueLength | Should Be $mockAppPoolDefaults.queueLength + } + + It 'Should return the cpuAction property' { + $result.cpuAction | Should Be $mockAppPoolDefaults.cpu.action + } + + It 'Should return the cpuLimit property' { + $result.cpuLimit | Should Be $mockAppPoolDefaults.cpu.limit + } + + It 'Should return the cpuResetInterval property' { + $result.cpuResetInterval | Should Be $mockAppPoolDefaults.cpu.resetInterval + } + + It 'Should return the cpuSmpAffinitized property' { + $result.cpuSmpAffinitized | Should Be $mockAppPoolDefaults.cpu.smpAffinitized + } + + It 'Should return the cpuSmpProcessorAffinityMask property' { + $result.cpuSmpProcessorAffinityMask | Should Be $mockAppPoolDefaults.cpu.smpProcessorAffinityMask + } + + It 'Should return the cpuSmpProcessorAffinityMask2 property' { + $result.cpuSmpProcessorAffinityMask2 | Should Be $mockAppPoolDefaults.cpu.smpProcessorAffinityMask2 + } + + It 'Should return the identityType property' { + $result.identityType | Should Be $mockAppPoolDefaults.processModel.identityType + } + + It 'Should return the Credential (userName) property' { + # Get-DscConfiguration returns MSFT_Credential with empty UserName + $result.Credential.userName | Should Be $mockAppPoolDefaults.processModel.userName + } + + It 'Should return the Credential (password) property' { + # Get-DscConfiguration returns MSFT_Credential with empty Password + $result.Credential.Password | Should Be $mockAppPoolDefaults.processModel.password + } + + It 'Should return the idleTimeout property' { + $result.idleTimeout | Should Be $mockAppPoolDefaults.processModel.idleTimeout + } + + It 'Should return the idleTimeoutAction property' { + $result.idleTimeoutAction | Should Be $mockAppPoolDefaults.processModel.idleTimeoutAction + } + + It 'Should return the loadUserProfile property' { + $result.loadUserProfile | Should Be $mockAppPoolDefaults.processModel.loadUserProfile + } + + It 'Should return the logonType property' { + $result.logonType | Should Be $mockAppPoolDefaults.processModel.logonType + } + + It 'Should return the logEventOnProcessModel property' { + $result.logEventOnProcessModel | Should Be $mockAppPoolDefaults.processModel.logEventOnProcessModel + } + + It 'Should return the manualGroupMembership property' { + $result.manualGroupMembership | Should Be $mockAppPoolDefaults.processModel.manualGroupMembership + } + + It 'Should return the maxProcesses property' { + $result.maxProcesses | Should Be $mockAppPoolDefaults.processModel.maxProcesses + } + + It 'Should return the pingingEnabled property' { + $result.pingingEnabled | Should Be $mockAppPoolDefaults.processModel.pingingEnabled + } + + It 'Should return the pingInterval property' { + $result.pingInterval | Should Be $mockAppPoolDefaults.processModel.pingInterval + } + + It 'Should return the pingResponseTime property' { + $result.pingResponseTime | Should Be $mockAppPoolDefaults.processModel.pingResponseTime + } + + It 'Should return the setProfileEnvironment property' { + $result.setProfileEnvironment | Should Be $mockAppPoolDefaults.processModel.setProfileEnvironment + } + + It 'Should return the shutdownTimeLimit property' { + $result.shutdownTimeLimit | Should Be $mockAppPoolDefaults.processModel.shutdownTimeLimit + } + + It 'Should return the startupTimeLimit property' { + $result.startupTimeLimit | Should Be $mockAppPoolDefaults.processModel.startupTimeLimit + } + + It 'Should return the orphanActionExe property' { + $result.orphanActionExe | Should Be $mockAppPoolDefaults.failure.orphanActionExe + } + + It 'Should return the orphanActionParams property' { + $result.orphanActionParams | Should Be $mockAppPoolDefaults.failure.orphanActionParams + } + + It 'Should return the orphanWorkerProcess property' { + $result.orphanWorkerProcess | Should Be $mockAppPoolDefaults.failure.orphanWorkerProcess + } + + It 'Should return the loadBalancerCapabilities property' { + $result.loadBalancerCapabilities | Should Be $mockAppPoolDefaults.failure.loadBalancerCapabilities + } + + It 'Should return the rapidFailProtection property' { + $result.rapidFailProtection | Should Be $mockAppPoolDefaults.failure.rapidFailProtection + } + + It 'Should return the rapidFailProtectionInterval property' { + $result.rapidFailProtectionInterval | Should Be $mockAppPoolDefaults.failure.rapidFailProtectionInterval + } + + It 'Should return the rapidFailProtectionMaxCrashes property' { + $result.rapidFailProtectionMaxCrashes | Should Be $mockAppPoolDefaults.failure.rapidFailProtectionMaxCrashes + } + + It 'Should return the autoShutdownExe property' { + $result.autoShutdownExe | Should Be $mockAppPoolDefaults.failure.autoShutdownExe + } + + It 'Should return the autoShutdownParams property' { + $result.autoShutdownParams | Should Be $mockAppPoolDefaults.failure.autoShutdownParams + } + + It 'Should return the disallowOverlappingRotation property' { + $result.disallowOverlappingRotation | Should Be $mockAppPoolDefaults.recycling.disallowOverlappingRotation + } + + It 'Should return the disallowRotationOnConfigChange property' { + $result.disallowRotationOnConfigChange | Should Be $mockAppPoolDefaults.recycling.disallowRotationOnConfigChange + } + + It 'Should return the logEventOnRecycle property' { + $result.logEventOnRecycle | Should Be $mockAppPoolDefaults.recycling.logEventOnRecycle + } + + It 'Should return the restartMemoryLimit property' { + $result.restartMemoryLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.memory + } + + It 'Should return the restartPrivateMemoryLimit property' { + $result.restartPrivateMemoryLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.privateMemory + } + + It 'Should return the restartRequestsLimit property' { + $result.restartRequestsLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.requests + } - It 'Should return managedRuntimeVersion' { - $result.managedRuntimeVersion | ` - Should Be $mockAppPoolDefaults.managedRuntimeVersion + It 'Should return the restartTimeLimit property' { + $result.restartTimeLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.time } - It 'Should return processModel\identityType' { - $result.identityType | ` - Should Be $mockAppPoolDefaults.processModel.identityType + It 'Should return the restartSchedule property' { + + $restartScheduleValues = [String[]]@( + @($mockAppPoolDefaults.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $compareSplat = @{ + ReferenceObject = [String[]]@($result.restartSchedule) + DifferenceObject = $restartScheduleValues + ExcludeDifferent = $true + IncludeEqual = $true + } + + $compareResult = Compare-Object @compareSplat + + $compareResult.Count -eq $restartScheduleValues.Count | Should Be $true + } + } + } - Describe "$($script:DSCResourceName)\Test-TargetResource" { + Describe "how '$($script:DSCResourceName)\Test-TargetResource' responds" { + + Mock Assert-Module + + Context 'Test target resource with no property specified' { - $mockAppPoolDefaults = @{ - managedRuntimeVersion = 'v4.0' - processModel = @{ - identityType = 'NetworkService' + $mockAppPoolDefaults = @{ } - } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] + It 'Should return True' { + Test-TargetResource -ApplyTo 'Machine' | + Should Be $true } + } - Context 'Application pool defaults correct' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'NetworkService' + Context 'All the properties match the desired state' { + + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } + processModel = @{ + identityType = 'SpecificUser' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = 'P@$$w0rD' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = 'CONTOSO\JDoe' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + $mockRestartSchedule = [String[]]@( + @($mockAppPoolDefaults.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $testParamsSplat = @{ + autoStart = $mockAppPoolDefaults.autoStart + CLRConfigFile = $mockAppPoolDefaults.CLRConfigFile + enable32BitAppOnWin64 = $mockAppPoolDefaults.enable32BitAppOnWin64 + enableConfigurationOverride = $mockAppPoolDefaults.enableConfigurationOverride + managedPipelineMode = $mockAppPoolDefaults.managedPipelineMode + managedRuntimeLoader = $mockAppPoolDefaults.managedRuntimeLoader + managedRuntimeVersion = $mockAppPoolDefaults.managedRuntimeVersion + passAnonymousToken = $mockAppPoolDefaults.passAnonymousToken + startMode = $mockAppPoolDefaults.startMode + queueLength = $mockAppPoolDefaults.queueLength + cpuAction = $mockAppPoolDefaults.cpu.action + cpuLimit = $mockAppPoolDefaults.cpu.limit + cpuResetInterval = $mockAppPoolDefaults.cpu.resetInterval + cpuSmpAffinitized = $mockAppPoolDefaults.cpu.smpAffinitized + cpuSmpProcessorAffinityMask = $mockAppPoolDefaults.cpu.smpProcessorAffinityMask + cpuSmpProcessorAffinityMask2 = $mockAppPoolDefaults.cpu.smpProcessorAffinityMask2 + identityType = $mockAppPoolDefaults.processModel.identityType + Credential = $mockCredential + idleTimeout = $mockAppPoolDefaults.processModel.idleTimeout + idleTimeoutAction = $mockAppPoolDefaults.processModel.idleTimeoutAction + loadUserProfile = $mockAppPoolDefaults.processModel.loadUserProfile + logEventOnProcessModel = $mockAppPoolDefaults.processModel.logEventOnProcessModel + logonType = $mockAppPoolDefaults.processModel.logonType + manualGroupMembership = $mockAppPoolDefaults.processModel.manualGroupMembership + maxProcesses = $mockAppPoolDefaults.processModel.maxProcesses + pingingEnabled = $mockAppPoolDefaults.processModel.pingingEnabled + pingInterval = $mockAppPoolDefaults.processModel.pingInterval + pingResponseTime = $mockAppPoolDefaults.processModel.pingResponseTime + setProfileEnvironment = $mockAppPoolDefaults.processModel.setProfileEnvironment + shutdownTimeLimit = $mockAppPoolDefaults.processModel.shutdownTimeLimit + startupTimeLimit = $mockAppPoolDefaults.processModel.startupTimeLimit + orphanActionExe = $mockAppPoolDefaults.failure.orphanActionExe + orphanActionParams = $mockAppPoolDefaults.failure.orphanActionParams + orphanWorkerProcess = $mockAppPoolDefaults.failure.orphanWorkerProcess + loadBalancerCapabilities = $mockAppPoolDefaults.failure.loadBalancerCapabilities + rapidFailProtection = $mockAppPoolDefaults.failure.rapidFailProtection + rapidFailProtectionInterval = $mockAppPoolDefaults.failure.rapidFailProtectionInterval + rapidFailProtectionMaxCrashes = $mockAppPoolDefaults.failure.rapidFailProtectionMaxCrashes + autoShutdownExe = $mockAppPoolDefaults.failure.autoShutdownExe + autoShutdownParams = $mockAppPoolDefaults.failure.autoShutdownParams + disallowOverlappingRotation = $mockAppPoolDefaults.recycling.disallowOverlappingRotation + disallowRotationOnConfigChange = $mockAppPoolDefaults.recycling.disallowRotationOnConfigChange + logEventOnRecycle = $mockAppPoolDefaults.recycling.logEventOnRecycle + restartMemoryLimit = $mockAppPoolDefaults.recycling.periodicRestart.memory + restartPrivateMemoryLimit = $mockAppPoolDefaults.recycling.periodicRestart.privateMemory + restartRequestsLimit = $mockAppPoolDefaults.recycling.periodicRestart.requests + restartTimeLimit = $mockAppPoolDefaults.recycling.periodicRestart.time + restartSchedule = $mockRestartSchedule + } It 'Should return True' { - $result | Should Be $true + Test-TargetResource -ApplyTo Machine @testParamsSplat | + Should Be $true } + } - Context 'Application pool different managedRuntimeVersion' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v2.0' ` - -IdentityType 'NetworkService' + Context 'Test the autoStart property' { + + $mockAppPoolDefaults = @{ + autoStart = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoStart $true | + Should Be $true + } - It 'Should return False' { - $result | Should Be $false + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoStart $false | + Should Be $false } + } - Context 'Application pool different processModel/@identityType' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'LocalSystem' + Context 'Test the CLRConfigFile property' { + + $mockAppPoolDefaults = @{ + CLRConfigFile = '' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -CLRConfigFile '' | + Should Be $true + } - It 'Should return False' { - $result | Should Be $false + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -CLRConfigFile 'C:\inetpub\temp\aspnet.config' | + Should Be $false } + } - Context 'Application pool no value for managedRuntimeVersion' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -IdentityType 'NetworkService' + Context 'Test the enable32BitAppOnWin64 property' { - It 'Should return True' { - $result | Should Be $true + $mockAppPoolDefaults = @{ + enable32BitAppOnWin64 = $false + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -enable32BitAppOnWin64 $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -enable32BitAppOnWin64 $true | + Should Be $false + } + + } + + Context 'Test the enableConfigurationOverride property' { + + $mockAppPoolDefaults = @{ + enableConfigurationOverride = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -enableConfigurationOverride $true | + Should Be $true } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -enableConfigurationOverride $false | + Should Be $false + } + } - } - Describe "$($script:DSCResourceName)\Set-TargetResource" { + Context 'Test the managedPipelineMode property' { + + $mockAppPoolDefaults = @{ + managedPipelineMode = 'Integrated' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedPipelineMode 'Integrated' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedPipelineMode 'Classic' | + Should Be $false + } + + } + + Context 'Test the managedRuntimeLoader property' { + + $mockAppPoolDefaults = @{ + managedRuntimeLoader = 'webengine4.dll' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeLoader 'webengine4.dll' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeLoader '' | + Should Be $false + } + + } + + Context 'Test the managedRuntimeVersion property' { + + $mockAppPoolDefaults = @{ + managedRuntimeVersion = 'v4.0' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeVersion 'v4.0' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeVersion 'v2.0' | + Should Be $false + } + + } + + Context 'Test the passAnonymousToken property' { + + $mockAppPoolDefaults = @{ + passAnonymousToken = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -passAnonymousToken $true | + Should Be $true + } - $mockAppPoolDefaults = @{ - managedRuntimeVersion = 'v4.0' - processModel = @{ - identityType = 'NetworkService' + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -passAnonymousToken $false | + Should Be $false } + } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Context 'Test the startMode property' { + + $mockAppPoolDefaults = @{ + startMode = 'OnDemand' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -startMode 'OnDemand' | + Should Be $true + } - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -startMode 'AlwaysRunning' | + Should Be $false } + } - Mock Set-WebConfigurationProperty -MockWith { } + Context 'Test the queueLength property' { + + $mockAppPoolDefaults = @{ + queueLength = 1000 + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - Context 'Application pool defaults correct' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'NetworkService' + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -queueLength 1000 | + Should Be $true + } - It 'Should not call Set-WebConfigurationProperty' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 0 + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -queueLength 2000 | + Should Be $false } + } - Context 'Application pool different managedRuntimeVersion' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v2.0' ` - -IdentityType 'NetworkService' + Context 'Test the cpuAction property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + action = 'NoAction' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuAction 'NoAction' | + Should Be $true + } - It 'Should call Set-WebConfigurationProperty once' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 1 ` - -ParameterFilter { $Name -eq 'managedRuntimeVersion' } + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuAction 'KillW3wp' | + Should Be $false } + } - Context 'Application pool different processModel/@identityType' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'LocalSystem' + Context 'Test the cpuLimit property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + limit = 0 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuLimit 0 | + Should Be $true + } - It 'Should call Set-WebConfigurationProperty once' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 1 ` - -ParameterFilter { $Name -eq 'identityType' } + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuLimit 90000 | + Should Be $false } + } - } - } -} -finally -{ - Invoke-TestCleanup + + Context 'Test the cpuResetInterval property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + resetInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuResetInterval '00:05:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuResetInterval '00:10:00' | + Should Be $false + } + + } + + Context 'Test the cpuSmpAffinitized property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpAffinitized = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpAffinitized $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpAffinitized $true | + Should Be $false + } + + } + + Context 'Test the cpuSmpProcessorAffinityMask property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask 4294967295 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask 1 | + Should Be $false + } + + } + + Context 'Test the cpuSmpProcessorAffinityMask2 property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask2 = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask2 4294967295 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask2 1 | + Should Be $false + } + + } + + Context 'Test the identityType property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'ApplicationPoolIdentity' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -identityType 'ApplicationPoolIdentity' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -identityType 'NetworkService' | + Should Be $false + } + + } + + Context 'Test the Credential property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'SpecificUser' + password = '1q2w3e4r' + userName = 'CONTOSO\JDoe' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when both the userName and the password properties match the desired state' { + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $true + + } + + It 'Should return False when the userName property does not match the desired state' { + + $mockUserName = 'CONTOSO\GFawkes' + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $false + + } + + It 'Should return False when the password property does not match the desired state' { + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = '5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $false + + } + + } + + Context 'Test the idleTimeout property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeout = '00:20:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeout '00:20:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeout '00:15:00' | + Should Be $false + } + + } + + Context 'Test the idleTimeoutAction property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeoutAction = 'Terminate' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeoutAction 'Terminate' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeoutAction 'Suspend' | + Should Be $false + } + + } + + Context 'Test the loadUserProfile property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + loadUserProfile = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -loadUserProfile $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -loadUserProfile $false | + Should Be $false + } + + } + + Context 'Test the logEventOnProcessModel property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logEventOnProcessModel = 'IdleTimeout' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnProcessModel 'IdleTimeout' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnProcessModel '' | + Should Be $false + } + + } + + Context 'Test the logonType property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logonType = 'LogonBatch' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logonType 'LogonBatch' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logonType 'LogonService' | + Should Be $false + } + + } + + Context 'Test the manualGroupMembership property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + manualGroupMembership = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -manualGroupMembership $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -manualGroupMembership $true | + Should Be $false + } + + } + + Context 'Test the maxProcesses property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + maxProcesses = 1 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -maxProcesses 1 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -maxProcesses 2 | + Should Be $false + } + + } + + Context 'Test the pingingEnabled property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingingEnabled = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingingEnabled $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingingEnabled $false | + Should Be $false + } + + } + + Context 'Test the pingInterval property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingInterval = '00:00:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingInterval '00:00:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingInterval '00:01:00' | + Should Be $false + } + + } + + Context 'Test the pingResponseTime property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingResponseTime = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingResponseTime '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingResponseTime '00:02:00' | + Should Be $false + } + + } + + Context 'Test the setProfileEnvironment property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + setProfileEnvironment = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -setProfileEnvironment $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -setProfileEnvironment $true | + Should Be $false + } + + } + + Context 'Test the shutdownTimeLimit property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + shutdownTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -shutdownTimeLimit '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -shutdownTimeLimit '00:02:00' | + Should Be $false + } + + } + + Context 'Test the startupTimeLimit property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + startupTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -startupTimeLimit '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -startupTimeLimit '00:02:00' | + Should Be $false + } + + } + + Context 'Test the orphanActionExe property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionExe '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionExe 'C:\inetpub\temp\orphanAction.exe' | + Should Be $false + } + + } + + Context 'Test the orphanActionParams property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionParams '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionParams '/orphanActionParam1' | + Should Be $false + } + + } + + Context 'Test the orphanWorkerProcess property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanWorkerProcess = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanWorkerProcess $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanWorkerProcess $true | + Should Be $false + } + + } + + Context 'Test the loadBalancerCapabilities property' { + + $mockAppPoolDefaults = @{ + failure = @{ + loadBalancerCapabilities = 'HttpLevel' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -loadBalancerCapabilities 'HttpLevel' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -loadBalancerCapabilities 'TcpLevel' | + Should Be $false + } + + } + + Context 'Test the rapidFailProtection property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtection = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtection $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtection $false | + Should Be $false + } + + } + + Context 'Test the rapidFailProtectionInterval property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionInterval '00:05:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionInterval '00:10:00' | + Should Be $false + } + + } + + Context 'Test the rapidFailProtectionMaxCrashes property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionMaxCrashes = 5 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionMaxCrashes 5 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionMaxCrashes 10 | + Should Be $false + } + + } + + Context 'Test the autoShutdownExe property' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownExe '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownExe 'C:\inetpub\temp\autoShutdown.exe' | + Should Be $false + } + + } + + Context 'Test the autoShutdownParams property' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownParams '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownParams '/autoShutdownParam1' | + Should Be $false + } + + } + + Context 'Test the disallowOverlappingRotation property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowOverlappingRotation = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -disallowOverlappingRotation $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -disallowOverlappingRotation $true | + Should Be $false + } + + } + + Context 'Test the disallowRotationOnConfigChange property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowRotationOnConfigChange = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -disallowRotationOnConfigChange $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -disallowRotationOnConfigChange $true | + Should Be $false + } + + } + + Context 'Test the logEventOnRecycle property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnRecycle 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnRecycle 'Time,Memory,PrivateMemory' | + Should Be $false + } + + } + + Context 'Test the restartMemoryLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + memory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartMemoryLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartMemoryLimit 1048576 | + Should Be $false + } + + } + + Context 'Test the restartPrivateMemoryLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + privateMemory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartPrivateMemoryLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartPrivateMemoryLimit 1048576 | + Should Be $false + } + + } + + Context 'Test the restartRequestsLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + requests = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartRequestsLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartRequestsLimit 1000 | + Should Be $false + } + + } + + Context 'Test the restartTimeLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + time = '1.05:00:00' + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartTimeLimit '1.05:00:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartTimeLimit '2.10:00:00' | + Should Be $false + } + + } + + Context 'Test the restartSchedule property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartSchedule @('04:00:00', '08:00:00') | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartSchedule @('') | + Should Be $false + } + + } + + } + + Describe "how '$($script:DSCResourceName)\Set-TargetResource' responds" { + + Mock -CommandName Assert-Module -MockWith {} + + Context 'All the properties need to be set' { + + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } + processModel = @{ + identityType = 'ApplicationPoolIdentity' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = '' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = '' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '02:00:00'} + @{value = '04:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $mockUserName = 'CONTOSO\GFawkes' + $mockPassword = '5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + $setParamsSplat = @{ + autoStart = $false + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + enable32BitAppOnWin64 = $true + enableConfigurationOverride = $false + managedPipelineMode = 'Classic' + managedRuntimeLoader = '' + managedRuntimeVersion = 'v2.0' + passAnonymousToken = $false + startMode = 'AlwaysRunning' + queueLength = 2000 + cpuAction = 'KillW3wp' + cpuLimit = 90000 + cpuResetInterval = '00:10:00' + cpuSmpAffinitized = $true + cpuSmpProcessorAffinityMask = 1 + cpuSmpProcessorAffinityMask2 = 1 + identityType = 'SpecificUser' + Credential = $mockCredential + idleTimeout = '00:15:00' + idleTimeoutAction = 'Suspend' + loadUserProfile = $false + logEventOnProcessModel = '' + logonType = 'LogonService' + manualGroupMembership = $true + maxProcesses = 2 + pingingEnabled = $false + pingInterval = '00:01:00' + pingResponseTime = '00:02:00' + setProfileEnvironment = $true + shutdownTimeLimit = '00:02:00' + startupTimeLimit = '00:02:00' + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + orphanActionParams = '/orphanActionParam1' + orphanWorkerProcess = $true + loadBalancerCapabilities = 'TcpLevel' + rapidFailProtection = $false + rapidFailProtectionInterval = '00:10:00' + rapidFailProtectionMaxCrashes = 10 + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + autoShutdownParams = '/autoShutdownParam1' + disallowOverlappingRotation = $true + disallowRotationOnConfigChange = $true + logEventOnRecycle = 'Time,Memory,PrivateMemory' + restartMemoryLimit = 1048576 + restartPrivateMemoryLimit = 1048576 + restartRequestsLimit = 1000 + restartTimeLimit = '2.10:00:00' + restartSchedule = @('06:00:00', '08:00:00') + } + + Mock Invoke-AppCmd + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call all the mocks' { + Assert-MockCalled Invoke-AppCmd -Exactly 52 + } + + } + + Context 'The autoStart property needs to be set' { + + $mockAppPoolDefaults = @{ + autoStart = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoStart = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/autoStart:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The CLRConfigFile property needs to be set' { + + $mockAppPoolDefaults = @{ + CLRConfigFile = '' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/CLRConfigFile:C:\inetpub\temp\aspnet.config'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The enable32BitAppOnWin64 property needs to be set' { + + $mockAppPoolDefaults = @{ + enable32BitAppOnWin64 = $false + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + enable32BitAppOnWin64 = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enable32BitAppOnWin64:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The enableConfigurationOverride property needs to be set' { + + $mockAppPoolDefaults = @{ + enableConfigurationOverride = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + enableConfigurationOverride = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enableConfigurationOverride:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedPipelineMode property needs to be set' { + + $mockAppPoolDefaults = @{ + managedPipelineMode = 'Integrated' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedPipelineMode = 'Classic' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedPipelineMode:Classic'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedRuntimeLoader property needs to be set' { + + $mockAppPoolDefaults = @{ + managedRuntimeLoader = 'webengine4.dll' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedRuntimeLoader = '' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeLoader:'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedRuntimeVersion property needs to be set' { + + $mockAppPoolDefaults = @{ + managedRuntimeVersion = 'v4.0' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedRuntimeVersion = 'v2.0' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeVersion:v2.0'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The passAnonymousToken property needs to be set' { + + $mockAppPoolDefaults = @{ + passAnonymousToken = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + passAnonymousToken = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/passAnonymousToken:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The startMode property needs to be set' { + + $mockAppPoolDefaults = @{ + startMode = 'OnDemand' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + startMode = 'AlwaysRunning' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/startMode:AlwaysRunning'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The queueLength property needs to be set' { + + $mockAppPoolDefaults = @{ + queueLength = 1000 + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + queueLength = 2000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/queueLength:2000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuAction property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + action = 'NoAction' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuAction = 'KillW3wp' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.action:KillW3wp'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + limit = 0 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuLimit = 90000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.limit:90000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuResetInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + resetInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuResetInterval = '00:10:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.resetInterval:00:10:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpAffinitized property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpAffinitized = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpAffinitized = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpAffinitized:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpProcessorAffinityMask property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpProcessorAffinityMask = 1 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask:1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpProcessorAffinityMask2 property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask2 = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpProcessorAffinityMask2 = 1 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask2:1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The identityType property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'ApplicationPoolIdentity' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + identityType = 'SpecificUser' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.identityType:SpecificUser'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The idleTimeout property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeout = '00:20:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + idleTimeout = '00:15:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeout:00:15:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The idleTimeoutAction property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeoutAction = 'Terminate' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + idleTimeoutAction = 'Suspend' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeoutAction:Suspend'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The loadUserProfile property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + loadUserProfile = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + loadUserProfile = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.loadUserProfile:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logEventOnProcessModel property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logEventOnProcessModel = 'IdleTimeout' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logEventOnProcessModel = '' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logEventOnProcessModel:'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logonType property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logonType = 'LogonBatch' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logonType = 'LogonService' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logonType:LogonService'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The manualGroupMembership property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + manualGroupMembership = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + manualGroupMembership = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.manualGroupMembership:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The maxProcesses property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + maxProcesses = 1 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + maxProcesses = 2 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.maxProcesses:2'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingingEnabled property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingingEnabled = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingingEnabled = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingingEnabled:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingInterval = '00:00:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingInterval = '00:01:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingInterval:00:01:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingResponseTime property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingResponseTime = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingResponseTime = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingResponseTime:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The setProfileEnvironment property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + setProfileEnvironment = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + setProfileEnvironment = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.setProfileEnvironment:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The shutdownTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + shutdownTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + shutdownTimeLimit = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.shutdownTimeLimit:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The startupTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + startupTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + startupTimeLimit = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.startupTimeLimit:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanActionExe property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanActionParams property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanActionParams = '/orphanActionParam1' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionParams:/orphanActionParam1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanWorkerProcess property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanWorkerProcess = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanWorkerProcess = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanWorkerProcess:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The loadBalancerCapabilities property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + loadBalancerCapabilities = 'HttpLevel' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + loadBalancerCapabilities = 'TcpLevel' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.loadBalancerCapabilities:TcpLevel'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtection property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtection = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtection = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtection:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtectionInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtectionInterval = '00:10:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionInterval:00:10:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtectionMaxCrashes property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionMaxCrashes = 5 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtectionMaxCrashes = 10 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionMaxCrashes:10'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The autoShutdownExe property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The autoShutdownParams property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownParams = '' + } + + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoShutdownParams = '/autoShutdownParam1' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownParams:/autoShutdownParam1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The disallowOverlappingRotation property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowOverlappingRotation = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + disallowOverlappingRotation = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowOverlappingRotation:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The disallowRotationOnConfigChange property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowRotationOnConfigChange = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + disallowRotationOnConfigChange = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowRotationOnConfigChange:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logEventOnRecycle property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logEventOnRecycle = 'Time,Memory,PrivateMemory' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartMemoryLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + memory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartMemoryLimit = 1048576 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.memory:1048576'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartPrivateMemoryLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + privateMemory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartPrivateMemoryLimit = 1048576 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.privateMemory:1048576'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartRequestsLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + requests = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartRequestsLimit = 1000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.requests:1000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + time = '1.05:00:00' + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartTimeLimit = '2.10:00:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.time:2.10:00:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartSchedule property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + schedule = @{ + Collection = @( + @{value = '04:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartSchedule = @('08:00:00') + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 + } + + } + + } + + } + + #endregion +} +finally +{ + Restore-TestEnvironment -TestEnvironment $TestEnvironment } From 3d81178b9f2959d45f1bc5d1c1d9c05dd02d3ab2 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:55:46 +0300 Subject: [PATCH 10/22] Updated sample usage in readme and in sample file --- Examples/Sample_xWebAppPoolDefaults.ps1 | 53 ++++++++- README.md | 137 +++++++++++++++++++++++- 2 files changed, 182 insertions(+), 8 deletions(-) diff --git a/Examples/Sample_xWebAppPoolDefaults.ps1 b/Examples/Sample_xWebAppPoolDefaults.ps1 index 6eca34e0b..b1b67dfc1 100644 --- a/Examples/Sample_xWebAppPoolDefaults.ps1 +++ b/Examples/Sample_xWebAppPoolDefaults.ps1 @@ -21,9 +21,56 @@ Configuration Sample_xWebAppPoolDefaults # Configures the application pool defaults. xWebAppPoolDefaults PoolDefaults { - ApplyTo = 'Machine' - ManagedRuntimeVersion = 'v4.0' - IdentityType = 'ApplicationPoolIdentity' + ApplyTo = 'Machine' + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpuAction = 'NoAction' + cpuLimit = 90000 + cpuResetInterval = (New-TimeSpan -Minutes 5).ToString() + cpuSmpAffinitized = $false + cpuSmpProcessorAffinityMask = 4294967295 + cpuSmpProcessorAffinityMask2 = 4294967295 + identityType = 'ApplicationPoolIdentity' + idleTimeout = (New-TimeSpan -Minutes 20).ToString() + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + pingingEnabled = $true + pingInterval = (New-TimeSpan -Seconds 30).ToString() + pingResponseTime = (New-TimeSpan -Seconds 90).ToString() + setProfileEnvironment = $false + shutdownTimeLimit = (New-TimeSpan -Seconds 90).ToString() + startupTimeLimit = (New-TimeSpan -Seconds 90).ToString() + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = (New-TimeSpan -Minutes 5).ToString() + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + restartMemoryLimit = 0 + restartPrivateMemoryLimit = 0 + restartRequestsLimit = 0 + restartTimeLimit = (New-TimeSpan -Minutes 1440).ToString() + restartSchedule = @('00:00:00', '08:00:00', '16:00:00') } + + } } diff --git a/README.md b/README.md index 8d8e99255..1f85270d6 100644 --- a/README.md +++ b/README.md @@ -242,8 +242,90 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### xWebAppPoolDefaults * **ApplyTo**: Required Key value, always **Machine** -* **ManagedRuntimeVersion**: CLR Version {v2.0|v4.0|} empty string for unmanaged. -* **ApplicationPoolIdentity**: {ApplicationPoolIdentity | LocalService | LocalSystem | NetworkService} +* **autoStart** : When set to `$true`, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started. +* **CLRConfigFile** : Indicates the .NET configuration file for the application pool. +* **enable32BitAppOnWin64** : When set to `$true`, enables a 32-bit application to run on a computer that runs a 64-bit version of Windows. +* **enableConfigurationOverride** : When set to `$true`, indicates that delegated settings in Web.config files will be processed for applications within this application pool. + When set to `$false`, all settings in Web.config files will be ignored for this application pool. +* **managedPipelineMode** : Indicates the request-processing mode that is used to process requests for managed content. The values that are allowed for this property are: `Integrated`, `Classic`. +* **managedRuntimeLoader** : Indicates the managed loader to use for pre-loading the application pool. +* **managedRuntimeVersion** : Indicates the CLR version to be used by the application pool. The values that are allowed for this property are: `v4.0`, `v2.0`, and `""`. +* **passAnonymousToken** : When set to `$true`, the Windows Process Activation Service (WAS) creates and passes a token for the built-in IUSR anonymous user account to the Anonymous authentication module. + The Anonymous authentication module uses the token to impersonate the built-in account. When this property is set to `$false`, the token will not be passed. +* **startMode** : Indicates the startup type for the application pool. The values that are allowed for this property are: `OnDemand`, `AlwaysRunning`. +* **queueLength** : Indicates the maximum number of requests that HTTP.sys will queue for the application pool. The value must be a valid integer between `10` and `65535`. +* **cpuAction** : Configures the action that IIS takes when a worker process exceeds its configured CPU limit. + The values that are allowed for this property are: `NoAction`, `KillW3wp`, `Throttle`, and `ThrottleUnderLoad`. +* **cpuLimit** : Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in the application pool are allowed to consume over a period of time as indicated by the **cpuResetInterval** property. + The value must be a valid integer between `0` and `100000`. +* **cpuResetInterval** : Indicates the reset period (in minutes) for CPU monitoring and throttling limits on the application pool. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `0` to `1440`. + Setting the value of this property to `00:00:00` disables CPU monitoring. +* **cpuSmpAffinitized** : Indicates whether a particular worker process assigned to the application pool should also be assigned to a given CPU. +* **cpuSmpProcessorAffinityMask** : Indicates the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. + Before this property takes effect, the **cpuSmpAffinitized** property must be set to `$true` for the application pool. + The value must be a valid integer between `0` and `4294967295`. +* **cpuSmpProcessorAffinityMask2** : Indicates the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. + Before this property takes effect, the **cpuSmpAffinitized** property must be set to `$true` for the application pool. + The value must be a valid integer between `0` and `4294967295`. +* **identityType** : Indicates the account identity under which the application pool runs. + The values that are allowed for this property are: `ApplicationPoolIdentity`, `LocalService`, `LocalSystem`, `NetworkService`, and `SpecificUser`. +* **Credential** : Indicates the custom account crededentials. This property is only valid when the **identityType** property is set to `SpecificUser`. +* **idleTimeout** : Indicates the amount of time (in minutes) a worker process will remain idle before it shuts down. + The value must be a string representation of a TimeSpan value and must be less than the **restartTimeLimit** property value. The valid range (in minutes) is `0` to `43200`. +* **idleTimeoutAction** : Indicates the action to perform when the idle timeout duration has been reached. + The values that are allowed for this property are: `Terminate`, `Suspend`. +* **loadUserProfile** : Indicates whether IIS loads the user profile for the application pool identity. +* **logEventOnProcessModel** : Indicates that IIS should generate an event log entry for each occurrence of the specified process model events. +* **logonType** : Indicates the logon type for the process identity. The values that are allowed for this property are: `LogonBatch`, `LogonService`. +* **manualGroupMembership** : Indicates whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token. +* **maxProcesses** : Indicates the maximum number of worker processes that would be used for the application pool. + The value must be a valid integer between `0` and `2147483647`. +* **pingingEnabled** : Indicates whether pinging (health monitoring) is enabled for the worker process(es) serving this application pool. +* **pingInterval** : Indicates the period of time (in seconds) between health monitoring pings sent to the worker process(es) serving this application pool. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **pingResponseTime** : Indicates the maximum time (in seconds) that a worker process is given to respond to a health monitoring ping. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **setProfileEnvironment** : Indicates the environment to be set based on the user profile for the new process. +* **shutdownTimeLimit** : Indicates the period of time (in seconds) a worker process is given to finish processing requests and shut down. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **startupTimeLimit** : Indicates the period of time (in seconds) a worker process is given to start up and initialize. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **orphanActionExe** : Indicates an executable to run when a worker process is orphaned. +* **orphanActionParams** : Indicates parameters for the executable that is specified in the **orphanActionExe** property. +* **orphanWorkerProcess** : Indicates whether to assign a worker process to an orphan state instead of terminating it when the application pool fails. + If `$true`, an unresponsive worker process will be orphaned instead of terminated. +* **loadBalancerCapabilities** : Indicates the response behavior of a service when it is unavailable. The values that are allowed for this property are: `HttpLevel`, `TcpLevel`. + If set to `HttpLevel` and the application pool is stopped, HTTP.sys will return HTTP 503 error. If set to `TcpLevel`, HTTP.sys will reset the connection. +* **rapidFailProtection** : Indicates whether rapid-fail protection is enabled. + If `$true`, the application pool is shut down if there are a specified number of worker process crashes within a specified time period. +* **rapidFailProtectionInterval** : Indicates the time interval (in minutes) during which the specified number of worker process crashes must occur before the application pool is shut down by rapid-fail protection. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `1` to `144000`. +* **rapidFailProtectionMaxCrashes** : Indicates the maximum number of worker process crashes permitted before the application pool is shut down by rapid-fail protection. + The value must be a valid integer between `0` and `2147483647`. +* **autoShutdownExe** : Indicates an executable to run when the application pool is shut down by rapid-fail protection. +* **autoShutdownParams** : Indicates parameters for the executable that is specified in the **autoShutdownExe** property. +* **disallowOverlappingRotation** : Indicates whether the W3SVC service should start another worker process to replace the existing worker process while that process is shutting down. + If `$true`, the application pool recycle will happen such that the existing worker process exits before another worker process is created. +* **disallowRotationOnConfigChange** : Indicates whether the W3SVC service should rotate worker processes in the application pool when the configuration has changed. + If `$true`, the application pool will not recycle when its configuration is changed. +* **logEventOnRecycle** : Indicates that IIS should generate an event log entry for each occurrence of the specified recycling events. +* **restartMemoryLimit** : Indicates the maximum amount of virtual memory (in KB) a worker process can consume before causing the application pool to recycle. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means there is no limit. +* **restartPrivateMemoryLimit** : Indicates the maximum amount of private memory (in KB) a worker process can consume before causing the application pool to recycle. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means there is no limit. +* **restartRequestsLimit** : Indicates the maximum number of requests the application pool can process before it is recycled. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means the application pool can process an unlimited number of requests. +* **restartTimeLimit** : Indicates the period of time (in minutes) after which the application pool will recycle. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `0` to `432000`. + A value of `00:00:00` means the application pool does not recycle on a regular interval. +* **restartSchedule** : Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. + The value must be an array of string representations of TimeSpan values. + TimeSpan values must be between `00:00:00` and `23:59:59` seconds inclusive, with a granularity of 60 seconds. + Setting the value of this property to `""` disables the schedule. ### xWebSiteDefaults @@ -1080,9 +1162,54 @@ configuration Sample_IISServerDefaults xWebAppPoolDefaults PoolDefaults { - ApplyTo = 'Machine' - ManagedRuntimeVersion = 'v4.0' - IdentityType = 'ApplicationPoolIdentity' + ApplyTo = 'Machine' + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpuAction = 'NoAction' + cpuLimit = 90000 + cpuResetInterval = (New-TimeSpan -Minutes 5).ToString() + cpuSmpAffinitized = $false + cpuSmpProcessorAffinityMask = 4294967295 + cpuSmpProcessorAffinityMask2 = 4294967295 + identityType = 'ApplicationPoolIdentity' + idleTimeout = (New-TimeSpan -Minutes 20).ToString() + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + pingingEnabled = $true + pingInterval = (New-TimeSpan -Seconds 30).ToString() + pingResponseTime = (New-TimeSpan -Seconds 90).ToString() + setProfileEnvironment = $false + shutdownTimeLimit = (New-TimeSpan -Seconds 90).ToString() + startupTimeLimit = (New-TimeSpan -Seconds 90).ToString() + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = (New-TimeSpan -Minutes 5).ToString() + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + restartMemoryLimit = 0 + restartPrivateMemoryLimit = 0 + restartRequestsLimit = 0 + restartTimeLimit = (New-TimeSpan -Minutes 1440).ToString() + restartSchedule = @('00:00:00', '08:00:00', '16:00:00') } } } From 9aa67f2a61ddfa3d3cc7d5e85d2a1b73c59d24bc Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 23:33:51 +0300 Subject: [PATCH 11/22] Added required new lines at the end of files --- .../MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 | 2 +- .../MSFT_xWebAppPoolDefaults.schema.mof | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 102f51ed2..f5da96ef2 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -809,4 +809,4 @@ function Get-AppPoolDefault { #endregion -Export-ModuleMember -Function *-TargetResource \ No newline at end of file +Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof index 6b4991147..47e1a9d79 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof @@ -53,4 +53,4 @@ class MSFT_xWebAppPoolDefaults : OMI_BaseResource [Write, Description("Indicates the period of time (in minutes) after which the application pool will recycle. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 432000. A value of 0 means the application pool does not recycle on a regular interval.")] String restartTimeLimit; [Write, Description("Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. The value must be an array of string representations of TimeSpan values. TimeSpan values must be between 00:00:00 and 23:59:59 seconds inclusive, with a granularity of 60 seconds. Setting the value of this property to '' disables the schedule.")] String restartSchedule[]; -}; \ No newline at end of file +}; From 17d1cf4059fa8631a8cde8c6b33995198030b16a Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Thu, 21 Dec 2017 22:56:28 +0300 Subject: [PATCH 12/22] Integration tests --- .../MSFT_xWebAppPoolDefaults.psm1 | 23 +-- ..._xWebAppPoolDefaults.Integration.Tests.ps1 | 159 ++++++----------- .../MSFT_xWebAppPoolDefaults.config.ps1 | 167 +++++++++++++----- 3 files changed, 189 insertions(+), 160 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index f5da96ef2..982b5fcfa 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -5,7 +5,8 @@ Import-Module -Name "$PSScriptRoot\..\Helper.psm1" data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' - VerboseGetTargetResource = Get-TargetResource has been run. + ErrorAppCmdNonZeroExitCode = AppCmd.exe has exited with error code "{0}". + VerboseGetTargetResource = Get-TargetResource has been run. ErrorAppPoolDefaultsNotFound = Application pool defaults element could not be located. VerboseAppPoolDefaultsFound = Application pool defaults was found. @@ -312,8 +313,6 @@ function Set-TargetResource { # Set Application Pool Properties - Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) - $PropertyData.Where( { ($_.Name -in $PSBoundParameters.Keys) -and @@ -331,8 +330,9 @@ function Set-TargetResource { Write-Verbose -Message ( $LocalizedData['VerboseSetProperty'] -f $propertyName ) + Invoke-AppCmd -ArgumentList ( - '/{0}:{1}' -f $propertyPath, $PSBoundParameters[$propertyName] + '/{0}:{1}' -f "applicationPoolDefaults.$($propertyPath)", $PSBoundParameters[$propertyName] ) } } @@ -346,7 +346,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - '/processModel.userName:{0}' -f $Credential.UserName + '/applicationPoolDefaults.processModel.userName:{0}' -f $Credential.UserName ) } @@ -358,7 +358,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - '/processModel.password:{0}' -f $clearTextPassword + '/applicationPoolDefaults.processModel.password:{0}' -f $clearTextPassword ) } } @@ -386,8 +386,8 @@ function Set-TargetResource { ) { Write-Verbose -Message ($LocalizedData['VerboseClearCredential']) - Invoke-AppCmd -ArgumentList '/processModel.userName:' - Invoke-AppCmd -ArgumentList '/processModel.password:' + Invoke-AppCmd -ArgumentList '/applicationPoolDefaults.processModel.userName:' + Invoke-AppCmd -ArgumentList '/applicationPoolDefaults.processModel.password:' } if ($PSBoundParameters.ContainsKey('restartSchedule')) { @@ -421,7 +421,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - "/+recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject ) } # Remove value @@ -432,7 +432,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - "/-recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject ) } @@ -774,8 +774,9 @@ function Invoke-AppCmd { $ErrorActionPreference = 'Stop' $appcmdFilePath = "$env:SystemRoot\System32\inetsrv\appcmd.exe" - $allArguments = @("set", "config", "-section:applicationPools") + $ArgumentList + $allArguments = @("set", "config", "-section:system.applicationHost/applicationPools") + $ArgumentList + ("/commit:apphost") + # Write-Verbose -Message "calling $($appcmdFilePath) $($allArguments)" $appcmdResult = $(& $appcmdFilePath $allArguments) Write-Verbose -Message $($appcmdResult).ToString() diff --git a/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 b/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 index 3b6e4d551..cee617cc1 100644 --- a/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 @@ -1,6 +1,7 @@ +#requires -Version 4.0 -$script:DSCModuleName = 'xWebAdministration' -$script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' +$script:DSCModuleName = 'xWebAdministration' +$script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' #region HEADER @@ -16,148 +17,98 @@ Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\ $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` - -TestType Integration + -TestType Integration + #endregion -[string] $tempName = "$($script:DSCResourceName)_" + (Get-Date).ToString("yyyyMMdd_HHmmss") +# Test Setup +if ((Get-Service -Name 'W3SVC').Status -ne 'Running') +{ + Start-Service -Name 'W3SVC' +} + +$tempBackupName = "$($script:DSCResourceName)_$(Get-Date -Format 'yyyyMMdd_HHmmss')" # Using try/finally to always cleanup even if something awful happens. + try { - #region Integration Tests + # Create configuration backup + + Backup-WebConfiguration -Name $tempBackupName | Out-Null - # some constants - [string]$constPsPath = 'MACHINE/WEBROOT/APPHOST' - [string]$constAPDFilter = 'system.applicationHost/applicationPools/applicationPoolDefaults' - [string]$constSiteFilter = 'system.applicationHost/sites/' + #region Integration Tests $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" . $ConfigFile - $null = Backup-WebConfiguration -Name $tempName + Describe "$($script:DSCResourceName)_Integration" { - function Get-SiteValue([string]$path,[string]$name) - { - return (Get-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/$path" -name $name).value - } + #region Default Tests - Describe "$($script:DSCResourceName)_Integration" { - #region DEFAULT TESTS - It 'Should compile without throwing' { + It 'Should be able to compile and apply without throwing' { { - Invoke-Expression -Command "$($script:DSCResourceName)_Config -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw + Invoke-Expression -Command ( + '{0}_Config -OutputPath $TestDrive -ConfigurationData $ConfigData -ErrorAction Stop' -f + $script:DSCResourceName + ) + + Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Force -Wait -Verbose + } | Should Not Throw } It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should Not throw + { + Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should Not Throw } + #endregion - It 'Changing ManagedRuntimeVersion' { + It 'Should have set the resource and all the parameters should match' { + + $currentConfiguration = Get-DscConfiguration + + foreach ($parameter in $TestParameters.GetEnumerator()) { - # get the current value - [string] $originalValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion) + Write-Verbose -Message "The $($parameter.Name) property should be set." - # We are using environment variables here, because a inline PowerShell variable was empty after executing Start-DscConfiguration + if ($parameter.Name -eq 'Credential') + { + $appPoolDefaults = Get-WebConfiguration -Filter '/system.applicationHost/applicationPools/applicationPoolDefaults' + + $appPoolDefaults.processModel.userName | + Should Be $TestParameters['Credential'].UserName - # change the value to something else - if ($originalValue -eq 'v4.0') + $appPoolDefaults.processModel.password | + Should Be $TestParameters['Credential'].GetNetworkCredential().Password + } + elseif ($parameter.Name -eq 'ApplyTo') { - $env:PesterManagedRuntimeVersion = 'v2.0' + # ignored. } else { - $env:PesterManagedRuntimeVersion = 'v4.0' + $currentConfiguration."$($parameter.Name)" | + Should Be $TestParameters[$parameter.Name] } - - Invoke-Expression -Command "$($script:DSCResourceName)_ManagedRuntimeVersion -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | should not throw - - # get the configured value again - $changedValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion).Value - - # compare it to the one we just tried to set. - $changedValue | should be $env:PesterManagedRuntimeVersion - } - - It 'Changing IdentityType' { - # get the current value - [string] $originalValue = (Get-WebConfigurationProperty ` - -PSPath $constPsPath ` - -Filter $constAPDFilter/processModel ` - -Name identityType) - - if ($originalValue -eq 'ApplicationPoolIdentity') - { - $env:PesterApplicationPoolIdentity = 'LocalService' - } - else - { - $env:PesterApplicationPoolIdentity = 'ApplicationPoolIdentity' } - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_AppPoolIdentityType -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = (Get-WebConfigurationProperty -PSPath $constPsPath -Filter $constAPDFilter/processModel -Name identityType) - - $changedValue | Should Be $env:PesterApplicationPoolIdentity } - - It 'Changing LogFormat' { - [string] $originalValue = Get-SiteValue 'logFile' 'logFormat' - - if ($originalValue -eq 'W3C') - { - $env:PesterLogFormat = 'IIS' - } - else - { - $env:PesterLogFormat = 'W3C' - } - - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_LogFormat -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = Get-SiteValue 'logFile' 'logFormat' - - $changedValue | Should Be $env:PesterALogFormat - } - - It 'Changing Default AppPool' { - # get the current value - - [string] $originalValue = Get-SiteValue 'applicationDefaults' 'applicationPool' - - $env:PesterDefaultPool = 'DefaultAppPool' - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_DefaultPool -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = Get-SiteValue 'applicationDefaults' 'applicationPool' - $changedValue | should be $env:PesterDefaultPool + It 'Actual configuration should match the desired configuration' { + Test-DscConfiguration -Verbose | Should Be $true } } + #endregion } finally { #region FOOTER - Restore-WebConfiguration -Name $tempName - Remove-WebConfigurationBackup -Name $tempName + Restore-WebConfiguration -Name $tempBackupName + Remove-WebConfigurationBackup -Name $tempBackupName Restore-TestEnvironment -TestEnvironment $TestEnvironment #endregion diff --git a/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 b/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 index c804256ae..32c1aaad2 100644 --- a/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 +++ b/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 @@ -1,60 +1,137 @@ -[string] $constPsPath = 'MACHINE/WEBROOT/APPHOST' -[string] $constAPDFilter = 'system.applicationHost/applicationPools/applicationPoolDefaults' -[string] $constSiteFilter = 'system.applicationHost/sites/' +#requires -Version 4.0 -[string] $originalValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion).Value +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] +param () -configuration MSFT_xWebAppPoolDefaults_Config -{ - Import-DscResource -ModuleName xWebAdministration - - xWebAppPoolDefaults PoolDefaults - { - ApplyTo = 'Machine' - ManagedRuntimeVersion = $originalValue - } +$ConfigData = @{ + AllNodes = @( + @{ + NodeName = '*' + PSDscAllowPlainTextPassword = $true + } + @{ + NodeName = 'localhost' + } + ) } -configuration MSFT_xWebAppPoolDefaults_ManagedRuntimeVersion -{ - Import-DscResource -ModuleName xWebAdministration +$TestCredential = New-Object -TypeName PSCredential -ArgumentList ( + 'CONTOSO\JDoe', + ('5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force) +) - xWebAppPoolDefaults PoolDefaults - { - ApplyTo = 'Machine' - ManagedRuntimeVersion = $env:PesterManagedRuntimeVersion - } +$TestParameters = [Ordered]@{ + applyTo = 'Machine' + autoStart = $false + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + enable32BitAppOnWin64 = $true + enableConfigurationOverride = $false + managedPipelineMode = 'Classic' + managedRuntimeLoader = '' + managedRuntimeVersion = 'v2.0' + passAnonymousToken = $false + startMode = 'AlwaysRunning' + queueLength = 2000 + cpuAction = 'KillW3wp' + cpuLimit = 90000 + cpuResetInterval = '00:10:00' + cpuSmpAffinitized = $true + cpuSmpProcessorAffinityMask = 1 + cpuSmpProcessorAffinityMask2 = 1 + identityType = 'SpecificUser' + Credential = $TestCredential + idleTimeout = '00:15:00' + idleTimeoutAction = 'Suspend' + loadUserProfile = $false + logEventOnProcessModel = '' + logonType = 'LogonService' + manualGroupMembership = $true + maxProcesses = 2 + pingingEnabled = $false + pingInterval = '00:01:00' + pingResponseTime = '00:02:00' + setProfileEnvironment = $true + shutdownTimeLimit = '00:02:00' + startupTimeLimit = '00:02:00' + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + orphanActionParams = '/orphanActionParam1' + orphanWorkerProcess = $true + loadBalancerCapabilities = 'TcpLevel' + rapidFailProtection = $false + rapidFailProtectionInterval = '00:10:00' + rapidFailProtectionMaxCrashes = 10 + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + autoShutdownParams = '/autoShutdownParam1' + disallowOverlappingRotation = $true + disallowRotationOnConfigChange = $true + logEventOnRecycle = 'Time,Memory,PrivateMemory' + restartMemoryLimit = 1048576 + restartPrivateMemoryLimit = 1048576 + restartRequestsLimit = 1000 + restartTimeLimit = '2.10:00:00' + restartSchedule = @('05:00:00', '21:00:00') } -configuration MSFT_xWebAppPoolDefaults_AppPoolIdentityType +Configuration MSFT_xWebAppPoolDefaults_Config { Import-DscResource -ModuleName xWebAdministration - xWebAppPoolDefaults PoolDefaults + Node $AllNodes.NodeName { - ApplyTo = 'Machine' - IdentityType = $env:PesterApplicationPoolIdentity + xWebAppPoolDefaults Defaults + { + ApplyTo = $TestParameters.applyTo + autoStart = $TestParameters.autoStart + CLRConfigFile = $TestParameters.CLRConfigFile + enable32BitAppOnWin64 = $TestParameters.enable32BitAppOnWin64 + enableConfigurationOverride = $TestParameters.enableConfigurationOverride + managedPipelineMode = $TestParameters.managedPipelineMode + managedRuntimeLoader = $TestParameters.managedRuntimeLoader + managedRuntimeVersion = $TestParameters.managedRuntimeVersion + passAnonymousToken = $TestParameters.passAnonymousToken + startMode = $TestParameters.startMode + queueLength = $TestParameters.queueLength + cpuAction = $TestParameters.cpuAction + cpuLimit = $TestParameters.cpuLimit + cpuResetInterval = $TestParameters.cpuResetInterval + cpuSmpAffinitized = $TestParameters.cpuSmpAffinitized + cpuSmpProcessorAffinityMask = $TestParameters.cpuSmpProcessorAffinityMask + cpuSmpProcessorAffinityMask2 = $TestParameters.cpuSmpProcessorAffinityMask2 + identityType = $TestParameters.identityType + Credential = $TestParameters.Credential + idleTimeout = $TestParameters.idleTimeout + idleTimeoutAction = $TestParameters.idleTimeoutAction + loadUserProfile = $TestParameters.loadUserProfile + logEventOnProcessModel = $TestParameters.logEventOnProcessModel + logonType = $TestParameters.logonType + manualGroupMembership = $TestParameters.manualGroupMembership + maxProcesses = $TestParameters.maxProcesses + pingingEnabled = $TestParameters.pingingEnabled + pingInterval = $TestParameters.pingInterval + pingResponseTime = $TestParameters.pingResponseTime + setProfileEnvironment = $TestParameters.setProfileEnvironment + shutdownTimeLimit = $TestParameters.shutdownTimeLimit + startupTimeLimit = $TestParameters.startupTimeLimit + orphanActionExe = $TestParameters.orphanActionExe + orphanActionParams = $TestParameters.orphanActionParams + orphanWorkerProcess = $TestParameters.orphanWorkerProcess + loadBalancerCapabilities = $TestParameters.loadBalancerCapabilities + rapidFailProtection = $TestParameters.rapidFailProtection + rapidFailProtectionInterval = $TestParameters.rapidFailProtectionInterval + rapidFailProtectionMaxCrashes = $TestParameters.rapidFailProtectionMaxCrashes + autoShutdownExe = $TestParameters.autoShutdownExe + autoShutdownParams = $TestParameters.autoShutdownParams + disallowOverlappingRotation = $TestParameters.disallowOverlappingRotation + disallowRotationOnConfigChange = $TestParameters.disallowRotationOnConfigChange + logEventOnRecycle = $TestParameters.logEventOnRecycle + restartMemoryLimit = $TestParameters.restartMemoryLimit + restartPrivateMemoryLimit = $TestParameters.restartPrivateMemoryLimit + restartRequestsLimit = $TestParameters.restartRequestsLimit + restartTimeLimit = $TestParameters.restartTimeLimit + restartSchedule = $TestParameters.restartSchedule + } } } -configuration MSFT_xWebAppPoolDefaults_LogFormat -{ - Import-DscResource -ModuleName xWebAdministration - xWebSiteDefaults LogFormat - { - ApplyTo = 'Machine' - LogFormat = $env:PesterLogFormat - } -} - -configuration MSFT_xWebAppPoolDefaults_DefaultPool -{ - Import-DscResource -ModuleName xWebAdministration - - xWebSiteDefaults DefaultPool - { - ApplyTo = 'Machine' - DefaultApplicationPool = $env:PesterDefaultPool - } -} From 9ea26415e555df45e5d2acaa24b546000069500e Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Thu, 21 Dec 2017 23:27:40 +0300 Subject: [PATCH 13/22] changes in unit tests --- Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 index e39504357..5fe29e006 100644 --- a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 +++ b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 @@ -1711,7 +1711,7 @@ try autoStart = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/autoStart:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.autoStart:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1733,7 +1733,7 @@ try CLRConfigFile = 'C:\inetpub\temp\aspnet.config' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/CLRConfigFile:C:\inetpub\temp\aspnet.config'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.CLRConfigFile:C:\inetpub\temp\aspnet.config'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1755,7 +1755,7 @@ try enable32BitAppOnWin64 = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enable32BitAppOnWin64:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.enable32BitAppOnWin64:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1777,7 +1777,7 @@ try enableConfigurationOverride = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enableConfigurationOverride:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.enableConfigurationOverride:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1799,7 +1799,7 @@ try managedPipelineMode = 'Classic' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedPipelineMode:Classic'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedPipelineMode:Classic'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1821,7 +1821,7 @@ try managedRuntimeLoader = '' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeLoader:'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedRuntimeLoader:'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1843,7 +1843,7 @@ try managedRuntimeVersion = 'v2.0' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeVersion:v2.0'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedRuntimeVersion:v2.0'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1865,7 +1865,7 @@ try passAnonymousToken = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/passAnonymousToken:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.passAnonymousToken:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1887,7 +1887,7 @@ try startMode = 'AlwaysRunning' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/startMode:AlwaysRunning'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.startMode:AlwaysRunning'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1909,7 +1909,7 @@ try queueLength = 2000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/queueLength:2000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.queueLength:2000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1933,7 +1933,7 @@ try cpuAction = 'KillW3wp' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.action:KillW3wp'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.action:KillW3wp'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1957,7 +1957,7 @@ try cpuLimit = 90000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.limit:90000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.limit:90000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1981,7 +1981,7 @@ try cpuResetInterval = '00:10:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.resetInterval:00:10:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.resetInterval:00:10:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2005,7 +2005,7 @@ try cpuSmpAffinitized = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpAffinitized:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpAffinitized:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2029,7 +2029,7 @@ try cpuSmpProcessorAffinityMask = 1 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask:1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpProcessorAffinityMask:1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2053,7 +2053,7 @@ try cpuSmpProcessorAffinityMask2 = 1 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask2:1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpProcessorAffinityMask2:1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2077,7 +2077,7 @@ try identityType = 'SpecificUser' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.identityType:SpecificUser'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.identityType:SpecificUser'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2101,7 +2101,7 @@ try idleTimeout = '00:15:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeout:00:15:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.idleTimeout:00:15:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2125,7 +2125,7 @@ try idleTimeoutAction = 'Suspend' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeoutAction:Suspend'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.idleTimeoutAction:Suspend'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2149,7 +2149,7 @@ try loadUserProfile = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.loadUserProfile:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.loadUserProfile:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2173,7 +2173,7 @@ try logEventOnProcessModel = '' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logEventOnProcessModel:'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.logEventOnProcessModel:'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2197,7 +2197,7 @@ try logonType = 'LogonService' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logonType:LogonService'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.logonType:LogonService'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2221,7 +2221,7 @@ try manualGroupMembership = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.manualGroupMembership:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.manualGroupMembership:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2245,7 +2245,7 @@ try maxProcesses = 2 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.maxProcesses:2'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.maxProcesses:2'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2269,7 +2269,7 @@ try pingingEnabled = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingingEnabled:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingingEnabled:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2293,7 +2293,7 @@ try pingInterval = '00:01:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingInterval:00:01:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingInterval:00:01:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2317,7 +2317,7 @@ try pingResponseTime = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingResponseTime:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingResponseTime:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2341,7 +2341,7 @@ try setProfileEnvironment = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.setProfileEnvironment:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.setProfileEnvironment:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2365,7 +2365,7 @@ try shutdownTimeLimit = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.shutdownTimeLimit:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.shutdownTimeLimit:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2389,7 +2389,7 @@ try startupTimeLimit = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.startupTimeLimit:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.startupTimeLimit:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2413,7 +2413,7 @@ try orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2437,7 +2437,7 @@ try orphanActionParams = '/orphanActionParam1' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionParams:/orphanActionParam1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanActionParams:/orphanActionParam1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2461,7 +2461,7 @@ try orphanWorkerProcess = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanWorkerProcess:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanWorkerProcess:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2485,7 +2485,7 @@ try loadBalancerCapabilities = 'TcpLevel' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.loadBalancerCapabilities:TcpLevel'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.loadBalancerCapabilities:TcpLevel'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2509,7 +2509,7 @@ try rapidFailProtection = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtection:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtection:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2533,7 +2533,7 @@ try rapidFailProtectionInterval = '00:10:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionInterval:00:10:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtectionInterval:00:10:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2557,7 +2557,7 @@ try rapidFailProtectionMaxCrashes = 10 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionMaxCrashes:10'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtectionMaxCrashes:10'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2581,7 +2581,7 @@ try autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2606,7 +2606,7 @@ try autoShutdownParams = '/autoShutdownParam1' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownParams:/autoShutdownParam1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.autoShutdownParams:/autoShutdownParam1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2630,7 +2630,7 @@ try disallowOverlappingRotation = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowOverlappingRotation:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.disallowOverlappingRotation:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2654,7 +2654,7 @@ try disallowRotationOnConfigChange = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowRotationOnConfigChange:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.disallowRotationOnConfigChange:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2678,7 +2678,7 @@ try logEventOnRecycle = 'Time,Memory,PrivateMemory' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2704,7 +2704,7 @@ try restartMemoryLimit = 1048576 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.memory:1048576'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.memory:1048576'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2730,7 +2730,7 @@ try restartPrivateMemoryLimit = 1048576 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.privateMemory:1048576'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.privateMemory:1048576'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2756,7 +2756,7 @@ try restartRequestsLimit = 1000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.requests:1000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.requests:1000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2782,7 +2782,7 @@ try restartTimeLimit = '2.10:00:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.time:2.10:00:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.time:2.10:00:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2812,14 +2812,14 @@ try restartSchedule = @('08:00:00') } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='04:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='08:00:00']"} Set-TargetResource -ApplyTo Machine @setParamsSplat It 'Should call Invoke-AppCmd' { - Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 - Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 } } From 47ea0a34f89b9c74f0dd7e56c55bc1d80c0478ee Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 00:04:43 +0300 Subject: [PATCH 14/22] added missing application pool default settings --- .../MSFT_xWebAppPoolDefaults.psm1 | 828 +++++++++++++++--- .../MSFT_xWebAppPoolDefaults.schema.mof | 54 +- 2 files changed, 749 insertions(+), 133 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 6def1b06a..102f51ed2 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -2,19 +2,90 @@ Import-Module -Name "$PSScriptRoot\..\Helper.psm1" # Localized messages -data LocalizedData -{ +data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' - NoWebAdministrationModule = Please ensure that WebAdministration module is installed. - SettingValue = Changing default value '{0}' to '{1}' - ValueOk = Default value '{0}' is already '{1}' VerboseGetTargetResource = Get-TargetResource has been run. + + ErrorAppPoolDefaultsNotFound = Application pool defaults element could not be located. + VerboseAppPoolDefaultsFound = Application pool defaults was found. + VerbosePropertyNotInDesiredState = The "{0}" property of application pool defaults does not match the desired state. + VerboseCredentialToBeCleared = Custom account credentials of application pool defaults need to be cleared because the "identityType" property is not set to "SpecificUser". + VerboseCredentialToBeIgnored = The "Credential" property is only valid when the "identityType" property is set to "SpecificUser". + VerboseResourceInDesiredState = The target resource is already in the desired state. No action is required. + VerboseResourceNotInDesiredState = The target resource is not in the desired state. + VerboseSetProperty = Setting the "{0}" property of application pool defaults". + VerboseClearCredential = Clearing custom account credentials of application pool defaults because the "identityType" property is not set to "SpecificUser". + VerboseRestartScheduleValueAdd = Adding value "{0}" to the "restartSchedule" collection of application pool defaults. + VerboseRestartScheduleValueRemove = Removing value "{0}" from the "restartSchedule" collection of application pool defaults. '@ } -function Get-TargetResource -{ +# Writable properties except Credential. +data PropertyData { + @( + # General + @{Name = 'autoStart'; Path = 'autoStart'} + @{Name = 'CLRConfigFile'; Path = 'CLRConfigFile'} + @{Name = 'enable32BitAppOnWin64'; Path = 'enable32BitAppOnWin64'} + @{Name = 'enableConfigurationOverride'; Path = 'enableConfigurationOverride'} + @{Name = 'managedPipelineMode'; Path = 'managedPipelineMode'} + @{Name = 'managedRuntimeLoader'; Path = 'managedRuntimeLoader'} + @{Name = 'managedRuntimeVersion'; Path = 'managedRuntimeVersion'} + @{Name = 'passAnonymousToken'; Path = 'passAnonymousToken'} + @{Name = 'startMode'; Path = 'startMode'} + @{Name = 'queueLength'; Path = 'queueLength'} + + # CPU + @{Name = 'cpuAction'; Path = 'cpu.action'} + @{Name = 'cpuLimit'; Path = 'cpu.limit'} + @{Name = 'cpuResetInterval'; Path = 'cpu.resetInterval'} + @{Name = 'cpuSmpAffinitized'; Path = 'cpu.smpAffinitized'} + @{Name = 'cpuSmpProcessorAffinityMask'; Path = 'cpu.smpProcessorAffinityMask'} + @{Name = 'cpuSmpProcessorAffinityMask2'; Path = 'cpu.smpProcessorAffinityMask2'} + + # Process Model + @{Name = 'identityType'; Path = 'processModel.identityType'} + @{Name = 'idleTimeout'; Path = 'processModel.idleTimeout'} + @{Name = 'idleTimeoutAction'; Path = 'processModel.idleTimeoutAction'} + @{Name = 'loadUserProfile'; Path = 'processModel.loadUserProfile'} + @{Name = 'logEventOnProcessModel'; Path = 'processModel.logEventOnProcessModel'} + @{Name = 'logonType'; Path = 'processModel.logonType'} + @{Name = 'manualGroupMembership'; Path = 'processModel.manualGroupMembership'} + @{Name = 'maxProcesses'; Path = 'processModel.maxProcesses'} + @{Name = 'pingingEnabled'; Path = 'processModel.pingingEnabled'} + @{Name = 'pingInterval'; Path = 'processModel.pingInterval'} + @{Name = 'pingResponseTime'; Path = 'processModel.pingResponseTime'} + @{Name = 'setProfileEnvironment'; Path = 'processModel.setProfileEnvironment'} + @{Name = 'shutdownTimeLimit'; Path = 'processModel.shutdownTimeLimit'} + @{Name = 'startupTimeLimit'; Path = 'processModel.startupTimeLimit'} + + # Process Orphaning + @{Name = 'orphanActionExe'; Path = 'failure.orphanActionExe'} + @{Name = 'orphanActionParams'; Path = 'failure.orphanActionParams'} + @{Name = 'orphanWorkerProcess'; Path = 'failure.orphanWorkerProcess'} + + # Rapid-Fail Protection + @{Name = 'loadBalancerCapabilities'; Path = 'failure.loadBalancerCapabilities'} + @{Name = 'rapidFailProtection'; Path = 'failure.rapidFailProtection'} + @{Name = 'rapidFailProtectionInterval'; Path = 'failure.rapidFailProtectionInterval'} + @{Name = 'rapidFailProtectionMaxCrashes'; Path = 'failure.rapidFailProtectionMaxCrashes'} + @{Name = 'autoShutdownExe'; Path = 'failure.autoShutdownExe'} + @{Name = 'autoShutdownParams'; Path = 'failure.autoShutdownParams'} + + # Recycling + @{Name = 'disallowOverlappingRotation'; Path = 'recycling.disallowOverlappingRotation'} + @{Name = 'disallowRotationOnConfigChange'; Path = 'recycling.disallowRotationOnConfigChange'} + @{Name = 'logEventOnRecycle'; Path = 'recycling.logEventOnRecycle'} + @{Name = 'restartMemoryLimit'; Path = 'recycling.periodicRestart.memory'} + @{Name = 'restartPrivateMemoryLimit'; Path = 'recycling.periodicRestart.privateMemory'} + @{Name = 'restartRequestsLimit'; Path = 'recycling.periodicRestart.requests'} + @{Name = 'restartTimeLimit'; Path = 'recycling.periodicRestart.time'} + @{Name = 'restartSchedule'; Path = 'recycling.periodicRestart.schedule'} + ) +} + +function Get-TargetResource { <# .SYNOPSIS This will return a hashtable of results @@ -34,14 +105,46 @@ function Get-TargetResource Write-Verbose -Message $LocalizedData.VerboseGetTargetResource - return @{ - ManagedRuntimeVersion = (Get-Value -Path '' -Name 'managedRuntimeVersion') - IdentityType = (Get-Value -Path 'processModel' -Name 'identityType') + # XPath -Filter is case-sensitive. Use Where-Object to get the target application pool by name. + $appPool = Get-AppPoolDefault + + $cimCredential = $null + if ($appPool.processModel.identityType -eq 'SpecificUser') { + $cimCredential = New-CimInstance -ClientOnly ` + -ClassName MSFT_Credential ` + -Namespace root/microsoft/windows/DesiredStateConfiguration ` + -Property @{ + UserName = [String]$appPool.processModel.userName + Password = [String]$appPool.processModel.password + } } + + + $returnValue = @{ + Credential = $cimCredential + } + + $PropertyData.Where( + { + $_.Name -ne 'restartSchedule' + } + ).ForEach( + { + $property = Get-Property -Object $appPool -PropertyName $_.Path + $returnValue.Add($_.Name, $property) + } + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $returnValue.Add('restartSchedule', $restartScheduleCurrent) + + return $returnValue } -function Set-TargetResource -{ +function Set-TargetResource { <# .SYNOPSIS This will set the desired state @@ -57,24 +160,288 @@ function Set-TargetResource $ApplyTo, [Parameter()] - [ValidateSet('','v2.0','v4.0')] + [ValidateSet('', 'v2.0', 'v4.0')] [System.String] $ManagedRuntimeVersion, - [Parameter()] - [ValidateSet('ApplicationPoolIdentity','LocalService','LocalSystem','NetworkService')] - [System.String] - $IdentityType + + [Boolean] $autoStart, + + [String] $CLRConfigFile, + + [Boolean] $enable32BitAppOnWin64, + + [Boolean] $enableConfigurationOverride, + + [ValidateSet('Integrated', 'Classic')] + [String] $managedPipelineMode, + + [String] $managedRuntimeLoader, + + [Boolean] $passAnonymousToken, + + [ValidateSet('OnDemand', 'AlwaysRunning')] + [String] $startMode, + + [ValidateRange(10, 65535)] + [UInt32] $queueLength, + + [ValidateSet('NoAction', 'KillW3wp', 'Throttle', 'ThrottleUnderLoad')] + [String] $cpuAction, + + [ValidateRange(0, 100000)] + [UInt32] $cpuLimit, + + [ValidateScript( { + ([ValidateRange(0, 1440)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $cpuResetInterval, + + [Boolean] $cpuSmpAffinitized, + + [UInt32] $cpuSmpProcessorAffinityMask, + + [UInt32] $cpuSmpProcessorAffinityMask2, + + [ValidateSet( + 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', + 'NetworkService', 'SpecificUser' + )] + [String] $identityType, + + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential, + + [ValidateScript( { + ([ValidateRange(0, 43200)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $idleTimeout, + + [ValidateSet('Terminate', 'Suspend')] + [String] $idleTimeoutAction, + + [Boolean] $loadUserProfile, + + [String] $logEventOnProcessModel, + + [ValidateSet('LogonBatch', 'LogonService')] + [String] $logonType, + + [Boolean] $manualGroupMembership, + + [ValidateRange(0, 2147483647)] + [UInt32] $maxProcesses, + + [Boolean] $pingingEnabled, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingInterval, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingResponseTime, + + [Boolean] $setProfileEnvironment, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $shutdownTimeLimit, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $startupTimeLimit, + + [String] $orphanActionExe, + + [String] $orphanActionParams, + + [Boolean] $orphanWorkerProcess, + + [ValidateSet('HttpLevel', 'TcpLevel')] + [String] $loadBalancerCapabilities, + + [Boolean] $rapidFailProtection, + + [ValidateScript( { + ([ValidateRange(1, 144000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $rapidFailProtectionInterval, + + [ValidateRange(0, 2147483647)] + [UInt32] $rapidFailProtectionMaxCrashes, + + [String] $autoShutdownExe, + + [String] $autoShutdownParams, + + [Boolean] $disallowOverlappingRotation, + + [Boolean] $disallowRotationOnConfigChange, + + [String] $logEventOnRecycle, + + [UInt32] $restartMemoryLimit, + + [UInt32] $restartPrivateMemoryLimit, + + [UInt32] $restartRequestsLimit, + + [ValidateScript( { + ([ValidateRange(0, 432000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $restartTimeLimit, + + [ValidateScript( { + ($_ -eq '') -or + (& { + ([ValidateRange(0, 86399)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + }) + })] + [String[]] $restartSchedule ) Assert-Module + + $appPool = Get-AppPoolDefault + + # Set Application Pool Properties + + Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) + + $PropertyData.Where( + { + ($_.Name -in $PSBoundParameters.Keys) -and + ($_.Name -notin @('restartSchedule')) + } + ).ForEach( + { + $propertyName = $_.Name + $propertyPath = $_.Path + $property = Get-Property -Object $appPool -PropertyName $propertyPath + + if ( + $PSBoundParameters[$propertyName] -ne $property + ) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f $propertyName + ) + Invoke-AppCmd -ArgumentList ( + '/{0}:{1}' -f $propertyPath, $PSBoundParameters[$propertyName] + ) + } + } + ) + + if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters['identityType'] -eq 'SpecificUser') { + if ($appPool.processModel.userName -ne $Credential.UserName) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f 'Credential (userName)' + ) + + Invoke-AppCmd -ArgumentList ( + '/processModel.userName:{0}' -f $Credential.UserName + ) + } + + $clearTextPassword = $Credential.GetNetworkCredential().Password + + if ($appPool.processModel.password -cne $clearTextPassword) { + Write-Verbose -Message ( + $LocalizedData['VerboseSetProperty'] -f 'Credential (password)' + ) + + Invoke-AppCmd -ArgumentList ( + '/processModel.password:{0}' -f $clearTextPassword + ) + } + } + else { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeIgnored']) + } + } + + # Ensure userName and password are cleared if identityType isn't set to SpecificUser. + if ( + ( + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $true) -and + ($PSBoundParameters['identityType'] -ne 'SpecificUser') + ) -or + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $false) -and + ($appPool.processModel.identityType -ne 'SpecificUser') + ) + ) -and + ( + ([String]::IsNullOrEmpty($appPool.processModel.userName) -eq $false) -or + ([String]::IsNullOrEmpty($appPool.processModel.password) -eq $false) + ) + ) { + Write-Verbose -Message ($LocalizedData['VerboseClearCredential']) + + Invoke-AppCmd -ArgumentList '/processModel.userName:' + Invoke-AppCmd -ArgumentList '/processModel.password:' + } - Set-Value -Path '' -Name 'managedRuntimeVersion' -NewValue $ManagedRuntimeVersion - Set-Value -Path 'processModel' -Name 'identityType' -NewValue $IdentityType + if ($PSBoundParameters.ContainsKey('restartSchedule')) { + # Normalize the restartSchedule array values. + $restartScheduleDesired = [String[]]@( + $restartSchedule.Where( + { + $_ -ne '' + } + ).ForEach( + { + [TimeSpan]::Parse($_).ToString('hh\:mm\:ss') + } + ) | + Select-Object -Unique + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + Compare-Object -ReferenceObject $restartScheduleDesired ` + -DifferenceObject $restartScheduleCurrent | + ForEach-Object -Process { + + # Add value + if ($_.SideIndicator -eq '<=') { + Write-Verbose -Message ( + $LocalizedData['VerboseRestartScheduleValueAdd'] -f + $_.InputObject + ) + + Invoke-AppCmd -ArgumentList ( + "/+recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + ) + } + # Remove value + else { + Write-Verbose -Message ( + $LocalizedData['VerboseRestartScheduleValueRemove'] -f + $_.InputObject + ) + + Invoke-AppCmd -ArgumentList ( + "/-recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + ) + } + + } + } + } -function Test-TargetResource -{ +function Test-TargetResource { <# .SYNOPSIS This tests the desired state. If the state is not correct it will return $false. @@ -92,153 +459,354 @@ function Test-TargetResource $ApplyTo, [Parameter()] - [ValidateSet('','v2.0','v4.0')] + [ValidateSet('', 'v2.0', 'v4.0')] [System.String] $ManagedRuntimeVersion, - [Parameter()] - [ValidateSet('ApplicationPoolIdentity','LocalService','LocalSystem','NetworkService')] - [System.String] - $IdentityType + [Boolean] $autoStart, + + [String] $CLRConfigFile, + + [Boolean] $enable32BitAppOnWin64, + + [Boolean] $enableConfigurationOverride, + + [ValidateSet('Integrated', 'Classic')] + [String] $managedPipelineMode, + + [String] $managedRuntimeLoader, + + [Boolean] $passAnonymousToken, + + [ValidateSet('OnDemand', 'AlwaysRunning')] + [String] $startMode, + + [ValidateRange(10, 65535)] + [UInt32] $queueLength, + + [ValidateSet('NoAction', 'KillW3wp', 'Throttle', 'ThrottleUnderLoad')] + [String] $cpuAction, + + [ValidateRange(0, 100000)] + [UInt32] $cpuLimit, + + [ValidateScript( { + ([ValidateRange(0, 1440)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $cpuResetInterval, + + [Boolean] $cpuSmpAffinitized, + + [UInt32] $cpuSmpProcessorAffinityMask, + + [UInt32] $cpuSmpProcessorAffinityMask2, + + [ValidateSet( + 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', + 'NetworkService', 'SpecificUser' + )] + [String] $identityType, + + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential, + + [ValidateScript( { + ([ValidateRange(0, 43200)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $idleTimeout, + + [ValidateSet('Terminate', 'Suspend')] + [String] $idleTimeoutAction, + + [Boolean] $loadUserProfile, + + [String] $logEventOnProcessModel, + + [ValidateSet('LogonBatch', 'LogonService')] + [String] $logonType, + + [Boolean] $manualGroupMembership, + + [ValidateRange(0, 2147483647)] + [UInt32] $maxProcesses, + + [Boolean] $pingingEnabled, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingInterval, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $pingResponseTime, + + [Boolean] $setProfileEnvironment, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $shutdownTimeLimit, + + [ValidateScript( { + ([ValidateRange(1, 4294967)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + })] + [String] $startupTimeLimit, + + [String] $orphanActionExe, + + [String] $orphanActionParams, + + [Boolean] $orphanWorkerProcess, + + [ValidateSet('HttpLevel', 'TcpLevel')] + [String] $loadBalancerCapabilities, + + [Boolean] $rapidFailProtection, + + [ValidateScript( { + ([ValidateRange(1, 144000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $rapidFailProtectionInterval, + + [ValidateRange(0, 2147483647)] + [UInt32] $rapidFailProtectionMaxCrashes, + + [String] $autoShutdownExe, + + [String] $autoShutdownParams, + + [Boolean] $disallowOverlappingRotation, + + [Boolean] $disallowRotationOnConfigChange, + + [String] $logEventOnRecycle, + + [UInt32] $restartMemoryLimit, + + [UInt32] $restartPrivateMemoryLimit, + + [UInt32] $restartRequestsLimit, + + [ValidateScript( { + ([ValidateRange(0, 432000)]$valueInMinutes = [TimeSpan]::Parse($_).TotalMinutes); $? + })] + [String] $restartTimeLimit, + + [ValidateScript( { + ($_ -eq '') -or + (& { + ([ValidateRange(0, 86399)]$valueInSeconds = [TimeSpan]::Parse($_).TotalSeconds); $? + }) + })] + [String[]] $restartSchedule ) Assert-Module - if (-not((Confirm-Value -Path '' ` - -Name 'managedRuntimeVersion' ` - -NewValue $ManagedRuntimeVersion))) - { - return $false + $inDesiredState = $true + + $appPool = Get-AppPoolDefault + + $PropertyData.Where( + { + ($_.Name -in $PSBoundParameters.Keys) -and + ($_.Name -ne 'restartSchedule') + } + ).ForEach( + { + $propertyName = $_.Name + $propertyPath = $_.Path + $property = Get-Property -Object $appPool -PropertyName $propertyPath + + if ( + $PSBoundParameters[$propertyName] -ne $property + ) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f $propertyName + ) + + $inDesiredState = $false + } + } + ) + + + if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters['identityType'] -eq 'SpecificUser') { + if ($appPool.processModel.userName -ne $Credential.UserName) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f + 'Credential (userName)' + ) + + $inDesiredState = $false + } + + $clearTextPassword = $Credential.GetNetworkCredential().Password + + if ($appPool.processModel.password -cne $clearTextPassword) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f + 'Credential (password)' + ) + + $inDesiredState = $false + } + } + else { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeIgnored']) + } } - if (-not((Confirm-Value -Path 'processModel' ` - -Name 'identityType' ` - -NewValue $IdentityType))) - { - return $false + # Ensure userName and password are cleared if identityType isn't set to SpecificUser. + if ( + ( + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $true) -and + ($PSBoundParameters['identityType'] -ne 'SpecificUser') + ) -or + ( + ($PSBoundParameters.ContainsKey('identityType') -eq $false) -and + ($appPool.processModel.identityType -ne 'SpecificUser') + ) + ) -and + ( + ([String]::IsNullOrEmpty($appPool.processModel.userName) -eq $false) -or + ([String]::IsNullOrEmpty($appPool.processModel.password) -eq $false) + ) + ) { + Write-Verbose -Message ($LocalizedData['VerboseCredentialToBeCleared']) + + $inDesiredState = $false + } + + if ($PSBoundParameters.ContainsKey('restartSchedule')) { + # Normalize the restartSchedule array values. + $restartScheduleDesired = [String[]]@( + $restartSchedule.Where( + { + $_ -ne '' + } + ).ForEach( + { + [TimeSpan]::Parse($_).ToString('hh\:mm\:ss') + } + ) | + Select-Object -Unique + ) + + $restartScheduleCurrent = [String[]]@( + @($appPool.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + if ( + Compare-Object -ReferenceObject $restartScheduleDesired ` + -DifferenceObject $restartScheduleCurrent + ) { + Write-Verbose -Message ( + $LocalizedData['VerbosePropertyNotInDesiredState'] -f 'restartSchedule' + ) + + $inDesiredState = $false + } } - return $true + + if ($inDesiredState -eq $true) { + Write-Verbose -Message ($LocalizedData['VerboseResourceInDesiredState']) + } + else { + Write-Verbose -Message ($LocalizedData['VerboseResourceNotInDesiredState']) + } + + return $inDesiredState } #region Helper Functions -function Confirm-Value -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param + +function Get-Property { + param ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, + [object] $Object, + [string] $PropertyName) - [Parameter(Mandatory = $true)] - [System.String] - $Name, + $parts = $PropertyName.Split('.') + $firstPart = $parts[0] - [Parameter()] - [System.String] - $NewValue - ) - - if (-not($NewValue)) - { - # if no new value was specified, we assume this value is okay. - return $true - } + $value = $Object.$firstPart + if ($parts.Count -gt 1) { + $newParts = @() + 1..($parts.Count - 1) | ForEach-Object { + $newParts += $parts[$_] + } - $existingValue = Get-Value -Path $Path -Name $Name - if ($existingValue -ne $NewValue) - { - return $false + $newName = ($newParts -join '.') + return Get-Property -Object $value -PropertyName $newName } - else - { - $relPath = $Path + '/' + $Name - Write-Verbose($LocalizedData.ValueOk -f $relPath,$NewValue); - return $true + else { + return $value } -} +} + +<# + .SYNOPSIS + Runs appcmd.exe - if there's an error then the application will terminate + + .PARAMETER ArgumentList + Optional list of string arguments to be passed into appcmd.exe -function Set-Value -{ +#> +function Invoke-AppCmd { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, - - [Parameter(Mandatory = $true)] - [System.String] - $Name, - - [Parameter()] - [System.String] - $NewValue + [String[]] $ArgumentList ) - # if the variable doesn't exist, the user doesn't want to change this value - if (-not($NewValue)) - { - return - } + <# + This is a local preference for the function which will terminate + the program if there's an error invoking appcmd.exe + #> + $ErrorActionPreference = 'Stop' - $existingValue = Get-Value -Path $Path -Name $Name - if ($existingValue -ne $NewValue) - { - if ($Path -ne '') - { - $Path = '/' + $Path - } + $appcmdFilePath = "$env:SystemRoot\System32\inetsrv\appcmd.exe" + $allArguments = @("set", "config", "-section:applicationPools") + $ArgumentList + + $appcmdResult = $(& $appcmdFilePath $allArguments) + Write-Verbose -Message $($appcmdResult).ToString() - Set-WebConfigurationProperty ` - -PSPath 'MACHINE/WEBROOT/APPHOST' ` - -Filter "system.applicationHost/applicationPools/applicationPoolDefaults$Path" ` - -Name $Name ` - -Value "$NewValue" - - $relPath = $Path + '/' + $Name - Write-Verbose($LocalizedData.SettingValue -f $relPath,$NewValue); + if ($LASTEXITCODE -ne 0) { + $errorMessage = $LocalizedData['ErrorAppCmdNonZeroExitCode'] -f $LASTEXITCODE + + New-TerminatingError -ErrorId 'ErrorAppCmdNonZeroExitCode' ` + -ErrorMessage $errorMessage ` + -ErrorCategory 'InvalidResult' } } -function Get-Value -{ - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [System.String] - $Path, - [Parameter(Mandatory = $true)] - [System.String] - $Name - ) +function Get-AppPoolDefault { + # XPath -Filter is case-sensitive. Use Where-Object to get the target application pool by name. + $appPool = Get-WebConfiguration ` + -PSPath 'MACHINE/WEBROOT/APPHOST' ` + -Filter '/system.applicationHost/applicationPools/applicationPoolDefaults' + - if ($Path -ne '') - { - $Path = '/' + $Path + if ($null -eq $appPool) { + New-TerminatingError -ErrorId 'ErrorAppPoolDefaultsNotFound' ` + -ErrorMessage $LocalizedData['ErrorAppPoolDefaultsNotFound'] ` + -ErrorCategory 'InvalidResult' } - $result = Get-WebConfigurationProperty ` - -PSPath 'MACHINE/WEBROOT/APPHOST' ` - -Filter "system.applicationHost/applicationPools/applicationPoolDefaults$Path" ` - -Name $Name + Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) - if ($result -is [Microsoft.IIs.PowerShell.Framework.ConfigurationAttribute]) - { - return $result.Value - } else { - return $result - } + return $appPool } #endregion -Export-ModuleMember -Function *-TargetResource +Export-ModuleMember -Function *-TargetResource \ No newline at end of file diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof index 99b2f22c9..6b4991147 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof @@ -3,6 +3,54 @@ class MSFT_xWebAppPoolDefaults : OMI_BaseResource { [Key, Description("Dummy value because we need a key, always 'Machine'"), ValueMap{"Machine"}, Values{"Machine"}] string ApplyTo; - [write, Description("applicationPools/applicationPoolDefaults/managedRuntimeVersion"), ValueMap{"","v2.0","v4.0"}, Values{"","v2.0","v4.0"}] string ManagedRuntimeVersion; - [write, Description("applicationPools/applicationPoolDefaults/processModel/identityType"), ValueMap{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService"}, Values{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService"}] string IdentityType; -}; + + [Write, Description("When set to true, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started.")] Boolean autoStart; + [Write, Description("Indicates the .NET configuration file for the application pool.")] String CLRConfigFile; + [Write, Description("When set to true, enables a 32-bit application to run on a computer that runs a 64-bit version of Windows.")] Boolean enable32BitAppOnWin64; + [Write, Description("When set to true, indicates that delegated settings in Web.config files will processed for applications within this application pool. When set to false, all settings in Web.config files will be ignored for this application pool.")] Boolean enableConfigurationOverride; + [Write, Description("Indicates the request-processing mode that is used to process requests for managed content. The values that are allowed for this property are: Integrated, Classic."), ValueMap{"Integrated","Classic"},Values{"Integrated","Classic"}] String managedPipelineMode; + [Write, Description("Indicates the managed loader to use for pre-loading the application pool.")] String managedRuntimeLoader; + [Write, Description("Indicates the CLR version to be used by the application pool. The values that are allowed for this property are: v4.0, v2.0, and ''."), ValueMap{"v4.0","v2.0",""},Values{"v4.0","v2.0",""}] String managedRuntimeVersion; + [Write, Description("When set to true, the Windows Process Activation Service (WAS) creates and passes a token for the built-in IUSR anonymous user account to the Anonymous authentication module. The Anonymous authentication module uses the token to impersonate the built-in account. When this property is set to false, the token will not be passed.")] Boolean passAnonymousToken; + [Write, Description("Indicates the startup type for the application pool. The values that are allowed for this property are: OnDemand, AlwaysRunning."), ValueMap{"OnDemand","AlwaysRunning"},Values{"OnDemand","AlwaysRunning"}] String startMode; + [Write, Description("Indicates the maximum number of requests that HTTP.sys will queue for the application pool. The value must be a valid integer between 10 and 65535.")] UInt32 queueLength; + [Write, Description("Configures the action that IIS takes when a worker process exceeds its configured CPU limit. The values that are allowed for this property are: NoAction, KillW3wp, Throttle, and ThrottleUnderLoad."), ValueMap{"NoAction","KillW3wp","Throttle","ThrottleUnderLoad"},Values{"NoAction","KillW3wp","Throttle","ThrottleUnderLoad"}] String cpuAction; + [Write, Description("Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in the application pool are allowed to consume over a period of time as indicated by the cpuResetInterval property. The value must be a valid integer between 0 and 100000.")] UInt32 cpuLimit; + [Write, Description("Indicates the reset period (in minutes) for CPU monitoring and throttling limits on the application pool. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 1440. Setting the value of this property to 0 disables CPU monitoring.")] String cpuResetInterval; + [Write, Description("Indicates whether a particular worker process assigned to the application pool should also be assigned to a given CPU.")] Boolean cpuSmpAffinitized; + [Write, Description("Indicates the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. Before this property takes effect, the cpuSmpAffinitized property must be set to true for the application pool. The value must be a valid integer between 0 and 4294967295.")] UInt32 cpuSmpProcessorAffinityMask; + [Write, Description("Indicates the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. Before this property takes effect, the cpuSmpAffinitized property must be set to true for the application pool. The value must be a valid integer between 0 and 4294967295.")] UInt32 cpuSmpProcessorAffinityMask2; + [Write, Description("Indicates the account identity under which the application pool runs. The values that are allowed for this property are: ApplicationPoolIdentity, LocalService, LocalSystem, NetworkService, and SpecificUser."), ValueMap{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"}, Values{"ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"}] String identityType; + [Write, Description("Indicates the custom account crededentials. This property is only valid when the identityType property is set to SpecificUser."), EmbeddedInstance("MSFT_Credential")] String Credential; + [Write, Description("Indicates the amount of time (in minutes) a worker process will remain idle before it shuts down. The value must be a string representation of a TimeSpan value and must be less than the restartTimeLimit property value. The valid range (in minutes) is 0 to 43200.")] String idleTimeout; + [Write, Description("Indicates the action to perform when the idle timeout duration has been reached. The values that are allowed for this property are: Terminate, Suspend."), ValueMap{"Terminate","Suspend"}, Values{"Terminate","Suspend"}] String idleTimeoutAction; + [Write, Description("Indicates whether IIS loads the user profile for the application pool identity.")] Boolean loadUserProfile; + [Write, Description("Indicates that IIS should generate an event log entry for each occurrence of the specified process model events.")] String logEventOnProcessModel; + [Write, Description("Indicates the logon type for the process identity. The values that are allowed for this property are: LogonBatch, LogonService."), ValueMap{"LogonBatch","LogonService"},Values{"LogonBatch","LogonService"}] String logonType; + [Write, Description("Indicates whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token.")] Boolean manualGroupMembership; + [Write, Description("Indicates the maximum number of worker processes that would be used for the application pool. The value must be a valid integer between 0 and 2147483647.")] UInt32 maxProcesses; + [Write, Description("Indicates whether pinging (health monitoring) is enabled for the worker process(es) serving this application pool.")] Boolean pingingEnabled; + [Write, Description("Indicates the period of time (in seconds) between health monitoring pings sent to the worker process(es) serving this application pool. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String pingInterval; + [Write, Description("Indicates the maximum time (in seconds) that a worker process is given to respond to a health monitoring ping. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String pingResponseTime; + [Write, Description("Indicates the environment to be set based on the user profile for the new process.")] Boolean setProfileEnvironment; + [Write, Description("Indicates the period of time (in seconds) a worker process is given to finish processing requests and shut down. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String shutdownTimeLimit; + [Write, Description("Indicates the period of time (in seconds) a worker process is given to start up and initialize. The value must be a string representation of a TimeSpan value. The valid range (in seconds) is 1 to 4294967.")] String startupTimeLimit; + [Write, Description("Indicates an executable to run when a worker process is orphaned.")] String orphanActionExe; + [Write, Description("Indicates parameters for the executable that is specified in the orphanActionExe property.")] String orphanActionParams; + [Write, Description("Indicates whether to assign a worker process to an orphan state instead of terminating it when the application pool fails. If true, an unresponsive worker process will be orphaned instead of terminated.")] Boolean orphanWorkerProcess; + [Write, Description("Indicates the response behavior of a service when it is unavailable. The values that are allowed for this property are: HttpLevel, TcpLevel. If set to HttpLevel and the application pool is stopped, HTTP.sys will return HTTP 503 error. If set to TcpLevel, HTTP.sys will reset the connection."), ValueMap{"HttpLevel","TcpLevel"},Values{"HttpLevel","TcpLevel"}] String loadBalancerCapabilities; + [Write, Description("Indicates whether rapid-fail protection is enabled. If true, the application pool is shut down if there are a specified number of worker process crashes within a specified time period.")] Boolean rapidFailProtection; + [Write, Description("Indicates the time interval (in minutes) during which the specified number of worker process crashes must occur before the application pool is shut down by rapid-fail protection. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 1 to 144000.")] String rapidFailProtectionInterval; + [Write, Description("Indicates the maximum number of worker process crashes permitted before the application pool is shut down by rapid-fail protection. The value must be a valid integer between 0 and 2147483647.")] UInt32 rapidFailProtectionMaxCrashes; + [Write, Description("Indicates an executable to run when the application pool is shut down by rapid-fail protection.")] String autoShutdownExe; + [Write, Description("Indicates parameters for the executable that is specified in the autoShutdownExe property.")] String autoShutdownParams; + [Write, Description("Indicates whether the W3SVC service should start another worker process to replace the existing worker process while that process is shutting down. If true, the application pool recycle will happen such that the existing worker process exits before another worker process is created.")] Boolean disallowOverlappingRotation; + [Write, Description("Indicates whether the W3SVC service should rotate worker processes in the application pool when the configuration has changed. If true, the application pool will not recycle when its configuration is changed.")] Boolean disallowRotationOnConfigChange; + [Write, Description("Indicates that IIS should generate an event log entry for each occurrence of the specified recycling events.")] String logEventOnRecycle; + [Write, Description("Indicates the maximum amount of virtual memory (in KB) a worker process can consume before causing the application pool to recycle. The value must be a valid integer between 0 and 4294967295. A value of 0 means there is no limit.")] UInt32 restartMemoryLimit; + [Write, Description("Indicates the maximum amount of private memory (in KB) a worker process can consume before causing the application pool to recycle. The value must be a valid integer between 0 and 4294967295. A value of 0 means there is no limit.")] UInt32 restartPrivateMemoryLimit; + [Write, Description("Indicates the maximum number of requests the application pool can process before it is recycled. The value must be a valid integer between 0 and 4294967295. A value of 0 means the application pool can process an unlimited number of requests.")] UInt32 restartRequestsLimit; + [Write, Description("Indicates the period of time (in minutes) after which the application pool will recycle. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 432000. A value of 0 means the application pool does not recycle on a regular interval.")] String restartTimeLimit; + [Write, Description("Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. The value must be an array of string representations of TimeSpan values. TimeSpan values must be between 00:00:00 and 23:59:59 seconds inclusive, with a granularity of 60 seconds. Setting the value of this property to '' disables the schedule.")] String restartSchedule[]; + +}; \ No newline at end of file From c678fc5587c92d3a9a909c44390a7346cbccb7ce Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:36:08 +0300 Subject: [PATCH 15/22] Unit tests for application pool defaults with all attributes --- Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 | 2856 ++++++++++++++++- 1 file changed, 2749 insertions(+), 107 deletions(-) diff --git a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 index c6161a95f..e39504357 100644 --- a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 +++ b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 @@ -1,194 +1,2836 @@ -#region HEADER +#requires -Version 4.0 + +# Suppressing this rule because IIS requires PlainText for one of the functions used in this test +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param () $script:DSCModuleName = 'xWebAdministration' $script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' -# Unit Test Template Version: 1.2.1 +#region HEADER $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone','https://github.com/PowerShell/DscResource.Tests.git', ` - (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests')) + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } -Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path ` - -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'Tests\MockWebAdministrationWindowsFeature.psm1') $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` -TestType Unit - -#endregion HEADER - -function Invoke-TestSetup { -} - -function Invoke-TestCleanup { - Restore-TestEnvironment -TestEnvironment $TestEnvironment -} +#endregion # Begin Testing try { - Invoke-TestSetup + #region Pester Tests InModuleScope $script:DSCResourceName { Describe "$($script:DSCResourceName)\Get-TargetResource" { - Context 'Get application pool defaults' { + Mock Assert-Module + + Context 'Application pool defaults' { + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } processModel = @{ identityType = 'SpecificUser' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = 'P@$$w0rd' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = 'CONTOSO\JDoe' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } } } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] - } + $result = Get-TargetResource -ApplyTo 'Machine' + + It 'Should return the autoStart property' { + $result.autoStart | Should Be $mockAppPoolDefaults.autoStart } - $result = Get-TargetResource -ApplyTo 'Machine' + It 'Should return the CLRConfigFile property' { + $result.CLRConfigFile | Should Be $mockAppPoolDefaults.CLRConfigFile + } + + It 'Should return the enable32BitAppOnWin64 property' { + $result.enable32BitAppOnWin64 | Should Be $mockAppPoolDefaults.enable32BitAppOnWin64 + } + + It 'Should return the enableConfigurationOverride property' { + $result.enableConfigurationOverride | Should Be $mockAppPoolDefaults.enableConfigurationOverride + } + + It 'Should return the managedPipelineMode property' { + $result.managedPipelineMode | Should Be $mockAppPoolDefaults.managedPipelineMode + } + + It 'Should return the managedRuntimeLoader property' { + $result.managedRuntimeLoader | Should Be $mockAppPoolDefaults.managedRuntimeLoader + } + + It 'Should return the managedRuntimeVersion property' { + $result.managedRuntimeVersion | Should Be $mockAppPoolDefaults.managedRuntimeVersion + } + + It 'Should return the passAnonymousToken property' { + $result.passAnonymousToken | Should Be $mockAppPoolDefaults.passAnonymousToken + } + + It 'Should return the startMode property' { + $result.startMode | Should Be $mockAppPoolDefaults.startMode + } + + It 'Should return the queueLength property' { + $result.queueLength | Should Be $mockAppPoolDefaults.queueLength + } + + It 'Should return the cpuAction property' { + $result.cpuAction | Should Be $mockAppPoolDefaults.cpu.action + } + + It 'Should return the cpuLimit property' { + $result.cpuLimit | Should Be $mockAppPoolDefaults.cpu.limit + } + + It 'Should return the cpuResetInterval property' { + $result.cpuResetInterval | Should Be $mockAppPoolDefaults.cpu.resetInterval + } + + It 'Should return the cpuSmpAffinitized property' { + $result.cpuSmpAffinitized | Should Be $mockAppPoolDefaults.cpu.smpAffinitized + } + + It 'Should return the cpuSmpProcessorAffinityMask property' { + $result.cpuSmpProcessorAffinityMask | Should Be $mockAppPoolDefaults.cpu.smpProcessorAffinityMask + } + + It 'Should return the cpuSmpProcessorAffinityMask2 property' { + $result.cpuSmpProcessorAffinityMask2 | Should Be $mockAppPoolDefaults.cpu.smpProcessorAffinityMask2 + } + + It 'Should return the identityType property' { + $result.identityType | Should Be $mockAppPoolDefaults.processModel.identityType + } + + It 'Should return the Credential (userName) property' { + # Get-DscConfiguration returns MSFT_Credential with empty UserName + $result.Credential.userName | Should Be $mockAppPoolDefaults.processModel.userName + } + + It 'Should return the Credential (password) property' { + # Get-DscConfiguration returns MSFT_Credential with empty Password + $result.Credential.Password | Should Be $mockAppPoolDefaults.processModel.password + } + + It 'Should return the idleTimeout property' { + $result.idleTimeout | Should Be $mockAppPoolDefaults.processModel.idleTimeout + } + + It 'Should return the idleTimeoutAction property' { + $result.idleTimeoutAction | Should Be $mockAppPoolDefaults.processModel.idleTimeoutAction + } + + It 'Should return the loadUserProfile property' { + $result.loadUserProfile | Should Be $mockAppPoolDefaults.processModel.loadUserProfile + } + + It 'Should return the logonType property' { + $result.logonType | Should Be $mockAppPoolDefaults.processModel.logonType + } + + It 'Should return the logEventOnProcessModel property' { + $result.logEventOnProcessModel | Should Be $mockAppPoolDefaults.processModel.logEventOnProcessModel + } + + It 'Should return the manualGroupMembership property' { + $result.manualGroupMembership | Should Be $mockAppPoolDefaults.processModel.manualGroupMembership + } + + It 'Should return the maxProcesses property' { + $result.maxProcesses | Should Be $mockAppPoolDefaults.processModel.maxProcesses + } + + It 'Should return the pingingEnabled property' { + $result.pingingEnabled | Should Be $mockAppPoolDefaults.processModel.pingingEnabled + } + + It 'Should return the pingInterval property' { + $result.pingInterval | Should Be $mockAppPoolDefaults.processModel.pingInterval + } + + It 'Should return the pingResponseTime property' { + $result.pingResponseTime | Should Be $mockAppPoolDefaults.processModel.pingResponseTime + } + + It 'Should return the setProfileEnvironment property' { + $result.setProfileEnvironment | Should Be $mockAppPoolDefaults.processModel.setProfileEnvironment + } + + It 'Should return the shutdownTimeLimit property' { + $result.shutdownTimeLimit | Should Be $mockAppPoolDefaults.processModel.shutdownTimeLimit + } + + It 'Should return the startupTimeLimit property' { + $result.startupTimeLimit | Should Be $mockAppPoolDefaults.processModel.startupTimeLimit + } + + It 'Should return the orphanActionExe property' { + $result.orphanActionExe | Should Be $mockAppPoolDefaults.failure.orphanActionExe + } + + It 'Should return the orphanActionParams property' { + $result.orphanActionParams | Should Be $mockAppPoolDefaults.failure.orphanActionParams + } + + It 'Should return the orphanWorkerProcess property' { + $result.orphanWorkerProcess | Should Be $mockAppPoolDefaults.failure.orphanWorkerProcess + } + + It 'Should return the loadBalancerCapabilities property' { + $result.loadBalancerCapabilities | Should Be $mockAppPoolDefaults.failure.loadBalancerCapabilities + } + + It 'Should return the rapidFailProtection property' { + $result.rapidFailProtection | Should Be $mockAppPoolDefaults.failure.rapidFailProtection + } + + It 'Should return the rapidFailProtectionInterval property' { + $result.rapidFailProtectionInterval | Should Be $mockAppPoolDefaults.failure.rapidFailProtectionInterval + } + + It 'Should return the rapidFailProtectionMaxCrashes property' { + $result.rapidFailProtectionMaxCrashes | Should Be $mockAppPoolDefaults.failure.rapidFailProtectionMaxCrashes + } + + It 'Should return the autoShutdownExe property' { + $result.autoShutdownExe | Should Be $mockAppPoolDefaults.failure.autoShutdownExe + } + + It 'Should return the autoShutdownParams property' { + $result.autoShutdownParams | Should Be $mockAppPoolDefaults.failure.autoShutdownParams + } + + It 'Should return the disallowOverlappingRotation property' { + $result.disallowOverlappingRotation | Should Be $mockAppPoolDefaults.recycling.disallowOverlappingRotation + } + + It 'Should return the disallowRotationOnConfigChange property' { + $result.disallowRotationOnConfigChange | Should Be $mockAppPoolDefaults.recycling.disallowRotationOnConfigChange + } + + It 'Should return the logEventOnRecycle property' { + $result.logEventOnRecycle | Should Be $mockAppPoolDefaults.recycling.logEventOnRecycle + } + + It 'Should return the restartMemoryLimit property' { + $result.restartMemoryLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.memory + } + + It 'Should return the restartPrivateMemoryLimit property' { + $result.restartPrivateMemoryLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.privateMemory + } + + It 'Should return the restartRequestsLimit property' { + $result.restartRequestsLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.requests + } - It 'Should return managedRuntimeVersion' { - $result.managedRuntimeVersion | ` - Should Be $mockAppPoolDefaults.managedRuntimeVersion + It 'Should return the restartTimeLimit property' { + $result.restartTimeLimit | Should Be $mockAppPoolDefaults.recycling.periodicRestart.time } - It 'Should return processModel\identityType' { - $result.identityType | ` - Should Be $mockAppPoolDefaults.processModel.identityType + It 'Should return the restartSchedule property' { + + $restartScheduleValues = [String[]]@( + @($mockAppPoolDefaults.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $compareSplat = @{ + ReferenceObject = [String[]]@($result.restartSchedule) + DifferenceObject = $restartScheduleValues + ExcludeDifferent = $true + IncludeEqual = $true + } + + $compareResult = Compare-Object @compareSplat + + $compareResult.Count -eq $restartScheduleValues.Count | Should Be $true + } + } + } - Describe "$($script:DSCResourceName)\Test-TargetResource" { + Describe "how '$($script:DSCResourceName)\Test-TargetResource' responds" { + + Mock Assert-Module + + Context 'Test target resource with no property specified' { - $mockAppPoolDefaults = @{ - managedRuntimeVersion = 'v4.0' - processModel = @{ - identityType = 'NetworkService' + $mockAppPoolDefaults = @{ } - } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] + It 'Should return True' { + Test-TargetResource -ApplyTo 'Machine' | + Should Be $true } + } - Context 'Application pool defaults correct' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'NetworkService' + Context 'All the properties match the desired state' { + + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } + processModel = @{ + identityType = 'SpecificUser' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = 'P@$$w0rD' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = 'CONTOSO\JDoe' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + $mockRestartSchedule = [String[]]@( + @($mockAppPoolDefaults.recycling.periodicRestart.schedule.Collection).ForEach('value') + ) + + $testParamsSplat = @{ + autoStart = $mockAppPoolDefaults.autoStart + CLRConfigFile = $mockAppPoolDefaults.CLRConfigFile + enable32BitAppOnWin64 = $mockAppPoolDefaults.enable32BitAppOnWin64 + enableConfigurationOverride = $mockAppPoolDefaults.enableConfigurationOverride + managedPipelineMode = $mockAppPoolDefaults.managedPipelineMode + managedRuntimeLoader = $mockAppPoolDefaults.managedRuntimeLoader + managedRuntimeVersion = $mockAppPoolDefaults.managedRuntimeVersion + passAnonymousToken = $mockAppPoolDefaults.passAnonymousToken + startMode = $mockAppPoolDefaults.startMode + queueLength = $mockAppPoolDefaults.queueLength + cpuAction = $mockAppPoolDefaults.cpu.action + cpuLimit = $mockAppPoolDefaults.cpu.limit + cpuResetInterval = $mockAppPoolDefaults.cpu.resetInterval + cpuSmpAffinitized = $mockAppPoolDefaults.cpu.smpAffinitized + cpuSmpProcessorAffinityMask = $mockAppPoolDefaults.cpu.smpProcessorAffinityMask + cpuSmpProcessorAffinityMask2 = $mockAppPoolDefaults.cpu.smpProcessorAffinityMask2 + identityType = $mockAppPoolDefaults.processModel.identityType + Credential = $mockCredential + idleTimeout = $mockAppPoolDefaults.processModel.idleTimeout + idleTimeoutAction = $mockAppPoolDefaults.processModel.idleTimeoutAction + loadUserProfile = $mockAppPoolDefaults.processModel.loadUserProfile + logEventOnProcessModel = $mockAppPoolDefaults.processModel.logEventOnProcessModel + logonType = $mockAppPoolDefaults.processModel.logonType + manualGroupMembership = $mockAppPoolDefaults.processModel.manualGroupMembership + maxProcesses = $mockAppPoolDefaults.processModel.maxProcesses + pingingEnabled = $mockAppPoolDefaults.processModel.pingingEnabled + pingInterval = $mockAppPoolDefaults.processModel.pingInterval + pingResponseTime = $mockAppPoolDefaults.processModel.pingResponseTime + setProfileEnvironment = $mockAppPoolDefaults.processModel.setProfileEnvironment + shutdownTimeLimit = $mockAppPoolDefaults.processModel.shutdownTimeLimit + startupTimeLimit = $mockAppPoolDefaults.processModel.startupTimeLimit + orphanActionExe = $mockAppPoolDefaults.failure.orphanActionExe + orphanActionParams = $mockAppPoolDefaults.failure.orphanActionParams + orphanWorkerProcess = $mockAppPoolDefaults.failure.orphanWorkerProcess + loadBalancerCapabilities = $mockAppPoolDefaults.failure.loadBalancerCapabilities + rapidFailProtection = $mockAppPoolDefaults.failure.rapidFailProtection + rapidFailProtectionInterval = $mockAppPoolDefaults.failure.rapidFailProtectionInterval + rapidFailProtectionMaxCrashes = $mockAppPoolDefaults.failure.rapidFailProtectionMaxCrashes + autoShutdownExe = $mockAppPoolDefaults.failure.autoShutdownExe + autoShutdownParams = $mockAppPoolDefaults.failure.autoShutdownParams + disallowOverlappingRotation = $mockAppPoolDefaults.recycling.disallowOverlappingRotation + disallowRotationOnConfigChange = $mockAppPoolDefaults.recycling.disallowRotationOnConfigChange + logEventOnRecycle = $mockAppPoolDefaults.recycling.logEventOnRecycle + restartMemoryLimit = $mockAppPoolDefaults.recycling.periodicRestart.memory + restartPrivateMemoryLimit = $mockAppPoolDefaults.recycling.periodicRestart.privateMemory + restartRequestsLimit = $mockAppPoolDefaults.recycling.periodicRestart.requests + restartTimeLimit = $mockAppPoolDefaults.recycling.periodicRestart.time + restartSchedule = $mockRestartSchedule + } It 'Should return True' { - $result | Should Be $true + Test-TargetResource -ApplyTo Machine @testParamsSplat | + Should Be $true } + } - Context 'Application pool different managedRuntimeVersion' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v2.0' ` - -IdentityType 'NetworkService' + Context 'Test the autoStart property' { + + $mockAppPoolDefaults = @{ + autoStart = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoStart $true | + Should Be $true + } - It 'Should return False' { - $result | Should Be $false + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoStart $false | + Should Be $false } + } - Context 'Application pool different processModel/@identityType' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'LocalSystem' + Context 'Test the CLRConfigFile property' { + + $mockAppPoolDefaults = @{ + CLRConfigFile = '' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -CLRConfigFile '' | + Should Be $true + } - It 'Should return False' { - $result | Should Be $false + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -CLRConfigFile 'C:\inetpub\temp\aspnet.config' | + Should Be $false } + } - Context 'Application pool no value for managedRuntimeVersion' { - $result = Test-TargetResource -ApplyTo 'Machine' ` - -IdentityType 'NetworkService' + Context 'Test the enable32BitAppOnWin64 property' { - It 'Should return True' { - $result | Should Be $true + $mockAppPoolDefaults = @{ + enable32BitAppOnWin64 = $false + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -enable32BitAppOnWin64 $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -enable32BitAppOnWin64 $true | + Should Be $false + } + + } + + Context 'Test the enableConfigurationOverride property' { + + $mockAppPoolDefaults = @{ + enableConfigurationOverride = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -enableConfigurationOverride $true | + Should Be $true } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -enableConfigurationOverride $false | + Should Be $false + } + } - } - Describe "$($script:DSCResourceName)\Set-TargetResource" { + Context 'Test the managedPipelineMode property' { + + $mockAppPoolDefaults = @{ + managedPipelineMode = 'Integrated' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedPipelineMode 'Integrated' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedPipelineMode 'Classic' | + Should Be $false + } + + } + + Context 'Test the managedRuntimeLoader property' { + + $mockAppPoolDefaults = @{ + managedRuntimeLoader = 'webengine4.dll' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeLoader 'webengine4.dll' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeLoader '' | + Should Be $false + } + + } + + Context 'Test the managedRuntimeVersion property' { + + $mockAppPoolDefaults = @{ + managedRuntimeVersion = 'v4.0' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeVersion 'v4.0' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -managedRuntimeVersion 'v2.0' | + Should Be $false + } + + } + + Context 'Test the passAnonymousToken property' { + + $mockAppPoolDefaults = @{ + passAnonymousToken = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -passAnonymousToken $true | + Should Be $true + } - $mockAppPoolDefaults = @{ - managedRuntimeVersion = 'v4.0' - processModel = @{ - identityType = 'NetworkService' + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -passAnonymousToken $false | + Should Be $false } + } - Mock Get-WebConfigurationProperty -MockWith { - $path = $Filter.Replace('system.applicationHost/applicationPools/applicationPoolDefaults', '') + Context 'Test the startMode property' { + + $mockAppPoolDefaults = @{ + startMode = 'OnDemand' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -startMode 'OnDemand' | + Should Be $true + } - if ([System.String]::IsNullOrEmpty($path)) { - return $mockAppPoolDefaults[$Name] - } else { - $path = $path.Replace('/', '') - return $mockAppPoolDefaults[$path][$Name] + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -startMode 'AlwaysRunning' | + Should Be $false } + } - Mock Set-WebConfigurationProperty -MockWith { } + Context 'Test the queueLength property' { + + $mockAppPoolDefaults = @{ + queueLength = 1000 + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} - Context 'Application pool defaults correct' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'NetworkService' + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -queueLength 1000 | + Should Be $true + } - It 'Should not call Set-WebConfigurationProperty' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 0 + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -queueLength 2000 | + Should Be $false } + } - Context 'Application pool different managedRuntimeVersion' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v2.0' ` - -IdentityType 'NetworkService' + Context 'Test the cpuAction property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + action = 'NoAction' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuAction 'NoAction' | + Should Be $true + } - It 'Should call Set-WebConfigurationProperty once' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 1 ` - -ParameterFilter { $Name -eq 'managedRuntimeVersion' } + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuAction 'KillW3wp' | + Should Be $false } + } - Context 'Application pool different processModel/@identityType' { - Set-TargetResource -ApplyTo 'Machine' ` - -ManagedRuntimeVersion 'v4.0' ` - -IdentityType 'LocalSystem' + Context 'Test the cpuLimit property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + limit = 0 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuLimit 0 | + Should Be $true + } - It 'Should call Set-WebConfigurationProperty once' { - Assert-MockCalled Set-WebConfigurationProperty -Exactly 1 ` - -ParameterFilter { $Name -eq 'identityType' } + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuLimit 90000 | + Should Be $false } + } - } - } -} -finally -{ - Invoke-TestCleanup + + Context 'Test the cpuResetInterval property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + resetInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuResetInterval '00:05:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuResetInterval '00:10:00' | + Should Be $false + } + + } + + Context 'Test the cpuSmpAffinitized property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpAffinitized = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpAffinitized $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpAffinitized $true | + Should Be $false + } + + } + + Context 'Test the cpuSmpProcessorAffinityMask property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask 4294967295 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask 1 | + Should Be $false + } + + } + + Context 'Test the cpuSmpProcessorAffinityMask2 property' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask2 = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask2 4294967295 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -cpuSmpProcessorAffinityMask2 1 | + Should Be $false + } + + } + + Context 'Test the identityType property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'ApplicationPoolIdentity' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -identityType 'ApplicationPoolIdentity' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -identityType 'NetworkService' | + Should Be $false + } + + } + + Context 'Test the Credential property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'SpecificUser' + password = '1q2w3e4r' + userName = 'CONTOSO\JDoe' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when both the userName and the password properties match the desired state' { + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $true + + } + + It 'Should return False when the userName property does not match the desired state' { + + $mockUserName = 'CONTOSO\GFawkes' + $mockPassword = $mockAppPoolDefaults.processModel.password | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $false + + } + + It 'Should return False when the password property does not match the desired state' { + + $mockUserName = $mockAppPoolDefaults.processModel.userName + $mockPassword = '5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + Test-TargetResource -ApplyTo Machine -identityType 'SpecificUser' -Credential $mockCredential | + Should Be $false + + } + + } + + Context 'Test the idleTimeout property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeout = '00:20:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeout '00:20:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeout '00:15:00' | + Should Be $false + } + + } + + Context 'Test the idleTimeoutAction property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeoutAction = 'Terminate' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeoutAction 'Terminate' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -idleTimeoutAction 'Suspend' | + Should Be $false + } + + } + + Context 'Test the loadUserProfile property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + loadUserProfile = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -loadUserProfile $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -loadUserProfile $false | + Should Be $false + } + + } + + Context 'Test the logEventOnProcessModel property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logEventOnProcessModel = 'IdleTimeout' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnProcessModel 'IdleTimeout' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnProcessModel '' | + Should Be $false + } + + } + + Context 'Test the logonType property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logonType = 'LogonBatch' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logonType 'LogonBatch' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logonType 'LogonService' | + Should Be $false + } + + } + + Context 'Test the manualGroupMembership property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + manualGroupMembership = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -manualGroupMembership $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -manualGroupMembership $true | + Should Be $false + } + + } + + Context 'Test the maxProcesses property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + maxProcesses = 1 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -maxProcesses 1 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -maxProcesses 2 | + Should Be $false + } + + } + + Context 'Test the pingingEnabled property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingingEnabled = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingingEnabled $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingingEnabled $false | + Should Be $false + } + + } + + Context 'Test the pingInterval property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingInterval = '00:00:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingInterval '00:00:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingInterval '00:01:00' | + Should Be $false + } + + } + + Context 'Test the pingResponseTime property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingResponseTime = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -pingResponseTime '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -pingResponseTime '00:02:00' | + Should Be $false + } + + } + + Context 'Test the setProfileEnvironment property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + setProfileEnvironment = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -setProfileEnvironment $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -setProfileEnvironment $true | + Should Be $false + } + + } + + Context 'Test the shutdownTimeLimit property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + shutdownTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -shutdownTimeLimit '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -shutdownTimeLimit '00:02:00' | + Should Be $false + } + + } + + Context 'Test the startupTimeLimit property' { + + $mockAppPoolDefaults = @{ + processModel = @{ + startupTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -startupTimeLimit '00:01:30' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -startupTimeLimit '00:02:00' | + Should Be $false + } + + } + + Context 'Test the orphanActionExe property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionExe '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionExe 'C:\inetpub\temp\orphanAction.exe' | + Should Be $false + } + + } + + Context 'Test the orphanActionParams property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionParams '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanActionParams '/orphanActionParam1' | + Should Be $false + } + + } + + Context 'Test the orphanWorkerProcess property' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanWorkerProcess = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -orphanWorkerProcess $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -orphanWorkerProcess $true | + Should Be $false + } + + } + + Context 'Test the loadBalancerCapabilities property' { + + $mockAppPoolDefaults = @{ + failure = @{ + loadBalancerCapabilities = 'HttpLevel' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -loadBalancerCapabilities 'HttpLevel' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -loadBalancerCapabilities 'TcpLevel' | + Should Be $false + } + + } + + Context 'Test the rapidFailProtection property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtection = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtection $true | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtection $false | + Should Be $false + } + + } + + Context 'Test the rapidFailProtectionInterval property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionInterval '00:05:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionInterval '00:10:00' | + Should Be $false + } + + } + + Context 'Test the rapidFailProtectionMaxCrashes property' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionMaxCrashes = 5 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionMaxCrashes 5 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -rapidFailProtectionMaxCrashes 10 | + Should Be $false + } + + } + + Context 'Test the autoShutdownExe property' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownExe '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownExe 'C:\inetpub\temp\autoShutdown.exe' | + Should Be $false + } + + } + + Context 'Test the autoShutdownParams property' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownParams '' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -autoShutdownParams '/autoShutdownParam1' | + Should Be $false + } + + } + + Context 'Test the disallowOverlappingRotation property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowOverlappingRotation = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -disallowOverlappingRotation $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -disallowOverlappingRotation $true | + Should Be $false + } + + } + + Context 'Test the disallowRotationOnConfigChange property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowRotationOnConfigChange = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -disallowRotationOnConfigChange $false | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -disallowRotationOnConfigChange $true | + Should Be $false + } + + } + + Context 'Test the logEventOnRecycle property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnRecycle 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -logEventOnRecycle 'Time,Memory,PrivateMemory' | + Should Be $false + } + + } + + Context 'Test the restartMemoryLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + memory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartMemoryLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartMemoryLimit 1048576 | + Should Be $false + } + + } + + Context 'Test the restartPrivateMemoryLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + privateMemory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartPrivateMemoryLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartPrivateMemoryLimit 1048576 | + Should Be $false + } + + } + + Context 'Test the restartRequestsLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + requests = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartRequestsLimit 0 | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartRequestsLimit 1000 | + Should Be $false + } + + } + + Context 'Test the restartTimeLimit property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + time = '1.05:00:00' + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartTimeLimit '1.05:00:00' | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartTimeLimit '2.10:00:00' | + Should Be $false + } + + } + + Context 'Test the restartSchedule property' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + schedule = @{ + Collection = @( + @{value = '04:00:00'} + @{value = '08:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + It 'Should return True when the property matches the desired state' { + Test-TargetResource -ApplyTo Machine -restartSchedule @('04:00:00', '08:00:00') | + Should Be $true + } + + It 'Should return False when the property does not match the desired state' { + Test-TargetResource -ApplyTo Machine -restartSchedule @('') | + Should Be $false + } + + } + + } + + Describe "how '$($script:DSCResourceName)\Set-TargetResource' responds" { + + Mock -CommandName Assert-Module -MockWith {} + + Context 'All the properties need to be set' { + + $mockAppPoolDefaults = @{ + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpu = @{ + action = 'NoAction' + limit = 0 + resetInterval = '00:05:00' + smpAffinitized = $false + smpProcessorAffinityMask = 4294967295 + smpProcessorAffinityMask2 = 4294967295 + } + processModel = @{ + identityType = 'ApplicationPoolIdentity' + idleTimeout = '00:20:00' + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + password = '' + pingingEnabled = $true + pingInterval = '00:00:30' + pingResponseTime = '00:01:30' + setProfileEnvironment = $false + shutdownTimeLimit = '00:01:30' + startupTimeLimit = '00:01:30' + userName = '' + } + failure = @{ + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = '00:05:00' + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + } + recycling = @{ + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + periodicRestart = @{ + memory = 0 + privateMemory = 0 + requests = 0 + time = '1.05:00:00' + schedule = @{ + Collection = @( + @{value = '02:00:00'} + @{value = '04:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $mockUserName = 'CONTOSO\GFawkes' + $mockPassword = '5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force + $mockCredential = New-Object -TypeName PSCredential -ArgumentList $mockUserName, $mockPassword + + $setParamsSplat = @{ + autoStart = $false + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + enable32BitAppOnWin64 = $true + enableConfigurationOverride = $false + managedPipelineMode = 'Classic' + managedRuntimeLoader = '' + managedRuntimeVersion = 'v2.0' + passAnonymousToken = $false + startMode = 'AlwaysRunning' + queueLength = 2000 + cpuAction = 'KillW3wp' + cpuLimit = 90000 + cpuResetInterval = '00:10:00' + cpuSmpAffinitized = $true + cpuSmpProcessorAffinityMask = 1 + cpuSmpProcessorAffinityMask2 = 1 + identityType = 'SpecificUser' + Credential = $mockCredential + idleTimeout = '00:15:00' + idleTimeoutAction = 'Suspend' + loadUserProfile = $false + logEventOnProcessModel = '' + logonType = 'LogonService' + manualGroupMembership = $true + maxProcesses = 2 + pingingEnabled = $false + pingInterval = '00:01:00' + pingResponseTime = '00:02:00' + setProfileEnvironment = $true + shutdownTimeLimit = '00:02:00' + startupTimeLimit = '00:02:00' + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + orphanActionParams = '/orphanActionParam1' + orphanWorkerProcess = $true + loadBalancerCapabilities = 'TcpLevel' + rapidFailProtection = $false + rapidFailProtectionInterval = '00:10:00' + rapidFailProtectionMaxCrashes = 10 + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + autoShutdownParams = '/autoShutdownParam1' + disallowOverlappingRotation = $true + disallowRotationOnConfigChange = $true + logEventOnRecycle = 'Time,Memory,PrivateMemory' + restartMemoryLimit = 1048576 + restartPrivateMemoryLimit = 1048576 + restartRequestsLimit = 1000 + restartTimeLimit = '2.10:00:00' + restartSchedule = @('06:00:00', '08:00:00') + } + + Mock Invoke-AppCmd + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call all the mocks' { + Assert-MockCalled Invoke-AppCmd -Exactly 52 + } + + } + + Context 'The autoStart property needs to be set' { + + $mockAppPoolDefaults = @{ + autoStart = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoStart = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/autoStart:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The CLRConfigFile property needs to be set' { + + $mockAppPoolDefaults = @{ + CLRConfigFile = '' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/CLRConfigFile:C:\inetpub\temp\aspnet.config'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The enable32BitAppOnWin64 property needs to be set' { + + $mockAppPoolDefaults = @{ + enable32BitAppOnWin64 = $false + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + enable32BitAppOnWin64 = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enable32BitAppOnWin64:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The enableConfigurationOverride property needs to be set' { + + $mockAppPoolDefaults = @{ + enableConfigurationOverride = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + enableConfigurationOverride = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enableConfigurationOverride:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedPipelineMode property needs to be set' { + + $mockAppPoolDefaults = @{ + managedPipelineMode = 'Integrated' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedPipelineMode = 'Classic' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedPipelineMode:Classic'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedRuntimeLoader property needs to be set' { + + $mockAppPoolDefaults = @{ + managedRuntimeLoader = 'webengine4.dll' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedRuntimeLoader = '' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeLoader:'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The managedRuntimeVersion property needs to be set' { + + $mockAppPoolDefaults = @{ + managedRuntimeVersion = 'v4.0' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + managedRuntimeVersion = 'v2.0' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeVersion:v2.0'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The passAnonymousToken property needs to be set' { + + $mockAppPoolDefaults = @{ + passAnonymousToken = $true + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + passAnonymousToken = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/passAnonymousToken:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The startMode property needs to be set' { + + $mockAppPoolDefaults = @{ + startMode = 'OnDemand' + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + startMode = 'AlwaysRunning' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/startMode:AlwaysRunning'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The queueLength property needs to be set' { + + $mockAppPoolDefaults = @{ + queueLength = 1000 + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + queueLength = 2000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/queueLength:2000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuAction property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + action = 'NoAction' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuAction = 'KillW3wp' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.action:KillW3wp'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + limit = 0 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuLimit = 90000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.limit:90000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuResetInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + resetInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuResetInterval = '00:10:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.resetInterval:00:10:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpAffinitized property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpAffinitized = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpAffinitized = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpAffinitized:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpProcessorAffinityMask property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpProcessorAffinityMask = 1 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask:1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The cpuSmpProcessorAffinityMask2 property needs to be set' { + + $mockAppPoolDefaults = @{ + cpu = @{ + smpProcessorAffinityMask2 = 4294967295 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + cpuSmpProcessorAffinityMask2 = 1 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask2:1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The identityType property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + identityType = 'ApplicationPoolIdentity' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + identityType = 'SpecificUser' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.identityType:SpecificUser'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The idleTimeout property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeout = '00:20:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + idleTimeout = '00:15:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeout:00:15:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The idleTimeoutAction property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + idleTimeoutAction = 'Terminate' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + idleTimeoutAction = 'Suspend' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeoutAction:Suspend'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The loadUserProfile property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + loadUserProfile = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + loadUserProfile = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.loadUserProfile:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logEventOnProcessModel property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logEventOnProcessModel = 'IdleTimeout' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logEventOnProcessModel = '' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logEventOnProcessModel:'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logonType property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + logonType = 'LogonBatch' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logonType = 'LogonService' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logonType:LogonService'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The manualGroupMembership property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + manualGroupMembership = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + manualGroupMembership = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.manualGroupMembership:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The maxProcesses property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + maxProcesses = 1 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + maxProcesses = 2 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.maxProcesses:2'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingingEnabled property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingingEnabled = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingingEnabled = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingingEnabled:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingInterval = '00:00:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingInterval = '00:01:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingInterval:00:01:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The pingResponseTime property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + pingResponseTime = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + pingResponseTime = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingResponseTime:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The setProfileEnvironment property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + setProfileEnvironment = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + setProfileEnvironment = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.setProfileEnvironment:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The shutdownTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + shutdownTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + shutdownTimeLimit = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.shutdownTimeLimit:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The startupTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + processModel = @{ + startupTimeLimit = '00:01:30' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + startupTimeLimit = '00:02:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.startupTimeLimit:00:02:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanActionExe property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanActionParams property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanActionParams = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanActionParams = '/orphanActionParam1' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionParams:/orphanActionParam1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The orphanWorkerProcess property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + orphanWorkerProcess = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + orphanWorkerProcess = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanWorkerProcess:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The loadBalancerCapabilities property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + loadBalancerCapabilities = 'HttpLevel' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + loadBalancerCapabilities = 'TcpLevel' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.loadBalancerCapabilities:TcpLevel'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtection property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtection = $true + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtection = $false + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtection:False'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtectionInterval property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionInterval = '00:05:00' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtectionInterval = '00:10:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionInterval:00:10:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The rapidFailProtectionMaxCrashes property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + rapidFailProtectionMaxCrashes = 5 + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + rapidFailProtectionMaxCrashes = 10 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionMaxCrashes:10'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The autoShutdownExe property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownExe = '' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The autoShutdownParams property needs to be set' { + + $mockAppPoolDefaults = @{ + failure = @{ + autoShutdownParams = '' + } + + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + autoShutdownParams = '/autoShutdownParam1' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownParams:/autoShutdownParam1'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The disallowOverlappingRotation property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowOverlappingRotation = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + disallowOverlappingRotation = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowOverlappingRotation:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The disallowRotationOnConfigChange property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + disallowRotationOnConfigChange = $false + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + disallowRotationOnConfigChange = $true + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowRotationOnConfigChange:True'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The logEventOnRecycle property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + logEventOnRecycle = 'Time,Memory,PrivateMemory' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartMemoryLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + memory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartMemoryLimit = 1048576 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.memory:1048576'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartPrivateMemoryLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + privateMemory = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartPrivateMemoryLimit = 1048576 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.privateMemory:1048576'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartRequestsLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + requests = 0 + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartRequestsLimit = 1000 + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.requests:1000'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartTimeLimit property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + time = '1.05:00:00' + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartTimeLimit = '2.10:00:00' + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.time:2.10:00:00'} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -Exactly 1 + } + + } + + Context 'The restartSchedule property needs to be set' { + + $mockAppPoolDefaults = @{ + recycling = @{ + periodicRestart = @{ + schedule = @{ + Collection = @( + @{value = '04:00:00'} + ) + } + } + } + } + + Mock Get-AppPoolDefault -MockWith {$mockAppPoolDefaults} + + $setParamsSplat = @{ + restartSchedule = @('08:00:00') + } + + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} + + Set-TargetResource -ApplyTo Machine @setParamsSplat + + It 'Should call Invoke-AppCmd' { + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 + } + + } + + } + + } + + #endregion +} +finally +{ + Restore-TestEnvironment -TestEnvironment $TestEnvironment } From 1f47806f756e2f4f63ea79750b2f0cfa823aed98 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:41:30 +0300 Subject: [PATCH 16/22] updated release notes --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8d8e99255..611225b5f 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,8 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### Unreleased +* Added missing settings for **xWebAppPoolDefaults**. Fixes #105. + ### 1.20.0.0 * Fix Get-DscConfiguration failure with xWebApplication and xWebSite resources From ebe8ae6a020c94fdbebcfbc06fd150bc9199cda3 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 22:55:46 +0300 Subject: [PATCH 17/22] Updated sample usage in readme and in sample file --- Examples/Sample_xWebAppPoolDefaults.ps1 | 53 ++++++++- README.md | 137 +++++++++++++++++++++++- 2 files changed, 182 insertions(+), 8 deletions(-) diff --git a/Examples/Sample_xWebAppPoolDefaults.ps1 b/Examples/Sample_xWebAppPoolDefaults.ps1 index 6eca34e0b..b1b67dfc1 100644 --- a/Examples/Sample_xWebAppPoolDefaults.ps1 +++ b/Examples/Sample_xWebAppPoolDefaults.ps1 @@ -21,9 +21,56 @@ Configuration Sample_xWebAppPoolDefaults # Configures the application pool defaults. xWebAppPoolDefaults PoolDefaults { - ApplyTo = 'Machine' - ManagedRuntimeVersion = 'v4.0' - IdentityType = 'ApplicationPoolIdentity' + ApplyTo = 'Machine' + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpuAction = 'NoAction' + cpuLimit = 90000 + cpuResetInterval = (New-TimeSpan -Minutes 5).ToString() + cpuSmpAffinitized = $false + cpuSmpProcessorAffinityMask = 4294967295 + cpuSmpProcessorAffinityMask2 = 4294967295 + identityType = 'ApplicationPoolIdentity' + idleTimeout = (New-TimeSpan -Minutes 20).ToString() + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + pingingEnabled = $true + pingInterval = (New-TimeSpan -Seconds 30).ToString() + pingResponseTime = (New-TimeSpan -Seconds 90).ToString() + setProfileEnvironment = $false + shutdownTimeLimit = (New-TimeSpan -Seconds 90).ToString() + startupTimeLimit = (New-TimeSpan -Seconds 90).ToString() + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = (New-TimeSpan -Minutes 5).ToString() + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + restartMemoryLimit = 0 + restartPrivateMemoryLimit = 0 + restartRequestsLimit = 0 + restartTimeLimit = (New-TimeSpan -Minutes 1440).ToString() + restartSchedule = @('00:00:00', '08:00:00', '16:00:00') } + + } } diff --git a/README.md b/README.md index 611225b5f..bc84cf22a 100644 --- a/README.md +++ b/README.md @@ -242,8 +242,90 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ### xWebAppPoolDefaults * **ApplyTo**: Required Key value, always **Machine** -* **ManagedRuntimeVersion**: CLR Version {v2.0|v4.0|} empty string for unmanaged. -* **ApplicationPoolIdentity**: {ApplicationPoolIdentity | LocalService | LocalSystem | NetworkService} +* **autoStart** : When set to `$true`, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started. +* **CLRConfigFile** : Indicates the .NET configuration file for the application pool. +* **enable32BitAppOnWin64** : When set to `$true`, enables a 32-bit application to run on a computer that runs a 64-bit version of Windows. +* **enableConfigurationOverride** : When set to `$true`, indicates that delegated settings in Web.config files will be processed for applications within this application pool. + When set to `$false`, all settings in Web.config files will be ignored for this application pool. +* **managedPipelineMode** : Indicates the request-processing mode that is used to process requests for managed content. The values that are allowed for this property are: `Integrated`, `Classic`. +* **managedRuntimeLoader** : Indicates the managed loader to use for pre-loading the application pool. +* **managedRuntimeVersion** : Indicates the CLR version to be used by the application pool. The values that are allowed for this property are: `v4.0`, `v2.0`, and `""`. +* **passAnonymousToken** : When set to `$true`, the Windows Process Activation Service (WAS) creates and passes a token for the built-in IUSR anonymous user account to the Anonymous authentication module. + The Anonymous authentication module uses the token to impersonate the built-in account. When this property is set to `$false`, the token will not be passed. +* **startMode** : Indicates the startup type for the application pool. The values that are allowed for this property are: `OnDemand`, `AlwaysRunning`. +* **queueLength** : Indicates the maximum number of requests that HTTP.sys will queue for the application pool. The value must be a valid integer between `10` and `65535`. +* **cpuAction** : Configures the action that IIS takes when a worker process exceeds its configured CPU limit. + The values that are allowed for this property are: `NoAction`, `KillW3wp`, `Throttle`, and `ThrottleUnderLoad`. +* **cpuLimit** : Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in the application pool are allowed to consume over a period of time as indicated by the **cpuResetInterval** property. + The value must be a valid integer between `0` and `100000`. +* **cpuResetInterval** : Indicates the reset period (in minutes) for CPU monitoring and throttling limits on the application pool. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `0` to `1440`. + Setting the value of this property to `00:00:00` disables CPU monitoring. +* **cpuSmpAffinitized** : Indicates whether a particular worker process assigned to the application pool should also be assigned to a given CPU. +* **cpuSmpProcessorAffinityMask** : Indicates the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. + Before this property takes effect, the **cpuSmpAffinitized** property must be set to `$true` for the application pool. + The value must be a valid integer between `0` and `4294967295`. +* **cpuSmpProcessorAffinityMask2** : Indicates the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in the application pool should be bound. + Before this property takes effect, the **cpuSmpAffinitized** property must be set to `$true` for the application pool. + The value must be a valid integer between `0` and `4294967295`. +* **identityType** : Indicates the account identity under which the application pool runs. + The values that are allowed for this property are: `ApplicationPoolIdentity`, `LocalService`, `LocalSystem`, `NetworkService`, and `SpecificUser`. +* **Credential** : Indicates the custom account crededentials. This property is only valid when the **identityType** property is set to `SpecificUser`. +* **idleTimeout** : Indicates the amount of time (in minutes) a worker process will remain idle before it shuts down. + The value must be a string representation of a TimeSpan value and must be less than the **restartTimeLimit** property value. The valid range (in minutes) is `0` to `43200`. +* **idleTimeoutAction** : Indicates the action to perform when the idle timeout duration has been reached. + The values that are allowed for this property are: `Terminate`, `Suspend`. +* **loadUserProfile** : Indicates whether IIS loads the user profile for the application pool identity. +* **logEventOnProcessModel** : Indicates that IIS should generate an event log entry for each occurrence of the specified process model events. +* **logonType** : Indicates the logon type for the process identity. The values that are allowed for this property are: `LogonBatch`, `LogonService`. +* **manualGroupMembership** : Indicates whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token. +* **maxProcesses** : Indicates the maximum number of worker processes that would be used for the application pool. + The value must be a valid integer between `0` and `2147483647`. +* **pingingEnabled** : Indicates whether pinging (health monitoring) is enabled for the worker process(es) serving this application pool. +* **pingInterval** : Indicates the period of time (in seconds) between health monitoring pings sent to the worker process(es) serving this application pool. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **pingResponseTime** : Indicates the maximum time (in seconds) that a worker process is given to respond to a health monitoring ping. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **setProfileEnvironment** : Indicates the environment to be set based on the user profile for the new process. +* **shutdownTimeLimit** : Indicates the period of time (in seconds) a worker process is given to finish processing requests and shut down. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **startupTimeLimit** : Indicates the period of time (in seconds) a worker process is given to start up and initialize. + The value must be a string representation of a TimeSpan value. The valid range (in seconds) is `1` to `4294967`. +* **orphanActionExe** : Indicates an executable to run when a worker process is orphaned. +* **orphanActionParams** : Indicates parameters for the executable that is specified in the **orphanActionExe** property. +* **orphanWorkerProcess** : Indicates whether to assign a worker process to an orphan state instead of terminating it when the application pool fails. + If `$true`, an unresponsive worker process will be orphaned instead of terminated. +* **loadBalancerCapabilities** : Indicates the response behavior of a service when it is unavailable. The values that are allowed for this property are: `HttpLevel`, `TcpLevel`. + If set to `HttpLevel` and the application pool is stopped, HTTP.sys will return HTTP 503 error. If set to `TcpLevel`, HTTP.sys will reset the connection. +* **rapidFailProtection** : Indicates whether rapid-fail protection is enabled. + If `$true`, the application pool is shut down if there are a specified number of worker process crashes within a specified time period. +* **rapidFailProtectionInterval** : Indicates the time interval (in minutes) during which the specified number of worker process crashes must occur before the application pool is shut down by rapid-fail protection. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `1` to `144000`. +* **rapidFailProtectionMaxCrashes** : Indicates the maximum number of worker process crashes permitted before the application pool is shut down by rapid-fail protection. + The value must be a valid integer between `0` and `2147483647`. +* **autoShutdownExe** : Indicates an executable to run when the application pool is shut down by rapid-fail protection. +* **autoShutdownParams** : Indicates parameters for the executable that is specified in the **autoShutdownExe** property. +* **disallowOverlappingRotation** : Indicates whether the W3SVC service should start another worker process to replace the existing worker process while that process is shutting down. + If `$true`, the application pool recycle will happen such that the existing worker process exits before another worker process is created. +* **disallowRotationOnConfigChange** : Indicates whether the W3SVC service should rotate worker processes in the application pool when the configuration has changed. + If `$true`, the application pool will not recycle when its configuration is changed. +* **logEventOnRecycle** : Indicates that IIS should generate an event log entry for each occurrence of the specified recycling events. +* **restartMemoryLimit** : Indicates the maximum amount of virtual memory (in KB) a worker process can consume before causing the application pool to recycle. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means there is no limit. +* **restartPrivateMemoryLimit** : Indicates the maximum amount of private memory (in KB) a worker process can consume before causing the application pool to recycle. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means there is no limit. +* **restartRequestsLimit** : Indicates the maximum number of requests the application pool can process before it is recycled. + The value must be a valid integer between `0` and `4294967295`. + A value of `0` means the application pool can process an unlimited number of requests. +* **restartTimeLimit** : Indicates the period of time (in minutes) after which the application pool will recycle. + The value must be a string representation of a TimeSpan value. The valid range (in minutes) is `0` to `432000`. + A value of `00:00:00` means the application pool does not recycle on a regular interval. +* **restartSchedule** : Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. + The value must be an array of string representations of TimeSpan values. + TimeSpan values must be between `00:00:00` and `23:59:59` seconds inclusive, with a granularity of 60 seconds. + Setting the value of this property to `""` disables the schedule. ### xWebSiteDefaults @@ -1082,9 +1164,54 @@ configuration Sample_IISServerDefaults xWebAppPoolDefaults PoolDefaults { - ApplyTo = 'Machine' - ManagedRuntimeVersion = 'v4.0' - IdentityType = 'ApplicationPoolIdentity' + ApplyTo = 'Machine' + autoStart = $true + CLRConfigFile = '' + enable32BitAppOnWin64 = $false + enableConfigurationOverride = $true + managedPipelineMode = 'Integrated' + managedRuntimeLoader = 'webengine4.dll' + managedRuntimeVersion = 'v4.0' + passAnonymousToken = $true + startMode = 'OnDemand' + queueLength = 1000 + cpuAction = 'NoAction' + cpuLimit = 90000 + cpuResetInterval = (New-TimeSpan -Minutes 5).ToString() + cpuSmpAffinitized = $false + cpuSmpProcessorAffinityMask = 4294967295 + cpuSmpProcessorAffinityMask2 = 4294967295 + identityType = 'ApplicationPoolIdentity' + idleTimeout = (New-TimeSpan -Minutes 20).ToString() + idleTimeoutAction = 'Terminate' + loadUserProfile = $true + logEventOnProcessModel = 'IdleTimeout' + logonType = 'LogonBatch' + manualGroupMembership = $false + maxProcesses = 1 + pingingEnabled = $true + pingInterval = (New-TimeSpan -Seconds 30).ToString() + pingResponseTime = (New-TimeSpan -Seconds 90).ToString() + setProfileEnvironment = $false + shutdownTimeLimit = (New-TimeSpan -Seconds 90).ToString() + startupTimeLimit = (New-TimeSpan -Seconds 90).ToString() + orphanActionExe = '' + orphanActionParams = '' + orphanWorkerProcess = $false + loadBalancerCapabilities = 'HttpLevel' + rapidFailProtection = $true + rapidFailProtectionInterval = (New-TimeSpan -Minutes 5).ToString() + rapidFailProtectionMaxCrashes = 5 + autoShutdownExe = '' + autoShutdownParams = '' + disallowOverlappingRotation = $false + disallowRotationOnConfigChange = $false + logEventOnRecycle = 'Time,Requests,Schedule,Memory,IsapiUnhealthy,OnDemand,ConfigChange,PrivateMemory' + restartMemoryLimit = 0 + restartPrivateMemoryLimit = 0 + restartRequestsLimit = 0 + restartTimeLimit = (New-TimeSpan -Minutes 1440).ToString() + restartSchedule = @('00:00:00', '08:00:00', '16:00:00') } } } From f67488824fe9314070a2f8e880937491e9d8b8b0 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 23:33:51 +0300 Subject: [PATCH 18/22] Added required new lines at the end of files --- .../MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 | 2 +- .../MSFT_xWebAppPoolDefaults.schema.mof | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 102f51ed2..f5da96ef2 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -809,4 +809,4 @@ function Get-AppPoolDefault { #endregion -Export-ModuleMember -Function *-TargetResource \ No newline at end of file +Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof index 6b4991147..47e1a9d79 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.schema.mof @@ -53,4 +53,4 @@ class MSFT_xWebAppPoolDefaults : OMI_BaseResource [Write, Description("Indicates the period of time (in minutes) after which the application pool will recycle. The value must be a string representation of a TimeSpan value. The valid range (in minutes) is 0 to 432000. A value of 0 means the application pool does not recycle on a regular interval.")] String restartTimeLimit; [Write, Description("Indicates a set of specific local times, in 24 hour format, when the application pool is recycled. The value must be an array of string representations of TimeSpan values. TimeSpan values must be between 00:00:00 and 23:59:59 seconds inclusive, with a granularity of 60 seconds. Setting the value of this property to '' disables the schedule.")] String restartSchedule[]; -}; \ No newline at end of file +}; From 8bf7e72e5e01be1da8e7ba79cda24947c97630f9 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Thu, 21 Dec 2017 22:56:28 +0300 Subject: [PATCH 19/22] Integration tests --- .../MSFT_xWebAppPoolDefaults.psm1 | 23 +-- ..._xWebAppPoolDefaults.Integration.Tests.ps1 | 159 ++++++----------- .../MSFT_xWebAppPoolDefaults.config.ps1 | 167 +++++++++++++----- 3 files changed, 189 insertions(+), 160 deletions(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index f5da96ef2..982b5fcfa 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -5,7 +5,8 @@ Import-Module -Name "$PSScriptRoot\..\Helper.psm1" data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' - VerboseGetTargetResource = Get-TargetResource has been run. + ErrorAppCmdNonZeroExitCode = AppCmd.exe has exited with error code "{0}". + VerboseGetTargetResource = Get-TargetResource has been run. ErrorAppPoolDefaultsNotFound = Application pool defaults element could not be located. VerboseAppPoolDefaultsFound = Application pool defaults was found. @@ -312,8 +313,6 @@ function Set-TargetResource { # Set Application Pool Properties - Write-Verbose -Message ($LocalizedData['VerboseAppPoolDefaultsFound']) - $PropertyData.Where( { ($_.Name -in $PSBoundParameters.Keys) -and @@ -331,8 +330,9 @@ function Set-TargetResource { Write-Verbose -Message ( $LocalizedData['VerboseSetProperty'] -f $propertyName ) + Invoke-AppCmd -ArgumentList ( - '/{0}:{1}' -f $propertyPath, $PSBoundParameters[$propertyName] + '/{0}:{1}' -f "applicationPoolDefaults.$($propertyPath)", $PSBoundParameters[$propertyName] ) } } @@ -346,7 +346,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - '/processModel.userName:{0}' -f $Credential.UserName + '/applicationPoolDefaults.processModel.userName:{0}' -f $Credential.UserName ) } @@ -358,7 +358,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - '/processModel.password:{0}' -f $clearTextPassword + '/applicationPoolDefaults.processModel.password:{0}' -f $clearTextPassword ) } } @@ -386,8 +386,8 @@ function Set-TargetResource { ) { Write-Verbose -Message ($LocalizedData['VerboseClearCredential']) - Invoke-AppCmd -ArgumentList '/processModel.userName:' - Invoke-AppCmd -ArgumentList '/processModel.password:' + Invoke-AppCmd -ArgumentList '/applicationPoolDefaults.processModel.userName:' + Invoke-AppCmd -ArgumentList '/applicationPoolDefaults.processModel.password:' } if ($PSBoundParameters.ContainsKey('restartSchedule')) { @@ -421,7 +421,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - "/+recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject ) } # Remove value @@ -432,7 +432,7 @@ function Set-TargetResource { ) Invoke-AppCmd -ArgumentList ( - "/-recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject + "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='{0}']" -f $_.InputObject ) } @@ -774,8 +774,9 @@ function Invoke-AppCmd { $ErrorActionPreference = 'Stop' $appcmdFilePath = "$env:SystemRoot\System32\inetsrv\appcmd.exe" - $allArguments = @("set", "config", "-section:applicationPools") + $ArgumentList + $allArguments = @("set", "config", "-section:system.applicationHost/applicationPools") + $ArgumentList + ("/commit:apphost") + # Write-Verbose -Message "calling $($appcmdFilePath) $($allArguments)" $appcmdResult = $(& $appcmdFilePath $allArguments) Write-Verbose -Message $($appcmdResult).ToString() diff --git a/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 b/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 index 3b6e4d551..cee617cc1 100644 --- a/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xWebAppPoolDefaults.Integration.Tests.ps1 @@ -1,6 +1,7 @@ +#requires -Version 4.0 -$script:DSCModuleName = 'xWebAdministration' -$script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' +$script:DSCModuleName = 'xWebAdministration' +$script:DSCResourceName = 'MSFT_xWebAppPoolDefaults' #region HEADER @@ -16,148 +17,98 @@ Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\ $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` - -TestType Integration + -TestType Integration + #endregion -[string] $tempName = "$($script:DSCResourceName)_" + (Get-Date).ToString("yyyyMMdd_HHmmss") +# Test Setup +if ((Get-Service -Name 'W3SVC').Status -ne 'Running') +{ + Start-Service -Name 'W3SVC' +} + +$tempBackupName = "$($script:DSCResourceName)_$(Get-Date -Format 'yyyyMMdd_HHmmss')" # Using try/finally to always cleanup even if something awful happens. + try { - #region Integration Tests + # Create configuration backup + + Backup-WebConfiguration -Name $tempBackupName | Out-Null - # some constants - [string]$constPsPath = 'MACHINE/WEBROOT/APPHOST' - [string]$constAPDFilter = 'system.applicationHost/applicationPools/applicationPoolDefaults' - [string]$constSiteFilter = 'system.applicationHost/sites/' + #region Integration Tests $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" . $ConfigFile - $null = Backup-WebConfiguration -Name $tempName + Describe "$($script:DSCResourceName)_Integration" { - function Get-SiteValue([string]$path,[string]$name) - { - return (Get-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/$path" -name $name).value - } + #region Default Tests - Describe "$($script:DSCResourceName)_Integration" { - #region DEFAULT TESTS - It 'Should compile without throwing' { + It 'Should be able to compile and apply without throwing' { { - Invoke-Expression -Command "$($script:DSCResourceName)_Config -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw + Invoke-Expression -Command ( + '{0}_Config -OutputPath $TestDrive -ConfigurationData $ConfigData -ErrorAction Stop' -f + $script:DSCResourceName + ) + + Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Force -Wait -Verbose + } | Should Not Throw } It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should Not throw + { + Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should Not Throw } + #endregion - It 'Changing ManagedRuntimeVersion' { + It 'Should have set the resource and all the parameters should match' { + + $currentConfiguration = Get-DscConfiguration + + foreach ($parameter in $TestParameters.GetEnumerator()) { - # get the current value - [string] $originalValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion) + Write-Verbose -Message "The $($parameter.Name) property should be set." - # We are using environment variables here, because a inline PowerShell variable was empty after executing Start-DscConfiguration + if ($parameter.Name -eq 'Credential') + { + $appPoolDefaults = Get-WebConfiguration -Filter '/system.applicationHost/applicationPools/applicationPoolDefaults' + + $appPoolDefaults.processModel.userName | + Should Be $TestParameters['Credential'].UserName - # change the value to something else - if ($originalValue -eq 'v4.0') + $appPoolDefaults.processModel.password | + Should Be $TestParameters['Credential'].GetNetworkCredential().Password + } + elseif ($parameter.Name -eq 'ApplyTo') { - $env:PesterManagedRuntimeVersion = 'v2.0' + # ignored. } else { - $env:PesterManagedRuntimeVersion = 'v4.0' + $currentConfiguration."$($parameter.Name)" | + Should Be $TestParameters[$parameter.Name] } - - Invoke-Expression -Command "$($script:DSCResourceName)_ManagedRuntimeVersion -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | should not throw - - # get the configured value again - $changedValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion).Value - - # compare it to the one we just tried to set. - $changedValue | should be $env:PesterManagedRuntimeVersion - } - - It 'Changing IdentityType' { - # get the current value - [string] $originalValue = (Get-WebConfigurationProperty ` - -PSPath $constPsPath ` - -Filter $constAPDFilter/processModel ` - -Name identityType) - - if ($originalValue -eq 'ApplicationPoolIdentity') - { - $env:PesterApplicationPoolIdentity = 'LocalService' - } - else - { - $env:PesterApplicationPoolIdentity = 'ApplicationPoolIdentity' } - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_AppPoolIdentityType -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = (Get-WebConfigurationProperty -PSPath $constPsPath -Filter $constAPDFilter/processModel -Name identityType) - - $changedValue | Should Be $env:PesterApplicationPoolIdentity } - - It 'Changing LogFormat' { - [string] $originalValue = Get-SiteValue 'logFile' 'logFormat' - - if ($originalValue -eq 'W3C') - { - $env:PesterLogFormat = 'IIS' - } - else - { - $env:PesterLogFormat = 'W3C' - } - - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_LogFormat -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = Get-SiteValue 'logFile' 'logFormat' - - $changedValue | Should Be $env:PesterALogFormat - } - - It 'Changing Default AppPool' { - # get the current value - - [string] $originalValue = Get-SiteValue 'applicationDefaults' 'applicationPool' - - $env:PesterDefaultPool = 'DefaultAppPool' - # Compile the MOF File - { - Invoke-Expression -Command "$($script:DSCResourceName)_DefaultPool -OutputPath `$TestDrive" - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force - } | Should not throw - - $changedValue = Get-SiteValue 'applicationDefaults' 'applicationPool' - $changedValue | should be $env:PesterDefaultPool + It 'Actual configuration should match the desired configuration' { + Test-DscConfiguration -Verbose | Should Be $true } } + #endregion } finally { #region FOOTER - Restore-WebConfiguration -Name $tempName - Remove-WebConfigurationBackup -Name $tempName + Restore-WebConfiguration -Name $tempBackupName + Remove-WebConfigurationBackup -Name $tempBackupName Restore-TestEnvironment -TestEnvironment $TestEnvironment #endregion diff --git a/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 b/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 index c804256ae..32c1aaad2 100644 --- a/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 +++ b/Tests/Integration/MSFT_xWebAppPoolDefaults.config.ps1 @@ -1,60 +1,137 @@ -[string] $constPsPath = 'MACHINE/WEBROOT/APPHOST' -[string] $constAPDFilter = 'system.applicationHost/applicationPools/applicationPoolDefaults' -[string] $constSiteFilter = 'system.applicationHost/sites/' +#requires -Version 4.0 -[string] $originalValue = (Get-WebConfigurationProperty -pspath $constPsPath -filter $constAPDFilter -name managedRuntimeVersion).Value +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] +param () -configuration MSFT_xWebAppPoolDefaults_Config -{ - Import-DscResource -ModuleName xWebAdministration - - xWebAppPoolDefaults PoolDefaults - { - ApplyTo = 'Machine' - ManagedRuntimeVersion = $originalValue - } +$ConfigData = @{ + AllNodes = @( + @{ + NodeName = '*' + PSDscAllowPlainTextPassword = $true + } + @{ + NodeName = 'localhost' + } + ) } -configuration MSFT_xWebAppPoolDefaults_ManagedRuntimeVersion -{ - Import-DscResource -ModuleName xWebAdministration +$TestCredential = New-Object -TypeName PSCredential -ArgumentList ( + 'CONTOSO\JDoe', + ('5t6y7u8i' | ConvertTo-SecureString -AsPlainText -Force) +) - xWebAppPoolDefaults PoolDefaults - { - ApplyTo = 'Machine' - ManagedRuntimeVersion = $env:PesterManagedRuntimeVersion - } +$TestParameters = [Ordered]@{ + applyTo = 'Machine' + autoStart = $false + CLRConfigFile = 'C:\inetpub\temp\aspnet.config' + enable32BitAppOnWin64 = $true + enableConfigurationOverride = $false + managedPipelineMode = 'Classic' + managedRuntimeLoader = '' + managedRuntimeVersion = 'v2.0' + passAnonymousToken = $false + startMode = 'AlwaysRunning' + queueLength = 2000 + cpuAction = 'KillW3wp' + cpuLimit = 90000 + cpuResetInterval = '00:10:00' + cpuSmpAffinitized = $true + cpuSmpProcessorAffinityMask = 1 + cpuSmpProcessorAffinityMask2 = 1 + identityType = 'SpecificUser' + Credential = $TestCredential + idleTimeout = '00:15:00' + idleTimeoutAction = 'Suspend' + loadUserProfile = $false + logEventOnProcessModel = '' + logonType = 'LogonService' + manualGroupMembership = $true + maxProcesses = 2 + pingingEnabled = $false + pingInterval = '00:01:00' + pingResponseTime = '00:02:00' + setProfileEnvironment = $true + shutdownTimeLimit = '00:02:00' + startupTimeLimit = '00:02:00' + orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' + orphanActionParams = '/orphanActionParam1' + orphanWorkerProcess = $true + loadBalancerCapabilities = 'TcpLevel' + rapidFailProtection = $false + rapidFailProtectionInterval = '00:10:00' + rapidFailProtectionMaxCrashes = 10 + autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' + autoShutdownParams = '/autoShutdownParam1' + disallowOverlappingRotation = $true + disallowRotationOnConfigChange = $true + logEventOnRecycle = 'Time,Memory,PrivateMemory' + restartMemoryLimit = 1048576 + restartPrivateMemoryLimit = 1048576 + restartRequestsLimit = 1000 + restartTimeLimit = '2.10:00:00' + restartSchedule = @('05:00:00', '21:00:00') } -configuration MSFT_xWebAppPoolDefaults_AppPoolIdentityType +Configuration MSFT_xWebAppPoolDefaults_Config { Import-DscResource -ModuleName xWebAdministration - xWebAppPoolDefaults PoolDefaults + Node $AllNodes.NodeName { - ApplyTo = 'Machine' - IdentityType = $env:PesterApplicationPoolIdentity + xWebAppPoolDefaults Defaults + { + ApplyTo = $TestParameters.applyTo + autoStart = $TestParameters.autoStart + CLRConfigFile = $TestParameters.CLRConfigFile + enable32BitAppOnWin64 = $TestParameters.enable32BitAppOnWin64 + enableConfigurationOverride = $TestParameters.enableConfigurationOverride + managedPipelineMode = $TestParameters.managedPipelineMode + managedRuntimeLoader = $TestParameters.managedRuntimeLoader + managedRuntimeVersion = $TestParameters.managedRuntimeVersion + passAnonymousToken = $TestParameters.passAnonymousToken + startMode = $TestParameters.startMode + queueLength = $TestParameters.queueLength + cpuAction = $TestParameters.cpuAction + cpuLimit = $TestParameters.cpuLimit + cpuResetInterval = $TestParameters.cpuResetInterval + cpuSmpAffinitized = $TestParameters.cpuSmpAffinitized + cpuSmpProcessorAffinityMask = $TestParameters.cpuSmpProcessorAffinityMask + cpuSmpProcessorAffinityMask2 = $TestParameters.cpuSmpProcessorAffinityMask2 + identityType = $TestParameters.identityType + Credential = $TestParameters.Credential + idleTimeout = $TestParameters.idleTimeout + idleTimeoutAction = $TestParameters.idleTimeoutAction + loadUserProfile = $TestParameters.loadUserProfile + logEventOnProcessModel = $TestParameters.logEventOnProcessModel + logonType = $TestParameters.logonType + manualGroupMembership = $TestParameters.manualGroupMembership + maxProcesses = $TestParameters.maxProcesses + pingingEnabled = $TestParameters.pingingEnabled + pingInterval = $TestParameters.pingInterval + pingResponseTime = $TestParameters.pingResponseTime + setProfileEnvironment = $TestParameters.setProfileEnvironment + shutdownTimeLimit = $TestParameters.shutdownTimeLimit + startupTimeLimit = $TestParameters.startupTimeLimit + orphanActionExe = $TestParameters.orphanActionExe + orphanActionParams = $TestParameters.orphanActionParams + orphanWorkerProcess = $TestParameters.orphanWorkerProcess + loadBalancerCapabilities = $TestParameters.loadBalancerCapabilities + rapidFailProtection = $TestParameters.rapidFailProtection + rapidFailProtectionInterval = $TestParameters.rapidFailProtectionInterval + rapidFailProtectionMaxCrashes = $TestParameters.rapidFailProtectionMaxCrashes + autoShutdownExe = $TestParameters.autoShutdownExe + autoShutdownParams = $TestParameters.autoShutdownParams + disallowOverlappingRotation = $TestParameters.disallowOverlappingRotation + disallowRotationOnConfigChange = $TestParameters.disallowRotationOnConfigChange + logEventOnRecycle = $TestParameters.logEventOnRecycle + restartMemoryLimit = $TestParameters.restartMemoryLimit + restartPrivateMemoryLimit = $TestParameters.restartPrivateMemoryLimit + restartRequestsLimit = $TestParameters.restartRequestsLimit + restartTimeLimit = $TestParameters.restartTimeLimit + restartSchedule = $TestParameters.restartSchedule + } } } -configuration MSFT_xWebAppPoolDefaults_LogFormat -{ - Import-DscResource -ModuleName xWebAdministration - xWebSiteDefaults LogFormat - { - ApplyTo = 'Machine' - LogFormat = $env:PesterLogFormat - } -} - -configuration MSFT_xWebAppPoolDefaults_DefaultPool -{ - Import-DscResource -ModuleName xWebAdministration - - xWebSiteDefaults DefaultPool - { - ApplyTo = 'Machine' - DefaultApplicationPool = $env:PesterDefaultPool - } -} From 014e5c5f68961a8bc4a61922a65baefb7d94be28 Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Thu, 21 Dec 2017 23:27:40 +0300 Subject: [PATCH 20/22] changes in unit tests --- Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 index e39504357..5fe29e006 100644 --- a/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 +++ b/Tests/Unit/MSFT_xWebAppPoolDefaults.Tests.ps1 @@ -1711,7 +1711,7 @@ try autoStart = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/autoStart:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.autoStart:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1733,7 +1733,7 @@ try CLRConfigFile = 'C:\inetpub\temp\aspnet.config' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/CLRConfigFile:C:\inetpub\temp\aspnet.config'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.CLRConfigFile:C:\inetpub\temp\aspnet.config'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1755,7 +1755,7 @@ try enable32BitAppOnWin64 = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enable32BitAppOnWin64:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.enable32BitAppOnWin64:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1777,7 +1777,7 @@ try enableConfigurationOverride = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/enableConfigurationOverride:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.enableConfigurationOverride:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1799,7 +1799,7 @@ try managedPipelineMode = 'Classic' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedPipelineMode:Classic'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedPipelineMode:Classic'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1821,7 +1821,7 @@ try managedRuntimeLoader = '' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeLoader:'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedRuntimeLoader:'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1843,7 +1843,7 @@ try managedRuntimeVersion = 'v2.0' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/managedRuntimeVersion:v2.0'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.managedRuntimeVersion:v2.0'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1865,7 +1865,7 @@ try passAnonymousToken = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/passAnonymousToken:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.passAnonymousToken:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1887,7 +1887,7 @@ try startMode = 'AlwaysRunning' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/startMode:AlwaysRunning'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.startMode:AlwaysRunning'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1909,7 +1909,7 @@ try queueLength = 2000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/queueLength:2000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.queueLength:2000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1933,7 +1933,7 @@ try cpuAction = 'KillW3wp' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.action:KillW3wp'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.action:KillW3wp'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1957,7 +1957,7 @@ try cpuLimit = 90000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.limit:90000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.limit:90000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -1981,7 +1981,7 @@ try cpuResetInterval = '00:10:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.resetInterval:00:10:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.resetInterval:00:10:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2005,7 +2005,7 @@ try cpuSmpAffinitized = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpAffinitized:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpAffinitized:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2029,7 +2029,7 @@ try cpuSmpProcessorAffinityMask = 1 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask:1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpProcessorAffinityMask:1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2053,7 +2053,7 @@ try cpuSmpProcessorAffinityMask2 = 1 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/cpu.smpProcessorAffinityMask2:1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.cpu.smpProcessorAffinityMask2:1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2077,7 +2077,7 @@ try identityType = 'SpecificUser' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.identityType:SpecificUser'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.identityType:SpecificUser'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2101,7 +2101,7 @@ try idleTimeout = '00:15:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeout:00:15:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.idleTimeout:00:15:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2125,7 +2125,7 @@ try idleTimeoutAction = 'Suspend' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.idleTimeoutAction:Suspend'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.idleTimeoutAction:Suspend'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2149,7 +2149,7 @@ try loadUserProfile = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.loadUserProfile:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.loadUserProfile:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2173,7 +2173,7 @@ try logEventOnProcessModel = '' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logEventOnProcessModel:'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.logEventOnProcessModel:'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2197,7 +2197,7 @@ try logonType = 'LogonService' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.logonType:LogonService'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.logonType:LogonService'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2221,7 +2221,7 @@ try manualGroupMembership = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.manualGroupMembership:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.manualGroupMembership:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2245,7 +2245,7 @@ try maxProcesses = 2 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.maxProcesses:2'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.maxProcesses:2'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2269,7 +2269,7 @@ try pingingEnabled = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingingEnabled:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingingEnabled:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2293,7 +2293,7 @@ try pingInterval = '00:01:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingInterval:00:01:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingInterval:00:01:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2317,7 +2317,7 @@ try pingResponseTime = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.pingResponseTime:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.pingResponseTime:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2341,7 +2341,7 @@ try setProfileEnvironment = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.setProfileEnvironment:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.setProfileEnvironment:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2365,7 +2365,7 @@ try shutdownTimeLimit = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.shutdownTimeLimit:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.shutdownTimeLimit:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2389,7 +2389,7 @@ try startupTimeLimit = '00:02:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/processModel.startupTimeLimit:00:02:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.processModel.startupTimeLimit:00:02:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2413,7 +2413,7 @@ try orphanActionExe = 'C:\inetpub\temp\orphanAction.exe' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanActionExe:C:\inetpub\temp\orphanAction.exe'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2437,7 +2437,7 @@ try orphanActionParams = '/orphanActionParam1' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanActionParams:/orphanActionParam1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanActionParams:/orphanActionParam1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2461,7 +2461,7 @@ try orphanWorkerProcess = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.orphanWorkerProcess:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.orphanWorkerProcess:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2485,7 +2485,7 @@ try loadBalancerCapabilities = 'TcpLevel' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.loadBalancerCapabilities:TcpLevel'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.loadBalancerCapabilities:TcpLevel'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2509,7 +2509,7 @@ try rapidFailProtection = $false } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtection:False'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtection:False'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2533,7 +2533,7 @@ try rapidFailProtectionInterval = '00:10:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionInterval:00:10:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtectionInterval:00:10:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2557,7 +2557,7 @@ try rapidFailProtectionMaxCrashes = 10 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.rapidFailProtectionMaxCrashes:10'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.rapidFailProtectionMaxCrashes:10'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2581,7 +2581,7 @@ try autoShutdownExe = 'C:\inetpub\temp\autoShutdown.exe' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.autoShutdownExe:C:\inetpub\temp\autoShutdown.exe'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2606,7 +2606,7 @@ try autoShutdownParams = '/autoShutdownParam1' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/failure.autoShutdownParams:/autoShutdownParam1'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.failure.autoShutdownParams:/autoShutdownParam1'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2630,7 +2630,7 @@ try disallowOverlappingRotation = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowOverlappingRotation:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.disallowOverlappingRotation:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2654,7 +2654,7 @@ try disallowRotationOnConfigChange = $true } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.disallowRotationOnConfigChange:True'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.disallowRotationOnConfigChange:True'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2678,7 +2678,7 @@ try logEventOnRecycle = 'Time,Memory,PrivateMemory' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.logEventOnRecycle:Time,Memory,PrivateMemory'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2704,7 +2704,7 @@ try restartMemoryLimit = 1048576 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.memory:1048576'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.memory:1048576'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2730,7 +2730,7 @@ try restartPrivateMemoryLimit = 1048576 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.privateMemory:1048576'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.privateMemory:1048576'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2756,7 +2756,7 @@ try restartRequestsLimit = 1000 } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.requests:1000'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.requests:1000'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2782,7 +2782,7 @@ try restartTimeLimit = '2.10:00:00' } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/recycling.periodicRestart.time:2.10:00:00'} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq '/applicationPoolDefaults.recycling.periodicRestart.time:2.10:00:00'} Set-TargetResource -ApplyTo Machine @setParamsSplat @@ -2812,14 +2812,14 @@ try restartSchedule = @('08:00:00') } - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} - Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='04:00:00']"} + Mock Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='08:00:00']"} Set-TargetResource -ApplyTo Machine @setParamsSplat It 'Should call Invoke-AppCmd' { - Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 - Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/-applicationPoolDefaults.recycling.periodicRestart.schedule.[value='04:00:00']"} -Exactly 1 + Assert-MockCalled Invoke-AppCmd -ParameterFilter {$ArgumentList[-1] -eq "/+applicationPoolDefaults.recycling.periodicRestart.schedule.[value='08:00:00']"} -Exactly 1 } } From b8a2165a200d930e50686a10232b57ef7625b0cd Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 00:04:43 +0300 Subject: [PATCH 21/22] added missing application pool default settings --- .../MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index 982b5fcfa..df399fbb6 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -810,4 +810,4 @@ function Get-AppPoolDefault { #endregion -Export-ModuleMember -Function *-TargetResource +Export-ModuleMember -Function *-TargetResource \ No newline at end of file From f9100cbfbae5e11f097092a9f095c6ef0edf329b Mon Sep 17 00:00:00 2001 From: Onur BIYIK Date: Tue, 19 Dec 2017 23:33:51 +0300 Subject: [PATCH 22/22] Added required new lines at the end of files --- .../MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 index df399fbb6..982b5fcfa 100644 --- a/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 +++ b/DSCResources/MSFT_xWebAppPoolDefaults/MSFT_xWebAppPoolDefaults.psm1 @@ -810,4 +810,4 @@ function Get-AppPoolDefault { #endregion -Export-ModuleMember -Function *-TargetResource \ No newline at end of file +Export-ModuleMember -Function *-TargetResource