diff --git a/CHANGELOG.md b/CHANGELOG.md index e452d6739b..c9f7d15969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * PPTenantSettings * Corrected issue in the resource schema. The description was a multi-line string, which is not allowed. +* SPOSiteScript + * Fix error in Get-TargetResource when a site-script is identified by title only + FIXES [#5821](https://github.com/microsoft/Microsoft365DSC/issues/5821) * TeamsChannel * Apply ordering during export. FIXES [#5829](https://github.com/microsoft/Microsoft365DSC/issues/5829) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SPOSiteScript/MSFT_SPOSiteScript.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SPOSiteScript/MSFT_SPOSiteScript.psm1 index 62042afbe3..2a94760b7c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SPOSiteScript/MSFT_SPOSiteScript.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SPOSiteScript/MSFT_SPOSiteScript.psm1 @@ -89,21 +89,19 @@ function Get-TargetResource # if ([System.String]::IsNullOrEmpty($Identity)) { - [Array]$SiteScripts = Get-PnPSiteScript -ErrorAction Stop | Where-Object -FilterScript { $_.Title -eq $Title } - - $SiteScript = $null - ##### Check to see if more than one site script is returned - if ($SiteScripts.Length -gt -1) - { - $SiteScript = Get-PnPSiteScript -Identity $SiteScripts[0].Id -ErrorAction Stop - } + $SiteScript = Get-PnPSiteScript -ErrorAction Stop | Where-Object -FilterScript { $_.Title -eq $Title } | Select-Object -First 1 # No script was returned - if ($null -eq $SiteScripts) + if ($null -eq $SiteScript) { Write-Verbose -Message "No Site Script with the Title, {$Title}, was found." return $nullReturn } + else + { + # get site script *with* content + $SiteScript = Get-PnPSiteScript -Identity $SiteScript.Id + } } else { @@ -222,10 +220,7 @@ function Set-TargetResource # region Telemetry $CurrentValues = Get-TargetResource @PSBoundParameters - $CurrentParameters = $PSBoundParameters - $CurrentParameters.Remove('Ensure') | Out-Null - $CurrentParameters.Remove('Credential') | Out-Null - $CurrentParameters.Remove('ApplicationSecret') | Out-Null + $CurrentParameters = Remove-M365DSCAuthenticationParameter $PSBoundParameters # end region if ($Ensure -eq 'Present' -and $CurrentValues.Ensure -eq 'Absent') @@ -267,12 +262,12 @@ function Set-TargetResource try { # The Site Script exists and it shouldn't - [Array]$SiteScripts = Get-PnPSiteScript | Where-Object -FilterScript { $_.Title -eq $Title } -ErrorAction SilentlyContinue + [Array]$SiteScript = Get-PnPSiteScript | Where-Object -FilterScript { $_.Title -eq $Title } -ErrorAction SilentlyContinue ##### Check to see if more than one site script is returned - if ($SiteScripts.Length -gt 0) + if ($SiteScript.Count -gt 1) { - $SiteScript = Get-PnPSiteScript -Identity $SiteScripts[0].Id + $SiteScript = Get-PnPSiteScript -Identity $SiteScript[0].Id } ##### End of Check } @@ -287,6 +282,16 @@ function Set-TargetResource throw $Message } } + try { + Remove-PnPSiteScript -Identity $sitescript.Id -Force -ErrorAction Stop + } + catch { + New-M365DSCLogEntry -Message 'Error removing Site Script:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } if ($Ensure -ne 'Absent') { @@ -298,12 +303,12 @@ function Set-TargetResource [Array]$SiteScripts = Get-PnPSiteScript | Where-Object -FilterScript { $_.Title -eq $Title } -ErrorAction SilentlyContinue ##### Check to see if more than one site script is returned - if ($SiteScripts.Length -gt 0) + if ($SiteScripts.Count -gt 0) { # #the only way to get the $content is to query the site again, but this time with the ID and not the Title like above $UpdateParams = @{ - Id = $SiteScripts[0].Id + Identity = $SiteScripts[0].Id Title = $Title Content = $Content Description = $Description @@ -319,7 +324,11 @@ function Set-TargetResource } catch { - Write-Warning -Message "Unable to update Site Script, {$Title}" + New-M365DSCLogEntry -Message 'Error updating Site Script:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential } } } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SPOSiteScript.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SPOSiteScript.Tests.ps1 index 382afd0761..fdb90d6e71 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SPOSiteScript.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SPOSiteScript.Tests.ps1 @@ -55,6 +55,12 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + Mock -CommandName Set-PnPSiteScript -MockWith { + } + + Mock -CommandName Remove-PnPSiteScript -MockWith { + } + Mock -CommandName Start-Sleep -MockWith { } @@ -81,13 +87,23 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Add-PnPSiteScript -MockWith { return @{ - Name = $null + Id = '12345-67890-abcde-f0123' } } - Mock -CommandName Get-PnPSiteScript -MockWith { + # calls to Get-PnPSiteScript without proper Identity returns nothing + Mock -CommandName Get-PnPSiteScript -ParameterFilter {Identity -ne '12345-67890-abcde-f0123'} -MockWith { return $null } + # after Add-PnPSiteScript has been called, Get-PnPSiteScript should return the created site-script + Mock -CommandName Get-PnPSiteScript -ParameterFilter {Identity -eq '12345-67890-abcde-f0123'} -MockWith { + return @{ + Id = '12345-67890-abcde-f0123' + Title = 'Title One' + Content = $script + Description = "This is the description for the Site Script: 'Test Title'" + } + } } It 'Should return absent from the Get method' { @@ -100,10 +116,11 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Creates the site script in the Set method' { Set-TargetResource @testParams + Should -Invoke -CommandName Add-PnPSiteScript -Exactly -Times 1 } } - Context -Name 'The site script already exist but is not in the desired state' -Fixture { + Context -Name 'The site script already exist and is in the desired state' -Fixture { BeforeAll { $testParams = @{ Identity = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' @@ -116,22 +133,81 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-PnPSiteScript -MockWith { return @{ - Title = 'Title One' + Id = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' + Title = 'Title One' + Content = $script + Description = "This is the description for the Site Script: 'Test Title'" } } + } + + It 'Should return present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'The site script already exist but is not in the desired state' -Fixture { + BeforeAll { + $testParams = @{ + Identity = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' + Title = 'Title One' + Content = $script + Description = "This is the description for the Site Script: 'Test Title'" + Credential = $Credential + Ensure = 'Present' + } - Mock -CommandName Get-PnPTenantTheme -MockWith { + Mock -CommandName Get-PnPSiteScript -MockWith { return @{ - Identity = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' - Title = 'Title Two' - Content = $script - Description = "This is the description for the Site Script: 'Test Title'" + Id = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' + Title = 'Title One' + Description = "wrong description" } } } - It 'Should update the Theme from the Set method' { + It 'Should return present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should update the site script from the Set method' { Set-TargetResource @testParams + Should -Invoke -CommandName Set-PnPSiteScript -Exactly -Times 1 + } + } + + Context -Name 'The site script identified by Title already exist but is not in the desired state' -Fixture { + BeforeAll { + $testParams = @{ + Title = 'Title One' + Content = $script + Description = "This is the description for the Site Script: 'Test Title'" + Credential = $Credential + Ensure = 'Present' + } + + Mock -CommandName Get-PnPSiteScript -MockWith { + return @( + @{ + Identity = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' + Title = 'Title One' + Description = "This is the first sitescript with title 'Title One'" + }, + @{ + Identity = '01234567-890a-bcde-f094-e8df5f9aa202' + Title = 'Title One' + Description = "This is another sitescript with the same title" + } + ) + } } It 'Should return present from the Get method' { @@ -141,9 +217,14 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Should return false from the Test method' { Test-TargetResource @testParams | Should -Be $false } + + It 'Should update the site script from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Set-PnPSiteScript -Exactly -Times 1 + } } - Context -Name 'Testing theme removal' -Fixture { + Context -Name 'Testing site script removal' -Fixture { BeforeAll { $testParams = @{ Identity = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' @@ -151,25 +232,30 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Content = $script Description = "This is the description for the Site Script: 'Test Title'" Credential = $Credential - Ensure = 'Present' + Ensure = 'Absent' } - Mock -CommandName Get-PnPTenantTheme -MockWith { + Mock -CommandName Get-PnPSiteScript -MockWith { return @{ - Identity = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' - Title = 'Title Two' + Id = '6c42cc50-7f90-45c2-9094-e8df5f9aa202' + Title = 'Title One' Content = $script Description = "This is the description for the Site Script: 'Test Title'" } } + } - Mock -CommandName Remove-PnPTenantTheme -MockWith { - return 'Theme has been successfully removed' - } + It 'Should return present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' } - It 'Should remove the Theme successfully' { + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should remove the site script successfully' { Set-TargetResource @testParams + Should -Invoke -CommandName Remove-PnPSiteScript -Exactly -Times 1 } } @@ -187,41 +273,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Title = 'Test' } } - - Mock -CommandName Get-PnPTenantTheme -MockWith { - return @{ - Name = 'TestTheme' - IsInverted = $false - Palette = @{ - 'themePrimary' = '#0078d4' - 'themeLighterAlt' = '#eff6fc' - 'themeLighter' = '#deecf9' - 'themeLight' = '#c7e0f4' - 'themeTertiary' = '#71afe5' - 'themeSecondary' = '#2b88d8' - 'themeDarkAlt' = '#106ebe' - 'themeDark' = '#005a9e' - 'themeDarker' = '#004578' - 'neutralLighterAlt' = '#f8f8f8' - 'neutralLighter' = '#f4f4f4' - 'neutralLight' = '#eaeaea' - 'neutralQuaternaryAlt' = '#dadada' - 'neutralQuaternary' = '#d0d0d0' - 'neutralTertiaryAlt' = '#c8c8c8' - 'neutralTertiary' = '#c2c2c2' - 'neutralSecondary' = '#858585' - 'neutralPrimaryAlt' = '#4b4b4b' - 'neutralPrimary' = '#333' - 'neutralDark' = '#272727' - 'black' = '#1d1d1d' - 'white' = '#fff' - 'bodyBackground' = '#0078d4' - 'bodyText' = '#fff' - } - Credential = $Credential - Ensure = 'Present' - } - } } It 'Should Reverse Engineer resource from the Export method' { diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 94492080d2..8748448aed 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -82181,6 +82181,23 @@ function Remove-PnPSiteDesign $Force ) } +function Remove-PnpSiteScript +{ + [CmdletBinding()] + param( + [Parameter()] + [PSObject] + $Identity, + + [Parameter()] + [PSObject] + $Connection, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Force + ) +} function Remove-PnPStorageEntity { [CmdletBinding()]