From f18f5161ddb68bb7000c459ca24039709c0131a1 Mon Sep 17 00:00:00 2001 From: Reggie Gibson <31147354+regedit32@users.noreply.github.com> Date: Fri, 4 May 2018 08:57:46 -0400 Subject: [PATCH] Added LogCustomFields to xWebSite (#342) - Updated xWebSite to include ability to manage custom logging fields (issue #267). --- .MetaTestOptIn.json | 3 + DSCResources/MSFT_xWebsite/MSFT_xWebsite.psm1 | 171 +++++++++++- .../MSFT_xWebsite/MSFT_xWebsite.schema.mof | 9 + README.md | 5 + .../MSFT_xWebsite.Integration.Tests.ps1 | 18 +- Tests/Integration/MSFT_xWebsite.config.ps1 | 44 ++- Tests/Integration/MSFT_xWebsite.config.psd1 | 6 + Tests/Unit/MSFT_xWebsite.Tests.ps1 | 258 +++++++++++++++++- 8 files changed, 496 insertions(+), 18 deletions(-) create mode 100644 .MetaTestOptIn.json diff --git a/.MetaTestOptIn.json b/.MetaTestOptIn.json new file mode 100644 index 000000000..ad716d658 --- /dev/null +++ b/.MetaTestOptIn.json @@ -0,0 +1,3 @@ +[ + "null" +] diff --git a/DSCResources/MSFT_xWebsite/MSFT_xWebsite.psm1 b/DSCResources/MSFT_xWebsite/MSFT_xWebsite.psm1 index af2b9e25b..971cbfa1c 100644 --- a/DSCResources/MSFT_xWebsite/MSFT_xWebsite.psm1 +++ b/DSCResources/MSFT_xWebsite/MSFT_xWebsite.psm1 @@ -49,6 +49,7 @@ data LocalizedData VerboseSetTargetUpdateLogTruncateSize = TruncateSize does not match and will be updated on Website "{0}". VerboseSetTargetUpdateLoglocalTimeRollover = LoglocalTimeRollover does not match and will be updated on Website "{0}". VerboseSetTargetUpdateLogFormat = LogFormat is not in the desired state and will be updated on Website "{0}" + VerboseSetTargetUpdateLogCustomFields = LogCustomFields is not in the desired state and will be updated on Website "{0}" VerboseTestTargetFalseEnsure = The Ensure state for website "{0}" does not match the desired state. VerboseTestTargetFalsePhysicalPath = Physical Path of website "{0}" does not match the desired state. VerboseTestTargetFalseState = The state of website "{0}" does not match the desired state. @@ -69,6 +70,7 @@ data LocalizedData VerboseTestTargetFalseLogTruncateSize = LogTruncateSize does not match desired state on Website "{0}". VerboseTestTargetFalseLoglocalTimeRollover = LoglocalTimeRollover does not match desired state on Website "{0}". VerboseTestTargetFalseLogFormat = LogFormat does not match desired state on Website "{0}". + VerboseTestTargetFalseLogCustomFields = LogCustomFields does not match desired state on Website "{0}". VerboseConvertToWebBindingIgnoreBindingInformation = BindingInformation is ignored for bindings of type "{0}" in case at least one of the following properties is specified: IPAddress, Port, HostName. VerboseConvertToWebBindingDefaultPort = Port is not specified. The default "{0}" port "{1}" will be used. VerboseConvertToWebBindingDefaultCertificateStoreName = CertificateStoreName is not specified. The default value "{0}" will be used. @@ -130,6 +132,8 @@ function Get-TargetResource $webConfiguration = $websiteAutoStartProviders | ` Where-Object -Property Name -eq -Value $ServiceAutoStartProvider | ` Select-Object Name,Type + + $cimLogCustomFields = ConvertTo-CimLogCustomFields -InputObject $website.logFile.customFields.Collection } # Multiple websites with the same name exist. This is not supported and is an error else @@ -161,6 +165,7 @@ function Get-TargetResource LogtruncateSize = $website.logfile.truncateSize LoglocalTimeRollover = $website.logfile.localTimeRollover LogFormat = $website.logfile.logFormat + LogCustomFields = $cimLogCustomFields } } @@ -244,7 +249,10 @@ function Set-TargetResource [ValidateSet('IIS','W3C','NCSA')] [String] - $LogFormat + $LogFormat, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $LogCustomFields ) Assert-Module @@ -491,7 +499,7 @@ function Set-TargetResource -Name LogFile.period -Value 'MaxSize' } - # Update LoglocalTimeRollover if neeed + # Update LoglocalTimeRollover if needed if ($PSBoundParameters.ContainsKey('LoglocalTimeRollover') -and ` ($LoglocalTimeRollover -ne ` ([System.Convert]::ToBoolean($website.logfile.LocalTimeRollover)))) @@ -501,7 +509,6 @@ function Set-TargetResource Set-ItemProperty -Path "IIS:\Sites\$Name" ` -Name LogFile.localTimeRollover -Value $LoglocalTimeRollover } - } # Create website if it does not exist else @@ -740,7 +747,7 @@ function Set-TargetResource -Name LogFile.period -Value 'MaxSize' } - # Update LoglocalTimeRollover if neeed + # Update LoglocalTimeRollover if needed if ($PSBoundParameters.ContainsKey('LoglocalTimeRollover') -and ` ($LoglocalTimeRollover -ne ` ([System.Convert]::ToBoolean($website.logfile.LocalTimeRollover)))) @@ -751,6 +758,15 @@ function Set-TargetResource -Name LogFile.localTimeRollover -Value $LoglocalTimeRollover } } + + # Update LogCustomFields if needed + if ($PSBoundParameters.ContainsKey('LogCustomFields') -and ` + (-not (Test-LogCustomField -Site $Name -LogCustomField $LogCustomFields))) + { + Write-Verbose -Message ($LocalizedData.VerboseSetTargetUpdateLogCustomFields ` + -f $Name) + Set-LogCustomField -Site $Name -LogCustomField $LogCustomFields + } } # Remove website else @@ -850,7 +866,10 @@ function Test-TargetResource [ValidateSet('IIS','W3C','NCSA')] [String] - $LogFormat + $LogFormat, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $LogCustomFields ) Assert-Module @@ -1058,6 +1077,15 @@ function Test-TargetResource -f $Name) return $false } + + # Check LogCustomFields if needed + if ($PSBoundParameters.ContainsKey('LogCustomFields') -and ` + (-not (Test-LogCustomField -Site $Name -LogCustomField $LogCustomFields))) + { + Write-Verbose -Message ($LocalizedData.VerboseTestTargetUpdateLogCustomFields ` + -f $Name) + return $false + } } if ($inDesiredState -eq $true) @@ -1587,6 +1615,44 @@ function ConvertTo-WebBinding } } +<# + .SYNOPSIS + Converts IIS custom log field collection to instances of the MSFT_xLogCustomFieldInformation CIM class. +#> +function ConvertTo-CimLogCustomFields +{ + [CmdletBinding()] + [OutputType([Microsoft.Management.Infrastructure.CimInstance[]])] + param + ( + [Parameter(Mandatory = $true)] + [AllowEmptyCollection()] + [AllowNull()] + [Object[]] + $InputObject + ) + + $cimClassName = 'MSFT_xLogCustomFieldInformation' + $cimNamespace = 'root/microsoft/Windows/DesiredStateConfiguration' + $cimCollection = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' + + foreach ($customField in $InputObject) + { + $cimProperties = @{ + LogFieldName = $customField.LogFieldName + SourceName = $customField.SourceName + SourceType = $customField.SourceType + } + + $cimCollection += (New-CimInstance -ClassName $cimClassName ` + -Namespace $cimNamespace ` + -Property $cimProperties ` + -ClientOnly) + } + + return $cimCollection +} + <# .SYNOPSYS Formats the input IP address string for use in the bindingInformation attribute. @@ -1747,6 +1813,48 @@ function Set-AuthenticationInfo } } +<# + .SYNOPSIS + Helper function used to set the LogCustomField for a website. + + .PARAMETER Site + Specifies the name of the Website. + + .PARAMETER LogCustomField + A CimInstance collection of what the LogCustomField should be. +#> +function Set-LogCustomField +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [String] + $Site, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $LogCustomField + ) + + $setCustomFields = @() + foreach ($customField in $LogCustomField) + { + $setCustomFields += @{ + logFieldName = $customField.LogFieldName + sourceName = $customField.SourceName + sourceType = $customField.SourceType + } + } + + # The second Set-WebConfigurationProperty is to handle an edge case where logfile.customFields is not updated correctly. May be caused by a possible bug in the IIS provider + for ($i = 1; $i -le 2; $i++) + { + Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "system.applicationHost/sites/site[@name='$Site']/logFile/customFields" -Name "." -Value $setCustomFields + } +} + <# .SYNOPSIS Helper function used to test the authenticationProperties state for an Application. @@ -2002,6 +2110,57 @@ function Test-WebsiteBinding return $inDesiredState } +<# + .SYNOPSIS + Helper function used to test the LogCustomField state for a website. + + .PARAMETER Site + Specifies the name of the Website. + + .PARAMETER LogCustomField + A CimInstance collection of what state the LogCustomField should be. +#> +function Test-LogCustomField +{ + [CmdletBinding()] + [OutputType([Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [String] + $Site, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $LogCustomField + ) + + $inDesiredSate = $true + + foreach ($customField in $LogCustomField) + { + $filterString = "/system.applicationHost/sites/site[@name='{0}']/logFile/customFields/add[@logFieldName='{1}']" -f $Site, $customField.LogFieldName + $presentCustomField = Get-WebConfigurationProperty -Filter $filterString -Name "." + + if ($presentCustomField) + { + $sourceNameMatch = $customField.SourceName -eq $presentCustomField.SourceName + $sourceTypeMatch = $customField.SourceType -eq $presentCustomField.sourceType + if (-not ($sourceNameMatch -and $sourceTypeMatch)) + { + $inDesiredSate = $false + } + } + else + { + $inDesiredSate = $false + } + } + + return $inDesiredSate +} + <# .SYNOPSIS Helper function used to update default pages of website. @@ -2143,5 +2302,3 @@ function Update-WebsiteBinding #endregion Export-ModuleMember -Function *-TargetResource - - diff --git a/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof b/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof index 05a148256..8575bfe46 100644 --- a/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof +++ b/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof @@ -21,6 +21,14 @@ class MSFT_xWebAuthenticationInformation [Write] Boolean Windows; }; +[ClassVersion("1.0.0")] +class MSFT_xLogCustomFieldInformation +{ + [Write] String LogFieldName; + [Write] String SourceName; + [Write, ValueMap{"RequestHeader","ResponseHeader","ServerVariable"},Values{"RequestHeader","ResponseHeader","ServerVariable"}] String SourceType; +}; + [ClassVersion("2.0.0"), FriendlyName("xWebsite")] class MSFT_xWebsite : OMI_BaseResource { @@ -43,4 +51,5 @@ class MSFT_xWebsite : OMI_BaseResource [Write, Description ("How large the file should be before it is truncated")] String LogTruncateSize; [Write, Description ("Use the localtime for file naming and rollover")] Boolean LoglocalTimeRollover; [Write, Description ("Format of the Logfiles. Only W3C supports LogFlags"), ValueMap{"IIS","W3C","NCSA"}, Values{"IIS","W3C","NCSA"}] String LogFormat; + [Write, EmbeddedInstance("MSFT_xLogCustomFieldInformation"), Description("Custom logging field information in the form of an array of embedded instances of MSFT_xLogCustomFieldInformation CIM class")] String LogCustomFields[]; }; diff --git a/README.md b/README.md index 8d8e99255..86cacc033 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,10 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **LogTruncateSize**: How large the file should be before it is truncated. If this is set then LogPeriod will be ignored if passed in and set to MaxSize. The value must be a valid integer between `1048576 (1MB)` and `4294967295 (4GB)`. * **LoglocalTimeRollover**: Use the localtime for file naming and rollover. The acceptable values for this property are: `$true`, `$false` * **LogFormat**: Format of the Logfiles. **Note**Only W3C supports LogFlags. The acceptable values for this property are: `IIS`,`W3C`,`NCSA` +* **LogCustomFields**: Custom logging field information the form of an array of embedded instances of the **MSFT_xLogCustomFieldInformation** CIM class that implements the following properties: + * **LogFieldName**: Field name to identify the custom field within the log file. Please note that the field name cannot contain spaces. + * **SourceName**: You can select `RequestHeader`, `ResponseHeader`, or `ServerVariable` (note that enhanced logging cannot log a server variable with a name that contains lower-case characters - to include a server variable in the event log just make sure that its name consists of all upper-case characters). + * **SourceType**: Name of the HTTP header or server variable (depending on the Source Type you selected) that contains a value that you want to log. ### xWebApplication @@ -257,6 +261,7 @@ Please check out common DSC Resources [contributing guidelines](https://github.c ## Versions ### Unreleased +* Updated **xWebSite** to include ability to manage custom logging fields ### 1.20.0.0 diff --git a/Tests/Integration/MSFT_xWebsite.Integration.Tests.ps1 b/Tests/Integration/MSFT_xWebsite.Integration.Tests.ps1 index 85ad2beff..8b801b86d 100644 --- a/Tests/Integration/MSFT_xWebsite.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xWebsite.Integration.Tests.ps1 @@ -123,7 +123,14 @@ try #Test DefaultPage is correct $defultPages[0] | Should Match $dscConfig.AllNodes.DefaultPage - } + #Test LogCustomFields is correct + $result.logFile.customFields.Collection[0].LogFieldName | Should Be $dscConfig.AllNodes.LogFieldName1 + $result.logFile.customFields.Collection[0].SourceName | Should Be $dscConfig.AllNodes.SourceName1 + $result.logFile.customFields.Collection[0].SourceType | Should Be $dscConfig.AllNodes.SourceType1 + $result.logFile.customFields.Collection[1].LogFieldName | Should Be $dscConfig.AllNodes.LogFieldName2 + $result.logFile.customFields.Collection[1].SourceName | Should Be $dscConfig.AllNodes.SourceName2 + $result.logFile.customFields.Collection[1].SourceType | Should Be $dscConfig.AllNodes.SourceType2 + } } @@ -195,7 +202,14 @@ try #Test DefaultPage is correct $defultPages[0] | Should Match $dscConfig.AllNodes.DefaultPage - } + #Test LogCustomFields is correct + $result.logFile.customFields.Collection[0].LogFieldName | Should Be $dscConfig.AllNodes.LogFieldName1 + $result.logFile.customFields.Collection[0].SourceName | Should Be $dscConfig.AllNodes.SourceName1 + $result.logFile.customFields.Collection[0].SourceType | Should Be $dscConfig.AllNodes.SourceType1 + $result.logFile.customFields.Collection[1].LogFieldName | Should Be $dscConfig.AllNodes.LogFieldName2 + $result.logFile.customFields.Collection[1].SourceName | Should Be $dscConfig.AllNodes.SourceName2 + $result.logFile.customFields.Collection[1].SourceType | Should Be $dscConfig.AllNodes.SourceType2 + } } diff --git a/Tests/Integration/MSFT_xWebsite.config.ps1 b/Tests/Integration/MSFT_xWebsite.config.ps1 index 360b00a33..361a88599 100644 --- a/Tests/Integration/MSFT_xWebsite.config.ps1 +++ b/Tests/Integration/MSFT_xWebsite.config.ps1 @@ -27,7 +27,7 @@ configuration MSFT_xWebsite_Present_Started Digest = $Node.AuthenticationInfoDigest Windows = $Node.AuthenticationInfoWindows } - BindingInfo = @(MSFT_xWebBindingInformation + BindingInfo = @(MSFT_xWebBindingInformation { Protocol = $Node.HTTPProtocol Port = $Node.HTTPPort @@ -61,13 +61,27 @@ configuration MSFT_xWebsite_Present_Started CertificateStoreName = $Node.CertificateStoreName SslFlags = $Node.SslFlags }) - DefaultPage = $Node.DefaultPage - EnabledProtocols = $Node.EnabledProtocols - PhysicalPath = $Node.PhysicalPath - PreloadEnabled = $Node.PreloadEnabled - ServiceAutoStartEnabled = $Node.ServiceAutoStartEnabled - ServiceAutoStartProvider = $Node.ServiceAutoStartProvider - State = 'Started' + DefaultPage = $Node.DefaultPage + EnabledProtocols = $Node.EnabledProtocols + PhysicalPath = $Node.PhysicalPath + PreloadEnabled = $Node.PreloadEnabled + ServiceAutoStartEnabled = $Node.ServiceAutoStartEnabled + ServiceAutoStartProvider = $Node.ServiceAutoStartProvider + State = 'Started' + LogCustomFields = @( + MSFT_xLogCustomFieldInformation + { + LogFieldName = $Node.LogFieldName1 + SourceName = $Node.SourceName1 + SourceType = $Node.SourceType1 + } + MSFT_xLogCustomFieldInformation + { + LogFieldName = $Node.LogFieldName2 + SourceName = $Node.SourceName2 + SourceType = $Node.SourceType2 + } + ) } } } @@ -141,6 +155,20 @@ configuration MSFT_xWebsite_Present_Stopped ServiceAutoStartEnabled = $Node.ServiceAutoStartEnabled ServiceAutoStartProvider = $Node.ServiceAutoStartProvider State = 'Stopped' + LogCustomFields = @( + MSFT_xLogCustomFieldInformation + { + LogFieldName = $Node.LogFieldName1 + SourceName = $Node.SourceName1 + SourceType = $Node.SourceType1 + } + MSFT_xLogCustomFieldInformation + { + LogFieldName = $Node.LogFieldName2 + SourceName = $Node.SourceName2 + SourceType = $Node.SourceType2 + } + ) } } } diff --git a/Tests/Integration/MSFT_xWebsite.config.psd1 b/Tests/Integration/MSFT_xWebsite.config.psd1 index b94e07c83..e0e219181 100644 --- a/Tests/Integration/MSFT_xWebsite.config.psd1 +++ b/Tests/Integration/MSFT_xWebsite.config.psd1 @@ -28,6 +28,12 @@ HTTPSHostname = 'https.website' CertificateStoreName = 'MY' SslFlags = '1' + LogFieldName1 = 'CustomField1' + SourceName1 = 'Accept-Encoding' + SourceType1 = 'RequestHeader' + LogFieldName2 = 'CustomField2' + SourceName2 = 'Warning' + SourceType2 = 'ResponseHeader' } ) } diff --git a/Tests/Unit/MSFT_xWebsite.Tests.ps1 b/Tests/Unit/MSFT_xWebsite.Tests.ps1 index 6e7c50c67..d475d54a3 100644 --- a/Tests/Unit/MSFT_xWebsite.Tests.ps1 +++ b/Tests/Unit/MSFT_xWebsite.Tests.ps1 @@ -86,6 +86,19 @@ try -ClientOnly ) + $mockLogCustomFields = @( + @{ + LogFieldName = 'LogField1' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } + @{ + LogFieldName = 'LogField2' + SourceName = 'Warning' + SourceType = 'ResponseHeader' + } + ) + $MockLogOutput = @{ directory = '%SystemDrive%\inetpub\logs\LogFiles' logExtFileFlags = 'Date','Time','ClientIP','UserName','ServerIP','Method','UriStem','UriQuery','HttpStatus','Win32Status','TimeTaken','ServerPort','UserAgent','Referer','HttpSubStatus' @@ -93,6 +106,7 @@ try period = 'Daily' truncateSize = '1048576' localTimeRollover = 'False' + customFields = @{Collection = $mockLogCustomFields} } $MockWebsite = @{ @@ -263,6 +277,15 @@ try It 'should return LogFormat' { $Result.logFormat | Should Be $MockWebsite.Logfile.logFormat } + + It 'should return LogCustomFields' { + $Result.LogCustomFields[0].LogFieldName | Should Be $mockLogCustomFields[0].LogFieldName + $Result.LogCustomFields[0].SourceName | Should Be $mockLogCustomFields[0].SourceName + $Result.LogCustomFields[0].SourceType | Should Be $mockLogCustomFields[0].SourceType + $Result.LogCustomFields[1].LogFieldName | Should Be $mockLogCustomFields[1].LogFieldName + $Result.LogCustomFields[1].SourceName | Should Be $mockLogCustomFields[1].SourceName + $Result.LogCustomFields[1].SourceType | Should Be $mockLogCustomFields[1].SourceType + } } } @@ -281,6 +304,27 @@ try } -ClientOnly ) + $MockCimLogCustomFields = @( + (New-CimInstance -ClassName MSFT_xLogCustomFieldInformation ` + -Namespace root/microsoft/Windows/DesiredStateConfiguration ` + -Property @{ + LogFieldName = 'LogField1' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } ` + -ClientOnly + ), + (New-CimInstance -ClassName MSFT_xLogCustomFieldInformation ` + -Namespace root/microsoft/Windows/DesiredStateConfiguration ` + -Property @{ + LogFieldName = 'LogField2' + SourceName = 'Warning' + SourceType = 'ResponseHeader' + } ` + -ClientOnly + ) + ) + $MockParameters = @{ Ensure = 'Present' Name = 'MockName' @@ -299,6 +343,7 @@ try LogPeriod = 'Hourly' LogTruncateSize = '2000000' LoglocalTimeRollover = $True + LogCustomFields = $MockCimLogCustomFields } $MockWebBinding = @( @@ -319,6 +364,19 @@ try } ) + $mockLogCustomFields = @( + @{ + LogFieldName = 'LogField1' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } + @{ + LogFieldName = 'LogField2' + SourceName = 'Warning' + SourceType = 'ResponseHeader' + } + ) + $MockLogOutput = @{ directory = '%SystemDrive%\inetpub\logs\LogFiles' logExtFileFlags = 'Date','Time','ClientIP','UserName','ServerIP','Method','UriStem','UriQuery','HttpStatus','Win32Status','TimeTaken','ServerPort','UserAgent','Referer','HttpSubStatus' @@ -326,6 +384,7 @@ try period = 'Daily' truncateSize = '1048576' localTimeRollover = 'False' + customFields = @{Collection = $mockLogCustomFields} } $MockWebsite = @{ @@ -742,6 +801,47 @@ try $result | Should be $false } } + + Context 'Check LogCustomFields is equal' { + Mock -CommandName Get-Website -MockWith {return $MockWebsite} + + Mock -CommandName Get-WebConfigurationProperty ` + -MockWith { return $mockLogCustomFields[0] } ` + -ParameterFilter { $Filter -match $MockParameters.LogCustomFields[0].LogFieldName } + + Mock -CommandName Get-WebConfigurationProperty ` + -MockWith { return $mockLogCustomFields[1] } ` + -ParameterFilter { $Filter -match $MockParameters.LogCustomFields[1].LogFieldName } + + $Result = Test-TargetResource -Ensure $MockParameters.Ensure ` + -Name $MockParameters.Name ` + -LogCustomFields $MockParameters.LogCustomFields + + It 'Should return true' { + $result | Should be $true + } + } + + Context 'Check LogCustomFields is different' { + Mock -CommandName Get-Website -MockWith {return $MockWebsite} + + $MockDifferentLogCustomFields = @{ + LogFieldName = 'DifferentField' + SourceName = 'Accept-Encoding' + SourceType = 'DifferentSourceType' + } + + Mock -CommandName Get-WebConfigurationProperty ` + -MockWith {return $MockDifferentLogCustomFields } + + $Result = Test-TargetResource -Ensure $MockParameters.Ensure ` + -Name $MockParameters.Name ` + -LogCustomFields $MockParameters.LogCustomFields + + It 'Should return false' { + $result | Should be $false + } + } } Describe "how $script:DSCResourceName\Set-TargetResource responds to Ensure = 'Present'" { @@ -764,6 +864,17 @@ try } -ClientOnly ) + $MockCimLogCustomFields = @( + New-CimInstance -ClassName MSFT_xLogCustomFieldInformation ` + -Namespace root/microsoft/Windows/DesiredStateConfiguration ` + -Property @{ + LogFieldName = 'ClientEncoding' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } ` + -ClientOnly + ) + $MockParameters = @{ Ensure = 'Present' Name = 'MockName' @@ -784,6 +895,7 @@ try LogTruncateSize = '2000000' LoglocalTimeRollover = $True LogFormat = 'W3C' + LogCustomFields = $MockCimLogCustomFields } $MockWebBinding = @( @@ -804,6 +916,19 @@ try } ) + $mockLogCustomFields = @( + @{ + LogFieldName = 'LogField1' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } + @{ + LogFieldName = 'LogField2' + SourceName = 'Warning' + SourceType = 'ResponseHeader' + } + ) + $MockLogOutput = @{ directory = '%SystemDrive%\inetpub\logs\LogFiles' @@ -812,6 +937,7 @@ try period = 'Daily' truncateSize = '1048576' localTimeRollover = 'False' + customFields = @{Collection = $mockLogCustomFields} } $MockWebsite = @{ @@ -870,6 +996,10 @@ try Mock -CommandName Test-AuthenticationEnabled { return $false } ` -ParameterFilter { ($Type -eq 'Windows') } + Mock -CommandName Set-WebConfigurationProperty + + Mock -CommandName Test-LogCustomField -MockWith { return $false } + Set-TargetResource @MockParameters It 'Should call all the mocks' { @@ -885,10 +1015,11 @@ try Assert-MockCalled -CommandName Set-Item -Exactly 3 Assert-MockCalled -CommandName Set-ItemProperty -Exactly 9 Assert-MockCalled -CommandName Start-Website -Exactly 1 + Assert-MockCalled -CommandName Set-WebConfigurationProperty -Exactly 2 + Assert-MockCalled -CommandName Test-LogCustomField -Exactly 1 } } - Context 'Create website with empty physical path' { Mock -CommandName Confirm-UniqueBinding -MockWith { return $true } @@ -3446,6 +3577,131 @@ try } } } + + Describe "$script:DSCResourceName\ConvertTo-CimLogCustomFields"{ + $mockLogCustomFields = @( + @{ + LogFieldName = 'LogField1' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } + @{ + LogFieldName = 'LogField2' + SourceName = 'Warning' + SourceType = 'ResponseHeader' + } + ) + + Context 'Expected behavior'{ + $Result = ConvertTo-CimLogCustomFields -InputObject $mockLogCustomFields + + It 'should return the LogFieldName' { + $Result[0].LogFieldName | Should Be $mockLogCustomFields[0].LogFieldName + $Result[0].LogFieldName | Should Be $mockLogCustomFields[0].LogFieldName + } + + It 'should return the SourceName' { + $Result[0].SourceName | Should Be $mockLogCustomFields[0].SourceName + $Result[0].SourceName | Should Be $mockLogCustomFields[0].SourceName + } + + It 'should return the SourceType' { + $Result[0].SourceType | Should Be $mockLogCustomFields[0].SourceType + $Result[0].SourceType | Should Be $mockLogCustomFields[0].SourceType + } + } + } + + Describe "$script:DSCResourceName\Test-LogCustomField"{ + $MockWebsiteName = 'ContosoSite' + + $MockCimLogCustomFields = @( + New-CimInstance -ClassName MSFT_xLogCustomFieldInformation ` + -Namespace root/microsoft/Windows/DesiredStateConfiguration ` + -Property @{ + LogFieldName = 'ClientEncoding' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } ` + -ClientOnly + ) + + Context 'LogCustomField in desired state'{ + $MockDesiredLogCustomFields = @{ + LogFieldName = 'ClientEncoding' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } + + Mock -CommandName Get-WebConfigurationProperty -MockWith { return $MockDesiredLogCustomFields } + + It 'should return True' { + Test-LogCustomField -Site $MockWebsiteName -LogCustomField $MockCimLogCustomFields | Should Be $True + } + } + + Context 'LogCustomField not in desired state'{ + $MockWrongLogCustomFields = @{ + LogFieldName = 'ClientEncoding' + SourceName = 'WrongSourceName' + SourceType = 'WrongSourceType' + } + + Mock -CommandName Get-WebConfigurationProperty -MockWith { return $MockWrongLogCustomFields } + + It 'should return False' { + Test-LogCustomField -Site $MockWebsiteName -LogCustomField $MockCimLogCustomFields | Should Be $False + } + } + + Context 'LogCustomField not present'{ + Mock -CommandName Get-WebConfigurationProperty -MockWith { return $false } + + It 'should return False' { + Test-LogCustomField -Site $MockWebsiteName -LogCustomField $MockCimLogCustomFields | Should Be $False + } + } + + } + + Describe "$script:DSCResourceName\Set-LogCustomField"{ + $MockWebsiteName = 'ContosoSite' + + $MockCimLogCustomFields = @( + New-CimInstance -ClassName MSFT_xLogCustomFieldInformation ` + -Namespace root/microsoft/Windows/DesiredStateConfiguration ` + -Property @{ + LogFieldName = 'ClientEncoding' + SourceName = 'Accept-Encoding' + SourceType = 'RequestHeader' + } ` + -ClientOnly + ) + + Context 'Create new LogCustomField'{ + Mock -CommandName Set-WebConfigurationProperty + + It 'should not throw an error' { + { Set-LogCustomField -Site $MockWebsiteName -LogCustomField $MockCimLogCustomFields } | Should Not Throw + } + + It 'should call should call expected mocks' { + Assert-MockCalled -CommandName Set-WebConfigurationProperty -Exactly 2 + } + } + + Context 'Modify existing LogCustomField'{ + Mock -CommandName Set-WebConfigurationProperty + + It 'should not throw an error' { + { Set-LogCustomField -Site $MockWebsiteName -LogCustomField $MockCimLogCustomFields } | Should Not Throw + } + + It 'should call should call expected mocks' { + Assert-MockCalled -CommandName Set-WebConfigurationProperty -Exactly 2 + } + } + } } #endregion }