diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e7c06e5..990edce5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- SPWebAppHttpThrottlingMonitor + - Added new resource to manage web application Http Throttling Monitor settings + ### Changed - SPFarm @@ -16,9 +21,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- SPAppDomain + - Corrected Verbose logging in Test method + - Corrected issue in Get method where ErrorAction had to be SilentlyContinue - SPContentDatabase - Fixed issue where WebAppUrl in the Desired State would cause the test to fail, always resulting in False. +- SPExcelServiceApp + - Updated links to Docs instead of old TechNet - SPInstallLanguagePack - Fixed detection of Norwegian language pack - SPManagedMetaDataServiceApp @@ -28,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed issue where an error was thrown if the specified RootDirectory didn't exist on the current server but did exist on the target server. - Fixed issue with using FQDNs instead of NetBIOS server names. +- SPWorkManagementServiceApp + - Updated links to Docs instead of old TechNet ## [4.7.0] - 2021-06-10 diff --git a/SharePointDsc/DSCResources/MSFT_SPAppDomain/MSFT_SPAppDomain.psm1 b/SharePointDsc/DSCResources/MSFT_SPAppDomain/MSFT_SPAppDomain.psm1 index 62d0d8375..23b6426c0 100644 --- a/SharePointDsc/DSCResources/MSFT_SPAppDomain/MSFT_SPAppDomain.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPAppDomain/MSFT_SPAppDomain.psm1 @@ -27,7 +27,7 @@ function Get-TargetResource -ScriptBlock { $params = $args[0] $appDomain = Get-SPAppDomain - $prefix = Get-SPAppSiteSubscriptionName -ErrorAction Continue + $prefix = Get-SPAppSiteSubscriptionName -ErrorAction SilentlyContinue return @{ AppDomain = $appDomain @@ -86,7 +86,7 @@ function Test-TargetResource $InstallAccount ) - Write-Verbose -Message "Getting app domain settings" + Write-Verbose -Message "Testing app domain settings" $CurrentValues = Get-TargetResource @PSBoundParameters diff --git a/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/MSFT_SPExcelServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/MSFT_SPExcelServiceApp.psm1 index c1a89972e..e2a6745fd 100644 --- a/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/MSFT_SPExcelServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/MSFT_SPExcelServiceApp.psm1 @@ -128,7 +128,7 @@ function Get-TargetResource $message = ("Only SharePoint 2013 is supported to deploy Excel Services " + ` "service applications via DSC, as SharePoint 2016 and SharePoint 2019 deprecated " + ` "this service. See " + ` - "https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx " + ` + "https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016 " + ` "for more info.") Add-SPDscEvent -Message $message ` -EntryType 'Error' ` @@ -324,7 +324,7 @@ function Set-TargetResource $message = ("Only SharePoint 2013 is supported to deploy Excel Services " + ` "service applications via DSC, as SharePoint 2016 and SharePoint 2019 deprecated " + ` "this service. See " + ` - "https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx " + ` + "https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016 " + ` "for more info.") Add-SPDscEvent -Message $message ` -EntryType 'Error' ` @@ -591,7 +591,7 @@ function Test-TargetResource $message = ("Only SharePoint 2013 is supported to deploy Excel Services " + ` "service applications via DSC, as SharePoint 2016 and SharePoint 2019 deprecated " + ` "this service. See " + ` - "https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx " + ` + "https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016 " + ` "for more info.") Add-SPDscEvent -Message $message ` -EntryType 'Error' ` diff --git a/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/Readme.md b/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/Readme.md index 838468949..30d1180d3 100644 --- a/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/Readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPExcelServiceApp/Readme.md @@ -12,5 +12,5 @@ parameter, the service application is provisioned. Only SharePoint 2013 is supported to deploy Excel Services service applications via DSC, as SharePoint 2016 and SharePoint 2019 have deprecated this service. See -[What's deprecated or removed from SharePoint Server 2016](https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx) +[What's deprecated or removed from SharePoint Server 2016](https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016) for more info. diff --git a/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/MSFT_SPWebAppHttpThrottlingMonitor.psm1 b/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/MSFT_SPWebAppHttpThrottlingMonitor.psm1 new file mode 100644 index 000000000..9aaf048ea --- /dev/null +++ b/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/MSFT_SPWebAppHttpThrottlingMonitor.psm1 @@ -0,0 +1,418 @@ +$script:SPDscUtilModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\SharePointDsc.Util' +Import-Module -Name $script:SPDscUtilModulePath + +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $WebAppUrl, + + [Parameter(Mandatory = $true)] + [System.String] + $Category, + + [Parameter(Mandatory = $true)] + [System.String] + $Counter, + + [Parameter()] + [System.String] + $CounterInstance = "", + + [Parameter()] + [System.UInt32[]] + $HealthScoreBuckets, + + [Parameter()] + [System.Boolean] + $IsDescending = $false, + + [Parameter()] + [ValidateSet("Present", "Absent")] + [System.String] + $Ensure = "Present", + + [Parameter()] + [System.Management.Automation.PSCredential] + $InstallAccount + ) + + Write-Verbose -Message "Getting web application '$WebAppUrl' HTTP Throttling Monitoring settings" + + if ($Ensure -eq 'Present') + { + if ($PSBoundParameters.ContainsKey("HealthScoreBuckets") -eq $false) + { + Write-Verbose -Message 'NOTE: The HealthScoreBuckets parameter is required when Ensure=Present' + } + } + + if ($PSBoundParameters.ContainsKey("HealthScoreBuckets")) + { + if ($HealthScoreBuckets[0] -gt $HealthScoreBuckets[1]) + { + Write-Verbose -Message "Order of HealthScoreBuckets is Descending" + $bucketsDescending = $true + } + else + { + Write-Verbose -Message "Order of HealthScoreBuckets is Ascending" + $bucketsDescending = $false + } + + if ($bucketsDescending -ne $IsDescending) + { + Write-Verbose -Message 'NOTE: The order of HealthScoreBuckets and IsDescending do not match. Make sure they do.' + } + } + + $PSBoundParameters.IsDescending = $IsDescending + $PSBoundParameters.CounterInstance = $CounterInstance + + $result = Invoke-SPDscCommand -Credential $InstallAccount ` + -Arguments $PSBoundParameters ` + -ScriptBlock { + $params = $args[0] + + $nullReturn = @{ + WebAppUrl = $params.WebAppUrl + Category = $params.Category + Counter = $params.Counter + CounterInstance = $params.CounterInstance + IsDescending = $params.IsDescending + HealthScoreBuckets = $null + Ensure = "Absent" + } + + $wa = Get-SPWebApplication -Identity $params.WebAppUrl -ErrorAction SilentlyContinue + if ($null -eq $wa) + { + return $nullReturn + } + + [Array]$httpTM = $null + if ([String]::IsNullOrEmpty($CounterInstance)) + { + $httpTM = (Get-SPWebApplicationHttpThrottlingMonitor $params.webappUrl) | Where-Object -FilterScript { + ($_.Category -eq $params.Category) -and ` + ($_.Counter -eq $params.Counter) + } + } + else + { + $httpTM = (Get-SPWebApplicationHttpThrottlingMonitor $params.webappUrl) | Where-Object -FilterScript { + ($_.Category -eq $params.Category) -and ` + ($_.Counter -eq $params.Counter) -and ` + ($_.Instance -eq $params.CounterInstance) + } + } + + if ($null -eq $httpTM) + { + return $nullReturn + } + + if ($httpTM.Count -gt 1) + { + throw "The specified Category and Counter returned more than one result. Please also specify a CounterInstance." + } + + $healthScoreBuckets = $httpTM.AssociatedHealthScoreCalculator.GetScoreBuckets() + if ($healthScoreBuckets[0] -gt $healthScoreBuckets[1]) + { + $isDescending = $true + } + else + { + $isDescending = $false + } + + $result = @{ + WebAppUrl = $params.WebAppUrl + Category = $params.Category + Counter = $params.Counter + CounterInstance = $params.CounterInstance + HealthScoreBuckets = $healthScoreBuckets + IsDescending = $isDescending + Ensure = "Present" + } + + return $result + } + return $result +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $WebAppUrl, + + [Parameter(Mandatory = $true)] + [System.String] + $Category, + + [Parameter(Mandatory = $true)] + [System.String] + $Counter, + + [Parameter()] + [System.String] + $CounterInstance = "", + + [Parameter()] + [System.UInt32[]] + $HealthScoreBuckets, + + [Parameter()] + [System.Boolean] + $IsDescending = $false, + + [Parameter()] + [ValidateSet("Present", "Absent")] + [System.String] + $Ensure = "Present", + + [Parameter()] + [System.Management.Automation.PSCredential] + $InstallAccount + ) + + Write-Verbose -Message "Setting web application '$WebAppUrl' HTTP Throttling Monitoring settings" + + if ($Ensure -eq 'Present') + { + if ($PSBoundParameters.ContainsKey("HealthScoreBuckets") -eq $false) + { + throw 'The HealthScoreBuckets parameter is required when Ensure=Present' + } + } + + if ($PSBoundParameters.ContainsKey("HealthScoreBuckets")) + { + if ($HealthScoreBuckets[0] -gt $HealthScoreBuckets[1]) + { + Write-Verbose -Message "Order of HealthScoreBuckets is Descending" + $bucketsDescending = $true + } + else + { + Write-Verbose -Message "Order of HealthScoreBuckets is Ascending" + $bucketsDescending = $false + } + + if ($bucketsDescending -ne $IsDescending) + { + throw 'The order of HealthScoreBuckets and IsDescending do not match. Make sure they do.' + } + } + + $PSBoundParameters.IsDescending = $IsDescending + $PSBoundParameters.CounterInstance = $CounterInstance + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Invoke-SPDscCommand -Credential $InstallAccount ` + -Arguments @($PSBoundParameters, $MyInvocation.MyCommand.Source, $CurrentValues) ` + -ScriptBlock { + $params = $args[0] + $eventSource = $args[1] + $CurrentValues = $args[2] + + $wa = Get-SPWebApplication -Identity $params.WebAppUrl -ErrorAction SilentlyContinue + if ($null -eq $wa) + { + $message = "Web application $($params.WebAppUrl) was not found" + Add-SPDscEvent -Message $message ` + -EntryType 'Error' ` + -EventID 100 ` + -Source $eventSource + throw $message + } + + if ($params.Ensure -eq "Present") + { + $sortParams = @{ + Descending = $params.IsDescending + } + $healthScoreBuckets = $params.HealthScoreBuckets | Sort-Object @sortParams + if ($CurrentValues.Ensure -eq "Absent") + { + Write-Verbose -Message 'Specified monitor does not exist, creating it!' + $throttle = $wa.HttpThrottleSettings + $throttle.AddPerformanceMonitor($params.Category, $params.Counter, $params.CounterInstance, $healthScoreBuckets, -not $params.IsDescending) + $throttle.Update() + } + else + { + Write-Verbose -Message 'Specified monitor exists, update it!' + $newParams = @{ + Identity = $params.WebAppUrl + Category = $params.Category + Counter = $params.Counter + HealthScoreBuckets = $healthScoreBuckets + IsDesc = $params.IsDescending + } + + if ([String]::IsNullOrEmpty($params.CounterInstance) -eq $false) + { + $newParams.Instance = $params.CounterInstance + } + + Set-SPWebApplicationHttpThrottlingMonitor @newParams + } + } + + if ($params.Ensure -eq "Absent" -and $CurrentValues.Ensure -eq "Present") + { + Write-Verbose -Message 'Specified monitor exists, deleting it!' + $throttle = $wa.HttpThrottleSettings + if ([String]::IsNullOrEmpty($params.CounterInstance)) + { + $throttle.RemovePerformanceMonitor($params.Category, $params.Counter) + } + else + { + $throttle.RemovePerformanceMonitor($params.Category, $params.Counter, $params.CounterInstance) + } + $throttle.Update() + } + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $WebAppUrl, + + [Parameter(Mandatory = $true)] + [System.String] + $Category, + + [Parameter(Mandatory = $true)] + [System.String] + $Counter, + + [Parameter()] + [System.String] + $CounterInstance = "", + + [Parameter()] + [System.UInt32[]] + $HealthScoreBuckets, + + [Parameter()] + [System.Boolean] + $IsDescending = $false, + + [Parameter()] + [ValidateSet("Present", "Absent")] + [System.String] + $Ensure = "Present", + + [Parameter()] + [System.Management.Automation.PSCredential] + $InstallAccount + ) + + Write-Verbose -Message "Testing web application '$WebAppUrl' HTTP Throttling Monitoring settings" + + $PSBoundParameters.IsDescending = $IsDescending + $PSBoundParameters.CounterInstance = $CounterInstance + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-SPDscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-SPDscHashtableToString -Hashtable $PSBoundParameters)" + + if ($Ensure -eq "Present" -and ` + $CurrentValues.Ensure -eq "Present" -and ` + $PSBoundParameters.ContainsKey("HealthScoreBuckets") -and ` + $CurrentValues.ContainsKey("HealthScoreBuckets")) + { + if ($null -ne (Compare-Object -ReferenceObject $HealthScoreBuckets -DifferenceObject $CurrentValues.HealthScoreBuckets)) + { + Write-Verbose "HealthScoreBucket values do not match." + Write-Verbose -Message "Test-TargetResource returned False" + return $false + } + } + + $valuesToCheck = @( + "WebAppUrl", + "Category", + "Counter", + "CounterInstance", + "IsDescending", + "Ensure" + ) + + $result = Test-SPDscParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $valuesToCheck + + Write-Verbose -Message "Test-TargetResource returned $result" + + return $result +} + +function Export-TargetResource +{ + $VerbosePreference = "SilentlyContinue" + $ParentModuleBase = Get-Module "SharePointDsc" -ListAvailable | Select-Object -ExpandProperty Modulebase + $module = Join-Path -Path $ParentModuleBase -ChildPath "\DSCResources\MSFT_SPWebAppHttpThrottlingMonitor\MSFT_SPWebAppHttpThrottlingMonitor.psm1" -Resolve + $Content = '' + $params = Get-DSCFakeParameters -ModulePath $module + $webApps = Get-SPWebApplication + $i = 1 + $total = $webApps.Length + foreach ($webApp in $webApps) + { + try + { + Write-Host "Scanning HTTP Throttling Monitoring for Web App [$i/$total] {$($webApp.Url)}" + $params.WebAppUrl = $webApp.Url + + $monitors = Get-SPWebApplicationHttpThrottlingMonitor -Identity $webApp.Url + foreach ($monitor in $monitors) + { + $params.Category = $monitor.Category + $params.Counter = $monitor.Counter + $params.CounterInstance = $monitor.Instance + + $PartialContent = " SPWebAppHttpThrottlingMonitor " + [System.Guid]::NewGuid().ToString() + "`r`n" + $PartialContent += " {`r`n" + + $results = Get-TargetResource @params + + $results = Repair-Credentials -results $results + $currentBlock = Get-DSCBlock -Params $results -ModulePath $module + $currentBlock = Convert-DSCStringParamToVariable -DSCBlock $currentBlock -ParameterName "PsDscRunAsCredential" + $PartialContent += $currentBlock + $PartialContent += " }`r`n" + $Content += $PartialContent + } + } + catch + { + $Global:ErrorLog += "[SPWebAppHttpThrottlingMonitor] Couldn't properly retrieve all HTTP Throttling Monitors from Web Application {$($webApp.Url)}`r`n" + } + $i++ + } + return $Content +} + +Export-ModuleMember -Function *-TargetResource diff --git a/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/MSFT_SPWebAppHttpThrottlingMonitor.schema.mof b/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/MSFT_SPWebAppHttpThrottlingMonitor.schema.mof new file mode 100644 index 000000000..76e7eba61 --- /dev/null +++ b/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/MSFT_SPWebAppHttpThrottlingMonitor.schema.mof @@ -0,0 +1,12 @@ +[ClassVersion("1.0.0"), FriendlyName("SPWebAppHttpThrottlingMonitor")] +class MSFT_SPWebAppHttpThrottlingMonitor : OMI_BaseResource +{ + [Key, Description("The URL of the web app to set the throttling monitor for")] string WebAppUrl; + [Required, Description("Specifies the name of the performance counter category")] string Category; + [Required, Description("Specifies the name of the performance counter")] string Counter; + [Write, Description("Specifies bucket ranges to use in determining the calculation of the server Health Score for this counter")] uint32 HealthScoreBuckets[]; + [Write, Description("Specifies the instance of the performance counter")] string CounterInstance; + [Write, Description("Specifies that this counter is interpreted in descending order")] boolean IsDescending; + [Write, Description("Present if the throttling monitor should exist, absent if it should not"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("POWERSHELL 4 ONLY: The account to run this resource as, use PsDscRunAsCredential if using PowerShell 5"), EmbeddedInstance("MSFT_Credential")] string InstallAccount; +}; diff --git a/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/readme.md b/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/readme.md new file mode 100644 index 000000000..c04999330 --- /dev/null +++ b/SharePointDsc/DSCResources/MSFT_SPWebAppHttpThrottlingMonitor/readme.md @@ -0,0 +1,13 @@ +# Description + +**Type:** Distributed +**Requires CredSSP:** No + +This resource is responsible for managing the web application request throttling +settings. The desired web application is specified through the URL property, and +then any combination of settings can be applied. Any settings not included will +be left as the default (or whatever they have been manually changed to within +SharePoint). + +More information about the Request Throttling functionality can be found here: +https://docs.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ff407390(v=office.14) diff --git a/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/MSFT_SPWorkManagementServiceApp.psm1 b/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/MSFT_SPWorkManagementServiceApp.psm1 index 59c260b59..2dd053c28 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/MSFT_SPWorkManagementServiceApp.psm1 +++ b/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/MSFT_SPWorkManagementServiceApp.psm1 @@ -60,7 +60,7 @@ function Get-TargetResource { $message = ("Work Management Service Application is no longer available " + ` "in SharePoint 2016/2019: " + ` - "https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx") + "https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016") Add-SPDscEvent -Message $message ` -EntryType 'Error' ` -EventID 100 ` @@ -185,7 +185,7 @@ function Set-TargetResource { $message = ("Work Management Service Application is no longer available " + ` "in SharePoint 2016/2019: " + ` - "https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx") + "https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016") Add-SPDscEvent -Message $message ` -EntryType 'Error' ` -EventID 100 ` @@ -410,7 +410,7 @@ function Test-TargetResource { $message = ("Work Management Service Application is no longer available " + ` "in SharePoint 2016/2019: " + ` - "https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx") + "https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016") Add-SPDscEvent -Message $message ` -EntryType 'Error' ` -EventID 100 ` diff --git a/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/readme.md b/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/readme.md index 66294e47e..40c3900dd 100644 --- a/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/readme.md +++ b/SharePointDsc/DSCResources/MSFT_SPWorkManagementServiceApp/readme.md @@ -23,4 +23,4 @@ NOTE: You cannot use this resource with SharePoint 2016/2019, since the Work Management functionality has been removed in SharePoint 2016/2019. More information: -https://technet.microsoft.com/en-us/library/mt346112(v=office.16).aspx +https://docs.microsoft.com/en-us/SharePoint/what-s-new/what-s-deprecated-or-removed-from-sharepoint-server-2016 diff --git a/SharePointDsc/Examples/Resources/SPWebAppHttpThrottlingMonitor/1-ConfigureMemoryCounter.ps1 b/SharePointDsc/Examples/Resources/SPWebAppHttpThrottlingMonitor/1-ConfigureMemoryCounter.ps1 new file mode 100644 index 000000000..c50f8eb14 --- /dev/null +++ b/SharePointDsc/Examples/Resources/SPWebAppHttpThrottlingMonitor/1-ConfigureMemoryCounter.ps1 @@ -0,0 +1,67 @@ + +<#PSScriptInfo + +.VERSION 1.0.0 + +.GUID 80d306fa-8bd4-4a8d-9f7a-bf40df95e661 + +.AUTHOR DSC Community + +.COMPANYNAME DSC Community + +.COPYRIGHT DSC Community contributors. All rights reserved. + +.TAGS + +.LICENSEURI https://github.com/dsccommunity/SharePointDsc/blob/master/LICENSE + +.PROJECTURI https://github.com/dsccommunity/SharePointDsc + +.ICONURI https://dsccommunity.org/images/DSC_Logo_300p.png + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES +Updated author, copyright notice, and URLs. + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + This example shows how to configure the Memory counter to the + Throttling Settings of the specified web app + +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + + Import-DscResource -ModuleName SharePointDsc + + node localhost + { + SPWebAppHttpThrottlingMonitor PrimaryWebAppHTTPThrottlingSettings + { + WebAppUrl = 'http://example.contoso.local' + Category = 'Memory' + Counter = 'Available Mbytes' + HealthScoreBuckets = @(1000, 500, 400, 300, 200, 100, 80, 60, 40, 20) + IsDescending = $true + Ensure = 'Present' + PsDscRunAsCredential = $SetupAccount + } + } +} diff --git a/SharePointDsc/Examples/Resources/SPWebAppHttpThrottlingMonitor/2-ConfigureProcessorCounter.ps1 b/SharePointDsc/Examples/Resources/SPWebAppHttpThrottlingMonitor/2-ConfigureProcessorCounter.ps1 new file mode 100644 index 000000000..7f59cad17 --- /dev/null +++ b/SharePointDsc/Examples/Resources/SPWebAppHttpThrottlingMonitor/2-ConfigureProcessorCounter.ps1 @@ -0,0 +1,67 @@ + +<#PSScriptInfo + +.VERSION 1.0.0 + +.GUID 80d306fa-8bd4-4a8d-9f7a-bf40df95e661 + +.AUTHOR DSC Community + +.COMPANYNAME DSC Community + +.COPYRIGHT DSC Community contributors. All rights reserved. + +.TAGS + +.LICENSEURI https://github.com/dsccommunity/SharePointDsc/blob/master/LICENSE + +.PROJECTURI https://github.com/dsccommunity/SharePointDsc + +.ICONURI https://dsccommunity.org/images/DSC_Logo_300p.png + +.EXTERNALMODULEDEPENDENCIES + +.REQUIREDSCRIPTS + +.EXTERNALSCRIPTDEPENDENCIES + +.RELEASENOTES +Updated author, copyright notice, and URLs. + +.PRIVATEDATA + +#> + +<# + +.DESCRIPTION + This example shows how to configure the Processor counter to the + Throttling Settings of the specified web app + +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $SetupAccount + ) + + Import-DscResource -ModuleName SharePointDsc + + node localhost + { + SPWebAppHttpThrottlingMonitor PrimaryWebAppHTTPThrottlingSettings + { + WebAppUrl = 'http://example.contoso.local' + Category = 'Processor' + Counter = '% Processor Time' + CounterInstance = '_Total' + HealthScoreBuckets = @(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) + Ensure = 'Present' + PsDscRunAsCredential = $SetupAccount + } + } +} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a5366e30d..5bcbdd563 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -63,7 +63,7 @@ stages: - job: Test_HQRM displayName: 'HQRM' pool: - vmImage: 'windows-2019' + vmImage: 'windows-2022' timeoutInMinutes: 0 steps: - task: DownloadPipelineArtifact@2 @@ -92,7 +92,7 @@ stages: - job: Test_Unit_2013 displayName: 'Unit SP2013' pool: - vmImage: 'windows-2019' + vmImage: 'windows-2022' timeoutInMinutes: 0 steps: - task: DownloadPipelineArtifact@2 @@ -127,7 +127,7 @@ stages: - job: Test_Unit_2016 displayName: 'Unit SP2016' pool: - vmImage: 'windows-2019' + vmImage: 'windows-2022' timeoutInMinutes: 0 steps: - task: DownloadPipelineArtifact@2 @@ -163,7 +163,7 @@ stages: - job: Test_Unit_2019 displayName: 'Unit SP2019' pool: - vmImage: 'windows-2019' + vmImage: 'windows-2022' timeoutInMinutes: 0 steps: - task: DownloadPipelineArtifact@2 diff --git a/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppHttpThrottlingMonitor.Tests.ps1 b/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppHttpThrottlingMonitor.Tests.ps1 new file mode 100644 index 000000000..d54300f82 --- /dev/null +++ b/tests/Unit/SharePointDsc/SharePointDsc.SPWebAppHttpThrottlingMonitor.Tests.ps1 @@ -0,0 +1,560 @@ +[CmdletBinding()] +param +( + [Parameter()] + [string] + $SharePointCmdletModule = (Join-Path -Path $PSScriptRoot ` + -ChildPath "..\Stubs\SharePoint\15.0.4805.1000\Microsoft.SharePoint.PowerShell.psm1" ` + -Resolve) +) + +$script:DSCModuleName = 'SharePointDsc' +$script:DSCResourceName = 'SPWebAppHttpThrottlingMonitor' +$script:DSCResourceFullName = 'MSFT_' + $script:DSCResourceName + +function Invoke-TestSetup +{ + try + { + Import-Module -Name DscResource.Test -Force + + Import-Module -Name (Join-Path -Path $PSScriptRoot ` + -ChildPath "..\UnitTestHelper.psm1" ` + -Resolve) + + $Global:SPDscHelper = New-SPDscUnitTestHelper -SharePointStubModule $SharePointCmdletModule ` + -DscResource $script:DSCResourceName + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + } + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:DSCModuleName ` + -DSCResourceName $script:DSCResourceFullName ` + -ResourceType 'Mof' ` + -TestType 'Unit' +} + +function Invoke-TestCleanup +{ + Restore-TestEnvironment -TestEnvironment $script:testEnvironment +} + +Invoke-TestSetup + +try +{ + InModuleScope -ModuleName $script:DSCResourceFullName -ScriptBlock { + Describe -Name $Global:SPDscHelper.DescribeHeader -Fixture { + BeforeAll { + Invoke-Command -ScriptBlock $Global:SPDscHelper.InitializeScript -NoNewScope + + # Initialize tests + + # Mocks for all contexts + + function Add-SPDscEvent + { + param ( + [Parameter(Mandatory = $true)] + [System.String] + $Message, + + [Parameter(Mandatory = $true)] + [System.String] + $Source, + + [Parameter()] + [ValidateSet('Error', 'Information', 'FailureAudit', 'SuccessAudit', 'Warning')] + [System.String] + $EntryType, + + [Parameter()] + [System.UInt32] + $EventID + ) + } + } + + # Test contexts + Context -Name "Ensure=Present, but the HealthScoreBuckets parameter is not provided" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + IsDescending = $false + Ensure = 'Present' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $webApp = @{ + DisplayName = 'Sites' + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + } -PassThru + + return @( + @{ + Category = 'Processor' + Counter = '% Processor Time' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + } + ) + } + } + + It "Should return IsDescending=true from the get method" { + (Get-TargetResource @testParams).IsDescending | Should -Be $true + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should -Throw 'The HealthScoreBuckets parameter is required when Ensure=Present' + } + } + + Context -Name "Specified HealthScoreBuckets order does not match the IsDescending parameter" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + HealthScoreBuckets = @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + IsDescending = $false + Ensure = 'Present' + } + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should -Throw 'The order of HealthScoreBuckets and IsDescending do not match. Make sure they do.' + } + } + + Context -Name "Specified Category and Counter returns more than one result" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + HealthScoreBuckets = @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + IsDescending = $true + Ensure = 'Present' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $webApp = @{ + DisplayName = 'Sites' + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + } -PassThru + + return @( + @{ + Category = 'Processor' + Counter = '% Processor Time' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + Instance = 0 + }, + @{ + Category = 'Processor' + Counter = '% Processor Time' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + Instance = 1 + } + ) + } + } + + It "Should throw an exception in the get method" { + { Get-TargetResource @testParams } | Should -Throw 'The specified Category and Counter returned more than one result. Please also specify a CounterInstance.' + } + + It "Should throw an exception in the test method" { + { Test-TargetResource @testParams } | Should -Throw 'The specified Category and Counter returned more than one result. Please also specify a CounterInstance.' + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should -Throw 'The specified Category and Counter returned more than one result. Please also specify a CounterInstance.' + } + } + + Context -Name "Specified web application does not exist" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + HealthScoreBuckets = @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + IsDescending = $true + Ensure = 'Present' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + return $null + } + } + + It "Should return Ensure=Absent from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It "Should return false from the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should throw an exception in the set method" { + { Set-TargetResource @testParams } | Should -Throw "Web application $($testParams.WebAppUrl) was not found" + } + } + + Context -Name "Specified Counter is not present, but should be" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + HealthScoreBuckets = @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + IsDescending = $true + Ensure = 'Present' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $httpThrottleSettings = @{} + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name AddPerformanceMonitor -Value { + } -PassThru + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name Update -Value { + $Global:SPDscThrottleSettingsUpdated = $true + } -PassThru + + $webApp = @{ + DisplayName = 'Sites' + HttpThrottleSettings = $httpThrottleSettings + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + } -PassThru + + return @( + @{ + Category = 'Memory' + Counter = 'Available MBytes' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + } + ) + } + } + + It "Should return Ensure=Absent from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It "Should return False the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should create the counter monitor in the set method" { + $Global:SPDscThrottleSettingsUpdated = $false + Set-TargetResource @testParams + $Global:SPDscThrottleSettingsUpdated | Should -Be $true + } + } + + Context -Name "Specified Counter is present, but not configured correctly" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + HealthScoreBuckets = @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + IsDescending = $true + Ensure = 'Present' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $httpThrottleSettings = @{} + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name AddPerformanceMonitor -Value { + } -PassThru + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name Update -Value { + $Global:SPDscThrottleSettingsUpdated = $true + } -PassThru + + $webApp = @{ + DisplayName = 'Sites' + HttpThrottleSettings = $httpThrottleSettings + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(100, 90, 80, 70, 60, 50, 40, 30, 20, 10) + } -PassThru + + return @( + @{ + Category = 'Processor' + Counter = '% Processor Time' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + } + ) + } + + Mock -CommandName Set-SPWebApplicationHttpThrottlingMonitor -MockWith { } + } + + It "Should return Ensure=Present from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return False the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should correct the counter monitor in the set method" { + Set-TargetResource @testParams + Assert-MockCalled -CommandName Set-SPWebApplicationHttpThrottlingMonitor + } + } + + Context -Name "Specified Counter is not present and should not be" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + Ensure = 'Absent' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $httpThrottleSettings = @{} + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name AddPerformanceMonitor -Value { + } -PassThru + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name Update -Value { + $Global:SPDscThrottleSettingsUpdated = $true + } -PassThru + + $webApp = @{ + DisplayName = 'Sites' + HttpThrottleSettings = $httpThrottleSettings + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + } -PassThru + + return @( + @{ + Category = 'Memory' + Counter = 'Available MBytes' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + } + ) + } + } + + It "Should return Ensure=Absent from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It "Should return True the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Specified Counter is present, but should not be" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + Ensure = 'Absent' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $httpThrottleSettings = @{} + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name RemovePerformanceMonitor -Value { + } -PassThru + $httpThrottleSettings = $httpThrottleSettings | Add-Member -MemberType ScriptMethod -Name Update -Value { + $Global:SPDscThrottleSettingsRemoved = $true + } -PassThru + + $webApp = @{ + DisplayName = 'Sites' + HttpThrottleSettings = $httpThrottleSettings + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + } -PassThru + + return @( + @{ + Category = 'Processor' + Counter = '% Processor Time' + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + } + ) + } + + Mock -CommandName Set-SPWebApplicationHttpThrottlingMonitor -MockWith { } + } + + It "Should return Ensure=Present from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return False the test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should remove the counter monitor in the set method" { + $Global:SPDscThrottleSettingsRemoved = $false + Set-TargetResource @testParams + $Global:SPDscThrottleSettingsRemoved | Should -Be $true + } + } + + Context -Name "Specified Counter is present and is correctly configured" -Fixture { + BeforeAll { + $testParams = @{ + WebAppUrl = 'http://sites.sharepoint.com' + Category = 'Processor' + Counter = '% Processor Time' + CounterInstance = 0 + HealthScoreBuckets = @(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + IsDescending = $false + Ensure = 'Present' + } + + Mock -CommandName Get-SPWebapplication -MockWith { + $webApp = @{ + DisplayName = 'Sites' + } + return $webApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + $associatedHealthScoreCalculator = @{} + $associatedHealthScoreCalculator = $associatedHealthScoreCalculator | Add-Member -MemberType ScriptMethod -Name GetScoreBuckets -Value { + return @(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + } -PassThru + + return @( + @{ + Category = 'Processor' + Counter = '% Processor Time' + Instance = 0 + AssociatedHealthScoreCalculator = $associatedHealthScoreCalculator + } + ) + } + + Mock -CommandName Set-SPWebApplicationHttpThrottlingMonitor -MockWith { } + } + + It "Should return Ensure=Present from the get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return True the test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Running ReverseDsc Export" -Fixture { + BeforeAll { + Import-Module (Join-Path -Path (Split-Path -Path (Get-Module SharePointDsc -ListAvailable).Path -Parent) -ChildPath "Modules\SharePointDSC.Reverse\SharePointDSC.Reverse.psm1") + + Mock -CommandName Write-Host -MockWith { } + + Mock -CommandName Get-TargetResource -MockWith { + return @{ + WebAppUrl = "http://example.contoso.local" + Category = 'Processor' + Counter = '% Processor Time' + HealthScoreBuckets = @(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) + IsDescending = $true + Ensure = 'Present' + } + } + + Mock -CommandName Get-SPWebApplication -MockWith { + $spWebApp = [PSCustomObject]@{ + Url = "http://example.contoso.local" + } + return $spWebApp + } + + Mock -CommandName Get-SPWebApplicationHttpThrottlingMonitor -MockWith { + return @( + @{ + Category = 'Processor' + Counter = '% Processor Time' + } + ) + } + + if ($null -eq (Get-Variable -Name 'spFarmAccount' -ErrorAction SilentlyContinue)) + { + $mockPassword = ConvertTo-SecureString -String "password" -AsPlainText -Force + $Global:spFarmAccount = New-Object -TypeName System.Management.Automation.PSCredential ("contoso\spfarm", $mockPassword) + } + + $result = @' + SPWebAppHttpThrottlingMonitor [0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12} + { + Category = "Processor"; + Counter = "% Processor Time"; + Ensure = "Present"; + HealthScoreBuckets = @\(10987654321\); + IsDescending = \$True; + PsDscRunAsCredential = \$Credsspfarm; + WebAppUrl = "http://example.contoso.local"; + } + +'@ + } + + It "Should return valid DSC block from the Export method" { + Export-TargetResource | Should -Match $result + } + } + } + } +} +finally +{ + Invoke-TestCleanup +}