diff --git a/DSCClassResources/SBAuthorizationRule/SBAuthorizationRule.psd1 b/DSCClassResources/SBAuthorizationRule/SBAuthorizationRule.psd1 index ab3ef35..3062336 100644 --- a/DSCClassResources/SBAuthorizationRule/SBAuthorizationRule.psd1 +++ b/DSCClassResources/SBAuthorizationRule/SBAuthorizationRule.psd1 @@ -58,7 +58,7 @@ PowerShellVersion = '5.0' # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psd1' ) +NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psm1' ) # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. # FunctionsToExport = @() diff --git a/DSCClassResources/SBFarm/SBFarm.psd1 b/DSCClassResources/SBFarm/SBFarm.psd1 index 6b90256..e5ccf3a 100644 --- a/DSCClassResources/SBFarm/SBFarm.psd1 +++ b/DSCClassResources/SBFarm/SBFarm.psd1 @@ -58,7 +58,7 @@ PowerShellVersion = '5.0' # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psd1' ) +NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psm1' ) # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. # FunctionsToExport = @() diff --git a/DSCClassResources/SBFarm/SBFarm.psm1 b/DSCClassResources/SBFarm/SBFarm.psm1 index 625c6ae..e0bcf40 100644 --- a/DSCClassResources/SBFarm/SBFarm.psm1 +++ b/DSCClassResources/SBFarm/SBFarm.psm1 @@ -1,4 +1,5 @@ using module ..\SBBase +Using module ..\..\Modules\SB.Util\SB.Util.psd1 <# SBFarm creates a new farm and sets certain settings for a Service Bus for Windows Server farm. @@ -413,17 +414,21 @@ class SBFarm : SBBase $result.GatewayDBConnectionString = $sbFarm.GatewayDBConnectionString $result.GatewayDBConnectionStringCredential = $this.GatewayDBConnectionStringCredential - $params = @{ - SqlConnectionString = $sbFarm.GatewayDBConnectionString + + if([string]::IsNullOrEmpty($sbFarm.GatewayDBConnectionString) -eq $false) + { + $params = @{ + SqlConnectionString = $sbFarm.GatewayDBConnectionString + } + $params.PropertyName = "Data Source" + $result.GatewayDBConnectionStringDataSource = [string](Get-SqlConnectionStringPropertyValue @params) + $params.PropertyName = "Encrypt" + $result.GatewayDBConnectionStringEncrypt = [bool](Get-SqlConnectionStringPropertyValue @params) + $params.PropertyName = "Initial Catalog" + $result.GatewayDBConnectionStringInitialCatalog = [string](Get-SqlConnectionStringPropertyValue @params) + $params.PropertyName = "Integrated Security" + $result.GatewayDBConnectionStringIntegratedSecurity = [string](Get-SqlConnectionStringPropertyValue @params) } - $params.PropertyName = "Data Source" - $result.GatewayDBConnectionStringDataSource = [string](Get-SqlConnectionStringPropertyValue @params) - $params.PropertyName = "Encrypt" - $result.GatewayDBConnectionStringEncrypt = [bool](Get-SqlConnectionStringPropertyValue @params) - $params.PropertyName = "Initial Catalog" - $result.GatewayDBConnectionStringInitialCatalog = [string](Get-SqlConnectionStringPropertyValue @params) - $params.PropertyName = "Integrated Security" - $result.GatewayDBConnectionStringIntegratedSecurity = [string](Get-SqlConnectionStringPropertyValue @params) $result.HttpsPort = $sbFarm.HttpsPort $result.InternalPortRangeStart = $sbFarm.ClusterConnectionEndpointPort @@ -494,8 +499,29 @@ class SBFarm : SBBase $currentValuesHt = $currentValues.ToHashtable() $desiredValuesHt = $this.ToHashtable() - $desiredValuesHt.AdminApiUserName = $desiredValuesHt.AdminApiCredentials.UserName - $desiredValuesHt.TenantApiUserName = $desiredValuesHt.TenantApiCredentials.UserName + + if([string]::IsNullOrEmpty($desiredValuesHt.FarmDNS)) + { + $desiredValuesHt.FarmDNS = "" + } + + if([string]::IsNullOrEmpty($desiredValuesHt.AdminApiCredentials.UserName)) + { + $desiredValuesHt.AdminApiUserName = "" + } + else + { + $desiredValuesHt.AdminApiUserName = $desiredValuesHt.AdminApiCredentials.UserName + } + + if([string]::IsNullOrEmpty($desiredValuesHt.TenantApiCredentials.UserName)) + { + $desiredValuesHt.TenantApiUserName = "" + } + else + { + $desiredValuesHt.TenantApiUserName = $desiredValuesHt.TenantApiCredentials.UserName + } $params = @{ CurrentValues = $currentValuesHt @@ -559,20 +585,21 @@ class SBFarm : SBBase if ($null -ne $CertificateThumbprint) { $newSBFarmParams.FarmCertificateThumbprint = $CertificateThumbprint - + if ($null -eq $this.EncryptionCertificateThumbprint) { $newSBFarmParams.EncryptionCertificateThumbprint = $CertificateThumbprint } } } - + } else { Write-Verbose -Message "CertificateAutoGenerationKey is present, swapping pscredential for securestring" $newSBFarmParams.Remove("CertificateAutoGenerationKey") $newSBFarmParams.Remove("FarmCertificateThumbprint") + $newSBFarmParams.Remove("EncryptionCertificateThumbprint") $newSBFarmParams.CertificateAutoGenerationKey = $this.CertificateAutoGenerationKey.Password } @@ -657,7 +684,7 @@ class SBFarm : SBBase $newSBFarmParams.Remove("SBFarmDBConnectionStringIntegratedSecurity") $newSBFarmParams.Remove("SBFarmDBConnectionStringCredential") $newSBFarmParams.Remove("SBFarmDBConnectionStringEncrypt") - + Write-Verbose -Message "Removing FarmCertificateSubject regardless of if it was used" $newSBFarmParams.Remove("FarmCertificateSubject") diff --git a/DSCClassResources/SBHost/SBHost.psd1 b/DSCClassResources/SBHost/SBHost.psd1 index 6f5e6f2..c089831 100644 --- a/DSCClassResources/SBHost/SBHost.psd1 +++ b/DSCClassResources/SBHost/SBHost.psd1 @@ -58,7 +58,7 @@ PowerShellVersion = '5.0' # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psd1' ) +NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psm1' ) # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. # FunctionsToExport = @() diff --git a/DSCClassResources/SBHost/SBHost.psm1 b/DSCClassResources/SBHost/SBHost.psm1 index 70525cb..1b8b01a 100644 --- a/DSCClassResources/SBHost/SBHost.psm1 +++ b/DSCClassResources/SBHost/SBHost.psm1 @@ -1,4 +1,5 @@ using module ..\SBBase +Using module ..\..\Modules\SB.Util\SB.Util.psd1 <# SBHost adds and removes a host from a farm, and starts, stops and updates settings for a Service Bus for diff --git a/DSCClassResources/SBMessageContainer/SBMessageContainer.psd1 b/DSCClassResources/SBMessageContainer/SBMessageContainer.psd1 index fb44569..a21c87d 100644 --- a/DSCClassResources/SBMessageContainer/SBMessageContainer.psd1 +++ b/DSCClassResources/SBMessageContainer/SBMessageContainer.psd1 @@ -58,7 +58,7 @@ PowerShellVersion = '5.0' # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psd1' ) +NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psm1' ) # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. # FunctionsToExport = @() diff --git a/DSCClassResources/SBNamespace/SBNamespace.psd1 b/DSCClassResources/SBNamespace/SBNamespace.psd1 index dd65c2c..2ecda7d 100644 --- a/DSCClassResources/SBNamespace/SBNamespace.psd1 +++ b/DSCClassResources/SBNamespace/SBNamespace.psd1 @@ -58,7 +58,7 @@ PowerShellVersion = '5.0' # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psd1' ) +NestedModules = @( '..\..\Modules\SB.Util\SB.Util.psm1' ) # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. # FunctionsToExport = @() diff --git a/DSCClassResources/SBNamespace/SBNamespace.psm1 b/DSCClassResources/SBNamespace/SBNamespace.psm1 index d78790c..5af8f68 100644 --- a/DSCClassResources/SBNamespace/SBNamespace.psm1 +++ b/DSCClassResources/SBNamespace/SBNamespace.psm1 @@ -1,10 +1,11 @@ using module ..\SBBase +Using module ..\..\Modules\SB.Util\SB.Util.psd1 <# SBNamespace adds, removes and updates settings for a Service Bus for Windows Server namespace. #> [DscResource()] -class SBNameSpace : SBBase +class SBNamespace : SBBase { <# @@ -175,17 +176,17 @@ class SBNameSpace : SBBase return $true } - [bool] SBNamespaceShouldBeCreated([SBNameSpace] $CurrentValues) + [bool] SBNamespaceShouldBeCreated([SBNamespace] $CurrentValues) { return (($this.Ensure -eq [Ensure]::Present) -and ($CurrentValues.Ensure -eq [Ensure]::Absent)) } - [bool] SBNamespaceShouldBeRemoved([SBNameSpace] $CurrentValues) + [bool] SBNamespaceShouldBeRemoved([SBNamespace] $CurrentValues) { return (($this.Ensure -eq [Ensure]::Absent) -and ($CurrentValues.Ensure -eq [Ensure]::Present)) } - [bool] SBNamespaceShouldBeUpdated([SBNameSpace] $CurrentValues) + [bool] SBNamespaceShouldBeUpdated([SBNamespace] $CurrentValues) { $currentValuesHt = $CurrentValues.ToHashtable() @@ -237,11 +238,18 @@ class SBNameSpace : SBBase $formattedManageUsers = @() $formattedManageUsers = $ManageUsers | ForEach-Object{ - $formatAccountNameParams = @{ - FullAccountNameWithDomain = $_ - Format = 'UserLogonNamePreWindows2000' + if($this.IsLocalGroup($_)) + { + $_.ToLower() + } + else + { + $formatAccountNameParams = @{ + FullAccountNameWithDomain = $_ + Format = 'UserLogonNamePreWindows2000' + } + (Format-AccountName @formatAccountNameParams).ToLower() } - (Format-AccountName @formatAccountNameParams).ToLower() } return $formattedManageUsers @@ -401,4 +409,11 @@ class SBNameSpace : SBBase Write-Verbose -Message "Invoking Set-SBNamespace with configurable params" Set-SBNamespace @setSBNamespaceParams } + + [bool] IsLocalGroup([string] $Name) + { + $cimResult = (Get-CimInstance -class Win32_Group -filter "LocalAccount='True'" | Where-Object { $_.Name -eq $Name }) + + return -not($null -eq $cimResult) + } } diff --git a/Examples/Single Server/ServiceBusForWindowsServer.ps1 b/Examples/Single Server/ServiceBusForWindowsServer.ps1 index 46a19d0..50a1784 100644 --- a/Examples/Single Server/ServiceBusForWindowsServer.ps1 +++ b/Examples/Single Server/ServiceBusForWindowsServer.ps1 @@ -230,7 +230,7 @@ Configuration Example DependsOn = '[SBFarm]ContosoSBFarm' PsDscRunAsCredential = $DomainInstallAccount Ensure = 'Present' - Name = $ConfigurationData.NonNodeData.ServiceBus.SBNameSpaces.ContosoNamespace + Name = $ConfigurationData.NonNodeData.ServiceBus.SBNamespaces.ContosoNamespace ManageUsers = $DomainInstallAccount.UserName } diff --git a/Modules/SB.Util/SB.Util.psm1 b/Modules/SB.Util/SB.Util.psm1 index e8c30d8..ab957ae 100644 --- a/Modules/SB.Util/SB.Util.psm1 +++ b/Modules/SB.Util/SB.Util.psm1 @@ -141,6 +141,11 @@ function Test-SBParameterState() $KeyList | ForEach-Object -Process { if ($_ -ne "Verbose") { + if(($DesiredValues.ContainsKey($_) -eq $true) -and ($CurrentValues.$_ -eq $DesiredValues.$_)) + { + return + } + if (($CurrentValues.ContainsKey($_) -eq $false) ` -or ($CurrentValues.$_ -ne $DesiredValues.$_) ` -or (($DesiredValues.ContainsKey($_) -eq $true) -and ($DesiredValues.$_.GetType().IsArray))) @@ -158,6 +163,12 @@ function Test-SBParameterState() if ($CheckDesiredValue) { + if(($DesiredValues.$_ -eq $null) -and ($CurrentValues.$_ -ne $null)) + { + $returnValue = $false + return + } + $desiredType = $DesiredValues.$_.GetType() $fieldName = $_ if ($desiredType.IsArray -eq $true) @@ -249,6 +260,11 @@ function Test-SBParameterState() } } } + + if($returnValue -eq $false) + { + return + } } } return $returnValue @@ -411,16 +427,19 @@ function Get-SqlConnectionStringPropertyValue ) process { - $params = @{ - TypeName = 'System.Data.SqlClient.SqlConnectionStringBuilder' - ArgumentList = $SqlConnectionString - } - $sqlConnectionStringBuilder = New-Object @params if ($PropertyName -eq 'Integrated Security' -and $SqlConnectionString.Contains('Integrated Security=SSPI')) { return 'SSPI' } + + $params = @{ + TypeName = 'System.Data.SqlClient.SqlConnectionStringBuilder' + ArgumentList = $SqlConnectionString + } + + $sqlConnectionStringBuilder = New-Object @params + return $sqlConnectionStringBuilder[$PropertyName] } } diff --git a/Tests/Unit/SB.Util.Tests.ps1 b/Tests/Unit/SB.Util.Tests.ps1 index d46a3d9..dd32734 100644 --- a/Tests/Unit/SB.Util.Tests.ps1 +++ b/Tests/Unit/SB.Util.Tests.ps1 @@ -74,6 +74,26 @@ try Test-SBParameterState -CurrentValues $current -DesiredValues $desired | Should Be $false } + It "Returns true when values are empty" { + # Arrange + $desired = @{ + Example = "" + } + + # Act | Assert + Test-SBParameterState -CurrentValues $desired -DesiredValues $desired | Should Be $true + } + + It "Returns true when values are null" { + # Arrange + $desired = @{ + Example = $null + } + + # Act | Assert + Test-SBParameterState -CurrentValues $desired -DesiredValues $desired | Should Be $true + } + It "Returns false when a value is missing" { # Arrange $current = @{} @@ -126,6 +146,32 @@ try # Act | Assert Test-SBParameterState -CurrentValues $current -DesiredValues $desired | Should Be $false } + + It "Returns false when current is null and desired is null" { + # Arrange + $current = @{ + Example = $null + } + $desired = @{ + Example = "test" + } + + # Act | Assert + Test-SBParameterState -CurrentValues $current -DesiredValues $desired | Should Be $false + } + + It "Returns false when current is empty string and desired is null" { + # Arrange + $current = @{ + Example = "" + } + $desired = @{ + Example = $null + } + + # Act | Assert + Test-SBParameterState -CurrentValues $current -DesiredValues $desired | Should Be $false + } } Context "Validate ConvertTo-PlainText" { diff --git a/Tests/Unit/SBAuthorizationRule.Tests.ps1 b/Tests/Unit/SBAuthorizationRule.Tests.ps1 index d7620b4..c67bffa 100644 --- a/Tests/Unit/SBAuthorizationRule.Tests.ps1 +++ b/Tests/Unit/SBAuthorizationRule.Tests.ps1 @@ -48,11 +48,12 @@ try $testSBAuthorizationRule.NamespaceName = "TestNamespace" $testSBAuthorizationRule.Ensure = 'Present' - Mock New-SBAuthorizationRule {} - Mock Remove-SBAuthorizationRule {} - Mock Set-SBAuthorizationRule {} - Describe 'SBAuthorizationRule' { + + Mock New-SBAuthorizationRule {} + Mock Remove-SBAuthorizationRule {} + Mock Set-SBAuthorizationRule {} + Context "No authorization rule exists for a given name and namespace and should be created" { # Arrange Mock Get-SBAuthorizationRule { diff --git a/Tests/Unit/SBFarm.Tests.ps1 b/Tests/Unit/SBFarm.Tests.ps1 index 7b73272..54666c6 100644 --- a/Tests/Unit/SBFarm.Tests.ps1 +++ b/Tests/Unit/SBFarm.Tests.ps1 @@ -61,11 +61,12 @@ try } $testSBFarm.TenantApiCredentials = New-Object @tenantApiCredentialParams - Mock New-SBFarm {} - Mock Set-SBFarm {} - Mock Stop-SBFarm {} - Describe 'SBFarm' { + + Mock New-SBFarm {} + Mock Set-SBFarm {} + Mock Stop-SBFarm {} + Context "No farm is found or configured" { #Arrange Mock Get-SBFarm { diff --git a/Tests/Unit/SBHost.Tests.ps1 b/Tests/Unit/SBHost.Tests.ps1 index f311ca8..86ea45d 100644 --- a/Tests/Unit/SBHost.Tests.ps1 +++ b/Tests/Unit/SBHost.Tests.ps1 @@ -59,28 +59,30 @@ try $testSBHost.SBFarmDBConnectionStringDataSource = "SQLSERVER.contoso.com" $testSBHost.Started = $true - Mock Add-SBHost {} - Mock Remove-SBHost {} - Mock Start-SBHost {} - Mock Stop-SBHost {} - Mock Update-SBHost {} - Mock Get-CimInstance { - [CmdletBinding()] - param - ( - [Parameter(Mandatory)] - [string] - $ClassName - ) - return @{ - Domain = 'contoso.com' - } - } $env:COMPUTERNAME = "servicebus03" $hostName = "$env:COMPUTERNAME.$((Get-CimInstance -ClassName WIN32_ComputerSystem).Domain)" Describe 'SBHost' { + + Mock Add-SBHost {} + Mock Remove-SBHost {} + Mock Start-SBHost {} + Mock Stop-SBHost {} + Mock Update-SBHost {} + Mock Get-CimInstance { + [CmdletBinding()] + param + ( + [Parameter(Mandatory)] + [string] + $ClassName + ) + return @{ + Domain = 'contoso.com' + } + } + Context "Current host is not joined to farm and should be joined and started" { #Arrange Mock Get-SBFarm { diff --git a/Tests/Unit/SBHostCEIP.Tests.ps1 b/Tests/Unit/SBHostCEIP.Tests.ps1 index 5aecbb0..69f6812 100644 --- a/Tests/Unit/SBHostCEIP.Tests.ps1 +++ b/Tests/Unit/SBHostCEIP.Tests.ps1 @@ -65,10 +65,11 @@ try " Prompt you with additional messages that might interrupt your work." ) - Mock Enable-SBHostCEIP {} - Mock Disable-SBHostCEIP {} - Describe 'SBHostCEIP' { + + Mock Enable-SBHostCEIP {} + Mock Disable-SBHostCEIP {} + Context "Customer Experience Improvement Program telemetry is disabled and should be enabled" { # Arrange Mock Get-SBHostCEIP { diff --git a/Tests/Unit/SBMessageContainer.Tests.ps1 b/Tests/Unit/SBMessageContainer.Tests.ps1 index 0771e69..10ce6a1 100644 --- a/Tests/Unit/SBMessageContainer.Tests.ps1 +++ b/Tests/Unit/SBMessageContainer.Tests.ps1 @@ -48,10 +48,11 @@ try $testSBMessageContainer.ContainerDBConnectionStringInitialCatalog = "SBMessageContainer02" $testSBMessageContainer.Ensure = 'Present' - Mock New-SBMessageContainer {} - Mock Remove-SBMessageContainer {} - Describe 'SBMessageContainer' { + + Mock New-SBMessageContainer {} + Mock Remove-SBMessageContainer {} + Context "No container exists for a given database name" { # Arrange Mock Get-SBMessageContainer { diff --git a/Tests/Unit/SBNamespace.Tests.ps1 b/Tests/Unit/SBNamespace.Tests.ps1 index 88743ba..b58ce6c 100644 --- a/Tests/Unit/SBNamespace.Tests.ps1 +++ b/Tests/Unit/SBNamespace.Tests.ps1 @@ -29,7 +29,6 @@ $TestEnvironment = Initialize-TestEnvironment ` function Invoke-TestSetup { $serviceBusCmdletModule = Join-Path -Path $PSScriptRoot -ChildPath "Stubs\ServiceBus\2.0.40512.2\Microsoft.ServiceBus.Commands.psm1" -Resolve Import-Module -Name $serviceBusCmdletModule -Scope 'Global' -Force - Import-Module -Name (Join-Path -Path $moduleRoot -ChildPath "Modules\SB.Util\SB.Util.psm1") -Scope 'Global' -Force } function Invoke-TestCleanup { @@ -55,11 +54,12 @@ try $testSBNamespace.SecondarySymmetricKey = "RvxwTxTctasdf6KzKNfjQzjaV7oc53yUDl08ZUXQrFU=" $testSBNamespace.SubscriptionId = "00000000000000000000000000000000" - Mock New-SBNamespace {} - Mock Set-SBNamespace {} - Mock Remove-SBNamespace {} - Describe 'SBNamespace' { + + Mock New-SBNamespace {} + Mock Set-SBNamespace {} + Mock Remove-SBNamespace {} + Context "No namespace exists for a given name and should be created" { # Arrange Mock Get-SBNamespace { diff --git a/Tests/Unit/SBRuntimeSetting.Tests.ps1 b/Tests/Unit/SBRuntimeSetting.Tests.ps1 index 5a7b9a6..2e758af 100644 --- a/Tests/Unit/SBRuntimeSetting.Tests.ps1 +++ b/Tests/Unit/SBRuntimeSetting.Tests.ps1 @@ -44,11 +44,15 @@ try # Arrange $testSBRuntimeSetting = [SBRuntimeSetting]::new() - Mock Set-SBRuntimeSetting {} - Mock Stop-SBFarm {} - Mock Start-SBFarm {} - Describe 'SBRuntimeSetting' { + + Mock New-SBNamespace {} + Mock Set-SBNamespace {} + Mock Remove-SBNamespace {} + Mock Set-SBRuntimeSetting {} + Mock Start-SBFarm {} + Mock Stop-SBFarm {} + Context "Runtime setting exists and needs to be updated" { # Arrange Mock Get-SBRuntimeSetting { diff --git a/appveyor.yml b/appveyor.yml index 607da38..47331ec 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,19 +1,19 @@ #---------------------------------# # environment configuration # #---------------------------------# -version: 0.10.0.{build} +version: 0.10.1.{build} install: - git clone https://github.com/PowerShell/DscResource.Tests - ps: | Import-Module -Name .\DscResource.Tests\TestHelper.psm1 -Force Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force Install-Module -Name xCertificate -Repository PSGallery -Force - Install-Module -Name Pester -Repository PSGallery -Force + - cinst pester #---------------------------------# # build configuration # #---------------------------------# -image: WMF 5 +image: Visual Studio 2017 build: false #---------------------------------#