From 60f996144fd2d861635b71d856213e099a51c65e Mon Sep 17 00:00:00 2001 From: Daniel Hughes <2237515+dan-hughes@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:59:57 +0100 Subject: [PATCH] `Tests` - Migrate to Pester 5 (#144) --- .gitignore | 7 - .vscode/analyzersettings.psd1 | 148 +- .vscode/settings.json | 28 +- CHANGELOG.md | 1 + GitVersion.yml | 5 +- RequiredModules.psd1 | 43 +- Resolve-Dependency.ps1 | 1086 ++++++++-- Resolve-Dependency.psd1 | 10 + build.ps1 | 493 +++-- build.yaml | 190 +- source/ActiveDirectoryCSDsc.psd1 | 10 +- .../DSC_AdcsAuthorityInformationAccess.psm1 | 2 - .../DSC_AdcsCertificationAuthority.psm1 | 2 - ...SC_AdcsCertificationAuthoritySettings.psm1 | 4 +- .../DSC_AdcsEnrollmentPolicyWebService.psm1 | 2 - .../DSC_AdcsOnlineResponder.psm1 | 2 - .../DSC_AdcsTemplate/DSC_AdcsTemplate.psm1 | 2 - .../DSC_AdcsWebEnrollment.psm1 | 2 - .../ActiveDirectoryCSDsc.Common.psm1 | 14 +- .../en-US/ActiveDirectoryCSDsc.strings.psd1 | 10 + source/prefix.ps1 | 10 + ...rtificationAuthority.Integration.Tests.ps1 | 393 ++-- ...mentPolicyWebService.Integration.Tests.ps1 | 284 +-- tests/TestHelpers/AdcsStub.psm1 | 95 - tests/TestHelpers/CommonTestHelper.psm1 | 8 - .../ActiveDirectoryCSDsc.Common.Tests.ps1 | 128 +- ...C_AdcsAuthorityInformationAccess.Tests.ps1 | 1786 ++++++++++------- .../DSC_AdcsCertificationAuthority.Tests.ps1 | 711 ++++--- ...csCertificationAuthoritySettings.Tests.ps1 | 852 ++++---- ...C_AdcsEnrollmentPolicyWebService.Tests.ps1 | 871 ++++---- tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1 | 530 ++--- tests/Unit/DSC_AdcsTemplate.Tests.ps1 | 458 +++-- tests/Unit/DSC_AdcsWebEnrollment.Tests.ps1 | 535 ++--- tests/Unit/Stubs/AdcsAdministrationStub.psm1 | 529 +++++ tests/Unit/Stubs/AdcsDeploymentStub.psm1 | 626 ++++++ 35 files changed, 6455 insertions(+), 3422 deletions(-) create mode 100644 source/en-US/ActiveDirectoryCSDsc.strings.psd1 create mode 100644 source/prefix.ps1 delete mode 100644 tests/TestHelpers/AdcsStub.psm1 create mode 100644 tests/Unit/Stubs/AdcsAdministrationStub.psm1 create mode 100644 tests/Unit/Stubs/AdcsDeploymentStub.psm1 diff --git a/.gitignore b/.gitignore index e19cdf5..ff2de5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,3 @@ -*.suo -*.user -*.coverage .vs .vscode -.psproj -.sln -markdownissues.txt -TestResults.xml output/ diff --git a/.vscode/analyzersettings.psd1 b/.vscode/analyzersettings.psd1 index 89b0b86..d925a62 100644 --- a/.vscode/analyzersettings.psd1 +++ b/.vscode/analyzersettings.psd1 @@ -1,43 +1,115 @@ @{ - CustomRulePath = '.\output\RequiredModules\DscResource.AnalyzerRules' - includeDefaultRules = $true - IncludeRules = @( - # DSC Resource Kit style guideline rules. - 'PSAvoidDefaultValueForMandatoryParameter', - 'PSAvoidDefaultValueSwitchParameter', - 'PSAvoidInvokingEmptyMembers', - 'PSAvoidNullOrEmptyHelpMessageAttribute', - 'PSAvoidUsingCmdletAliases', - 'PSAvoidUsingComputerNameHardcoded', - 'PSAvoidUsingDeprecatedManifestFields', - 'PSAvoidUsingEmptyCatchBlock', - 'PSAvoidUsingInvokeExpression', - 'PSAvoidUsingPositionalParameters', - 'PSAvoidShouldContinueWithoutForce', - 'PSAvoidUsingWMICmdlet', - 'PSAvoidUsingWriteHost', - 'PSDSCReturnCorrectTypesForDSCFunctions', - 'PSDSCStandardDSCFunctionsInResource', - 'PSDSCUseIdenticalMandatoryParametersForDSC', - 'PSDSCUseIdenticalParametersForDSC', - 'PSMisleadingBacktick', - 'PSMissingModuleManifestField', - 'PSPossibleIncorrectComparisonWithNull', - 'PSProvideCommentHelp', - 'PSReservedCmdletChar', - 'PSReservedParams', - 'PSUseApprovedVerbs', - 'PSUseCmdletCorrectly', - 'PSUseOutputTypeCorrectly', - 'PSAvoidGlobalVars', - 'PSAvoidUsingConvertToSecureStringWithPlainText', - 'PSAvoidUsingPlainTextForPassword', - 'PSAvoidUsingUsernameAndPasswordParams', - 'PSDSCUseVerboseMessageInDSCResource', - 'PSShouldProcess', - 'PSUseDeclaredVarsMoreThanAssignments', - 'PSUsePSCredentialType', + CustomRulePath = @( + './output/RequiredModules/DscResource.AnalyzerRules' + './output/RequiredModules/Indented.ScriptAnalyzerRules' + ) + IncludeDefaultRules = $true + IncludeRules = @( + # DSC Community style guideline rules from the module ScriptAnalyzer. + 'PSAvoidDefaultValueForMandatoryParameter' + 'PSAvoidDefaultValueSwitchParameter' + 'PSAvoidInvokingEmptyMembers' + 'PSAvoidNullOrEmptyHelpMessageAttribute' + 'PSAvoidUsingCmdletAliases' + 'PSAvoidUsingComputerNameHardcoded' + 'PSAvoidUsingDeprecatedManifestFields' + 'PSAvoidUsingEmptyCatchBlock' + 'PSAvoidUsingInvokeExpression' + 'PSAvoidUsingPositionalParameters' + 'PSAvoidShouldContinueWithoutForce' + 'PSAvoidUsingWMICmdlet' + 'PSAvoidUsingWriteHost' + 'PSDSCReturnCorrectTypesForDSCFunctions' + 'PSDSCStandardDSCFunctionsInResource' + 'PSDSCUseIdenticalMandatoryParametersForDSC' + 'PSDSCUseIdenticalParametersForDSC' + 'PSMisleadingBacktick' + 'PSMissingModuleManifestField' + 'PSPossibleIncorrectComparisonWithNull' + 'PSProvideCommentHelp' + 'PSReservedCmdletChar' + 'PSReservedParams' + 'PSUseApprovedVerbs' + 'PSUseCmdletCorrectly' + 'PSUseOutputTypeCorrectly' + 'PSAvoidGlobalVars' + 'PSAvoidUsingConvertToSecureStringWithPlainText' + 'PSAvoidUsingPlainTextForPassword' + 'PSAvoidUsingUsernameAndPasswordParams' + 'PSDSCUseVerboseMessageInDSCResource' + 'PSShouldProcess' + 'PSUseDeclaredVarsMoreThanAssignments' + 'PSUsePSCredentialType' + + # Additional rules from the module ScriptAnalyzer + 'PSUseConsistentWhitespace' + 'UseCorrectCasing' + 'PSPlaceOpenBrace' + 'PSPlaceCloseBrace' + 'AlignAssignmentStatement' + 'AvoidUsingDoubleQuotesForConstantString' + 'UseShouldProcessForStateChangingFunctions' + # Rules from the modules DscResource.AnalyzerRules 'Measure-*' + + # Rules from the module Indented.ScriptAnalyzerRules + 'AvoidCreatingObjectsFromAnEmptyString' + 'AvoidDashCharacters' + 'AvoidEmptyNamedBlocks' + 'AvoidFilter' + 'AvoidHelpMessage' + 'AvoidNestedFunctions' + 'AvoidNewObjectToCreatePSObject' + 'AvoidParameterAttributeDefaultValues' + 'AvoidProcessWithoutPipeline' + 'AvoidSmartQuotes' + 'AvoidThrowOutsideOfTry' + 'AvoidWriteErrorStop' + 'AvoidWriteOutput' + 'UseSyntacticallyCorrectExamples' ) + + <# + The following types are not rules but parse errors reported by PSScriptAnalyzer + so they cannot be ecluded. They need to be filtered out from the result of + Invoke-ScriptAnalyzer. + + TypeNotFound - Because classes in the project cannot be found unless built. + RequiresModuleInvalid - Because 'using module' in prefix.ps1 cannot be resolved as source file. + #> + ExcludeRules = @() + + Rules = @{ + PSUseConsistentWhitespace = @{ + Enable = $true + CheckOpenBrace = $true + CheckInnerBrace = $true + CheckOpenParen = $true + CheckOperator = $false + CheckSeparator = $true + CheckPipe = $true + CheckPipeForRedundantWhitespace = $true + CheckParameter = $false + } + + PSPlaceOpenBrace = @{ + Enable = $true + OnSameLine = $false + NewLineAfter = $true + IgnoreOneLineBlock = $false + } + + PSPlaceCloseBrace = @{ + Enable = $true + NoEmptyLineBefore = $true + IgnoreOneLineBlock = $false + NewLineAfter = $true + } + + PSAlignAssignmentStatement = @{ + Enable = $true + CheckHashtable = $true + } + } } diff --git a/.vscode/settings.json b/.vscode/settings.json index a060627..f8efa40 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,16 +7,22 @@ "powershell.codeFormatting.whitespaceAroundOperator": true, "powershell.codeFormatting.whitespaceAfterSeparator": true, "powershell.codeFormatting.ignoreOneLineBlock": false, - "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationAfterEveryPipeline", + "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline", "powershell.codeFormatting.preset": "Custom", "powershell.codeFormatting.alignPropertyValuePairs": true, + "powershell.codeFormatting.useConstantStrings": true, + "powershell.developer.bundledModulesPath": "${cwd}/output/RequiredModules", + "powershell.scriptAnalysis.settingsPath": "/.vscode/analyzersettings.psd1", + "powershell.scriptAnalysis.enable": true, "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true, "files.insertFinalNewline": true, - "powershell.scriptAnalysis.settingsPath": ".vscode\\analyzersettings.psd1", - "powershell.scriptAnalysis.enable": true, "files.associations": { "*.ps1xml": "xml" }, + "cSpell.dictionaries": [ + "powershell" + ], "cSpell.words": [ "COMPANYNAME", "ICONURI", @@ -32,7 +38,21 @@ "pscmdlet", "steppable" ], + "cSpell.ignorePaths": [ + ".git" + ], "[markdown]": { + "files.trimTrailingWhitespace": true, "files.encoding": "utf8" - } + }, + "powershell.pester.useLegacyCodeLens": false, + "pester.testFilePath": [ + "[tT]ests/[qQ][aA]/*.[tT]ests.[pP][sS]1", + "[tT]ests/[uU]nit/**/*.[tT]ests.[pP][sS]1", + "[tT]ests/[uU]nit/*.[tT]ests.[pP][sS]1" + ], + "pester.runTestsInNewProcess": true, + "pester.pesterModulePath": "./output/RequiredModules/Pester", + "powershell.pester.codeLens": true, + "pester.suppressCodeLensNotice": true, } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d80c82..ee4f0b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Azure pipelines - Remove deprecated images, make the build work - Azure Pipelines - Reverted `PublishCodeCoverageResults` back to v1 to display line level coverage in ADO. - `Tests` - Added tests for catch blocks in `AdcsCertificationAuthority`, `AcdsOnlineResponder`, `AdcsWebEnrollment`. +- `Tests` - Migrate all tests to Pester 5 ## [5.0.0] - 2020-06-20 diff --git a/GitVersion.yml b/GitVersion.yml index e450dcc..628fc97 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,7 +1,7 @@ mode: ContinuousDelivery next-version: 4.1.0 -major-version-bump-message: '\s?(breaking|major|breaking\schange)' -minor-version-bump-message: '\s?(add|feature|minor)' +major-version-bump-message: '(breaking\schange|breaking)\b' +minor-version-bump-message: '(adds?|minor)\b' patch-version-bump-message: '\s?(fix|patch)' no-bump-message: '\+semver:\s?(none|skip)' assembly-informational-format: '{NuGetVersionV2}+Sha.{Sha}.Date.{CommitDate}' @@ -21,6 +21,7 @@ branches: increment: Patch regex: (hot)?fix(es)?[\/-] source-branches: ['master'] + ignore: sha: [] merge-message-formats: {} diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index 6e1bb95..713605e 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -1,15 +1,27 @@ @{ - PSDependOptions = @{ + PSDependOptions = @{ AddToPath = $true Target = 'output\RequiredModules' Parameters = @{ - Repository = '' + Repository = 'PSGallery' + } + } + + InvokeBuild = 'latest' + PSScriptAnalyzer = 'latest' + ConvertToSARIF = 'latest' # cSpell: disable-line + + <# + If preview release of Pester prevents release we should temporary shift + back to stable. + #> + Pester = @{ + Version = 'latest' + Parameters = @{ + AllowPrerelease = $true } } - InvokeBuild = 'latest' - PSScriptAnalyzer = 'latest' - Pester = '4.10.1' Plaster = 'latest' ModuleBuilder = 'latest' ChangelogManagement = 'latest' @@ -17,8 +29,23 @@ 'Sampler.GitHubTasks' = 'latest' MarkdownLinkCheck = 'latest' 'DscResource.Test' = 'latest' - 'DscResource.AnalyzerRules' = 'latest' - 'DscResource.DocGenerator' = 'latest' - 'DscResource.Common' = 'latest' xDscResourceDesigner = 'latest' + + # Build dependencies needed for using the module + 'DscResource.Base' = 'latest' + 'DscResource.Common' = 'latest' + + # Analyzer rules + 'DscResource.AnalyzerRules' = 'latest' + 'Indented.ScriptAnalyzerRules' = 'latest' + + # Prerequisite modules for documentation. + #'DscResource.DocGenerator' = 'latest' + 'DscResource.DocGenerator' = @{ + Version = 'latest' + Parameters = @{ + AllowPrerelease = $true + } + } + PlatyPS = 'latest' } diff --git a/Resolve-Dependency.ps1 b/Resolve-Dependency.ps1 index ec909b8..17cc98e 100644 --- a/Resolve-Dependency.ps1 +++ b/Resolve-Dependency.ps1 @@ -1,288 +1,1060 @@ +<# + .DESCRIPTION + Bootstrap script for PSDepend. + + .PARAMETER DependencyFile + Specifies the configuration file for the this script. The default value is + 'RequiredModules.psd1' relative to this script's path. + + .PARAMETER PSDependTarget + Path for PSDepend to be bootstrapped and save other dependencies. + Can also be CurrentUser or AllUsers if you wish to install the modules in + such scope. The default value is 'output/RequiredModules' relative to + this script's path. + + .PARAMETER Proxy + Specifies the URI to use for Proxy when attempting to bootstrap + PackageProvider and PowerShellGet. + + .PARAMETER ProxyCredential + Specifies the credential to contact the Proxy when provided. + + .PARAMETER Scope + Specifies the scope to bootstrap the PackageProvider and PSGet if not available. + THe default value is 'CurrentUser'. + + .PARAMETER Gallery + Specifies the gallery to use when bootstrapping PackageProvider, PSGet and + when calling PSDepend (can be overridden in Dependency files). The default + value is 'PSGallery'. + + .PARAMETER GalleryCredential + Specifies the credentials to use with the Gallery specified above. + + .PARAMETER AllowOldPowerShellGetModule + Allow you to use a locally installed version of PowerShellGet older than + 1.6.0 (not recommended). Default it will install the latest PowerShellGet + if an older version than 2.0 is detected. + + .PARAMETER MinimumPSDependVersion + Allow you to specify a minimum version fo PSDepend, if you're after specific + features. + + .PARAMETER AllowPrerelease + Not yet written. + + .PARAMETER WithYAML + Not yet written. + + .PARAMETER UseModuleFast + Specifies to use ModuleFast instead of PowerShellGet to resolve dependencies + faster. + + .PARAMETER ModuleFastBleedingEdge + Specifies to use ModuleFast code that is in the ModuleFast's main branch + in its GitHub repository. The parameter UseModuleFast must also be set to + true. + + .PARAMETER UsePSResourceGet + Specifies to use the new PSResourceGet module instead of the (now legacy) PowerShellGet module. + + .PARAMETER PSResourceGetVersion + String specifying the module version for PSResourceGet if the `UsePSResourceGet` switch is utilized. + + .NOTES + Load defaults for parameters values from Resolve-Dependency.psd1 if not + provided as parameter. +#> [CmdletBinding()] param ( [Parameter()] - [String] + [System.String] $DependencyFile = 'RequiredModules.psd1', [Parameter()] - [String] - # Path for PSDepend to be bootstrapped and save other dependencies. - # Can also be CurrentUser or AllUsers if you wish to install the modules in such scope - # Default to $PWD.Path/output/modules - $PSDependTarget = (Join-Path $PSScriptRoot './output/RequiredModules'), + [System.String] + $PSDependTarget = (Join-Path -Path $PSScriptRoot -ChildPath 'output/RequiredModules'), [Parameter()] - [uri] - # URI to use for Proxy when attempting to Bootstrap PackageProvider & PowerShellGet + [System.Uri] $Proxy, [Parameter()] - # Credential to contact the Proxy when provided - [PSCredential]$ProxyCredential, + [System.Management.Automation.PSCredential] + $ProxyCredential, [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] - [String] - # Scope to bootstrap the PackageProvider and PSGet if not available + [System.String] $Scope = 'CurrentUser', [Parameter()] - [String] - # Gallery to use when bootstrapping PackageProvider, PSGet and when calling PSDepend (can be overridden in Dependency files) + [System.String] $Gallery = 'PSGallery', [Parameter()] - [PSCredential] - # Credentials to use with the Gallery specified above + [System.Management.Automation.PSCredential] $GalleryCredential, - [Parameter()] - [switch] - # Allow you to use a locally installed version of PowerShellGet older than 1.6.0 (not recommended, default to $false) + [System.Management.Automation.SwitchParameter] $AllowOldPowerShellGetModule, [Parameter()] - [String] - # Allow you to specify a minimum version fo PSDepend, if you're after specific features. + [System.String] $MinimumPSDependVersion, [Parameter()] - [Switch] + [System.Management.Automation.SwitchParameter] $AllowPrerelease, [Parameter()] - [Switch] - $WithYAML + [System.Management.Automation.SwitchParameter] + $WithYAML, + + [Parameter()] + [System.Collections.Hashtable] + $RegisterGallery, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $UseModuleFast, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ModuleFastBleedingEdge, + + [Parameter()] + [System.String] + $ModuleFastVersion, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $UsePSResourceGet, + + [Parameter()] + [System.String] + $PSResourceGetVersion, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $UsePowerShellGetCompatibilityModule, + + [Parameter()] + [System.String] + $UsePowerShellGetCompatibilityModuleVersion ) -# Load Defaults for parameters values from Resolve-Dependency.psd1 if not provided as parameter try { - Write-Verbose -Message "Importing Bootstrap default parameters from '$PSScriptRoot/Resolve-Dependency.psd1'." - $ResolveDependencyDefaults = Import-PowerShellDataFile -Path (Join-Path $PSScriptRoot '.\Resolve-Dependency.psd1' -Resolve -ErrorAction Stop) - $ParameterToDefault = $MyInvocation.MyCommand.ParameterSets.Where{ $_.Name -eq $PSCmdlet.ParameterSetName }.Parameters.Keys - if ($ParameterToDefault.Count -eq 0) + if ($PSVersionTable.PSVersion.Major -le 5) + { + if (-not (Get-Command -Name 'Import-PowerShellDataFile' -ErrorAction 'SilentlyContinue')) + { + Import-Module -Name Microsoft.PowerShell.Utility -RequiredVersion '3.1.0.0' + } + } + + Write-Verbose -Message 'Importing Bootstrap default parameters from ''$PSScriptRoot/Resolve-Dependency.psd1''.' + + $resolveDependencyConfigPath = Join-Path -Path $PSScriptRoot -ChildPath '.\Resolve-Dependency.psd1' -Resolve -ErrorAction 'Stop' + + $resolveDependencyDefaults = Import-PowerShellDataFile -Path $resolveDependencyConfigPath + + $parameterToDefault = $MyInvocation.MyCommand.ParameterSets.Where{ $_.Name -eq $PSCmdlet.ParameterSetName }.Parameters.Keys + + if ($parameterToDefault.Count -eq 0) { - $ParameterToDefault = $MyInvocation.MyCommand.Parameters.Keys + $parameterToDefault = $MyInvocation.MyCommand.Parameters.Keys } - # Set the parameters available in the Parameter Set, or it's not possible to choose yet, so all parameters are an option - foreach ($ParamName in $ParameterToDefault) + + # Set the parameters available in the Parameter Set, or it's not possible to choose yet, so all parameters are an option. + foreach ($parameterName in $parameterToDefault) { - if (-Not $PSBoundParameters.Keys.Contains($ParamName) -and $ResolveDependencyDefaults.ContainsKey($ParamName)) + if (-not $PSBoundParameters.Keys.Contains($parameterName) -and $resolveDependencyDefaults.ContainsKey($parameterName)) { - Write-Verbose -Message "Setting $ParamName with $($ResolveDependencyDefaults[$ParamName])" + Write-Verbose -Message "Setting parameter '$parameterName' to value '$($resolveDependencyDefaults[$parameterName])'." + try { - $variableValue = $ResolveDependencyDefaults[$ParamName] - if ($variableValue -is [string]) + $variableValue = $resolveDependencyDefaults[$parameterName] + + if ($variableValue -is [System.String]) { $variableValue = $ExecutionContext.InvokeCommand.ExpandString($variableValue) } - $PSBoundParameters.Add($ParamName, $variableValue) - Set-Variable -Name $ParamName -value $variableValue -Force -ErrorAction SilentlyContinue + + $PSBoundParameters.Add($parameterName, $variableValue) + + Set-Variable -Name $parameterName -Value $variableValue -Force -ErrorAction 'SilentlyContinue' } catch { - Write-Verbose -Message "Error adding default for $ParamName : $($_.Exception.Message)" + Write-Verbose -Message "Error adding default for $parameterName : $($_.Exception.Message)." } } } } catch { - Write-Warning -Message "Error attempting to import Bootstrap's default parameters from $(Join-Path $PSScriptRoot '.\Resolve-Dependency.psd1'): $($_.Exception.Message)." + Write-Warning -Message "Error attempting to import Bootstrap's default parameters from '$resolveDependencyConfigPath': $($_.Exception.Message)." } -Write-Progress -Activity "Bootstrap:" -PercentComplete 0 -CurrentOperation "NuGet Bootstrap" - -if (!(Get-PackageProvider -Name NuGet -ForceBootstrap -ErrorAction SilentlyContinue)) +# Handle when both ModuleFast and PSResourceGet is configured or/and passed as parameter. +if ($UseModuleFast -and $UsePSResourceGet) { - $providerBootstrapParams = @{ - Name = 'nuget' - force = $true - ForceBootstrap = $true - ErrorAction = 'Stop' + Write-Information -MessageData 'Both ModuleFast and PSResourceGet is configured or/and passed as parameter.' -InformationAction 'Continue' + + if ($PSVersionTable.PSVersion -ge '7.2') + { + $UsePSResourceGet = $false + + Write-Information -MessageData 'PowerShell 7.2 or higher being used, prefer ModuleFast over PSResourceGet.' -InformationAction 'Continue' } + else + { + $UseModuleFast = $false + + Write-Information -MessageData 'Windows PowerShell or PowerShell <=7.1 is being used, prefer PSResourceGet since ModuleFast is not supported on this version of PowerShell.' -InformationAction 'Continue' + } +} - switch ($PSBoundParameters.Keys) +# Only bootstrap ModuleFast if it is not already imported. +if ($UseModuleFast -and -not (Get-Module -Name 'ModuleFast')) +{ + try { - 'Proxy' + $moduleFastBootstrapScriptBlockParameters = @{} + + if ($ModuleFastBleedingEdge) { - $providerBootstrapParams.Add('Proxy', $Proxy) + Write-Information -MessageData 'ModuleFast is configured to use Bleeding Edge (directly from ModuleFast''s main branch).' -InformationAction 'Continue' + + $moduleFastBootstrapScriptBlockParameters.UseMain = $true } - 'ProxyCredential' + elseif($ModuleFastVersion) { - $providerBootstrapParams.Add('ProxyCredential', $ProxyCredential) + if ($ModuleFastVersion -notmatch 'v') + { + $ModuleFastVersion = 'v{0}' -f $ModuleFastVersion + } + + Write-Information -MessageData ('ModuleFast is configured to use version {0}.' -f $ModuleFastVersion) -InformationAction 'Continue' + + $moduleFastBootstrapScriptBlockParameters.Release = $ModuleFastVersion } - 'Scope' + else { - $providerBootstrapParams.Add('Scope', $Scope) + Write-Information -MessageData 'ModuleFast is configured to use latest released version.' -InformationAction 'Continue' } + + $moduleFastBootstrapUri = 'bit.ly/modulefast' # cSpell: disable-line + + Write-Debug -Message ('Using bootstrap script at {0}' -f $moduleFastBootstrapUri) + + $invokeWebRequestParameters = @{ + Uri = $moduleFastBootstrapUri + ErrorAction = 'Stop' + } + + $moduleFastBootstrapScript = Invoke-WebRequest @invokeWebRequestParameters + + $moduleFastBootstrapScriptBlock = [ScriptBlock]::Create($moduleFastBootstrapScript) + + & $moduleFastBootstrapScriptBlock @moduleFastBootstrapScriptBlockParameters } + catch + { + Write-Warning -Message ('ModuleFast could not be bootstrapped. Reverting to PSResourceGet. Error: {0}' -f $_.Exception.Message) + + $UseModuleFast = $false + $UsePSResourceGet = $true + } +} + +if ($UsePSResourceGet) +{ + $psResourceGetModuleName = 'Microsoft.PowerShell.PSResourceGet' - if ($AllowPrerelease) + # If PSResourceGet was used prior it will be locked and we can't replace it. + if ((Test-Path -Path "$PSDependTarget/$psResourceGetModuleName" -PathType 'Container') -and (Get-Module -Name $psResourceGetModuleName)) { - $providerBootstrapParams.Add('AllowPrerelease', $true) + Write-Information -MessageData ('{0} is already bootstrapped and imported into the session. If there is a need to refresh the module, open a new session and resolve dependencies again.' -f $psResourceGetModuleName) -InformationAction 'Continue' } + else + { + Write-Debug -Message ('{0} do not exist, saving the module to RequiredModules.' -f $psResourceGetModuleName) - Write-Information "Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed)" - $null = Install-PackageProvider @providerBootstrapParams - $latestNuGetVersion = (Get-PackageProvider -Name NuGet -ListAvailable | Select-Object -First 1).Version.ToString() - Write-Information "Bootstrap: Importing NuGet Package Provider version $latestNuGetVersion to current session." - $Null = Import-PackageProvider -Name NuGet -RequiredVersion $latestNuGetVersion -Force -} + $psResourceGetDownloaded = $false -Write-Progress -Activity "Bootstrap:" -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" + try + { + if (-not $PSResourceGetVersion) + { + # Default to latest version if no version is passed in parameter or specified in configuration. + $psResourceGetUri = "https://www.powershellgallery.com/api/v2/package/$psResourceGetModuleName" + } + else + { + $psResourceGetUri = "https://www.powershellgallery.com/api/v2/package/$psResourceGetModuleName/$PSResourceGetVersion" + } -# Fail if the given PSGallery is not Registered -$Policy = (Get-PSRepository $Gallery -ErrorAction Stop).InstallationPolicy -Set-PSRepository -Name $Gallery -InstallationPolicy Trusted -ErrorAction Ignore -try + $invokeWebRequestParameters = @{ + # TODO: Should support proxy parameters passed to the script. + Uri = $psResourceGetUri + OutFile = "$PSDependTarget/$psResourceGetModuleName.nupkg" # cSpell: ignore nupkg + ErrorAction = 'Stop' + } + + $previousProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + + # Bootstrapping Microsoft.PowerShell.PSResourceGet. + Invoke-WebRequest @invokeWebRequestParameters + + $ProgressPreference = $previousProgressPreference + + $psResourceGetDownloaded = $true + } + catch + { + Write-Warning -Message ('{0} could not be bootstrapped. Reverting to PowerShellGet. Error: {1}' -f $psResourceGetModuleName, $_.Exception.Message) + } + + $UsePSResourceGet = $false + + if ($psResourceGetDownloaded) + { + # On Windows PowerShell the command Expand-Archive do not like .nupkg as a zip archive extension. + $zipFileName = ((Split-Path -Path $invokeWebRequestParameters.OutFile -Leaf) -replace 'nupkg', 'zip') + + $renameItemParameters = @{ + Path = $invokeWebRequestParameters.OutFile + NewName = $zipFileName + Force = $true + } + + Rename-Item @renameItemParameters + + $psResourceGetZipArchivePath = Join-Path -Path (Split-Path -Path $invokeWebRequestParameters.OutFile -Parent) -ChildPath $zipFileName + + $expandArchiveParameters = @{ + Path = $psResourceGetZipArchivePath + DestinationPath = "$PSDependTarget/$psResourceGetModuleName" + Force = $true + } + + Expand-Archive @expandArchiveParameters + + Remove-Item -Path $psResourceGetZipArchivePath + + Import-Module -Name $expandArchiveParameters.DestinationPath -Force + + # Successfully bootstrapped PSResourceGet, so let's use it. + $UsePSResourceGet = $true + } + } + + if ($UsePSResourceGet) + { + $psResourceGetModule = Get-Module -Name $psResourceGetModuleName + + $psResourceGetModuleVersion = $psResourceGetModule.Version.ToString() + + if ($psResourceGetModule.PrivateData.PSData.Prerelease) + { + $psResourceGetModuleVersion += '-{0}' -f $psResourceGetModule.PrivateData.PSData.Prerelease + } + + Write-Information -MessageData ('Using {0} v{1}.' -f $psResourceGetModuleName, $psResourceGetModuleVersion) -InformationAction 'Continue' + + if ($UsePowerShellGetCompatibilityModule) + { + $savePowerShellGetParameters = @{ + Name = 'PowerShellGet' + Path = $PSDependTarget + Repository = 'PSGallery' + TrustRepository = $true + } + + if ($UsePowerShellGetCompatibilityModuleVersion) + { + $savePowerShellGetParameters.Version = $UsePowerShellGetCompatibilityModuleVersion + + # Check if the version is a prerelease. + if ($UsePowerShellGetCompatibilityModuleVersion -match '\d+\.\d+\.\d+-.*') + { + $savePowerShellGetParameters.Prerelease = $true + } + } + + Save-PSResource @savePowerShellGetParameters + + Import-Module -Name "$PSDependTarget/PowerShellGet" + } + } +} + +# Check if legacy PowerShellGet and PSDepend must be bootstrapped. +if (-not ($UseModuleFast -or $UsePSResourceGet)) { - Write-Progress -Activity "Bootstrap:" -PercentComplete 25 -CurrentOperation "Checking PowerShellGet" - # Ensure the module is loaded and retrieve the version you have - $PowerShellGetVersion = (Import-Module PowerShellGet -PassThru -ErrorAction SilentlyContinue).Version + if ($PSVersionTable.PSVersion.Major -le 5) + { + <# + Making sure the imported PackageManagement module is not from PS7 module + path. The VSCode PS extension is changing the $env:PSModulePath and + prioritize the PS7 path. This is an issue with PowerShellGet because + it loads an old version if available (or fail to load latest). + #> + Get-Module -ListAvailable PackageManagement | + Where-Object -Property 'ModuleBase' -NotMatch 'powershell.7' | + Select-Object -First 1 | + Import-Module -Force + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 0 -CurrentOperation 'NuGet Bootstrap' - Write-Verbose "Bootstrap: The PowerShellGet version is $PowerShellGetVersion" - # Versions below 1.6.0 are considered old, unreliable & not recommended - if (!$PowerShellGetVersion -or ($PowerShellGetVersion -lt [System.version]'1.6.0' -and !$AllowOldPowerShellGetModule)) + $importModuleParameters = @{ + Name = 'PowerShellGet' + MinimumVersion = '2.0' + MaximumVersion = '2.8.999' + ErrorAction = 'SilentlyContinue' + PassThru = $true + } + + if ($AllowOldPowerShellGetModule) { - Write-Progress -Activity "Bootstrap:" -PercentComplete 40 -CurrentOperation "Installing newer version of PowerShellGet" - $InstallPSGetParam = @{ - Name = 'PowerShellGet' - Force = $true - SkipPublisherCheck = $true - AllowClobber = $true - Scope = $Scope - Repository = $Gallery + $importModuleParameters.Remove('MinimumVersion') + } + + $powerShellGetModule = Import-Module @importModuleParameters + + # Install the package provider if it is not available. + $nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable -ErrorAction 'SilentlyContinue' | + Select-Object -First 1 + + if (-not $powerShellGetModule -and -not $nuGetProvider) + { + $providerBootstrapParameters = @{ + Name = 'NuGet' + Force = $true + ForceBootstrap = $true + ErrorAction = 'Stop' + Scope = $Scope } switch ($PSBoundParameters.Keys) { 'Proxy' { - $InstallPSGetParam.Add('Proxy', $Proxy) + $providerBootstrapParameters.Add('Proxy', $Proxy) } + 'ProxyCredential' { - $InstallPSGetParam.Add('ProxyCredential', $ProxyCredential) + $providerBootstrapParameters.Add('ProxyCredential', $ProxyCredential) } - 'GalleryCredential' + + 'AllowPrerelease' { - $InstallPSGetParam.Add('Credential', $GalleryCredential) + $providerBootstrapParameters.Add('AllowPrerelease', $AllowPrerelease) } } - Install-Module @InstallPSGetParam - Remove-Module PowerShellGet -force -ErrorAction SilentlyContinue - Import-Module PowerShellGet -Force - $NewLoadedVersion = (Get-Module PowerShellGet).Version.ToString() - Write-Information "Bootstrap: PowerShellGet version loaded is $NewLoadedVersion" - Write-Progress -Activity "Bootstrap:" -PercentComplete 60 -CurrentOperation "Installing newer version of PowerShellGet" + Write-Information -MessageData 'Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed).' + + $null = Install-PackageProvider @providerBootstrapParameters + + $nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable | Select-Object -First 1 + + $nuGetProviderVersion = $nuGetProvider.Version.ToString() + + Write-Information -MessageData "Bootstrap: Importing NuGet Package Provider version $nuGetProviderVersion to current session." + + $Null = Import-PackageProvider -Name 'NuGet' -RequiredVersion $nuGetProviderVersion -Force } - # Try to import the PSDepend module from the available modules - try + if ($RegisterGallery) { - $ImportPSDependParam = @{ - Name = 'PSDepend' - ErrorAction = 'Stop' - Force = $true + if ($RegisterGallery.ContainsKey('Name') -and -not [System.String]::IsNullOrEmpty($RegisterGallery.Name)) + { + $Gallery = $RegisterGallery.Name + } + else + { + $RegisterGallery.Name = $Gallery } - if ($MinimumPSDependVersion) + Write-Progress -Activity 'Bootstrap:' -PercentComplete 7 -CurrentOperation "Verifying private package repository '$Gallery'" -Completed + + $previousRegisteredRepository = Get-PSRepository -Name $Gallery -ErrorAction 'SilentlyContinue' + + if ($previousRegisteredRepository.SourceLocation -ne $RegisterGallery.SourceLocation) { - $ImportPSDependParam.add('MinimumVersion', $MinimumPSDependVersion) + if ($previousRegisteredRepository) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 9 -CurrentOperation "Re-registrering private package repository '$Gallery'" -Completed + + Unregister-PSRepository -Name $Gallery + + $unregisteredPreviousRepository = $true + } + else + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 9 -CurrentOperation "Registering private package repository '$Gallery'" -Completed + } + + Register-PSRepository @RegisterGallery } - $null = Import-Module @ImportPSDependParam } - catch + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" + + # Fail if the given PSGallery is not registered. + $previousGalleryInstallationPolicy = (Get-PSRepository -Name $Gallery -ErrorAction 'Stop').Trusted + + $updatedGalleryInstallationPolicy = $false + + if ($previousGalleryInstallationPolicy -ne $true) { - # PSDepend module not found, installing or saving it - if ($PSDependTarget -in 'CurrentUser', 'AllUsers') + $updatedGalleryInstallationPolicy = $true + + # Only change policy if the repository is not trusted + Set-PSRepository -Name $Gallery -InstallationPolicy 'Trusted' -ErrorAction 'Ignore' + } +} + +try +{ + # Check if legacy PowerShellGet and PSDepend must be used. + if (-not ($UseModuleFast -or $UsePSResourceGet)) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 25 -CurrentOperation 'Checking PowerShellGet' + + # Ensure the module is loaded and retrieve the version you have. + $powerShellGetVersion = (Import-Module -Name 'PowerShellGet' -PassThru -ErrorAction 'SilentlyContinue').Version + + Write-Verbose -Message "Bootstrap: The PowerShellGet version is $powerShellGetVersion" + + # Versions below 2.0 are considered old, unreliable & not recommended + if (-not $powerShellGetVersion -or ($powerShellGetVersion -lt [System.Version] '2.0' -and -not $AllowOldPowerShellGetModule)) { - Write-Debug "PSDepend module not found. Attempting to install from Gallery $Gallery" - Write-Warning "Installing PSDepend in $PSDependTarget Scope" - $InstallPSDependParam = @{ - Name = 'PSDepend' - Repository = $Gallery - Force = $true - Scope = $PSDependTarget - SkipPublisherCheck = $true - AllowClobber = $true + Write-Progress -Activity 'Bootstrap:' -PercentComplete 40 -CurrentOperation 'Fetching newer version of PowerShellGet' + + # PowerShellGet module not found, installing or saving it. + if ($PSDependTarget -in 'CurrentUser', 'AllUsers') + { + Write-Debug -Message "PowerShellGet module not found. Attempting to install from Gallery $Gallery." + + Write-Warning -Message "Installing PowerShellGet in $PSDependTarget Scope." + + $installPowerShellGetParameters = @{ + Name = 'PowerShellGet' + Force = $true + SkipPublisherCheck = $true + AllowClobber = $true + Scope = $Scope + Repository = $Gallery + MaximumVersion = '2.8.999' + } + + switch ($PSBoundParameters.Keys) + { + 'Proxy' + { + $installPowerShellGetParameters.Add('Proxy', $Proxy) + } + + 'ProxyCredential' + { + $installPowerShellGetParameters.Add('ProxyCredential', $ProxyCredential) + } + + 'GalleryCredential' + { + $installPowerShellGetParameters.Add('Credential', $GalleryCredential) + } + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 60 -CurrentOperation 'Installing newer version of PowerShellGet' + + Install-Module @installPowerShellGetParameters } + else + { + Write-Debug -Message "PowerShellGet module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" + + $saveModuleParameters = @{ + Name = 'PowerShellGet' + Repository = $Gallery + Path = $PSDependTarget + Force = $true + MaximumVersion = '2.8.999' + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 60 -CurrentOperation "Saving PowerShellGet from $Gallery to $Scope" + + Save-Module @saveModuleParameters + } + + Write-Debug -Message 'Removing previous versions of PowerShellGet and PackageManagement from session' + + Get-Module -Name 'PowerShellGet' -All | Remove-Module -Force -ErrorAction 'SilentlyContinue' + Get-Module -Name 'PackageManagement' -All | Remove-Module -Force + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 65 -CurrentOperation 'Loading latest version of PowerShellGet' - if ($MinimumPSDependVersion) + Write-Debug -Message 'Importing latest PowerShellGet and PackageManagement versions into session' + + if ($AllowOldPowerShellGetModule) + { + $powerShellGetModule = Import-Module -Name 'PowerShellGet' -Force -PassThru + } + else { - $InstallPSDependParam.add('MinimumVersion', $MinimumPSDependVersion) + Import-Module -Name 'PackageManagement' -MinimumVersion '1.4.8.1' -Force + + $powerShellGetModule = Import-Module -Name 'PowerShellGet' -MinimumVersion '2.2.5' -Force -PassThru } - Write-Progress -Activity "Bootstrap:" -PercentComplete 75 -CurrentOperation "Installing PSDepend from $Gallery" - Install-Module @InstallPSDependParam + $powerShellGetVersion = $powerShellGetModule.Version.ToString() + + Write-Information -MessageData "Bootstrap: PowerShellGet version loaded is $powerShellGetVersion" } - else + + # Try to import the PSDepend module from the available modules. + $getModuleParameters = @{ + Name = 'PSDepend' + ListAvailable = $true + } + + $psDependModule = Get-Module @getModuleParameters + + if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) { - Write-Debug "PSDepend module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" - $SaveModuleParam = @{ - Name = 'PSDepend' - Repository = $Gallery - Path = $PSDependTarget + try + { + $psDependModule = $psDependModule | Where-Object -FilterScript { $_.Version -ge $MinimumPSDependVersion } + } + catch + { + throw ('There was a problem finding the minimum version of PSDepend. Error: {0}' -f $_) } + } - if ($MinimumPSDependVersion) + if (-not $psDependModule) + { + Write-Debug -Message 'PSDepend module not found.' + + # PSDepend module not found, installing or saving it. + if ($PSDependTarget -in 'CurrentUser', 'AllUsers') { - $SaveModuleParam.add('MinimumVersion', $MinimumPSDependVersion) + Write-Debug -Message "Attempting to install from Gallery '$Gallery'." + + Write-Warning -Message "Installing PSDepend in $PSDependTarget Scope." + + $installPSDependParameters = @{ + Name = 'PSDepend' + Repository = $Gallery + Force = $true + Scope = $PSDependTarget + SkipPublisherCheck = $true + AllowClobber = $true + } + + if ($MinimumPSDependVersion) + { + $installPSDependParameters.Add('MinimumVersion', $MinimumPSDependVersion) + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 75 -CurrentOperation "Installing PSDepend from $Gallery" + + Install-Module @installPSDependParameters + } + else + { + Write-Debug -Message "Attempting to Save from Gallery $Gallery to $PSDependTarget" + + $saveModuleParameters = @{ + Name = 'PSDepend' + Repository = $Gallery + Path = $PSDependTarget + Force = $true + } + + if ($MinimumPSDependVersion) + { + $saveModuleParameters.add('MinimumVersion', $MinimumPSDependVersion) + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 75 -CurrentOperation "Saving PSDepend from $Gallery to $PSDependTarget" + + Save-Module @saveModuleParameters } + } - Write-Progress -Activity "Bootstrap:" -PercentComplete 75 -CurrentOperation "Saving & Importing PSDepend from $Gallery to $Scope" - Save-Module @SaveModuleParam + Write-Progress -Activity 'Bootstrap:' -PercentComplete 80 -CurrentOperation 'Importing PSDepend' + + $importModulePSDependParameters = @{ + Name = 'PSDepend' + ErrorAction = 'Stop' + Force = $true + } + + if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) + { + $importModulePSDependParameters.Add('MinimumVersion', $MinimumPSDependVersion) + } + + # We should have successfully bootstrapped PSDepend. Fail if not available. + $null = Import-Module @importModulePSDependParameters + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 81 -CurrentOperation 'Invoke PSDepend' + + if ($WithYAML) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 82 -CurrentOperation 'Verifying PowerShell module PowerShell-Yaml' + + if (-not (Get-Module -ListAvailable -Name 'PowerShell-Yaml')) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 85 -CurrentOperation 'Installing PowerShell module PowerShell-Yaml' + + Write-Verbose -Message "PowerShell-Yaml module not found. Attempting to Save from Gallery '$Gallery' to '$PSDependTarget'." + + $SaveModuleParam = @{ + Name = 'PowerShell-Yaml' + Repository = $Gallery + Path = $PSDependTarget + Force = $true + } + + Save-Module @SaveModuleParam + } + else + { + Write-Verbose -Message 'PowerShell-Yaml is already available' + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 88 -CurrentOperation 'Importing PowerShell module PowerShell-Yaml' } - } - finally - { - Write-Progress -Activity "Bootstrap:" -PercentComplete 100 -CurrentOperation "Loading PSDepend" - # We should have successfully bootstrapped PSDepend. Fail if not available - Import-Module PSDepend -ErrorAction Stop } - if ($WithYAML) + if (Test-Path -Path $DependencyFile) { - if (-Not (Get-Module -ListAvailable -Name 'PowerShell-Yaml')) + if ($UseModuleFast -or $UsePSResourceGet) { - Write-Verbose "PowerShell-Yaml module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" - $SaveModuleParam = @{ - Name = 'PowerShell-Yaml' - Repository = $Gallery - Path = $PSDependTarget + $requiredModules = Import-PowerShellDataFile -Path $DependencyFile + + $requiredModules = $requiredModules.GetEnumerator() | + Where-Object -FilterScript { $_.Name -ne 'PSDependOptions' } + + if ($UseModuleFast) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 90 -CurrentOperation 'Invoking ModuleFast' + + Write-Progress -Activity 'ModuleFast:' -PercentComplete 0 -CurrentOperation 'Restoring Build Dependencies' + + $modulesToSave = @( + 'PSDepend' # Always include PSDepend for backward compatibility. + ) + + if ($WithYAML) + { + $modulesToSave += 'PowerShell-Yaml' + } + + if ($UsePowerShellGetCompatibilityModule) + { + Write-Debug -Message 'PowerShellGet compatibility module is configured to be used.' + + # This is needed to ensure that the PowerShellGet compatibility module works. + $psResourceGetModuleName = 'Microsoft.PowerShell.PSResourceGet' + + if ($PSResourceGetVersion) + { + $modulesToSave += ('{0}:[{1}]' -f $psResourceGetModuleName, $PSResourceGetVersion) + } + else + { + $modulesToSave += $psResourceGetModuleName + } + + $powerShellGetCompatibilityModuleName = 'PowerShellGet' + + if ($UsePowerShellGetCompatibilityModuleVersion) + { + $modulesToSave += ('{0}:[{1}]' -f $powerShellGetCompatibilityModuleName, $UsePowerShellGetCompatibilityModuleVersion) + } + else + { + $modulesToSave += $powerShellGetCompatibilityModuleName + } + } + + foreach ($requiredModule in $requiredModules) + { + # If the RequiredModules.psd1 entry is an Hashtable then special handling is needed. + if ($requiredModule.Value -is [System.Collections.Hashtable]) + { + if (-not $requiredModule.Value.Version) + { + $requiredModuleVersion = 'latest' + } + else + { + $requiredModuleVersion = $requiredModule.Value.Version + } + + if ($requiredModuleVersion -eq 'latest') + { + $moduleNameSuffix = '' + + if ($requiredModule.Value.Parameters.AllowPrerelease -eq $true) + { + <# + Adding '!' to the module name indicate to ModuleFast + that is should also evaluate pre-releases. + #> + $moduleNameSuffix = '!' + } + + $modulesToSave += ('{0}{1}' -f $requiredModule.Name, $moduleNameSuffix) + } + else + { + $modulesToSave += ('{0}:[{1}]' -f $requiredModule.Name, $requiredModuleVersion) + } + } + else + { + if ($requiredModule.Value -eq 'latest') + { + $modulesToSave += $requiredModule.Name + } + else + { + # Handle different nuget version operators already present. + if ($requiredModule.Value -match '[!|:|[|(|,|>|<|=]') + { + $modulesToSave += ('{0}{1}' -f $requiredModule.Name, $requiredModule.Value) + } + else + { + # Assuming the version is a fixed version. + $modulesToSave += ('{0}:[{1}]' -f $requiredModule.Name, $requiredModule.Value) + } + } + } + } + + Write-Debug -Message ("Required modules to retrieve plan for:`n{0}" -f ($modulesToSave | Out-String)) + + $installModuleFastParameters = @{ + Destination = $PSDependTarget + DestinationOnly = $true + NoPSModulePathUpdate = $true + NoProfileUpdate = $true + Update = $true + Confirm = $false + } + + $moduleFastPlan = Install-ModuleFast -Specification $modulesToSave -Plan @installModuleFastParameters + + Write-Debug -Message ("Missing modules that need to be saved:`n{0}" -f ($moduleFastPlan | Out-String)) + + if ($moduleFastPlan) + { + # Clear all modules in plan from the current session so they can be fetched again. + $moduleFastPlan.Name | Get-Module | Remove-Module -Force + + $moduleFastPlan | Install-ModuleFast @installModuleFastParameters + } + else + { + Write-Verbose -Message 'All required modules were already up to date' + } + + Write-Progress -Activity 'ModuleFast:' -PercentComplete 100 -CurrentOperation 'Dependencies restored' -Completed } - Save-Module @SaveModuleParam - Import-Module "PowerShell-Yaml" -ErrorAction Stop + if ($UsePSResourceGet) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 90 -CurrentOperation 'Invoking PSResourceGet' + + $modulesToSave = @( + @{ + Name = 'PSDepend' # Always include PSDepend for backward compatibility. + } + ) + + if ($WithYAML) + { + $modulesToSave += @{ + Name = 'PowerShell-Yaml' + } + } + + # Prepare hashtable that can be concatenated to the Save-PSResource parameters. + foreach ($requiredModule in $requiredModules) + { + # If the RequiredModules.psd1 entry is an Hashtable then special handling is needed. + if ($requiredModule.Value -is [System.Collections.Hashtable]) + { + $saveModuleHashtable = @{ + Name = $requiredModule.Name + } + + if ($requiredModule.Value.Version -and $requiredModule.Value.Version -ne 'latest') + { + $saveModuleHashtable.Version = $requiredModule.Value.Version + } + + if ($requiredModule.Value.Parameters.AllowPrerelease -eq $true) + { + $saveModuleHashtable.Prerelease = $true + } + + $modulesToSave += $saveModuleHashtable + } + else + { + if ($requiredModule.Value -eq 'latest') + { + $modulesToSave += @{ + Name = $requiredModule.Name + } + } + else + { + $modulesToSave += @{ + Name = $requiredModule.Name + Version = $requiredModule.Value + } + } + } + } + + $percentagePerModule = [System.Math]::Floor(100 / $modulesToSave.Length) + + $progressPercentage = 0 + + Write-Progress -Activity 'PSResourceGet:' -PercentComplete $progressPercentage -CurrentOperation 'Restoring Build Dependencies' + + foreach ($currentModule in $modulesToSave) + { + Write-Progress -Activity 'PSResourceGet:' -PercentComplete $progressPercentage -CurrentOperation 'Restoring Build Dependencies' -Status ('Saving module {0}' -f $savePSResourceParameters.Name) + + $savePSResourceParameters = @{ + Path = $PSDependTarget + TrustRepository = $true + Confirm = $false + } + + # Concatenate the module parameters to the Save-PSResource parameters. + $savePSResourceParameters += $currentModule + + # Modules that Sampler depend on that cannot be refreshed without a new session. + $skipModule = @('PowerShell-Yaml') + + if ($savePSResourceParameters.Name -in $skipModule -and (Get-Module -Name $savePSResourceParameters.Name)) + { + Write-Progress -Activity 'PSResourceGet:' -PercentComplete $progressPercentage -CurrentOperation 'Restoring Build Dependencies' -Status ('Skipping module {0}' -f $savePSResourceParameters.Name) + + Write-Information -MessageData ('Skipping the module {0} since it cannot be refresh while loaded into the session. To refresh the module open a new session and resolve dependencies again.' -f $savePSResourceParameters.Name) -InformationAction 'Continue' + } + else + { + # Clear all module from the current session so any new version fetched will be re-imported. + Get-Module -Name $savePSResourceParameters.Name | Remove-Module -Force + + Save-PSResource @savePSResourceParameters -ErrorVariable 'savePSResourceError' + + if ($savePSResourceError) + { + Write-Warning -Message 'Save-PSResource could not save (replace) one or more dependencies. This can be due to the module is loaded into the session (and referencing assemblies). Close the current session and open a new session and try again.' + } + } + + $progressPercentage += $percentagePerModule + } + + Write-Progress -Activity 'PSResourceGet:' -PercentComplete 100 -CurrentOperation 'Dependencies restored' -Completed + } } else { - Write-Verbose "PowerShell-Yaml is already available" + Write-Progress -Activity 'Bootstrap:' -PercentComplete 90 -CurrentOperation 'Invoking PSDepend' + + Write-Progress -Activity 'PSDepend:' -PercentComplete 0 -CurrentOperation 'Restoring Build Dependencies' + + $psDependParameters = @{ + Force = $true + Path = $DependencyFile + } + + # TODO: Handle when the Dependency file is in YAML, and -WithYAML is specified. + Invoke-PSDepend @psDependParameters + + Write-Progress -Activity 'PSDepend:' -PercentComplete 100 -CurrentOperation 'Dependencies restored' -Completed } } - - Write-Progress -Activity "PSDepend:" -PercentComplete 0 -CurrentOperation "Restoring Build Dependencies" - if (Test-Path $DependencyFile) + else { - $PSDependParams = @{ - Force = $true - Path = $DependencyFile - } - - # TODO: Handle when the Dependency file is in YAML, and -WithYAML is specified - Invoke-PSDepend @PSDependParams + Write-Warning -Message "The dependency file '$DependencyFile' could not be found." } - Write-Progress -Activity "PSDepend:" -PercentComplete 100 -CurrentOperation "Dependencies restored" -Completed + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 100 -CurrentOperation 'Bootstrap complete' -Completed } finally { - # Reverting the Installation Policy for the given gallery - Set-PSRepository -Name $Gallery -InstallationPolicy $Policy - Write-Verbose "Project Bootstrapped, returning to Invoke-Build" + if ($RegisterGallery) + { + Write-Verbose -Message "Removing private package repository '$Gallery'." + Unregister-PSRepository -Name $Gallery + } + + if ($unregisteredPreviousRepository) + { + Write-Verbose -Message "Reverting private package repository '$Gallery' to previous location URI:s." + + $registerPSRepositoryParameters = @{ + Name = $previousRegisteredRepository.Name + InstallationPolicy = $previousRegisteredRepository.InstallationPolicy + } + + if ($previousRegisteredRepository.SourceLocation) + { + $registerPSRepositoryParameters.SourceLocation = $previousRegisteredRepository.SourceLocation + } + + if ($previousRegisteredRepository.PublishLocation) + { + $registerPSRepositoryParameters.PublishLocation = $previousRegisteredRepository.PublishLocation + } + + if ($previousRegisteredRepository.ScriptSourceLocation) + { + $registerPSRepositoryParameters.ScriptSourceLocation = $previousRegisteredRepository.ScriptSourceLocation + } + + if ($previousRegisteredRepository.ScriptPublishLocation) + { + $registerPSRepositoryParameters.ScriptPublishLocation = $previousRegisteredRepository.ScriptPublishLocation + } + + Register-PSRepository @registerPSRepositoryParameters + } + + if ($updatedGalleryInstallationPolicy -eq $true -and $previousGalleryInstallationPolicy -ne $true) + { + # Only try to revert installation policy if the repository exist + if ((Get-PSRepository -Name $Gallery -ErrorAction 'SilentlyContinue')) + { + # Reverting the Installation Policy for the given gallery if it was not already trusted + Set-PSRepository -Name $Gallery -InstallationPolicy 'Untrusted' + } + } + + Write-Verbose -Message 'Project Bootstrapped, returning to Invoke-Build.' } diff --git a/Resolve-Dependency.psd1 b/Resolve-Dependency.psd1 index 2ae8c0d..07945f8 100644 --- a/Resolve-Dependency.psd1 +++ b/Resolve-Dependency.psd1 @@ -2,4 +2,14 @@ Gallery = 'PSGallery' AllowPrerelease = $false WithYAML = $true + + #UseModuleFast = $true + #ModuleFastVersion = '0.1.2' + #ModuleFastBleedingEdge = $true + + UsePSResourceGet = $true + #PSResourceGetVersion = '1.0.1' + + UsePowerShellGetCompatibilityModule = $true + UsePowerShellGetCompatibilityModuleVersion = '3.0.23-beta23' } diff --git a/build.ps1 b/build.ps1 index 4630cb8..f4a0fae 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,381 +1,538 @@ <# + .DESCRIPTION + Bootstrap and build script for PowerShell module CI/CD pipeline. -.DESCRIPTION - Bootstrap and build script for PowerShell module pipeline + .PARAMETER Tasks + The task or tasks to run. The default value is '.' (runs the default task). + .PARAMETER CodeCoverageThreshold + The code coverage target threshold to uphold. Set to 0 to disable. + The default value is '' (empty string). + + .PARAMETER BuildConfig + Not yet written. + + .PARAMETER OutputDirectory + Specifies the folder to build the artefact into. The default value is 'output'. + + .PARAMETER BuiltModuleSubdirectory + Subdirectory name to build the module (under $OutputDirectory). The default + value is '' (empty string). + + .PARAMETER RequiredModulesDirectory + Can be a path (relative to $PSScriptRoot or absolute) to tell Resolve-Dependency + and PSDepend where to save the required modules. It is also possible to use + 'CurrentUser' och 'AllUsers' to install missing dependencies. You can override + the value for PSDepend in the Build.psd1 build manifest. The default value is + 'output/RequiredModules'. + + .PARAMETER PesterScript + One or more paths that will override the Pester configuration in build + configuration file when running the build task Invoke_Pester_Tests. + + If running Pester 5 test, use the alias PesterPath to be future-proof. + + .PARAMETER PesterTag + Filter which tags to run when invoking Pester tests. This is used in the + Invoke-Pester.pester.build.ps1 tasks. + + .PARAMETER PesterExcludeTag + Filter which tags to exclude when invoking Pester tests. This is used in + the Invoke-Pester.pester.build.ps1 tasks. + + .PARAMETER DscTestTag + Filter which tags to run when invoking DSC Resource tests. This is used + in the DscResource.Test.build.ps1 tasks. + + .PARAMETER DscTestExcludeTag + Filter which tags to exclude when invoking DSC Resource tests. This is + used in the DscResource.Test.build.ps1 tasks. + + .PARAMETER ResolveDependency + Not yet written. + + .PARAMETER BuildInfo + The build info object from ModuleBuilder. Defaults to an empty hashtable. + + .PARAMETER AutoRestore + Not yet written. + + .PARAMETER UseModuleFast + Specifies to use ModuleFast instead of PowerShellGet to resolve dependencies + faster. + + .PARAMETER UsePSResourceGet + Specifies to use PSResourceGet instead of PowerShellGet to resolve dependencies + faster. This can also be configured in Resolve-Dependency.psd1. + + .PARAMETER UsePowerShellGetCompatibilityModule + Specifies to use the compatibility module PowerShellGet. This parameter + only works then the method of downloading dependencies is PSResourceGet. + This can also be configured in Resolve-Dependency.psd1. #> [CmdletBinding()] param ( [Parameter(Position = 0)] - [string[]]$Tasks = '.', + [System.String[]] + $Tasks = '.', [Parameter()] - [String] + [System.String] $CodeCoverageThreshold = '', [Parameter()] - [validateScript( + [System.String] + [ValidateScript( { Test-Path -Path $_ } )] $BuildConfig, [Parameter()] - # A Specific folder to build the artefact into. + [System.String] $OutputDirectory = 'output', [Parameter()] - # Subdirectory name to build the module (under $OutputDirectory) + [System.String] $BuiltModuleSubdirectory = '', - # Can be a path (relative to $PSScriptRoot or absolute) to tell Resolve-Dependency & PSDepend where to save the required modules, - # or use CurrentUser, AllUsers to target where to install missing dependencies - # You can override the value for PSDepend in the Build.psd1 build manifest - # This defaults to $OutputDirectory/modules (by default: ./output/modules) [Parameter()] + [System.String] $RequiredModulesDirectory = $(Join-Path 'output' 'RequiredModules'), [Parameter()] - [object[]] + # This alias is to prepare for the rename of this parameter to PesterPath when Pester 4 support is removed + [Alias('PesterPath')] + [System.Object[]] $PesterScript, - # Filter which tags to run when invoking Pester tests - # This is used in the Invoke-Pester.pester.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $PesterTag, - # Filter which tags to exclude when invoking Pester tests - # This is used in the Invoke-Pester.pester.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $PesterExcludeTag, - # Filter which tags to run when invoking DSC Resource tests - # This is used in the DscResource.Test.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $DscTestTag, - # Filter which tags to exclude when invoking DSC Resource tests - # This is used in the DscResource.Test.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $DscTestExcludeTag, [Parameter()] [Alias('bootstrap')] - [switch]$ResolveDependency, + [System.Management.Automation.SwitchParameter] + $ResolveDependency, [Parameter(DontShow)] [AllowNull()] + [System.Collections.Hashtable] $BuildInfo, [Parameter()] - [switch] - $AutoRestore + [System.Management.Automation.SwitchParameter] + $AutoRestore, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $UseModuleFast, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $UsePSResourceGet, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $UsePowerShellGetCompatibilityModule ) -# The BEGIN block (at the end of this file) handles the Bootstrap of the Environment before Invoke-Build can run the tasks -# if the -ResolveDependency (aka Bootstrap) is specified, the modules are already available, and can be auto loaded +<# + The BEGIN block (at the end of this file) handles the Bootstrap of the Environment + before Invoke-Build can run the tasks if the parameter ResolveDependency (or + parameter alias Bootstrap) is specified. +#> process { - if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') { - # Only run the process block through InvokeBuild (Look at the Begin block at the bottom of this script) + # Only run the process block through InvokeBuild (look at the Begin block at the bottom of this script). return } - # Execute the Build Process from the .build.ps1 path. - Push-Location -Path $PSScriptRoot -StackName BeforeBuild + # Execute the Build process from the .build.ps1 path. + Push-Location -Path $PSScriptRoot -StackName 'BeforeBuild' try { - Write-Host -ForeGroundColor magenta "[build] Parsing defined tasks" + Write-Host -Object "[build] Parsing defined tasks" -ForeGroundColor Magenta - # Load Default BuildInfo if not provided as parameter - if (!$PSBoundParameters.ContainsKey('BuildInfo')) + # Load the default BuildInfo if the parameter BuildInfo is not set. + if (-not $PSBoundParameters.ContainsKey('BuildInfo')) { try { - if (Test-Path $BuildConfig) + if (Test-Path -Path $BuildConfig) { - $ConfigFile = (Get-Item -Path $BuildConfig) - Write-Host "[build] Loading Configuration from $ConfigFile" - $BuildInfo = switch -Regex ($ConfigFile.Extension) + $configFile = Get-Item -Path $BuildConfig + + Write-Host -Object "[build] Loading Configuration from $configFile" + + $BuildInfo = switch -Regex ($configFile.Extension) { # Native Support for PSD1 '\.psd1' { + if (-not (Get-Command -Name Import-PowerShellDataFile -ErrorAction SilentlyContinue)) + { + Import-Module -Name Microsoft.PowerShell.Utility -RequiredVersion 3.1.0.0 + } + Import-PowerShellDataFile -Path $BuildConfig } + # Support for yaml when module PowerShell-Yaml is available '\.[yaml|yml]' { - Import-Module -ErrorAction Stop -Name 'powershell-yaml' - ConvertFrom-Yaml -Yaml (Get-Content -Raw $ConfigFile) + Import-Module -Name 'powershell-yaml' -ErrorAction Stop + + ConvertFrom-Yaml -Yaml (Get-Content -Raw $configFile) } - # Native Support for JSON and JSONC (by Removing comments) + + # Support for JSON and JSONC (by Removing comments) when module PowerShell-Yaml is available '\.[json|jsonc]' { - $JSONC = (Get-Content -Raw -Path $ConfigFile) - $JSON = $JSONC -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/' - # This should probably be converted to hashtable for splatting - $JSON | ConvertFrom-Json + $jsonFile = Get-Content -Raw -Path $configFile + + $jsonContent = $jsonFile -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/' + + # Yaml is superset of JSON. + ConvertFrom-Yaml -Yaml $jsonContent } + + # Unknown extension, return empty hashtable. default { - Write-Error "Extension '$_' not supported. using @{}" + Write-Error -Message "Extension '$_' not supported. using @{}" + @{ } } } } else { - Write-Host -Object "Configuration file $BuildConfig not found" -ForegroundColor Red + Write-Host -Object "Configuration file '$($BuildConfig.FullName)' not found" -ForegroundColor Red + + # No config file was found, return empty hashtable. $BuildInfo = @{ } } } catch { - Write-Host -Object "Error loading Config $ConfigFile.`r`n Are you missing dependencies?" -ForegroundColor Yellow - Write-Host -Object "Make sure you run './build.ps1 -ResolveDependency -tasks noop' to restore the Required modules the first time" -ForegroundColor Yellow + $logMessage = "Error loading Config '$($BuildConfig.FullName)'.`r`nAre you missing dependencies?`r`nMake sure you run './build.ps1 -ResolveDependency -tasks noop' before running build to restore the required modules." + + Write-Host -Object $logMessage -ForegroundColor Yellow + $BuildInfo = @{ } - Write-Error $_.Exception.Message + + Write-Error -Message $_.Exception.Message } } - # If the Invoke-Build Task Header is specified in the Build Info, set it + # If the Invoke-Build Task Header is specified in the Build Info, set it. if ($BuildInfo.TaskHeader) { - Set-BuildHeader ([scriptblock]::Create($BuildInfo.TaskHeader)) + Set-BuildHeader -Script ([scriptblock]::Create($BuildInfo.TaskHeader)) + } + + <# + Add BuildModuleOutput to PSModule Path environment variable. + Moved here (not in begin block) because build file can contains BuiltSubModuleDirectory value. + #> + if ($BuiltModuleSubdirectory) + { + if (-not (Split-Path -IsAbsolute -Path $BuiltModuleSubdirectory)) + { + $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuiltModuleSubdirectory + } + else + { + $BuildModuleOutput = $BuiltModuleSubdirectory + } + } # test if BuiltModuleSubDirectory set in build config file + elseif ($BuildInfo.ContainsKey('BuiltModuleSubDirectory')) + { + $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuildInfo['BuiltModuleSubdirectory'] + } + else + { + $BuildModuleOutput = $OutputDirectory } - # Import Tasks from modules via their exported aliases when defined in BUild Manifest - # https://github.com/nightroman/Invoke-Build/tree/master/Tasks/Import#example-2-import-from-a-module-with-tasks - if ($BuildInfo.containsKey('ModuleBuildTasks')) + # Pre-pending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder. + if ($powerShellModulePaths -notcontains $BuildModuleOutput) { - foreach ($Module in $BuildInfo['ModuleBuildTasks'].Keys) + Write-Host -Object "[build] Pre-pending '$BuildModuleOutput' folder to PSModulePath" -ForegroundColor Green + + $env:PSModulePath = $BuildModuleOutput + [System.IO.Path]::PathSeparator + $env:PSModulePath + } + + <# + Import Tasks from modules via their exported aliases when defined in Build Manifest. + https://github.com/nightroman/Invoke-Build/tree/master/Tasks/Import#example-2-import-from-a-module-with-tasks + #> + if ($BuildInfo.ContainsKey('ModuleBuildTasks')) + { + foreach ($module in $BuildInfo['ModuleBuildTasks'].Keys) { try { - Write-Host -ForegroundColor DarkGray -Verbose "Importing tasks from module $Module" - $LoadedModule = Import-Module $Module -PassThru -ErrorAction Stop - foreach ($TaskToExport in $BuildInfo['ModuleBuildTasks'].($Module)) + Write-Host -Object "Importing tasks from module $module" -ForegroundColor DarkGray + + $loadedModule = Import-Module -Name $module -PassThru -ErrorAction Stop + + foreach ($TaskToExport in $BuildInfo['ModuleBuildTasks'].($module)) { - $LoadedModule.ExportedAliases.GetEnumerator().Where{ - # using -like to support wildcard - Write-Host -ForegroundColor DarkGray "`t Loading $($_.Key)..." + $loadedModule.ExportedAliases.GetEnumerator().Where{ + Write-Host -Object "`t Loading $($_.Key)..." -ForegroundColor DarkGray + + # Using -like to support wildcard. $_.Key -like $TaskToExport }.ForEach{ - # Dot sourcing the Tasks via their exported aliases + # Dot-sourcing the Tasks via their exported aliases. . (Get-Alias $_.Key) } } } catch { - Write-Host -ForegroundColor Red -Object "Could not load tasks for module $Module." - Write-Error $_ + Write-Host -Object "Could not load tasks for module $module." -ForegroundColor Red + + Write-Error -Message $_ } } } - # Loading Build Tasks defined in the .build/ folder (will override the ones imported above if same task name) - Get-ChildItem -Path ".build/" -Recurse -Include *.ps1 -ErrorAction Ignore | ForEach-Object { - "Importing file $($_.BaseName)" | Write-Verbose - . $_.FullName - } + # Loading Build Tasks defined in the .build/ folder (will override the ones imported above if same task name). + Get-ChildItem -Path '.build/' -Recurse -Include '*.ps1' -ErrorAction Ignore | + ForEach-Object { + "Importing file $($_.BaseName)" | Write-Verbose + + . $_.FullName + } - # Synopsis: Empty task, useful to test the bootstrap process + # Synopsis: Empty task, useful to test the bootstrap process. task noop { } - # Define default task sequence ("."), can be overridden in the $BuildInfo + # Define default task sequence ("."), can be overridden in the $BuildInfo. task . { - Write-Build Yellow "No sequence currently defined for the default task" + Write-Build -Object 'No sequence currently defined for the default task' -ForegroundColor Yellow } - # Load Invoke-Build task sequences/workflows from $BuildInfo - Write-Host -ForegroundColor DarkGray "Adding Workflow from configuration:" - foreach ($Workflow in $BuildInfo.BuildWorkflow.keys) + Write-Host -Object 'Adding Workflow from configuration:' -ForegroundColor DarkGray + + # Load Invoke-Build task sequences/workflows from $BuildInfo. + foreach ($workflow in $BuildInfo.BuildWorkflow.keys) { - Write-Verbose "Creating Build Workflow '$Workflow' with tasks $($BuildInfo.BuildWorkflow.($Workflow) -join ', ')" - $WorkflowItem = $BuildInfo.BuildWorkflow.($Workflow) - if ($WorkflowItem.Trim() -match '^\{(?[\w\W]*)\}$') + Write-Verbose -Message "Creating Build Workflow '$Workflow' with tasks $($BuildInfo.BuildWorkflow.($Workflow) -join ', ')." + + $workflowItem = $BuildInfo.BuildWorkflow.($workflow) + + if ($workflowItem.Trim() -match '^\{(?[\w\W]*)\}$') { - $WorkflowItem = [ScriptBlock]::Create($Matches['sb']) + $workflowItem = [ScriptBlock]::Create($Matches['sb']) } - Write-Host -ForegroundColor DarkGray " +-> $Workflow" - task $Workflow $WorkflowItem + + Write-Host -Object " +-> $workflow" -ForegroundColor DarkGray + + task $workflow $workflowItem } - Write-Host -ForeGroundColor magenta "[build] Executing requested workflow: $($Tasks -join ', ')" + Write-Host -Object "[build] Executing requested workflow: $($Tasks -join ', ')" -ForeGroundColor Magenta } finally { - Pop-Location -StackName BeforeBuild + Pop-Location -StackName 'BeforeBuild' } } -Begin +begin { - # Find build config if not specified - if (-not $BuildConfig) { - $config = Get-ChildItem -Path "$PSScriptRoot\*" -Include 'build.y*ml', 'build.psd1', 'build.json*' -ErrorAction:Ignore - if (-not $config -or ($config -is [array] -and $config.Length -le 0)) { - throw "No build configuration found. Specify path via -BuildConfig" + # Find build config if not specified. + if (-not $BuildConfig) + { + $config = Get-ChildItem -Path "$PSScriptRoot\*" -Include 'build.y*ml', 'build.psd1', 'build.json*' -ErrorAction Ignore + + if (-not $config -or ($config -is [System.Array] -and $config.Length -le 0)) + { + throw 'No build configuration found. Specify path via parameter BuildConfig.' } - elseif ($config -is [array]) { - if ($config.Length -gt 1) { - throw "More than one build configuration found. Specify which one to use via -BuildConfig" + elseif ($config -is [System.Array]) + { + if ($config.Length -gt 1) + { + throw 'More than one build configuration found. Specify which path to use via parameter BuildConfig.' } + $BuildConfig = $config[0] } - else { + else + { $BuildConfig = $config } } + # Bootstrapping the environment before using Invoke-Build as task runner - if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') + if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { - Write-Host -foregroundColor Green "[pre-build] Starting Build Init" - Push-Location $PSScriptRoot -StackName BuildModule + Write-Host -Object "[pre-build] Starting Build Init" -ForegroundColor Green + + Push-Location $PSScriptRoot -StackName 'BuildModule' } if ($RequiredModulesDirectory -in @('CurrentUser', 'AllUsers')) { - # Installing modules instead of saving them - Write-Host -foregroundColor Green "[pre-build] Required Modules will be installed for $RequiredModulesDirectory, not saved." - # Tell Resolve-Dependency to use provided scope as the -PSDependTarget if not overridden in Build.psd1 + # Installing modules instead of saving them. + Write-Host -Object "[pre-build] Required Modules will be installed to the PowerShell module path that is used for $RequiredModulesDirectory." -ForegroundColor Green + + <# + The variable $PSDependTarget will be used below when building the splatting + variable before calling Resolve-Dependency.ps1, unless overridden in the + file Resolve-Dependency.psd1. + #> $PSDependTarget = $RequiredModulesDirectory } else { - if (-Not (Split-Path -IsAbsolute -Path $OutputDirectory)) + if (-not (Split-Path -IsAbsolute -Path $OutputDirectory)) { $OutputDirectory = Join-Path -Path $PSScriptRoot -ChildPath $OutputDirectory } - # Resolving the absolute path to save the required modules to - if (-Not (Split-Path -IsAbsolute -Path $RequiredModulesDirectory)) + # Resolving the absolute path to save the required modules to. + if (-not (Split-Path -IsAbsolute -Path $RequiredModulesDirectory)) { $RequiredModulesDirectory = Join-Path -Path $PSScriptRoot -ChildPath $RequiredModulesDirectory } - # Create the output/modules folder if not exists, or resolve the Absolute path otherwise - if (Resolve-Path $RequiredModulesDirectory -ErrorAction SilentlyContinue) + # Create the output/modules folder if not exists, or resolve the Absolute path otherwise. + if (Resolve-Path -Path $RequiredModulesDirectory -ErrorAction SilentlyContinue) { - Write-Debug "[pre-build] Required Modules path already exist at $RequiredModulesDirectory" - $RequiredModulesPath = Convert-Path $RequiredModulesDirectory + Write-Debug -Message "[pre-build] Required Modules path already exist at $RequiredModulesDirectory" + + $requiredModulesPath = Convert-Path -Path $RequiredModulesDirectory } else { - Write-Host -foregroundColor Green "[pre-build] Creating required modules directory $RequiredModulesDirectory." - $RequiredModulesPath = (New-Item -ItemType Directory -Force -Path $RequiredModulesDirectory).FullName - } + Write-Host -Object "[pre-build] Creating required modules directory $RequiredModulesDirectory." -ForegroundColor Green - # Prepending $RequiredModulesPath folder to PSModulePath to resolve from this folder FIRST - if ($RequiredModulesDirectory -notIn @('CurrentUser', 'AllUsers') -and - (($Env:PSModulePath -split [io.path]::PathSeparator) -notContains $RequiredModulesDirectory)) - { - Write-Host -foregroundColor Green "[pre-build] Prepending '$RequiredModulesDirectory' folder to PSModulePath" - $Env:PSModulePath = $RequiredModulesDirectory + [io.path]::PathSeparator + $Env:PSModulePath + $requiredModulesPath = (New-Item -ItemType Directory -Force -Path $RequiredModulesDirectory).FullName } - # Checking if the user should -ResolveDependency - if ((!(Get-Module -ListAvailable powershell-yaml) -or !(Get-Module -ListAvailable InvokeBuild) -or !(Get-Module -ListAvailable PSDepend)) -and !$ResolveDependency) + $powerShellModulePaths = $env:PSModulePath -split [System.IO.Path]::PathSeparator + + # Pre-pending $requiredModulesPath folder to PSModulePath to resolve from this folder FIRST. + if ($RequiredModulesDirectory -notin @('CurrentUser', 'AllUsers') -and + ($powerShellModulePaths -notcontains $RequiredModulesDirectory)) { - if ($AutoRestore -or !$PSBoundParameters.ContainsKey('Tasks') -or $Tasks -contains 'build') - { - Write-Host -ForegroundColor Yellow "[pre-build] Dependency missing, running './build.ps1 -ResolveDependency -Tasks noop' for you `r`n" - $ResolveDependency = $true - } - else - { - Write-Warning "Some required Modules are missing, make sure you first run with the '-ResolveDependency' parameter." - Write-Warning "Running 'build.ps1 -ResolveDependency -Tasks noop' will pull required modules without running the build task." - } + Write-Host -Object "[pre-build] Pre-pending '$RequiredModulesDirectory' folder to PSModulePath" -ForegroundColor Green + + $env:PSModulePath = $RequiredModulesDirectory + [System.IO.Path]::PathSeparator + $env:PSModulePath } - if ($BuiltModuleSubdirectory) + $powerShellYamlModule = Get-Module -Name 'powershell-yaml' -ListAvailable + $invokeBuildModule = Get-Module -Name 'InvokeBuild' -ListAvailable + $psDependModule = Get-Module -Name 'PSDepend' -ListAvailable + + # Checking if the user should -ResolveDependency. + if (-not ($powerShellYamlModule -and $invokeBuildModule -and $psDependModule) -and -not $ResolveDependency) { - if (-Not (Split-Path -IsAbsolute $BuiltModuleSubdirectory)) + if ($AutoRestore -or -not $PSBoundParameters.ContainsKey('Tasks') -or $Tasks -contains 'build') { - $BuildModuleOutput = Join-Path $OutputDirectory $BuiltModuleSubdirectory + Write-Host -Object "[pre-build] Dependency missing, running './build.ps1 -ResolveDependency -Tasks noop' for you `r`n" -ForegroundColor Yellow + + $ResolveDependency = $true } else { - $BuildModuleOutput = $BuiltModuleSubdirectory + Write-Warning -Message "Some required Modules are missing, make sure you first run with the '-ResolveDependency' parameter. Running 'build.ps1 -ResolveDependency -Tasks noop' will pull required modules without running the build task." } } - else - { - $BuildModuleOutput = $OutputDirectory - } - # Prepending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder - if (($Env:PSModulePath -split [io.path]::PathSeparator) -notContains $BuildModuleOutput) - { - Write-Host -foregroundColor Green "[pre-build] Prepending '$BuildModuleOutput' folder to PSModulePath" - $Env:PSModulePath = $BuildModuleOutput + [io.path]::PathSeparator + $Env:PSModulePath - } - - # Tell Resolve-Dependency to use $RequiredModulesPath as -PSDependTarget if not overridden in Build.psd1 - $PSDependTarget = $RequiredModulesPath + <# + The variable $PSDependTarget will be used below when building the splatting + variable before calling Resolve-Dependency.ps1, unless overridden in the + file Resolve-Dependency.psd1. + #> + $PSDependTarget = $requiredModulesPath } if ($ResolveDependency) { - Write-Host -Object "[pre-build] Resolving dependencies." -foregroundColor Green - $ResolveDependencyParams = @{ } + Write-Host -Object "[pre-build] Resolving dependencies using preferred method." -ForegroundColor Green + + $resolveDependencyParams = @{ } - # If BuildConfig is a Yaml file, bootstrap powershell-yaml via ResolveDependency + # If BuildConfig is a Yaml file, bootstrap powershell-yaml via ResolveDependency. if ($BuildConfig -match '\.[yaml|yml]$') { - $ResolveDependencyParams.add('WithYaml', $True) + $resolveDependencyParams.Add('WithYaml', $true) } - $ResolveDependencyAvailableParams = (Get-Command -Name '.\Resolve-Dependency.ps1').parameters.keys - foreach ($CmdParameter in $ResolveDependencyAvailableParams) - { + $resolveDependencyAvailableParams = (Get-Command -Name '.\Resolve-Dependency.ps1').Parameters.Keys + foreach ($cmdParameter in $resolveDependencyAvailableParams) + { # The parameter has been explicitly used for calling the .build.ps1 - if ($MyInvocation.BoundParameters.ContainsKey($CmdParameter)) + if ($MyInvocation.BoundParameters.ContainsKey($cmdParameter)) { - $ParamValue = $MyInvocation.BoundParameters.ContainsKey($CmdParameter) - Write-Debug " adding $CmdParameter :: $ParamValue [from user-provided parameters to Build.ps1]" - $ResolveDependencyParams.Add($CmdParameter, $ParamValue) + $paramValue = $MyInvocation.BoundParameters.Item($cmdParameter) + + Write-Debug " adding $cmdParameter :: $paramValue [from user-provided parameters to Build.ps1]" + + $resolveDependencyParams.Add($cmdParameter, $paramValue) } # Use defaults parameter value from Build.ps1, if any else { - if ($ParamValue = Get-Variable -Name $CmdParameter -ValueOnly -ErrorAction Ignore) + $paramValue = Get-Variable -Name $cmdParameter -ValueOnly -ErrorAction Ignore + + if ($paramValue) { - Write-Debug " adding $CmdParameter :: $ParamValue [from default Build.ps1 variable]" - $ResolveDependencyParams.add($CmdParameter, $ParamValue) + Write-Debug " adding $cmdParameter :: $paramValue [from default Build.ps1 variable]" + + $resolveDependencyParams.Add($cmdParameter, $paramValue) } } } - Write-Host -foregroundColor Green "[pre-build] Starting bootstrap process." - .\Resolve-Dependency.ps1 @ResolveDependencyParams + Write-Host -Object "[pre-build] Starting bootstrap process." -ForegroundColor Green + + .\Resolve-Dependency.ps1 @resolveDependencyParams } - if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') + if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { - Write-Verbose "Bootstrap completed. Handing back to InvokeBuild." + Write-Verbose -Message "Bootstrap completed. Handing back to InvokeBuild." + if ($PSBoundParameters.ContainsKey('ResolveDependency')) { - Write-Verbose "Dependency already resolved. Removing task" + Write-Verbose -Message "Dependency already resolved. Removing task." + $null = $PSBoundParameters.Remove('ResolveDependency') } - Write-Host -foregroundColor Green "[build] Starting build with InvokeBuild." + + Write-Host -Object "[build] Starting build with InvokeBuild." -ForegroundColor Green + Invoke-Build @PSBoundParameters -Task $Tasks -File $MyInvocation.MyCommand.Path - Pop-Location -StackName BuildModule + + Pop-Location -StackName 'BuildModule' + return } } diff --git a/build.yaml b/build.yaml index eb8db93..1332928 100644 --- a/build.yaml +++ b/build.yaml @@ -1,27 +1,6 @@ --- #################################################### -# ModuleBuilder Configuration # -#################################################### -CopyPaths: - - en-US - - DSCResources - - Modules -Encoding: UTF8 -VersionedOutputDirectory: true - -#################################################### -# ModuleBuilder Dependent Modules Configuration # -#################################################### - -NestedModule: - DscResource.Common: - CopyOnly: true - Path: ./output/RequiredModules/DscResource.Common - AddToManifest: false - Exclude: PSGetModuleInfo.xml - -#################################################### -# Pipeline Configuration # +# Pipeline Build Task Configuration (Invoke-Build) # #################################################### BuildWorkflow: '.': @@ -32,19 +11,26 @@ BuildWorkflow: - Clean - Build_Module_ModuleBuilder - Build_NestedModules_ModuleBuilder - - Create_changelog_release_output + - Create_Changelog_Release_Output + + docs: - Generate_Conceptual_Help - Generate_Wiki_Content + - Generate_Wiki_Sidebar + - Clean_Markdown_Metadata + - Package_Wiki_Content pack: - build - - package_module_nupkg + - docs + - package_module_nupkg # cSpell: disable-line - hqrmtest: - - DscResource_Tests_Stop_On_Fail + hqrmtest: # cSpell: disable-line + - Invoke_HQRM_Tests_Stop_On_Fail test: - Pester_Tests_Stop_On_Fail + - Convert_Pester_Coverage - Pester_If_Code_Coverage_Under_Threshold publish: @@ -53,36 +39,16 @@ BuildWorkflow: - Publish_GitHub_Wiki_Content #################################################### -# PESTER Configuration # +# ModuleBuilder Configuration # #################################################### - -Pester: - OutputFormat: NUnitXML - ExcludeFromCodeCoverage: - - Modules/DscResource.Common - Script: - - tests/Unit - - tests/Integration - ExcludeTag: - Tag: - CodeCoverageOutputFile: JaCoCo_coverage.xml - CodeCoverageOutputFileEncoding: ascii - CodeCoverageThreshold: 70 - -DscTest: - OutputFormat: NUnitXML - ExcludeTag: - - 'Common Tests - New Error-Level Script Analyzer Rules' - ExcludeSourceFile: - - output - ExcludeModuleFile: - - Modules/DscResource.Common - MainGitBranch: main - -Resolve-Dependency: - Gallery: 'PSGallery' - AllowPrerelease: false - Verbose: false +CopyPaths: + - en-US + - DSCResources + - Modules +Prefix: prefix.ps1 +Encoding: UTF8 +VersionedOutputDirectory: true +BuiltModuleSubdirectory: builtModule ModuleBuildTasks: Sampler: @@ -91,6 +57,8 @@ ModuleBuildTasks: - '*.ib.tasks' DscResource.DocGenerator: - 'Task.*' + DscResource.Test: + - 'Task.*' TaskHeader: | param($Path) @@ -103,9 +71,119 @@ TaskHeader: | Write-Build DarkGray " $($Task.InvocationInfo.ScriptName):$($Task.InvocationInfo.ScriptLineNumber)" "" +#################################################### +# Dependent Modules Configuration (Sampler) # +#################################################### +NestedModule: + DscResource.Common: + CopyOnly: true + Path: ./output/RequiredModules/DscResource.Common + AddToManifest: false + Exclude: PSGetModuleInfo.xml + + DscResource.Base: + CopyOnly: true + Path: ./output/RequiredModules/DscResource.Base + AddToManifest: false + Exclude: PSGetModuleInfo.xml + +#################################################### +# Pester Configuration (Sampler) # +#################################################### +Pester: + Configuration: + Run: + Path: + - tests/Unit + Output: + Verbosity: Detailed + StackTraceVerbosity: Full + CIFormat: Auto + CodeCoverage: + CoveragePercentTarget: 85 + OutputPath: JaCoCo_coverage.xml + OutputEncoding: ascii + UseBreakpoints: false + TestResult: + OutputFormat: NUnitXML + OutputEncoding: ascii + ExcludeFromCodeCoverage: + - Modules/DscResource.Common + - Modules/DscResource.Base + - prefix.ps1 + - ActiveDirectoryCSDsc.psm1 + +#################################################### +# Pester Configuration (DscResource.Test) # +#################################################### +DscTest: + Pester: + Configuration: + Filter: + ExcludeTag: + - "Common Tests - New Error-Level Script Analyzer Rules" + Output: + Verbosity: Detailed + CIFormat: Auto + TestResult: + Enabled: true + OutputFormat: NUnitXML + OutputEncoding: ascii + OutputPath: ./output/testResults/NUnitXml_HQRM_Tests.xml + Script: + ExcludeSourceFile: + - output + ExcludeModuleFile: + - Modules/DscResource.Common + - Modules/DscResource.Base + # Must exclude built module file because it should not be tested like MOF-based resources + - ActiveDirectoryCSDsc.psm1 + MainGitBranch: main + +#################################################### +# PSDepend Configuration # +#################################################### +Resolve-Dependency: + Gallery: 'PSGallery' + AllowPrerelease: false + Verbose: false + +#################################################### +# GitHub Configuration # +#################################################### GitHubConfig: GitHubFilesToAdd: - 'CHANGELOG.md' - GitHubConfigUserName: dscbot + ReleaseAssets: + - output/WikiContent.zip + GitHubConfigUserName: dscbot # cSpell: disable-line GitHubConfigUserEmail: dsccommunity@outlook.com UpdateChangelogOnPrerelease: false + +#################################################### +# DscResource.DocGenerator Configuration # +#################################################### +DscResource.DocGenerator: + Generate_Conceptual_Help: + MarkdownCodeRegularExpression: + - '\`(.+?)\`' # Match inline code-block + - '\\(\\)' # Match escaped backslash + - '\[[^\[]+\]\((.+?)\)' # Match markdown URL + - '_(.+?)_' # Match Italic (underscore) + - '\*\*(.+?)\*\*' # Match bold + - '\*(.+?)\*' # Match Italic (asterisk) + Publish_GitHub_Wiki_Content: + Debug: false + Generate_Wiki_Content: + MofResourceMetadata: + Type: MofResource + Category: Resources + ClassResourceMetadata: + Type: ClassResource + Category: Resources + CompositeResourceMetadata: + Type: CompositeResource + Category: Resources + Generate_Wiki_Sidebar: + Debug: false + AlwaysOverwrite: true diff --git a/source/ActiveDirectoryCSDsc.psd1 b/source/ActiveDirectoryCSDsc.psd1 index 9d63802..ff70012 100644 --- a/source/ActiveDirectoryCSDsc.psd1 +++ b/source/ActiveDirectoryCSDsc.psd1 @@ -33,15 +33,7 @@ AliasesToExport = @() # DSC resources to export from this module - DscResourcesToExport = @( - 'AdcsAuthorityInformationAccess', - 'AdcsCertificationAuthority', - 'AdcsCertificationAuthoritySettings', - 'AdcsEnrollmentPolicyWebService', - 'AdcsOnlineResponder', - 'AdcsWebEnrollment', - 'AdscTemplate' - ) + DscResourcesToExport = @() # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{ diff --git a/source/DSCResources/DSC_AdcsAuthorityInformationAccess/DSC_AdcsAuthorityInformationAccess.psm1 b/source/DSCResources/DSC_AdcsAuthorityInformationAccess/DSC_AdcsAuthorityInformationAccess.psm1 index 5321e97..9a25881 100644 --- a/source/DSCResources/DSC_AdcsAuthorityInformationAccess/DSC_AdcsAuthorityInformationAccess.psm1 +++ b/source/DSCResources/DSC_AdcsAuthorityInformationAccess/DSC_AdcsAuthorityInformationAccess.psm1 @@ -236,5 +236,3 @@ function Get-CaAiaUriList return [System.String[]] (Get-CAAuthorityInformationAccess | Where-Object -Property $ExtensionType -Eq $true).Uri } - -Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_AdcsCertificationAuthority/DSC_AdcsCertificationAuthority.psm1 b/source/DSCResources/DSC_AdcsCertificationAuthority/DSC_AdcsCertificationAuthority.psm1 index 64d1597..895bcb5 100644 --- a/source/DSCResources/DSC_AdcsCertificationAuthority/DSC_AdcsCertificationAuthority.psm1 +++ b/source/DSCResources/DSC_AdcsCertificationAuthority/DSC_AdcsCertificationAuthority.psm1 @@ -741,5 +741,3 @@ function Test-TargetResource throw $_ } # try } # function Test-TargetResource - -Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_AdcsCertificationAuthoritySettings/DSC_AdcsCertificationAuthoritySettings.psm1 b/source/DSCResources/DSC_AdcsCertificationAuthoritySettings/DSC_AdcsCertificationAuthoritySettings.psm1 index c23c36b..ff703e9 100644 --- a/source/DSCResources/DSC_AdcsCertificationAuthoritySettings/DSC_AdcsCertificationAuthoritySettings.psm1 +++ b/source/DSCResources/DSC_AdcsCertificationAuthoritySettings/DSC_AdcsCertificationAuthoritySettings.psm1 @@ -246,7 +246,7 @@ function Set-TargetResource -IsSingleInstance $IsSingleInstance ` -Verbose:$VerbosePreference - $settingUpdated = $false + $parameterUpdated = $false <# Step through each parameter and update any that are passed @@ -559,5 +559,3 @@ function Set-CertificateAuthoritySetting ($script:localizedData.UpdatingAdcsCaSettingMessage -f $Name, $Value) ) -join '' ) } # function Set-CertificateAuthoritySetting - -Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_AdcsEnrollmentPolicyWebService/DSC_AdcsEnrollmentPolicyWebService.psm1 b/source/DSCResources/DSC_AdcsEnrollmentPolicyWebService/DSC_AdcsEnrollmentPolicyWebService.psm1 index f0bbd07..8ab3719 100644 --- a/source/DSCResources/DSC_AdcsEnrollmentPolicyWebService/DSC_AdcsEnrollmentPolicyWebService.psm1 +++ b/source/DSCResources/DSC_AdcsEnrollmentPolicyWebService/DSC_AdcsEnrollmentPolicyWebService.psm1 @@ -512,5 +512,3 @@ function Test-Thumbprint } } } # end function Test-Thumbprint - -Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1 b/source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1 index f7d289e..bae7768 100644 --- a/source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1 +++ b/source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1 @@ -267,5 +267,3 @@ function Test-TargetResource throw $_ } # try } # function Test-TargetResource - -Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_AdcsTemplate/DSC_AdcsTemplate.psm1 b/source/DSCResources/DSC_AdcsTemplate/DSC_AdcsTemplate.psm1 index 83ea1c9..8b3f7ed 100644 --- a/source/DSCResources/DSC_AdcsTemplate/DSC_AdcsTemplate.psm1 +++ b/source/DSCResources/DSC_AdcsTemplate/DSC_AdcsTemplate.psm1 @@ -211,5 +211,3 @@ function Test-TargetResource } } } # function Test-TargetResource - -Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_AdcsWebEnrollment/DSC_AdcsWebEnrollment.psm1 b/source/DSCResources/DSC_AdcsWebEnrollment/DSC_AdcsWebEnrollment.psm1 index 54567de..a717f0f 100644 --- a/source/DSCResources/DSC_AdcsWebEnrollment/DSC_AdcsWebEnrollment.psm1 +++ b/source/DSCResources/DSC_AdcsWebEnrollment/DSC_AdcsWebEnrollment.psm1 @@ -290,5 +290,3 @@ function Test-TargetResource throw $_ } # try } # function Test-TargetResource - -Export-ModuleMember -Function *-TargetResource diff --git a/source/Modules/ActiveDirectoryCSDsc.Common/ActiveDirectoryCSDsc.Common.psm1 b/source/Modules/ActiveDirectoryCSDsc.Common/ActiveDirectoryCSDsc.Common.psm1 index 8b56ea0..7ad8ba8 100644 --- a/source/Modules/ActiveDirectoryCSDsc.Common/ActiveDirectoryCSDsc.Common.psm1 +++ b/source/Modules/ActiveDirectoryCSDsc.Common/ActiveDirectoryCSDsc.Common.psm1 @@ -1,6 +1,6 @@ -$modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Modules' +$script:resourceHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\DscResource.Common' -Import-Module -Name (Join-Path -Path $modulePath -ChildPath 'DscResource.Common') +Import-Module -Name $script:resourceHelperModulePath # Import Localization Strings $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' @@ -22,17 +22,17 @@ function Restart-ServiceIfExists $Name ) - Write-Verbose -Message ($script:localizedData.GetServiceInformation -f $Name) -Verbose - $servicesService = Get-Service @PSBoundParameters -ErrorAction Continue + Write-Verbose -Message ($script:localizedData.GetServiceInformation -f $Name) + $servicesService = Get-Service @PSBoundParameters -ErrorAction Continue -Verbose:$VerbosePreference if ($servicesService) { - Write-Verbose -Message ($script:localizedData.RestartService -f $Name) -Verbose - $servicesService | Restart-Service -Force -ErrorAction Stop -Verbose + Write-Verbose -Message ($script:localizedData.RestartService -f $Name) + $servicesService | Restart-Service -Force -ErrorAction Stop -Verbose:$VerbosePreference } else { - Write-Verbose -Message ($script:localizedData.UnknownService -f $Name) -Verbose + Write-Verbose -Message ($script:localizedData.UnknownService -f $Name) } } diff --git a/source/en-US/ActiveDirectoryCSDsc.strings.psd1 b/source/en-US/ActiveDirectoryCSDsc.strings.psd1 new file mode 100644 index 0000000..5e5ad93 --- /dev/null +++ b/source/en-US/ActiveDirectoryCSDsc.strings.psd1 @@ -0,0 +1,10 @@ +<# + .SYNOPSIS + The localized resource strings in English (en-US) for the + resource ActiveDirectoryCSDsc module. This file should only contain + localized strings for private functions, public command, and + classes (that are not a DSC resource). +#> + +ConvertFrom-StringData @' +'@ diff --git a/source/prefix.ps1 b/source/prefix.ps1 new file mode 100644 index 0000000..52ef749 --- /dev/null +++ b/source/prefix.ps1 @@ -0,0 +1,10 @@ +using module .\Modules\DscResource.Base + +$script:dscResourceCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath 'Modules/DscResource.Common' +Import-Module -Name $script:dscResourceCommonModulePath + +# TODO: The goal would be to remove this, when no classes and public or private functions need it. +$script:activeDirectoryCSDscCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath 'Modules/ActiveDirectoryCSDsc.Common' +Import-Module -Name $script:activeDirectoryCSDscCommonModulePath + +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' diff --git a/tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 b/tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 index 62b9a8b..15fd8e6 100644 --- a/tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 +++ b/tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 @@ -5,29 +5,61 @@ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] param () -#region HEADER -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsCertificationAuthority' +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } -try -{ - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' -} -catch [System.IO.FileNotFoundException] -{ - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } + + <# + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. + #> + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceFriendlyName = 'AdcsCertificationAuthority' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + + # Ensure that the tests can be performed on this computer + $script:skipIntegrationTests = $false + + # Ensure that the tests can be performed on this computer + if (-not (Test-WindowsFeature -Name 'ADCS-Cert-Authority')) + { + Write-Warning -Message 'Skipping integration tests for AdcsCertificationAuthority because the feature ADCS-Cert-Authority is not installed.' + $skipIntegrationTests = $true + } } -$script:testEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:dscModuleName ` - -DSCResourceName $script:dscResourceName ` - -ResourceType 'Mof' ` - -TestType 'Integration' +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceFriendlyName = 'AdcsCertificationAuthority' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' -Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') -try -{ <# IMPORTANT: To run these tests requires a local Administrator account to be available on the machine running the tests that can be used to install the @@ -41,24 +73,29 @@ try $script:adminUsername = 'AdcsAdminTest' $script:adminPassword = ConvertTo-SecureString -String 'NotPass12!' -AsPlainText -Force - # Ensure that the tests can be performed on this computer - if (-not (Test-WindowsFeature -Name 'ADCS-Cert-Authority')) - { - Write-Warning -Message 'Skipping integration tests for AdcsCertificationAuthority because the feature ADCS-Cert-Authority is not installed.' - return - } - # Create a new Local User in the administrators group $script:adminCredential = New-Object ` -TypeName System.Management.Automation.PSCredential ` -ArgumentList ($script:adminUsername, $script:adminPassword) New-LocalUserInAdministratorsGroup -Username $script:adminUsername -Password $script:adminPassword +} - Describe "$($script:dscResourceName)_Install_Integration" { +AfterAll { + Remove-LocalUser -Name $script:adminUsername -ErrorAction SilentlyContinue + Restore-TestEnvironment -TestEnvironment $script:testEnvironment + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe "$($script:dscResourceName)_Install_Integration" -Skip:$skipIntegrationTests { + BeforeAll { $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName)_Install.Config.ps1" . $configFile + } - Context 'Install ADCS Certification Authority' { + Context 'Install ADCS Certification Authority' { + BeforeAll { $configData = @{ AllNodes = @( @{ @@ -68,41 +105,43 @@ try } ) } + } - It 'Should compile and apply the MOF without throwing' { - { - & "$($script:dscResourceName)_Install_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $configData - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw - } + It 'Should compile and apply the MOF without throwing' { + { + & "$($script:dscResourceName)_Install_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq "$($script:dscResourceName)_Install_Config" - } - $current.Ensure | Should -Be 'Present' + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_Install_Config" } + $current.Ensure | Should -Be 'Present' } } +} - Describe 'DSC_AdcsCertificationAuthoritySettings_Integration' { - $configFile = Join-Path -Path $PSScriptRoot -ChildPath 'DSC_AdcsCertificationAuthoritySettings.config.ps1' - . $configFile -Verbose -ErrorAction Stop +Describe 'DSC_AdcsCertificationAuthoritySettings_Integration' -Skip:$skipIntegrationTests { + Context 'Configure ADCS Certification Authority Settings' { + BeforeAll { + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName)Settings.config.ps1" + . $configFile -Verbose -ErrorAction Stop - Context 'Configure ADCS Certification Authority Settings' { $configData = @{ AllNodes = @( @{ @@ -138,51 +177,56 @@ try } ) } + } - It 'Should compile and apply the MOF without throwing' { - { - & "DSC_AdcsCertificationAuthoritySettings_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $configData - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw - } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + It 'Should compile and apply the MOF without throwing' { + { + & 'DSC_AdcsCertificationAuthoritySettings_Config' ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq 'DSC_AdcsCertificationAuthoritySettings_Config' - } - $current.CACertPublicationURLs | Should -BeExactly $configData.AllNodes[0].CACertPublicationURLs - $current.CRLPublicationURLs | Should -BeExactly $configData.AllNodes[0].CRLPublicationURLs - $current.CRLOverlapUnits | Should -BeExactly $configData.AllNodes[0].CRLOverlapUnits - $current.CRLOverlapPeriod | Should -BeExactly $configData.AllNodes[0].CRLOverlapPeriod - $current.CRLPeriodUnits | Should -BeExactly $configData.AllNodes[0].CRLPeriodUnits - $current.CRLPeriod | Should -BeExactly $configData.AllNodes[0].CRLPeriod - $current.ValidityPeriodUnits | Should -BeExactly $configData.AllNodes[0].ValidityPeriodUnits - $current.ValidityPeriod | Should -BeExactly $configData.AllNodes[0].ValidityPeriod - $current.DSConfigDN | Should -BeExactly $configData.AllNodes[0].DSConfigDN - $current.DSDomainDN | Should -BeExactly $configData.AllNodes[0].DSDomainDN - $current.AuditFilter | Should -BeExactly $configData.AllNodes[0].AuditFilter + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq 'DSC_AdcsCertificationAuthoritySettings_Config' } + $current.CACertPublicationURLs | Should -BeExactly $configData.AllNodes[0].CACertPublicationURLs + $current.CRLPublicationURLs | Should -BeExactly $configData.AllNodes[0].CRLPublicationURLs + $current.CRLOverlapUnits | Should -BeExactly $configData.AllNodes[0].CRLOverlapUnits + $current.CRLOverlapPeriod | Should -BeExactly $configData.AllNodes[0].CRLOverlapPeriod + $current.CRLPeriodUnits | Should -BeExactly $configData.AllNodes[0].CRLPeriodUnits + $current.CRLPeriod | Should -BeExactly $configData.AllNodes[0].CRLPeriod + $current.ValidityPeriodUnits | Should -BeExactly $configData.AllNodes[0].ValidityPeriodUnits + $current.ValidityPeriod | Should -BeExactly $configData.AllNodes[0].ValidityPeriod + $current.DSConfigDN | Should -BeExactly $configData.AllNodes[0].DSConfigDN + $current.DSDomainDN | Should -BeExactly $configData.AllNodes[0].DSDomainDN + $current.AuditFilter | Should -BeExactly $configData.AllNodes[0].AuditFilter } } +} - Describe 'DSC_AdcsAuthorityInformationAccess_Integration' { +Describe 'DSC_AdcsAuthorityInformationAccess_Integration' -Skip:$skipIntegrationTests { + BeforeAll { $configFile = Join-Path -Path $PSScriptRoot -ChildPath 'DSC_AdcsAuthorityInformationAccess.config.ps1' . $configFile -Verbose -ErrorAction Stop + } - Context 'Set ADCS Certification Authority Authority Information Access' { + Context 'Set ADCS Certification Authority Authority Information Access' { + BeforeAll { $configData = @{ AllNodes = @( @{ @@ -199,39 +243,41 @@ try } ) } + } - It 'Should compile and apply the MOF without throwing' { - { - & "DSC_AdcsAuthorityInformationAccess_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $configData - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw - } + It 'Should compile and apply the MOF without throwing' { + { + & 'DSC_AdcsAuthorityInformationAccess_Config' ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq 'DSC_AdcsAuthorityInformationAccess_Config' - } - $current.IsSingleInstance | Should -BeExactly 'Yes' - $current.AiaList | Should -BeExactly $configData.AllNodes[0].AiaList - $current.OcspList | Should -BeExactly $configData.AllNodes[0].OcspList - $current.AllowRestartService | Should -BeFalse + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq 'DSC_AdcsAuthorityInformationAccess_Config' } + $current.IsSingleInstance | Should -BeExactly 'Yes' + $current.AiaList | Should -BeExactly $configData.AllNodes[0].AiaList + $current.OcspList | Should -BeExactly $configData.AllNodes[0].OcspList + $current.AllowRestartService | Should -BeFalse } + } - Context 'Clear ADCS Certification Authority Authority Information Access' { + Context 'Clear ADCS Certification Authority Authority Information Access' { + BeforeAll { $configData = @{ AllNodes = @( @{ @@ -242,44 +288,46 @@ try } ) } + } - It 'Should compile and apply the MOF without throwing' { - { - & "DSC_AdcsAuthorityInformationAccess_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $configData - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw - } + It 'Should compile and apply the MOF without throwing' { + { + & 'DSC_AdcsAuthorityInformationAccess_Config' ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq 'DSC_AdcsAuthorityInformationAccess_Config' - } - $current.IsSingleInstance | Should -BeExactly 'Yes' - $current.AiaList | Should -BeNullOrEmpty - $current.OcspList | Should -BeNullOrEmpty - $current.AllowRestartService | Should -BeFalse + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq 'DSC_AdcsAuthorityInformationAccess_Config' } + $current.IsSingleInstance | Should -BeExactly 'Yes' + $current.AiaList | Should -BeNullOrEmpty + $current.OcspList | Should -BeNullOrEmpty + $current.AllowRestartService | Should -BeFalse } } +} - Describe "$($script:dscResourceName)_Uninstall_Integration" { - $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName)_Uninstall.config.ps1" - . $configFile -Verbose -ErrorAction Stop +Describe "$($script:dscResourceName)_Uninstall_Integration" -Skip:$skipIntegrationTests { + Context 'Uninstall ADCS Certification Authority' { + BeforeAll { + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName)_Uninstall.config.ps1" + . $configFile -Verbose -ErrorAction Stop - Context 'Uninstall ADCS Certification Authority' { $configData = @{ AllNodes = @( @{ @@ -289,39 +337,34 @@ try } ) } + } - It 'Should compile and apply the MOF without throwing' { - { - & "$($script:dscResourceName)_Uninstall_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $configData ` - -ErrorAction Stop - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw - } + It 'Should compile and apply the MOF without throwing' { + { + & "$($script:dscResourceName)_Uninstall_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData ` + -ErrorAction Stop + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq "$($script:dscResourceName)_Uninstall_Config" - } - $current.Ensure | Should -Be 'Absent' + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_Uninstall_Config" } + $current.Ensure | Should -Be 'Absent' } } } -finally -{ - Remove-LocalUser -Name $script:adminUsername -ErrorAction SilentlyContinue - Restore-TestEnvironment -TestEnvironment $script:testEnvironment -} diff --git a/tests/Integration/DSC_AdcsEnrollmentPolicyWebService.Integration.Tests.ps1 b/tests/Integration/DSC_AdcsEnrollmentPolicyWebService.Integration.Tests.ps1 index bdd8e64..950ceb2 100644 --- a/tests/Integration/DSC_AdcsEnrollmentPolicyWebService.Integration.Tests.ps1 +++ b/tests/Integration/DSC_AdcsEnrollmentPolicyWebService.Integration.Tests.ps1 @@ -5,43 +5,39 @@ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] param () -#region HEADER -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsEnrollmentPolicyWebService' - -try -{ - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' -} -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:dscResourceName ` - -ResourceType 'Mof' ` - -TestType 'Integration' +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } -Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } -try -{ <# - IMPORTANT: To run these tests requires a domain admin account to be - available on the machine running the tests that can be used to install the - ADCS component being tested. Please change the following values to the - credentials that are set up for this purpose. - - These tests can not be run on AppVeyor because it requires a domain joined - machine. + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. #> - $script:adminUsername = "$($env:USERDNSDOMAIN)\Administrator" - $script:adminPassword = ConvertTo-SecureString -String 'NotPass12!' -AsPlainText -Force + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceFriendlyName = 'AdcsEnrollmentPolicyWebService' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') # Ensure that the tests can be performed on this computer - $skipIntegrationTests = $false + $script:skipIntegrationTests = $false if (-not (Test-WindowsFeature -Name 'ADCS-Enroll-Web-Pol')) { @@ -54,12 +50,33 @@ try Write-Warning -Message 'Skipping integration tests for AdcsEnrollmentPolicyWebService because it must be run on a domain joined server.' $skipIntegrationTests = $true } +} - # Integration tests can't be performed on this computer - if ($skipIntegrationTests) - { - return - } +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceFriendlyName = 'AdcsEnrollmentPolicyWebService' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + + <# + IMPORTANT: To run these tests requires a domain admin account to be + available on the machine running the tests that can be used to install the + ADCS component being tested. Please change the following values to the + credentials that are set up for this purpose. + + These tests can not be run on AppVeyor because it requires a domain joined + machine. + #> + $script:adminUsername = "$($env:USERDNSDOMAIN)\Administrator" + $script:adminPassword = ConvertTo-SecureString -String 'NotPass12!' -AsPlainText -Force # Get the Administrator credential $script:adminCredential = New-Object ` @@ -67,16 +84,30 @@ try -ArgumentList ($script:adminUsername, $script:AdminPassword) # Create an SSL certificate to be used for the Web Service - $certificate = New-SelfSignedCertificate ` + $script:certificate = New-SelfSignedCertificate ` -DnsName $ENV:ComputerName ` -CertStoreLocation Cert:\LocalMachine\My +} - Describe "$($script:dscResourceName) integration test" { - $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).Config.ps1" - . $configFile +AfterAll { + # Remove the SSL certificate created for the Web Service + if ($certificate) + { + $null = Remove-Item ` + -Path $certificate.PSPath ` + -Force + } + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} +Describe "$($script:dscResourceName) integration test" -Skip:$skipIntegrationTests { + BeforeDiscovery { # These are the test cases to run integration tests for - $testAdcsEnrollmentPolicyWebServiceTestCases = @( + $script:testAdcsEnrollmentPolicyWebServiceTestCases = @( @{ AuthenticationType = 'Certificate' KeyBasedRenewal = $false @@ -98,110 +129,97 @@ try KeyBasedRenewal = $true } ) + } - foreach ($testAdcsEnrollmentPolicyWebServiceTestCase in $testAdcsEnrollmentPolicyWebServiceTestCases) - { - $authenticationType = $testAdcsEnrollmentPolicyWebServiceTestCase.AuthenticationType - $keyBasedRenewal = $testAdcsEnrollmentPolicyWebServiceTestCase.KeyBasedRenewal - - Context "Install ADCS Enrollment Policy Web Service for AuthenticationType '$authenticationType' and KeyBasedRenewal '$keyBasedRenewal'" { - It 'Should compile and apply the MOF without throwing' { - { - $ConfigData = @{ - AllNodes = @( - @{ - NodeName = 'localhost' - AuthenticationType = $authenticationType - SslCertThumbprint = $certificate.Thumbprint - Credential = $script:adminCredential - KeyBasedRenewal = $keyBasedRenewal - Ensure = 'Present' - PsDscAllowPlainTextPassword = $true - } - ) - } + BeforeAll { + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).Config.ps1" + . $configFile + } - & "$($script:dscResourceName)_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $ConfigData - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw + Context 'Install ADCS Enrollment Policy Web Service for AuthenticationType and KeyBasedRenewal ' -ForEach $testAdcsEnrollmentPolicyWebServiceTestCases { + It 'Should compile and apply the MOF without throwing' { + { + $ConfigData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + AuthenticationType = $AuthenticationType + SslCertThumbprint = $certificate.Thumbprint + Credential = $script:adminCredential + KeyBasedRenewal = $KeyBasedRenewal + Ensure = 'Present' + PsDscAllowPlainTextPassword = $true + } + ) } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $ConfigData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object { - $_.ConfigurationName -eq "$($script:dscResourceName)_Config" - } - $current.Ensure | Should -Be 'Present' - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object { + $_.ConfigurationName -eq "$($script:dscResourceName)_Config" } + $current.Ensure | Should -Be 'Present' + } + } - Context "Uninstall ADCS Enrollment Policy Web Service for AuthenticationType '$authenticationType' and KeyBasedRenewal '$keyBasedRenewal'" { - It 'Should compile and apply the MOF without throwing' { - { - $ConfigData = @{ - AllNodes = @( - @{ - NodeName = 'localhost' - AuthenticationType = $authenticationType - SslCertThumbprint = $certificate.Thumbprint - Credential = $script:adminCredential - KeyBasedRenewal = $keyBasedRenewal - Ensure = 'Absent' - PsDscAllowPlainTextPassword = $true - } - ) + Context 'Uninstall ADCS Enrollment Policy Web Service for AuthenticationType and KeyBasedRenewal ' -ForEach $testAdcsEnrollmentPolicyWebServiceTestCases { + It 'Should compile and apply the MOF without throwing' { + { + $ConfigData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + AuthenticationType = $AuthenticationType + SslCertThumbprint = $certificate.Thumbprint + Credential = $script:adminCredential + KeyBasedRenewal = $KeyBasedRenewal + Ensure = 'Absent' + PsDscAllowPlainTextPassword = $true } - - & "$($script:dscResourceName)_Config" ` - -OutputPath $TestDrive ` - -ConfigurationData $ConfigData ` - -ErrorAction Stop - - Start-DscConfiguration ` - -Path $TestDrive ` - -ComputerName localhost ` - -Wait ` - -Verbose ` - -Force ` - -ErrorAction Stop - } | Should -Not -Throw + ) } - It 'Should be able to call Get-DscConfiguration without throwing' { - { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw - } + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $ConfigData ` + -ErrorAction Stop + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should have set the resource and all the parameters should match' { - $current = Get-DscConfiguration | Where-Object { - $_.ConfigurationName -eq "$($script:dscResourceName)_Config" - } - $current.Ensure | Should -Be 'Absent' - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object { + $_.ConfigurationName -eq "$($script:dscResourceName)_Config" } + $current.Ensure | Should -Be 'Absent' } } } -finally -{ - # Remove the SSL certificate created for the Web Service - if ($certificate) - { - $null = Remove-Item ` - -Path $certificate.PSPath ` - -Force - } - - Restore-TestEnvironment -TestEnvironment $script:testEnvironment -} diff --git a/tests/TestHelpers/AdcsStub.psm1 b/tests/TestHelpers/AdcsStub.psm1 deleted file mode 100644 index 27e863e..0000000 --- a/tests/TestHelpers/AdcsStub.psm1 +++ /dev/null @@ -1,95 +0,0 @@ -# This section suppresses rules PsScriptAnalyzer may catch in stub functions. -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUserNameAndPassWordParams', '')] -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')] -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] - -[CmdletBinding()] -param () - -<# - .SYNOPSIS - This is stub cmdlets for module: ADCSAdministration version: 2.0.0.0 which can be used in - Pester unit tests to be able to test code without having the actual module installed. - - .NOTES - Generated from module System.Collections.Hashtable on - operating system Microsoft Windows Server 2012 R2 Datacenter 64-bit (6.3.9600) -#> -function Add-CAAuthorityInformationAccess -{ - [CmdletBinding()] - param - ( - [Parameter()] - [Switch] - $AddToCertificateAia, - - [Parameter()] - [Switch] - $AddToCertificateOcsp, - - [Parameter(Mandatory = $true)] - [System.String] - $Uri, - - [Parameter()] - [Switch] - ${Force} - ) - - throw '{0}: StubNotImplemented' -f $MyInvocation.MyCommand -} - -<# - .SYNOPSIS - This is stub cmdlets for module: ADCSAdministration version: 2.0.0.0 which can be used in - Pester unit tests to be able to test code without having the actual module installed. - - .NOTES - Generated from module System.Collections.Hashtable on - operating system Microsoft Windows Server 2012 R2 Datacenter 64-bit (6.3.9600) -#> -function Get-CAAuthorityInformationAccess -{ - [CmdletBinding()] - param - ( - ) - - throw '{0}: StubNotImplemented' -f $MyInvocation.MyCommand -} - -<# - .SYNOPSIS - This is stub cmdlets for module: ADCSAdministration version: 2.0.0.0 which can be used in - Pester unit tests to be able to test code without having the actual module installed. - - .NOTES - Generated from module System.Collections.Hashtable on - operating system Microsoft Windows Server 2012 R2 Datacenter 64-bit (6.3.9600) -#> -function Remove-CAAuthorityInformationAccess -{ - [CmdletBinding()] - param - ( - [Parameter()] - [Switch] - $AddToCertificateAia, - - [Parameter()] - [Switch] - $AddToCertificateOcsp, - - [Parameter(Mandatory = $true)] - [System.String] - $Uri, - - [Parameter()] - [Switch] - ${Force} - ) - - throw '{0}: StubNotImplemented' -f $MyInvocation.MyCommand -} diff --git a/tests/TestHelpers/CommonTestHelper.psm1 b/tests/TestHelpers/CommonTestHelper.psm1 index 05d1b00..eb570ec 100644 --- a/tests/TestHelpers/CommonTestHelper.psm1 +++ b/tests/TestHelpers/CommonTestHelper.psm1 @@ -226,11 +226,3 @@ function Get-ObjectNotFoundException return New-Object @newObjectParameters } - -Export-ModuleMember -Function @( - 'Get-InvalidArgumentRecord' - 'Get-InvalidOperationRecord' - 'Test-WindowsFeature' - 'New-LocalUserInAdministratorsGroup' - 'Get-ObjectNotFoundException' -) diff --git a/tests/Unit/ActiveDirectoryCSDsc.Common.Tests.ps1 b/tests/Unit/ActiveDirectoryCSDsc.Common.Tests.ps1 index 4d4edac..8d6af6d 100644 --- a/tests/Unit/ActiveDirectoryCSDsc.Common.Tests.ps1 +++ b/tests/Unit/ActiveDirectoryCSDsc.Common.Tests.ps1 @@ -1,49 +1,95 @@ -#region HEADER -$script:projectPath = "$PSScriptRoot\..\.." | Convert-Path -$script:projectName = (Get-ChildItem -Path "$script:projectPath\*\*.psd1" | Where-Object -FilterScript { - ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and - $(try +<# + .SYNOPSIS + Unit test for helper functions in module ActiveDirectoryCSDsc.Common. + + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) { - Test-ModuleManifest -Path $_.FullName -ErrorAction Stop + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null } - catch - { - $false - }) - }).BaseName -$script:parentModule = Get-Module -Name $script:projectName -ListAvailable | Select-Object -First 1 -$script:subModulesFolder = Join-Path -Path $script:parentModule.ModuleBase -ChildPath 'Modules' -Remove-Module -Name $script:parentModule -Force -ErrorAction 'SilentlyContinue' + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:subModuleName = 'ActiveDirectoryCSDsc.Common' -$script:subModuleName = (Split-Path -Path $PSCommandPath -Leaf) -replace '\.Tests.ps1' -$script:subModuleFile = Join-Path -Path $script:subModulesFolder -ChildPath "$($script:subModuleName)/$($script:subModuleName).psm1" + $script:parentModule = Get-Module -Name $script:dscModuleName -ListAvailable | Select-Object -First 1 + $script:subModulesFolder = Join-Path -Path $script:parentModule.ModuleBase -ChildPath 'Modules' -Import-Module $script:subModuleFile -Force -ErrorAction Stop -#endregion HEADER + $script:subModulePath = Join-Path -Path $script:subModulesFolder -ChildPath $script:subModuleName -InModuleScope $script:subModuleName { - Describe 'ActiveDirectoryCSDsc.Common\Restart-SystemService' { - BeforeAll { - Mock -CommandName Restart-Service + Import-Module -Name $script:subModulePath -Force -ErrorAction 'Stop' - $restartServiceIfExistsParams = @{ - Name = 'BITS' - } + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:subModuleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:subModuleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:subModuleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:subModuleName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'ActiveDirectoryCSDsc.Common\Restart-SystemService' -Tag 'RestartSystemService' { + BeforeAll { + Mock -CommandName Restart-Service + + $restartServiceIfExistsParams = @{ + Name = 'BITS' } + } - Context 'When service does not exist and is not restarted' { + Context 'When service does not exist and is not restarted' { + BeforeAll { Mock -CommandName Get-Service + } - It 'Should call the expected mocks' { - Restart-ServiceIfExists @restartServiceIfExistsParams - Assert-MockCalled Get-Service -Exactly -Times 1 -Scope It -ParameterFilter { $Name -eq $restartServiceIfExistsParams.Name } - Assert-MockCalled Restart-Service -Exactly -Times 0 -Scope It - } + It 'Should call the expected mocks' { + Restart-ServiceIfExists @restartServiceIfExistsParams + + Should -Invoke -CommandName Get-Service -ParameterFilter { + $Name -eq $restartServiceIfExistsParams.Name + } -Exactly -Times 1 -Scope It + + Should -Invoke -CommandName Restart-Service -Exactly -Times 0 -Scope It } + } - Context 'When service exists and will be restarted' { - $getService_mock = { + Context 'When service exists and will be restarted' { + BeforeAll { + $mockGetService = { @{ Status = 'Running' Name = 'Servsvc' @@ -51,13 +97,17 @@ InModuleScope $script:subModuleName { } } - Mock -CommandName Get-Service -MockWith $getService_mock + Mock -CommandName Get-Service -MockWith $mockGetService + } - It 'Should call the expected mocks' { - Restart-ServiceIfExists @restartServiceIfExistsParams - Assert-MockCalled Get-Service -Exactly -Times 1 -Scope It -ParameterFilter { $Name -eq $restartServiceIfExistsParams.Name } - Assert-MockCalled Restart-Service -Exactly -Times 1 -Scope It - } + It 'Should call the expected mocks' { + Restart-ServiceIfExists @restartServiceIfExistsParams + + Should -Invoke -CommandName Get-Service -ParameterFilter { + $Name -eq $restartServiceIfExistsParams.Name + } -Exactly -Times 1 -Scope It + + Should -Invoke -CommandName Restart-Service -Exactly -Times 1 -Scope It } } } diff --git a/tests/Unit/DSC_AdcsAuthorityInformationAccess.Tests.ps1 b/tests/Unit/DSC_AdcsAuthorityInformationAccess.Tests.ps1 index c6f3ad4..f2e60bb 100644 --- a/tests/Unit/DSC_AdcsAuthorityInformationAccess.Tests.ps1 +++ b/tests/Unit/DSC_AdcsAuthorityInformationAccess.Tests.ps1 @@ -1,16 +1,39 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsAuthorityInformationAccess' +<# + .SYNOPSIS + Unit test for DSC_AdcsAuthorityInformationAccess DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceName = 'DSC_AdcsAuthorityInformationAccess' $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` @@ -19,918 +42,1271 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsAdministrationStub.psm1') + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsDeploymentStub.psm1') + + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName + + $script:AiaList = [System.String[]] @( + 'http://primary/Certs/.cer' + 'http://secondary/Certs/.cer' + ) + $script:OcspList = [System.String[]] @( + 'http://primary-ocsp-responder/ocsp' + 'http://secondary-ocsp-responder/ocsp' + ) + + InModuleScope -Parameters @{ + AiaList = $AiaList + OcspList = $OcspList + } -ScriptBlock { + $script:AiaList = $AiaList + $script:OcspList = $OcspList + } + + $script:getCaAiaUriListAiaMock = { + $AiaList + } + $script:getCaAiaUriListAiaParameterFilter = { + $ExtensionType -eq 'AddToCertificateAia' + } + $script:getCaAiaUriListOcspMock = { + $OcspList + } + $script:getCaAiaUriListOcspParameterFilter = { + $ExtensionType -eq 'AddToCertificateOcsp' + } + + $script:getTargetResourceMock = { + @{ + IsSingleInstance = 'Yes' + AiaUri = $AiaList + OcspUri = $OcspList + AllowRestartService = $false + } + } } -function Invoke-TestCleanup -{ +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force -} -Invoke-TestSetup - -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - $script:AiaList = [System.String[]] @( - 'http://primary/Certs/.cer' - 'http://secondary/Certs/.cer' - ) - $script:getCaAiaUriListAiaMock = { - $script:AiaList - } - $script:getCaAiaUriListAiaParameterFilter = { - $ExtensionType -eq 'AddToCertificateAia' - } - $script:OcspList = [System.String[]] @( - 'http://primary-ocsp-responder/ocsp' - 'http://secondary-ocsp-responder/ocsp' - ) - $script:getCaAiaUriListOcspMock = { - $script:OcspList - } - $script:getCaAiaUriListOcspParameterFilter = { - $ExtensionType -eq 'AddToCertificateOcsp' - } - $script:getTargetResourceMock = { - @{ - IsSingleInstance = 'Yes' - AiaUri = $script:AiaList - OcspUri = $script:OcspList - AllowRestartService = $false - } - } + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force + + Remove-Module -Name AdcsAdministrationStub -Force + Remove-Module -Name AdcsDeploymentStub -Force - Describe 'DSC_AdcsAuthorityInformationAccess\Get-TargetResource' -Tag 'Get' { + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'DSC_AdcsAuthorityInformationAccess\Get-TargetResource' -Tag 'Get' { + BeforeAll { + InModuleScope -ScriptBlock { $script:getTargetResourceParameters = @{ IsSingleInstance = 'Yes' - Verbose = $true } + } + } - Context 'When there are no AIA or OCSP URIs set' { - Mock -CommandName Get-CaAiaUriList ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith { @() } ` - -ParameterFilter $script:getCaAiaUriListOcspParameterFilter + Context 'When there are no AIA or OCSP URIs set' { + BeforeAll { + Mock -CommandName Get-CaAiaUriList ` + -MockWith { @() } ` + -ParameterFilter $getCaAiaUriListOcspParameterFilter - Mock -CommandName Get-CaAiaUriList ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith { @() } ` - -ParameterFilter $script:getCaAiaUriListAiaParameterFilter + Mock -CommandName Get-CaAiaUriList ` + -MockWith { @() } ` + -ParameterFilter $getCaAiaUriListAiaParameterFilter + } - It 'Should not throw an exception' { - { - $script:getTargetResourceResult = Get-TargetResource @script:getTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return expected hash table' { - $script:getTargetResourceResult.IsSingleInstance | Should -BeExactly 'Yes' - $script:getTargetResourceResult.AiaUri | Should -BeNullOrEmpty - $script:getTargetResourceResult.OcspUri | Should -BeNullOrEmpty - $script:getTargetResourceResult.AllowRestartService | Should -BeFalse - } + { + $script:getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When there are AIA and OCSP URIs set' { - Mock -CommandName Get-CaAiaUriList ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getCaAiaUriListOcspMock ` - -ParameterFilter $script:getCaAiaUriListOcspParameterFilter + It 'Should return expected hash table' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Mock -CommandName Get-CaAiaUriList ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getCaAiaUriListAiaMock ` - -ParameterFilter $script:getCaAiaUriListAiaParameterFilter + $getTargetResourceResult.IsSingleInstance | Should -BeExactly 'Yes' + $getTargetResourceResult.AiaUri | Should -BeNullOrEmpty + $getTargetResourceResult.OcspUri | Should -BeNullOrEmpty + $getTargetResourceResult.AllowRestartService | Should -BeFalse + } + } - It 'Should not throw an exception' { - { - $script:getTargetResourceResult = Get-TargetResource @script:getTargetResourceParameters - } | Should -Not -Throw - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CaAiaUriList ` + -Exactly -Times 2 -Scope Context + } + } - It 'Should return expected hash table' { - $script:getTargetResourceResult.IsSingleInstance | Should -BeExactly 'Yes' - $script:getTargetResourceResult.AiaUri | Should -BeExactly $script:AiaList - $script:getTargetResourceResult.OcspUri | Should -BeExactly $script:OcspList - $script:getTargetResourceResult.AllowRestartService | Should -BeFalse - } - } + Context 'When there are AIA and OCSP URIs set' { + BeforeAll { + Mock -CommandName Get-CaAiaUriList ` + -MockWith $getCaAiaUriListOcspMock ` + -ParameterFilter $getCaAiaUriListOcspParameterFilter + + Mock -CommandName Get-CaAiaUriList ` + -MockWith $getCaAiaUriListAiaMock ` + -ParameterFilter $getCaAiaUriListAiaParameterFilter } - Describe 'DSC_AdcsAuthorityInformationAccess\Set-TargetResource' -Tag 'Set' { - BeforeAll { - Mock -CommandName Add-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + { + $script:getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + } | Should -Not -Throw + } + } - Mock -CommandName Remove-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess + It 'Should return expected hash table' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Mock -CommandName Restart-ServiceIfExists ` - -ModuleName DSC_AdcsAuthorityInformationAccess + $getTargetResourceResult.IsSingleInstance | Should -BeExactly 'Yes' + $getTargetResourceResult.AiaUri | Should -BeExactly $AiaList + $getTargetResourceResult.OcspUri | Should -BeExactly $OcspList + $getTargetResourceResult.AllowRestartService | Should -BeFalse } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CaAiaUriList ` + -Exactly -Times 2 -Scope Context + } + } +} + +Describe 'DSC_AdcsAuthorityInformationAccess\Set-TargetResource' -Tag 'Set' { + BeforeAll { + Mock -CommandName Add-CAAuthorityInformationAccess - Context 'When AllowRestartService is true' { - Context 'When AIA and OCSP are passed but are both in the correct state' { - $setTargetResourceParameters = @{ + Mock -CommandName Remove-CAAuthorityInformationAccess + + Mock -CommandName Restart-ServiceIfExists + } + + Context 'When AllowRestartService is true' { + Context 'When AIA and OCSP are passed but are both in the correct state' { + BeforeAll { + InModuleScope -ScriptBlock { + + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList - OcspUri = $script:OcspList + AiaUri = $AiaList + OcspUri = $OcspList AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw + } + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -Exactly -Times 0 + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -Exactly -Times 0 -Scope Context - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -Exactly -Times 0 + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -Exactly -Times 0 -Scope Context - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -Exactly -Times 0 - } - } + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -Exactly -Times 0 -Scope Context - Context 'When AIA and OCSP are passed but OCSP is missing a URI' { - $setTargetResourceParameters = @{ + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When AIA and OCSP are passed but OCSP is missing a URI' { + BeforeAll { + InModuleScope -ScriptBlock { + + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList + ('http://tertiary/Certs/.cer') - OcspUri = $script:OcspList + AiaUri = $AiaList + ('http://tertiary/Certs/.cer') + OcspUri = $OcspList AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://tertiary/Certs/.cer' -and ` - $AddToCertificateAia -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -Exactly -Times 0 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -ParameterFilter { - $Name -eq 'CertSvc' - } ` - -Exactly -Times 1 - } + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When AIA and OCSP are passed but AIA is missing a URI' { - $setTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://tertiary/Certs/.cer' -and ` + $AddToCertificateAia -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -Exactly -Times 0 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -ParameterFilter { + $Name -eq 'CertSvc' + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When AIA and OCSP are passed but AIA is missing a URI' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList - OcspUri = $script:OcspList + @('http://tertiary-ocsp-responder/ocsp') + AiaUri = $AiaList + OcspUri = $OcspList + @('http://tertiary-ocsp-responder/ocsp') AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://tertiary-ocsp-responder/ocsp' -and ` - $AddToCertificateOcsp -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -Exactly -Times 0 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -ParameterFilter { - $Name -eq 'CertSvc' - } ` - -Exactly -Times 1 - } + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://tertiary-ocsp-responder/ocsp' -and ` + $AddToCertificateOcsp -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -Exactly -Times 0 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -ParameterFilter { + $Name -eq 'CertSvc' + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } - Context 'When AIA and OCSP are passed but OCSP has an extra URI' { - $setTargetResourceParameters = @{ + Context 'When AIA and OCSP are passed but OCSP has an extra URI' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' AiaUri = [System.String[]] @('http://primary/Certs/.cer') - OcspUri = $script:OcspList + OcspUri = $OcspList AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -Exactly -Times 0 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://secondary/Certs/.cer' -and ` - $AddToCertificateAia -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -ParameterFilter { - $Name -eq 'CertSvc' - } ` - -Exactly -Times 1 - } + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When AIA and OCSP are passed but AIA has an extra URI' { - $setTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -Exactly -Times 0 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://secondary/Certs/.cer' -and ` + $AddToCertificateAia -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -ParameterFilter { + $Name -eq 'CertSvc' + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When AIA and OCSP are passed but AIA has an extra URI' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList + AiaUri = $AiaList OcspUri = [System.String[]] @('http://primary-ocsp-responder/ocsp') AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock - - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -Exactly -Times 0 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://secondary-ocsp-responder/ocsp' -and ` - $AddToCertificateOcsp -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -ParameterFilter { - $Name -eq 'CertSvc' - } ` - -Exactly -Times 1 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When only AIA is passed but has different values' { - $setTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -Exactly -Times 0 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://secondary-ocsp-responder/ocsp' -and ` + $AddToCertificateOcsp -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -ParameterFilter { + $Name -eq 'CertSvc' + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When only AIA is passed but has different values' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' AiaUri = [System.String[]] @( 'http://secondary/Certs/.cer' 'http://tertiary/Certs/.cer' ) AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock - - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://tertiary/Certs/.cer' -and ` - $AddToCertificateAia -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://primary/Certs/.cer' -and ` - $AddToCertificateAia -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -ParameterFilter { - $Name -eq 'CertSvc' - } ` - -Exactly -Times 1 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When only OCSP is passed but has different values' { - $setTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://tertiary/Certs/.cer' -and ` + $AddToCertificateAia -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://primary/Certs/.cer' -and ` + $AddToCertificateAia -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -ParameterFilter { + $Name -eq 'CertSvc' + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When only OCSP is passed but has different values' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' OcspUri = [System.String[]] @( 'http://secondary-ocsp-responder/ocsp' 'http://tertiary-ocsp-responder/ocsp' ) AllowRestartService = $true - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock - - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://tertiary-ocsp-responder/ocsp' -and ` - $AddToCertificateOcsp -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://primary-ocsp-responder/ocsp' -and ` - $AddToCertificateOcsp -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -ParameterFilter { - $Name -eq 'CertSvc' - } ` - -Exactly -Times 1 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } } - Context 'When AllowRestartService is false' { - Context 'When only AIA is passed but has different values' { - $setTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://tertiary-ocsp-responder/ocsp' -and ` + $AddToCertificateOcsp -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://primary-ocsp-responder/ocsp' -and ` + $AddToCertificateOcsp -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -ParameterFilter { + $Name -eq 'CertSvc' + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + } + + Context 'When AllowRestartService is false' { + Context 'When only AIA is passed but has different values' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' AiaUri = [System.String[]] @( 'http://secondary/Certs/.cer' 'http://tertiary/Certs/.cer' ) AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://tertiary/Certs/.cer' -and ` - $AddToCertificateAia -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://primary/Certs/.cer' -and ` - $AddToCertificateAia -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -Exactly -Times 0 - } + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When only OCSP is passed but has different values' { - $setTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://tertiary/Certs/.cer' -and ` + $AddToCertificateAia -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://primary/Certs/.cer' -and ` + $AddToCertificateAia -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -Exactly -Times 0 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When only OCSP is passed but has different values' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:setTargetResourceParameters = @{ IsSingleInstance = 'Yes' OcspUri = [System.String[]] @( 'http://secondary-ocsp-responder/ocsp' 'http://tertiary-ocsp-responder/ocsp' ) AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Add-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://tertiary-ocsp-responder/ocsp' -and ` - $AddToCertificateOcsp -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Remove-CAAuthorityInformationAccess ` - -ParameterFilter { - $Uri -eq 'http://primary-ocsp-responder/ocsp' -and ` - $AddToCertificateOcsp -eq $true - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -Exactly -Times 0 - } + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw } } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Add-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://tertiary-ocsp-responder/ocsp' -and ` + $AddToCertificateOcsp -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Remove-CAAuthorityInformationAccess ` + -ParameterFilter { + $Uri -eq 'http://primary-ocsp-responder/ocsp' -and ` + $AddToCertificateOcsp -eq $true + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -Exactly -Times 0 -Scope Context + + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } } + } +} - Describe 'DSC_AdcsAuthorityInformationAccess\Test-TargetResource' -Tag 'Test' { - Context 'When AIA and OCSP are passed and in the desired state' { - $testTargetResourceParameters = @{ +Describe 'DSC_AdcsAuthorityInformationAccess\Test-TargetResource' -Tag 'Test' { + Context 'When AIA and OCSP are passed and in the desired state' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList - OcspUri = $script:OcspList + AiaUri = $AiaList + OcspUri = $OcspList AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw + } + } - It 'Should return true' { - $script:testTargetResourceResult | Should -BeTrue - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeTrue } + } - Context 'When AIA and OCSP are passed and OCSP contains an extra value' { - $testTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When AIA and OCSP are passed and OCSP contains an extra value' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList - OcspUri = $script:OcspList + @('http://tertiary-ocsp-responder/ocsp') + AiaUri = $AiaList + OcspUri = $OcspList + @('http://tertiary-ocsp-responder/ocsp') AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return false' { - $script:testTargetResourceResult | Should -BeFalse - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When AIA and OCSP are passed and AIA contains an extra value' { - $testTargetResourceParameters = @{ + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeFalse + } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When AIA and OCSP are passed and AIA contains an extra value' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList + ('http://tertiary/Certs/.cer') - OcspUri = $script:OcspList + AiaUri = $AiaList + ('http://tertiary/Certs/.cer') + OcspUri = $OcspList AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return false' { - $script:testTargetResourceResult | Should -BeFalse - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When AIA and OCSP are passed and both AIA and OCSP contains extra values' { - $testTargetResourceParameters = @{ - IsSingleInstance = 'Yes' - AiaUri = $script:AiaList + ('http://tertiary/Certs/.cer') - OcspUri = $script:OcspList + @('http://tertiary-ocsp-responder/ocsp') - AllowRestartService = $false - Verbose = $true - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + $testTargetResourceResult | Should -BeFalse + } + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } - It 'Should return false' { - $script:testTargetResourceResult | Should -BeFalse - } + Context 'When AIA and OCSP are passed and both AIA and OCSP contains extra values' { + BeforeAll { + $script:testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + AiaUri = $AiaList + ('http://tertiary/Certs/.cer') + OcspUri = $OcspList + @('http://tertiary-ocsp-responder/ocsp') + AllowRestartService = $false } - Context 'When AIA and OCSP are passed and OCSP is empty' { - $testTargetResourceParameters = @{ - IsSingleInstance = 'Yes' - AiaUri = $script:AiaList - OcspUri = [System.String[]] @() - AllowRestartService = $false - Verbose = $true - } + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw + } + } - It 'Should return false' { - $script:testTargetResourceResult | Should -BeFalse - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeFalse } + } - Context 'When AIA and OCSP are passed and AIA is empty' { - $testTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When AIA and OCSP are passed and OCSP is empty' { + BeforeAll { + $testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + AiaUri = $AiaList + OcspUri = [System.String[]] @() + AllowRestartService = $false + } + + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } + + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw + } + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeFalse + } + } + } + + Context 'When AIA and OCSP are passed and AIA is empty' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' AiaUri = [System.String[]] @() - OcspUri = $script:OcspList + OcspUri = $OcspList AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return false' { - $script:testTargetResourceResult | Should -BeFalse - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeFalse + } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } - Context 'When AIA and OCSP are passed and both AIA and OCSP are empty' { - $testTargetResourceParameters = @{ + Context 'When AIA and OCSP are passed and both AIA and OCSP are empty' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' AiaUri = [System.String[]] @() OcspUri = [System.String[]] @() AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return false' { - $script:testTargetResourceResult | Should -BeFalse - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeFalse + } + } - Context 'When only AIA is passed and is in desired state' { - $testTargetResourceParameters = @{ + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When only AIA is passed and is in desired state' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' - AiaUri = $script:AiaList + AiaUri = $AiaList AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return true' { - $script:testTargetResourceResult | Should -BeTrue - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } + } - Context 'When only OCSP is passed and is in desired state' { - $testTargetResourceParameters = @{ + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeTrue + } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When only OCSP is passed and is in desired state' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:testTargetResourceParameters = @{ IsSingleInstance = 'Yes' - OcspUri = $script:OcspList + OcspUri = $OcspList AllowRestartService = $false - Verbose = $true } + } - Mock -CommandName Get-TargetResource ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $script:getTargetResourceMock + Mock -CommandName Get-TargetResource ` + -MockWith $getTargetResourceMock + } - It 'Should not throw an exception' { - { - $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters - } | Should -Not -Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return true' { - $script:testTargetResourceResult | Should -BeTrue - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } } - Describe 'DSC_AdcsAuthorityInformationAccess\Get-CaAiaUriList' { - Context 'When ExtensionType is AddToCertificateAia and there are only AddToCertificateOcsp URIs' { - $getCAAuthorityInformationAccessMock = { - @( - [PSCustomObject] @{ - AddToCertificateAia = $false - AddToCertificateOcsp = $true - Uri = 'http://primary-ocsp-responder/ocsp' - } - ) - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Mock ` - -CommandName Get-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $getCAAuthorityInformationAccessMock + $testTargetResourceResult | Should -BeTrue + } + } - It 'Should not throw an exception' { - { - $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateAia' -Verbose - } | Should -Not -Throw - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -Exactly -Times 1 -Scope Context + } + } +} - It 'Should return null' { - $script:getCaAiaUriListResult | Should -BeNullOrEmpty - } +Describe 'DSC_AdcsAuthorityInformationAccess\Get-CaAiaUriList' { + Context 'When ExtensionType is AddToCertificateAia and there are only AddToCertificateOcsp URIs' { + BeforeAll { + $getCAAuthorityInformationAccessMock = { + @( + [PSCustomObject] @{ + AddToCertificateAia = $false + AddToCertificateOcsp = $true + Uri = 'http://primary-ocsp-responder/ocsp' + } + ) } - Context 'When ExtensionType is AddToCertificateAia and there is AddToCertificateAia URI and one AddToCertificateOcsp URI' { - $getCAAuthorityInformationAccessMock = { - @( - [PSCustomObject] @{ - AddToCertificateAia = $false - AddToCertificateOcsp = $true - Uri = 'http://primary-ocsp-responder/ocsp' - }, - [PSCustomObject] @{ - AddToCertificateAia = $true - AddToCertificateOcsp = $false - Uri = 'http://primary/Certs/.cer' - } - ) - } + Mock ` + -CommandName Get-CAAuthorityInformationAccess ` + -MockWith $getCAAuthorityInformationAccessMock + } - Mock ` - -CommandName Get-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $getCAAuthorityInformationAccessMock + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should not throw an exception' { - { - $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateAia' -Verbose - } | Should -Not -Throw - } + { + $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateAia' + } | Should -Not -Throw + } + } - It 'Should return null' { - $script:getCaAiaUriListResult | Should -BeExactly 'http://primary/Certs/.cer' - } + It 'Should return null' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getCaAiaUriListResult | Should -BeNullOrEmpty } + } - Context 'When ExtensionType is AddToCertificateAia and there is AddToCertificateAia URI and two AddToCertificateOcsp URIs' { - $getCAAuthorityInformationAccessMock = { - @( - [PSCustomObject] @{ - AddToCertificateAia = $false - AddToCertificateOcsp = $true - Uri = 'http://primary-ocsp-responder/ocsp' - }, - [PSCustomObject] @{ - AddToCertificateAia = $true - AddToCertificateOcsp = $false - Uri = 'http://primary/Certs/.cer' - }, - [PSCustomObject] @{ - AddToCertificateAia = $true - AddToCertificateOcsp = $false - Uri = 'http://secondary/Certs/.cer' - } - ) - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CAAuthorityInformationAccess ` + -Exactly -Times 1 -Scope Context + } + } - Mock ` - -CommandName Get-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $getCAAuthorityInformationAccessMock + Context 'When ExtensionType is AddToCertificateAia and there is AddToCertificateAia URI and one AddToCertificateOcsp URI' { + BeforeAll { + $getCAAuthorityInformationAccessMock = { + @( + [PSCustomObject] @{ + AddToCertificateAia = $false + AddToCertificateOcsp = $true + Uri = 'http://primary-ocsp-responder/ocsp' + }, + [PSCustomObject] @{ + AddToCertificateAia = $true + AddToCertificateOcsp = $false + Uri = 'http://primary/Certs/.cer' + } + ) + } - It 'Should not throw an exception' { - { - $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateAia' -Verbose - } | Should -Not -Throw - } + Mock ` + -CommandName Get-CAAuthorityInformationAccess ` + -MockWith $getCAAuthorityInformationAccessMock + } - It 'Should return null' { - $script:getCaAiaUriListResult[0] | Should -BeExactly 'http://primary/Certs/.cer' - $script:getCaAiaUriListResult[1] | Should -BeExactly 'http://secondary/Certs/.cer' - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateAia' + } | Should -Not -Throw } + } - Context 'When ExtensionType is AddToCertificateOcsp and there are only AddToCertificateAia URIs' { - $getCAAuthorityInformationAccessMock = { - @( - [PSCustomObject] @{ - AddToCertificateAia = $true - AddToCertificateOcsp = $false - Uri = 'http://primary/Certs/.cer' - } - ) - } + It 'Should return null' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Mock ` - -CommandName Get-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $getCAAuthorityInformationAccessMock + $getCaAiaUriListResult | Should -BeExactly 'http://primary/Certs/.cer' + } + } - It 'Should not throw an exception' { - { - $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateOcsp' -Verbose - } | Should -Not -Throw - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CAAuthorityInformationAccess ` + -Exactly -Times 1 -Scope Context + } + } - It 'Should return null' { - $script:getCaAiaUriListResult | Should -BeNullOrEmpty - } + Context 'When ExtensionType is AddToCertificateAia and there is AddToCertificateAia URI and two AddToCertificateOcsp URIs' { + BeforeAll { + $getCAAuthorityInformationAccessMock = { + @( + [PSCustomObject] @{ + AddToCertificateAia = $false + AddToCertificateOcsp = $true + Uri = 'http://primary-ocsp-responder/ocsp' + }, + [PSCustomObject] @{ + AddToCertificateAia = $true + AddToCertificateOcsp = $false + Uri = 'http://primary/Certs/.cer' + }, + [PSCustomObject] @{ + AddToCertificateAia = $true + AddToCertificateOcsp = $false + Uri = 'http://secondary/Certs/.cer' + } + ) } - Context 'When ExtensionType is AddToCertificateOcsp and there is AddToCertificateOcsp URI and one AddToCertificateAia URI' { - $getCAAuthorityInformationAccessMock = { - @( - [PSCustomObject] @{ - AddToCertificateAia = $false - AddToCertificateOcsp = $true - Uri = 'http://primary-ocsp-responder/ocsp' - }, - [PSCustomObject] @{ - AddToCertificateAia = $true - AddToCertificateOcsp = $false - Uri = 'http://primary/Certs/.cer' - } - ) - } + Mock ` + -CommandName Get-CAAuthorityInformationAccess ` + -MockWith $getCAAuthorityInformationAccessMock + } - Mock ` - -CommandName Get-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $getCAAuthorityInformationAccessMock + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should not throw an exception' { - { - $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateOcsp' -Verbose - } | Should -Not -Throw - } + { + $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateAia' + } | Should -Not -Throw + } + } - It 'Should return null' { - $script:getCaAiaUriListResult | Should -BeExactly 'http://primary-ocsp-responder/ocsp' - } + It 'Should return null' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getCaAiaUriListResult[0] | Should -BeExactly 'http://primary/Certs/.cer' + $getCaAiaUriListResult[1] | Should -BeExactly 'http://secondary/Certs/.cer' } + } - Context 'When ExtensionType is AddToCertificateOcsp and there is AddToCertificateOcsp URI and two AddToCertificateAia URIs' { - $getCAAuthorityInformationAccessMock = { - @( - [PSCustomObject] @{ - AddToCertificateAia = $false - AddToCertificateOcsp = $true - Uri = 'http://primary-ocsp-responder/ocsp' - }, - [PSCustomObject] @{ - AddToCertificateAia = $false - AddToCertificateOcsp = $true - Uri = 'http://secondary-ocsp-responder/ocsp' - }, - [PSCustomObject] @{ - AddToCertificateAia = $true - AddToCertificateOcsp = $false - Uri = 'http://primary/Certs/.cer' - } - ) - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CAAuthorityInformationAccess ` + -Exactly -Times 1 -Scope Context + } + } - Mock ` - -CommandName Get-CAAuthorityInformationAccess ` - -ModuleName DSC_AdcsAuthorityInformationAccess ` - -MockWith $getCAAuthorityInformationAccessMock + Context 'When ExtensionType is AddToCertificateOcsp and there are only AddToCertificateAia URIs' { + BeforeAll { + $getCAAuthorityInformationAccessMock = { + @( + [PSCustomObject] @{ + AddToCertificateAia = $true + AddToCertificateOcsp = $false + Uri = 'http://primary/Certs/.cer' + } + ) + } - It 'Should not throw an exception' { - { - $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateOcsp' -Verbose - } | Should -Not -Throw - } + Mock ` + -CommandName Get-CAAuthorityInformationAccess ` + -MockWith $getCAAuthorityInformationAccessMock + } - It 'Should return null' { - $script:getCaAiaUriListResult[0] | Should -BeExactly 'http://primary-ocsp-responder/ocsp' - $script:getCaAiaUriListResult[1] | Should -BeExactly 'http://secondary-ocsp-responder/ocsp' - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateOcsp' + } | Should -Not -Throw + } + } + + It 'Should return null' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getCaAiaUriListResult | Should -BeNullOrEmpty } } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CAAuthorityInformationAccess ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When ExtensionType is AddToCertificateOcsp and there is AddToCertificateOcsp URI and one AddToCertificateAia URI' { + BeforeAll { + $getCAAuthorityInformationAccessMock = { + @( + [PSCustomObject] @{ + AddToCertificateAia = $false + AddToCertificateOcsp = $true + Uri = 'http://primary-ocsp-responder/ocsp' + }, + [PSCustomObject] @{ + AddToCertificateAia = $true + AddToCertificateOcsp = $false + Uri = 'http://primary/Certs/.cer' + } + ) + } + + Mock ` + -CommandName Get-CAAuthorityInformationAccess ` + -MockWith $getCAAuthorityInformationAccessMock + } + + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateOcsp' + } | Should -Not -Throw + } + } + + It 'Should return null' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getCaAiaUriListResult | Should -BeExactly 'http://primary-ocsp-responder/ocsp' + } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CAAuthorityInformationAccess ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When ExtensionType is AddToCertificateOcsp and there is AddToCertificateOcsp URI and two AddToCertificateAia URIs' { + BeforeAll { + $getCAAuthorityInformationAccessMock = { + @( + [PSCustomObject] @{ + AddToCertificateAia = $false + AddToCertificateOcsp = $true + Uri = 'http://primary-ocsp-responder/ocsp' + }, + [PSCustomObject] @{ + AddToCertificateAia = $false + AddToCertificateOcsp = $true + Uri = 'http://secondary-ocsp-responder/ocsp' + }, + [PSCustomObject] @{ + AddToCertificateAia = $true + AddToCertificateOcsp = $false + Uri = 'http://primary/Certs/.cer' + } + ) + } + + Mock ` + -CommandName Get-CAAuthorityInformationAccess ` + -MockWith $getCAAuthorityInformationAccessMock + } + + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:getCaAiaUriListResult = Get-CaAiaUriList -ExtensionType 'AddToCertificateOcsp' + } | Should -Not -Throw + } + } + + It 'Should return the correct URIs' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getCaAiaUriListResult[0] | Should -BeExactly 'http://primary-ocsp-responder/ocsp' + $getCaAiaUriListResult[1] | Should -BeExactly 'http://secondary-ocsp-responder/ocsp' + } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Get-CAAuthorityInformationAccess ` + -Exactly -Times 1 -Scope Context + } } -} -finally -{ - Invoke-TestCleanup } diff --git a/tests/Unit/DSC_AdcsCertificationAuthority.Tests.ps1 b/tests/Unit/DSC_AdcsCertificationAuthority.Tests.ps1 index b95c793..96e033b 100644 --- a/tests/Unit/DSC_AdcsCertificationAuthority.Tests.ps1 +++ b/tests/Unit/DSC_AdcsCertificationAuthority.Tests.ps1 @@ -1,16 +1,39 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsCertificationAuthority' +<# + .SYNOPSIS + Unit test for DSC_AdcsCertificationAuthority DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceName = 'DSC_AdcsCertificationAuthority' $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` @@ -19,438 +42,406 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') -} + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsDeploymentStub.psm1') -function Invoke-TestCleanup -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force -} + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName -Invoke-TestSetup - -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException').Type) - { - <# + # Add Custom Type + if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException').Type) + { + <# Define the exception class: Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException so that unit tests can be run without ADCS being installed. #> - $exceptionDefinition = @' + $exceptionDefinition = @' namespace Microsoft.CertificateServices.Deployment.Common.CA { public class CertificationAuthoritySetupException: System.Exception { } } '@ - Add-Type -TypeDefinition $exceptionDefinition - } + Add-Type -TypeDefinition $exceptionDefinition + } - $dummyCredential = New-Object System.Management.Automation.PSCredential ("Administrator", (New-Object -Type SecureString)) + # Add Test Data + InModuleScope -ScriptBlock { + $dummyCredential = New-Object System.Management.Automation.PSCredential ('Administrator', (New-Object -Type SecureString)) - $testParametersPresent = @{ + $script:testParametersPresent = @{ IsSingleInstance = 'Yes' Ensure = 'Present' CAType = 'StandaloneRootCA' Credential = $dummyCredential - Verbose = $true + Verbose = $false } - $testParametersAbsent = @{ + $script:testParametersAbsent = @{ IsSingleInstance = 'Yes' Ensure = 'Absent' CAType = 'StandaloneRootCA' Credential = $dummyCredential - Verbose = $true + Verbose = $false } + } +} - function Install-AdcsCertificationAuthority - { - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $True)] - [ValidateSet('EnterpriseRootCA', 'EnterpriseSubordinateCA', 'StandaloneRootCA', 'StandaloneSubordinateCA')] - [System.String] - $CAType, - - [Parameter(Mandatory = $True)] - [System.Management.Automation.PSCredential] - $Credential, - - [Parameter()] - [System.String] - $CACommonName, - - [Parameter()] - [System.String] - $CADistinguishedNameSuffix, - - [Parameter()] - [System.String] - $CertFile, - - [Parameter()] - [System.Management.Automation.PSCredential] - $CertFilePassword, - - [Parameter()] - [System.String] - $CertificateID, - - [Parameter()] - [System.String] - $CryptoProviderName, - - [Parameter()] - [System.String] - $DatabaseDirectory, - - [Parameter()] - [System.String] - $HashAlgorithmName, - - [Parameter()] - [System.Boolean] - $IgnoreUnicode, - - [Parameter()] - [System.String] - $KeyContainerName, - - [Parameter()] - [System.UInt32] - $KeyLength, - - [Parameter()] - [System.String] - $LogDirectory, - - [Parameter()] - [System.String] - $OutputCertRequestFile, - - [Parameter()] - [System.Boolean] - $OverwriteExistingCAinDS, - - [Parameter()] - [System.Boolean] - $OverwriteExistingDatabase, - - [Parameter()] - [System.Boolean] - $OverwriteExistingKey, - - [Parameter()] - [System.String] - $ParentCA, - - [Parameter()] - [ValidateSet('Hours', 'Days', 'Months', 'Years')] - [System.String] - $ValidityPeriod, - - [Parameter()] - [System.UInt32] - $ValidityPeriodUnits, - - [Parameter()] - [Switch] - $Force, - - [Parameter()] - [Switch] - $WhatIf - ) - } - - function Uninstall-AdcsCertificationAuthority - { - [CmdletBinding()] - param - ( - [Parameter()] - [Switch] - $Force - ) - } - - Describe 'DSC_AdcsCertificationAuthority\Get-TargetResource' { - Context 'When the CA is installed' { - Mock ` - -CommandName Install-AdcsCertificationAuthority ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException') } ` - -Verifiable - - $result = Get-TargetResource @testParametersPresent - - It 'Should return Ensure set to Present' { - $result.Ensure | Should -Be 'Present' - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force + + Remove-Module -Name AdcsDeploymentStub -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + + +Describe 'DSC_AdcsCertificationAuthority\Get-TargetResource' -Tag 'Get' { + Context 'When the CA is installed' { + BeforeAll { + Mock ` + -CommandName Install-AdcsCertificationAuthority ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException') } ` + -Verifiable + } + + + It 'Should return Ensure set to Present' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource @script:testParametersPresent + $result.Ensure | Should -Be 'Present' } + } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } - Context 'When the CA is not installed' { - Mock -CommandName Install-AdcsCertificationAuthority + Context 'When the CA is not installed' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority + } - $result = Get-TargetResource @testParametersPresent - It 'Should return Ensure set to Absent' { - $result.Ensure | Should -Be 'Absent' - } + It 'Should return Ensure set to Absent' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + $result = Get-TargetResource @script:testParametersPresent + $result.Ensure | Should -Be 'Absent' } + } - Context 'When there is an unexpected error' { - Mock ` - -CommandName Install-AdcsCertificationAuthority ` - -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` - -Verifiable + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } - It 'Should throw an exception' { - { Get-TargetResource @testParametersPresent } | Should Throw - } + Context 'When there is an unexpected error' { + BeforeAll { + Mock ` + -CommandName Install-AdcsCertificationAuthority ` + -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` + -Verifiable + } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + { Get-TargetResource @script:testParametersPresent } | Should -Throw } } - Describe 'DSC_AdcsCertificationAuthority\Set-TargetResource' { - Context 'When theCA is not installed but should be' { - Mock -CommandName Install-AdcsCertificationAuthority - Mock -CommandName Uninstall-AdcsCertificationAuthority + It 'Should call expected mocks' { + Should -InvokeVerifiable - It 'Should not throw an exception' { - { Set-TargetResource @testParametersPresent } | Should Not Throw - } + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } +} - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 +Describe 'DSC_AdcsCertificationAuthority\Set-TargetResource' -Tag 'Set' { + Context 'When the CA is not installed but should be' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority + Mock -CommandName Uninstall-AdcsCertificationAuthority + } - Assert-MockCalled ` - -CommandName Uninstall-AdcsCertificationAuthority ` - -Exactly ` - -Times 0 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Set-TargetResource @script:testParametersPresent } | Should -Not -Throw } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context - Context 'When the CA is not installed but should be but an error is thrown installing it' { - Mock ` - -CommandName Install-AdcsCertificationAuthority ` - -MockWith { [PSObject] @{ErrorString = 'Something went wrong' } } + Should -Invoke ` + -CommandName Uninstall-AdcsCertificationAuthority ` + -Exactly ` + -Times 0 -Scope Context + } + } - Mock -CommandName Uninstall-AdcsCertificationAuthority + Context 'When the CA is not installed but should be but an error is thrown installing it' { + BeforeAll { + Mock ` + -CommandName Install-AdcsCertificationAuthority ` + -MockWith { [PSObject] @{ErrorString = 'Something went wrong' } } - It 'Should throw exception' { - $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + Mock -CommandName Uninstall-AdcsCertificationAuthority + } - { Set-TargetResource @testParametersPresent } | Should Throw $errorRecord - } + It 'Should throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 + $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' - Assert-MockCalled ` - -CommandName Uninstall-AdcsCertificationAuthority ` - -Exactly ` - -Times 0 - } + { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord } + } - Context 'When CA is multi tier and error should not throw for ErrorString with specific text' { - Mock ` - -CommandName Install-AdcsCertificationAuthority ` - -MockWith { [PSObject] @{ ErrorString = 'The Active Directory Certificate Services installation is incomplete' } } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context - It 'Should not throw exception' { + Should -Invoke ` + -CommandName Uninstall-AdcsCertificationAuthority ` + -Exactly ` + -Times 0 -Scope Context + } + } - { Set-TargetResource @testParametersPresent } | Should Not Throw - } + Context 'When CA is multi tier and error should not throw for ErrorString with specific text' { + BeforeAll { + Mock ` + -CommandName Install-AdcsCertificationAuthority ` + -MockWith { [PSObject] @{ ErrorString = 'The Active Directory Certificate Services installation is incomplete' } } + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + It 'Should not throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Set-TargetResource @testParametersPresent } | Should -Not -Throw } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When CA is multi tier and error should not throw for Error ID 398' { + BeforeAll { + Mock ` + -CommandName Install-AdcsCertificationAuthority ` + -MockWith { [PSObject] @{ + ErrorID = 398 + ErrorString = 'Something went wrong' + } } + } - Context 'When CA is multi tier and error should not throw for Error ID 398' { - Mock ` - -CommandName Install-AdcsCertificationAuthority ` - -MockWith { [PSObject] @{ - ErrorID = 398 - ErrorString = 'Something went wrong' - } } - - It 'Should not throw exception' { - - { Set-TargetResource @testParametersPresent } | Should Not Throw - } - - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + It 'Should not throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Set-TargetResource @testParametersPresent } | Should -Not -Throw } + } + + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the CA is installed but should not be' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority + Mock -CommandName Uninstall-AdcsCertificationAuthority + } - Context 'When the CA is installed but should not be' { - Mock -CommandName Install-AdcsCertificationAuthority - Mock -CommandName Uninstall-AdcsCertificationAuthority - - It 'Should not throw an exception' { - { Set-TargetResource @testParametersAbsent } | Should Not Throw - } - - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 0 - - Assert-MockCalled ` - -CommandName Uninstall-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Set-TargetResource @testParametersAbsent } | Should -Not -Throw } } - Describe 'DSC_AdcsCertificationAuthority\Test-TargetResource' { - Context 'When the CA is installed and should be' { - Mock -CommandName Install-AdcsCertificationAuthority ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException') } ` - -Verifiable + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 0 -Scope Context - $result = Test-TargetResource @testParametersPresent + Should -Invoke ` + -CommandName Uninstall-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } +} + +Describe 'DSC_AdcsCertificationAuthority\Test-TargetResource' -Tag 'Test' { + Context 'When the CA is installed and should be' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException') } ` + -Verifiable + } - It 'Should return true' { - $result | Should -BeTrue - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Test-TargetResource @testParametersPresent + $result | Should -BeTrue } + } - Context 'When the CA is installed but should not be' { - Mock -CommandName Install-AdcsCertificationAuthority ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException') } ` - -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } - $result = Test-TargetResource @testParametersAbsent + Context 'When the CA is installed but should not be' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupException') } ` + -Verifiable + } - It 'Should return false' { - $result | Should -BeFalse - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Test-TargetResource @testParametersAbsent + $result | Should -BeFalse } + } - Context 'When the CA is not installed but should be' { - Mock -CommandName Install-AdcsCertificationAuthority ` - -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } - $result = Test-TargetResource @testParametersPresent + Context 'When the CA is not installed but should be' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority ` + -Verifiable + } - It 'Should return false' { - $result | Should -BeFalse - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Test-TargetResource @testParametersPresent + $result | Should -BeFalse } + } - Context 'When the CA is not installed and should not be' { - Mock -CommandName Install-AdcsCertificationAuthority ` - -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } - $result = Test-TargetResource @testParametersAbsent + Context 'When the CA is not installed and should not be' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority ` + -Verifiable + } - It 'Should return true' { - $result | Should -BeTrue - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Test-TargetResource @testParametersAbsent + $result | Should -BeTrue } + } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } + } - Context 'Should throw on any other error' { - Mock -CommandName Install-AdcsCertificationAuthority ` - -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` - -Verifiable - - It 'Should throw an exception' { - { Test-TargetResource @testParametersPresent } | Should Throw - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsCertificationAuthority ` - -Exactly ` - -Times 1 - } + Context 'Should throw on any other error' { + BeforeAll { + Mock -CommandName Install-AdcsCertificationAuthority ` + -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` + -Verifiable + } + + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Test-TargetResource @testParametersPresent } | Should -Throw } } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsCertificationAuthority ` + -Exactly ` + -Times 1 -Scope Context + } } } -finally -{ - Invoke-TestCleanup -} diff --git a/tests/Unit/DSC_AdcsCertificationAuthoritySettings.Tests.ps1 b/tests/Unit/DSC_AdcsCertificationAuthoritySettings.Tests.ps1 index 8925fde..2fdaa23 100644 --- a/tests/Unit/DSC_AdcsCertificationAuthoritySettings.Tests.ps1 +++ b/tests/Unit/DSC_AdcsCertificationAuthoritySettings.Tests.ps1 @@ -1,17 +1,70 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsCertificationAuthoritySettings' +<# + .SYNOPSIS + Unit test for DSC_AdcsCertificationAuthoritySettings DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } + #Test moving test data to Discovery + + $parameterData = Import-LocalizedData ` + -BaseDirectory (Join-Path -Path $PSScriptRoot -ChildPath '..\..\source\DSCResources\DSC_AdcsCertificationAuthoritySettings\')` + -FileName 'DSC_AdcsCertificationAuthoritySettings.data.psd1' + + # Assemble test mocks and parameter splats + $script:baseParameterCurrentList = @{ } + $script:baseParameterMockedList = @{ } + $script:settingsList = @() + + foreach ($parameter in $parameterData.GetEnumerator()) + { + $script:baseParameterCurrentList += @{ + $parameter.Name = $parameter.Value.CurrentValue + } + + $script:baseParameterMockedList += @{ + $parameter.Name = $parameter.Value.MockedValue + } + + $script:settingsList += @{ + Name = $parameter.Key; + CurrentValue = $parameter.Value.CurrentValue; + NewValue = $parameter.Value.NewValue; + MockedValue = $parameter.Value.MockedValue; + SetValue = $parameter.Value.SetValue; + } + } +} + +BeforeAll { + $script:dscResourceName = 'DSC_AdcsCertificationAuthoritySettings' + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` -DSCResourceName $script:dscResourceName ` @@ -19,448 +72,519 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName + + # Test Data + $script:certificateAuthorityActiveName = 'CONTOSO-CA' + $script:certificateAuthorityRegistrySettingsPath = 'HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration' + + $script:certificateAuthorityRegistrySettingsActivePath = Join-Path ` + -Path $certificateAuthorityRegistrySettingsPath ` + -ChildPath $certificateAuthorityActiveName + + $script:getItemPropertyValueExistsMock = { + $script:certificateAuthorityActiveName + } + + $script:getItemPropertyValueExistsParameterFilter = { + $Path -eq $certificateAuthorityRegistrySettingsPath -and ` + $Name -eq 'Active' + } + + $script:getItemPropertyParameterFilter = { + $Path -eq $certificateAuthorityRegistrySettingsActivePath + } + + $script:getItemPropertyMock = { + return $baseParameterMockedList + } } -function Invoke-TestCleanup -{ +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force } -Invoke-TestSetup +Describe 'DSC_AdcsCertificationAuthoritySettings\Get-TargetResource' -Tag 'Get' { + BeforeAll { + InModuleScope -ScriptBlock { + $script:getTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + } + } + } -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - # Create the Mock Objects that will be used for running tests - $script:certificateAuthorityActiveName = 'CONTOSO-CA' - $script:certificateAuthorityRegistrySettingsActivePath = Join-Path ` - -Path $script:certificateAuthorityRegistrySettingsPath ` - -ChildPath $script:certificateAuthorityActiveName + Context 'When Active Directory Certification Authority is installed' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue ` + -MockWith $getItemPropertyValueExistsMock - # Assemble test mocks and parameter splats - $script:baseParameterCurrentList = @{ } - $script:baseParameterMockedList = @{ } + Mock -CommandName Get-ItemProperty ` + -MockWith $getItemPropertyMock + } + + It 'Should not throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + } | Should -Not -Throw - foreach ($parameter in $script:parameterList.GetEnumerator()) - { - $script:baseParameterCurrentList += @{ - $parameter.Name = $parameter.Value.CurrentValue } + } + + It 'Should return correct Active Directory Certification Authority setting ' -ForEach $settingsList { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getTargetResourceResult.$($Name) | Should -Be $CurrentValue + } + } + + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-ItemProperty ` + -ParameterFilter $getItemPropertyParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When Active Directory Certification Authority is not installed' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue + } - $script:baseParameterMockedList += @{ - $parameter.Name = $parameter.Value.MockedValue + It 'Should throw expected exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $exception = Get-ObjectNotFoundException -Message ($script:localizedData.CertificateAuthorityNoneActive -f ` + $script:certificateAuthorityRegistrySettingsPath) + { Get-TargetResource @script:getTargetResourceParameters } | Should -Throw $exception } } - $script:getTargetResourceParameters = @{ - IsSingleInstance = 'Yes' - Verbose = $True + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context } + } +} - $script:testAndSetTargetResourceParameters = @{ - IsSingleInstance = 'Yes' - Verbose = $True - } + $script:baseParameterCurrentList +Describe 'DSC_AdcsCertificationAuthoritySettings\Set-TargetResource' -Tag 'Set' { + BeforeAll { + InModuleScope -Parameters @{ + baseTestParameters = $baseParameterCurrentList + } -ScriptBlock { - $getItemPropertyValueExistsMock = { - $script:certificateAuthorityActiveName + $script:setTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + } + $baseTestParameters } + } + + Context 'When all Active Directory Certification Authority settings are in the correct state' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue ` + -MockWith $getItemPropertyValueExistsMock - $getItemPropertyValueExistsParameterFilter = { - $Path -eq $script:certificateAuthorityRegistrySettingsPath -and ` - $Name -eq 'Active' + Mock -CommandName Get-ItemProperty ` + -MockWith $getItemPropertyMock + + Mock -CommandName Set-CertificateAuthoritySetting } - $getItemPropertyParameterFilter = { - $Path -eq $script:certificateAuthorityRegistrySettingsActivePath + It 'Should not throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw + } } - $getItemPropertyMock = { - return $script:baseParameterMockedList + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-ItemProperty ` + -ParameterFilter $getItemPropertyParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Set-CertificateAuthoritySetting ` + -Exactly -Times 0 -Scope Context } + } - Describe 'DSC_AdcsCertificationAuthoritySettings\Get-TargetResource' { - Context 'When Active Directory Certification Authority is installed' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue ` - -MockWith $getItemPropertyValueExistsMock + Context 'When all Active Directory Certification Authority settings are in the correct state except ' -ForEach $settingsList { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue ` + -MockWith $getItemPropertyValueExistsMock - Mock -CommandName Get-ItemProperty ` - -MockWith $getItemPropertyMock - } + Mock -CommandName Get-ItemProperty ` + -MockWith $getItemPropertyMock - It 'Should not throw exception' { - { - $script:getTargetResourceResult = Get-TargetResource @script:getTargetResourceParameters - } | Should -Not -Throw - } + Mock -CommandName Set-CertificateAuthoritySetting - It 'Should return Active Directory Certification Authority settings' { - foreach ($parameter in $script:parameterList.GetEnumerator()) - { - $script:getTargetResourceResult.$($parameter.Name) | Should -Be $parameter.Value.CurrentValue - } - } + Mock -CommandName Restart-ServiceIfExists + } - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 + It 'Should not throw exception' { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Get-ItemProperty ` - -ParameterFilter $getItemPropertyParameterFilter ` - -Exactly -Times 1 - } + { + $currentSetTargetResourceParameters = @{ } + $setTargetResourceParameters + $currentSetTargetResourceParameters.$($Name) = $NewValue + Set-TargetResource @currentSetTargetResourceParameters + } | Should -Not -Throw } + } + + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-ItemProperty ` + -ParameterFilter $getItemPropertyParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Set-CertificateAuthoritySetting ` + -ParameterFilter { + $Name -eq $Name -and ` + $Value -eq $SetValue + } ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Restart-ServiceIfExists ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When Active Directory Certification Authority is not installed' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue + } - Context 'When Active Directory Certification Authority is not installed' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue - } + It 'Should throw expected exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 $exception = Get-ObjectNotFoundException -Message ($script:localizedData.CertificateAuthorityNoneActive -f ` $script:certificateAuthorityRegistrySettingsPath) - It 'Should throw expected exception' { - { - $script:getTargetResourceResult = Get-TargetResource @script:getTargetResourceParameters - } | Should -Throw $exception - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - } + { + Set-TargetResource @script:setTargetResourceParameters + } | Should -Throw $exception } } - Describe 'DSC_AdcsCertificationAuthoritySettings\Set-TargetResource' { - Context 'When all Active Directory Certification Authority settings are in the correct state' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue ` - -MockWith $getItemPropertyValueExistsMock + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } +} - Mock -CommandName Get-ItemProperty ` - -MockWith $getItemPropertyMock +Describe 'DSC_AdcsCertificationAuthoritySettings\Test-TargetResource' -Tag 'Test' { + BeforeAll { + InModuleScope -Parameters @{ + baseTestParameters = $baseParameterCurrentList + } -ScriptBlock { - Mock -CommandName Set-CertificateAuthoritySetting - } + $script:testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + } + $baseTestParameters + } + } - It 'Should not throw exception' { - { - Set-TargetResource @script:testAndSetTargetResourceParameters - } | Should -Not -Throw - } + Context 'When all Active Directory Certification Authority settings are in the correct state' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue ` + -MockWith $getItemPropertyValueExistsMock - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 + Mock -CommandName Get-ItemProperty ` + -MockWith $getItemPropertyMock + } - Assert-MockCalled ` - -CommandName Get-ItemProperty ` - -ParameterFilter $getItemPropertyParameterFilter ` - -Exactly -Times 1 + It 'Should not throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Set-CertificateAuthoritySetting ` - -Exactly -Times 0 - } + { + $script:testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + } | Should -Not -Throw } + } - foreach ($parameter in $script:parameterList.GetEnumerator()) - { - Context ('When all Active Directory Certification Authority settings are in the correct state except {0}' -f $parameter.Name) { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue ` - -MockWith $getItemPropertyValueExistsMock - - Mock -CommandName Get-ItemProperty ` - -MockWith $getItemPropertyMock - - Mock -CommandName Set-CertificateAuthoritySetting - - Mock -CommandName Restart-ServiceIfExists - } - - It 'Should not throw exception' { - { - $setTargetResourceParameters = @{ } + $script:testAndSetTargetResourceParameters - $setTargetResourceParameters.$($parameter.Name) = $parameter.Value.NewValue - Set-TargetResource @setTargetResourceParameters - } | Should -Not -Throw - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Get-ItemProperty ` - -ParameterFilter $getItemPropertyParameterFilter ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Set-CertificateAuthoritySetting ` - -ParameterFilter { - $Name -eq $parameter.Name -and ` - $Value -eq $parameter.Value.SetValue - } ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Restart-ServiceIfExists ` - -Exactly -Times 1 - } - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeTrue } + } - Context 'When Active Directory Certification Authority is not installed' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue - } + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context - $exception = Get-ObjectNotFoundException -Message ($script:localizedData.CertificateAuthorityNoneActive -f ` - $script:certificateAuthorityRegistrySettingsPath) + Should -Invoke ` + -CommandName Get-ItemProperty ` + -ParameterFilter $getItemPropertyParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } - It 'Should throw expected exception' { - { - $script:setTargetResourceResult = Set-TargetResource @script:testAndSetTargetResourceParameters - } | Should -Throw $exception - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - } - } + + Context 'When all Active Directory Certification Authority settings are in the correct state, except is different' -ForEach $settingsList { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue ` + -MockWith $getItemPropertyValueExistsMock + + Mock -CommandName Get-ItemProperty ` + -MockWith $getItemPropertyMock } - Describe 'DSC_AdcsCertificationAuthoritySettings\Test-TargetResource' { - Context 'When all Active Directory Certification Authority settings are in the correct state' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue ` - -MockWith $getItemPropertyValueExistsMock - - Mock -CommandName Get-ItemProperty ` - -MockWith $getItemPropertyMock - } - - It 'Should not throw exception' { - { - $script:testTargetResourceResult = Test-TargetResource @script:testAndSetTargetResourceParameters - } | Should -Not -Throw - } - - It 'Should return true' { - $testTargetResourceResult | Should -BeTrue - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Get-ItemProperty ` - -ParameterFilter $getItemPropertyParameterFilter ` - -Exactly -Times 1 - } + It 'Should not throw exception' { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $currentTestTargetResourceParameters = @{ } + $testTargetResourceParameters + $currentTestTargetResourceParameters[$Name] = $NewValue + $script:testTargetResourceResult = Test-TargetResource @currentTestTargetResourceParameters + } | Should -Not -Throw } + } - foreach ($parameter in $script:parameterList.GetEnumerator()) - { - Context "When all Active Directory Certification Authority settings are in the correct state, except $($parameter.Name) is different" { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue ` - -MockWith $getItemPropertyValueExistsMock - - Mock -CommandName Get-ItemProperty ` - -MockWith $getItemPropertyMock - } - - It 'Should not throw exception' { - { - $currentTestTargetResourceParameters = @{ } + $script:testAndSetTargetResourceParameters - $currentTestTargetResourceParameters[$parameter.Name] = $parameter.Value.NewValue - $script:testTargetResourceResult = Test-TargetResource @currentTestTargetResourceParameters - } | Should -Not -Throw - } - - It 'Should return false' { - $testTargetResourceResult | Should -BeFalse - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Get-ItemProperty ` - -ParameterFilter $getItemPropertyParameterFilter ` - -Exactly -Times 1 - } - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult | Should -BeFalse } + } - Context 'When Active Directory Certification Authority is not installed' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue - } + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-ItemProperty ` + -ParameterFilter $getItemPropertyParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } + + + Context 'When Active Directory Certification Authority is not installed' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue + } + + It 'Should throw expected exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 $exception = Get-ObjectNotFoundException -Message ($script:localizedData.CertificateAuthorityNoneActive -f ` $script:certificateAuthorityRegistrySettingsPath) - It 'Should throw expected exception' { - { - $script:testTargetResourceResult = Test-TargetResource @script:testAndSetTargetResourceParameters - } | Should -Throw $exception - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - } + { + Test-TargetResource @testTargetResourceParameters + } | Should -Throw $exception } } - Describe 'DSC_AdcsCertificationAuthoritySettings\Get-CertificateAuthoritySettings' { - Context 'When Active Directory Certification Authority is installed' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue ` - -MockWith $getItemPropertyValueExistsMock - - Mock -CommandName Get-ItemProperty ` - -MockWith $getItemPropertyMock - } - - It 'Should not throw exception' { - { - $script:getCertificateAuthoritySettingsResult = Get-CertificateAuthoritySettings - } | Should -Not -Throw - } - - It 'Should return Active Directory Certification Authority settings' { - foreach ($parameter in $script:parameterList.GetEnumerator()) - { - $script:getCertificateAuthoritySettingsResult.$($parameter.Name) | Should -Be $parameter.Value.MockedValue - } - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - - Assert-MockCalled ` - -CommandName Get-ItemProperty ` - -ParameterFilter $getItemPropertyParameterFilter ` - -Exactly -Times 1 - } + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } +} + +Describe 'DSC_AdcsCertificationAuthoritySettings\Get-CertificateAuthoritySettings' -Tag 'Private' { + Context 'When Active Directory Certification Authority is installed' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue ` + -MockWith $getItemPropertyValueExistsMock + + Mock -CommandName Get-ItemProperty ` + -MockWith $getItemPropertyMock + } + + It 'Should not throw exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { + $script:getCertificateAuthoritySettingsResult = Get-CertificateAuthoritySettings + } | Should -Not -Throw } + } + + It 'Should return Active Directory Certification Authority settings ' -ForEach $settingsList { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When Active Directory Certification Authority is not installed' { - BeforeAll { - Mock -CommandName Get-ItemPropertyValue - } + $getCertificateAuthoritySettingsResult.$($Name) | Should -Be $MockedValue + } + } + + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + + Should -Invoke ` + -CommandName Get-ItemProperty ` + -ParameterFilter $getItemPropertyParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } + + Context 'When Active Directory Certification Authority is not installed' { + BeforeAll { + Mock -CommandName Get-ItemPropertyValue + } + + It 'Should throw expected exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 $exception = Get-ObjectNotFoundException -Message ($script:localizedData.CertificateAuthorityNoneActive -f ` $script:certificateAuthorityRegistrySettingsPath) - It 'Should throw expected exception' { - { - $script:getCertificateAuthoritySettingsResult = Get-CertificateAuthoritySettings - } | Should -Throw $exception - } - - It 'Should call the expected mocks' { - Assert-MockCalled ` - -CommandName Get-ItemPropertyValue ` - -ParameterFilter $getItemPropertyValueExistsParameterFilter ` - -Exactly -Times 1 - } + { Get-CertificateAuthoritySettings } | Should -Throw $exception } } - Describe 'DSC_AdcsCertificationAuthoritySettings\Convert-AuditFilterToStringArray' { - Context 'When the AuditFilter is 0' { - It 'Should return null' { - Convert-AuditFilterToStringArray -AuditFilter 0 | Should -BeNullOrEmpty - } + It 'Should call the expected mocks' { + Should -Invoke ` + -CommandName Get-ItemPropertyValue ` + -ParameterFilter $getItemPropertyValueExistsParameterFilter ` + -Exactly -Times 1 -Scope Context + } + } +} + +Describe 'DSC_AdcsCertificationAuthoritySettings\Convert-AuditFilterToStringArray' -Tag 'Private' { + Context 'When the AuditFilter is 0' { + It 'Should return null' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + Convert-AuditFilterToStringArray -AuditFilter 0 | Should -BeNullOrEmpty } + } + } - Context 'When the AuditFilter is 3' { - It 'Should return StartAndStopADCS and BackupAndRestoreCADatabase' { - Convert-AuditFilterToStringArray -AuditFilter 3 | Should -Be @( - 'StartAndStopADCS' - 'BackupAndRestoreCADatabase' - ) - } + Context 'When the AuditFilter is 3' { + It 'Should return StartAndStopADCS and BackupAndRestoreCADatabase' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Convert-AuditFilterToStringArray -AuditFilter 3 | Should -Be @( + 'StartAndStopADCS' + 'BackupAndRestoreCADatabase' + ) } + } + } - Context 'When the AuditFilter is 127' { - It 'Should return all audit filters' { - Convert-AuditFilterToStringArray -AuditFilter 127 | Should -Be @( - 'StartAndStopADCS' - 'BackupAndRestoreCADatabase' - 'IssueAndManageCertificateRequests' - 'RevokeCertificatesAndPublishCRLs' - 'ChangeCASecuritySettings' - 'StoreAndRetrieveArchivedKeys' - 'ChangeCAConfiguration' - ) - } + Context 'When the AuditFilter is 127' { + It 'Should return all audit filters' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Convert-AuditFilterToStringArray -AuditFilter 127 | Should -Be @( + 'StartAndStopADCS' + 'BackupAndRestoreCADatabase' + 'IssueAndManageCertificateRequests' + 'RevokeCertificatesAndPublishCRLs' + 'ChangeCASecuritySettings' + 'StoreAndRetrieveArchivedKeys' + 'ChangeCAConfiguration' + ) } } + } +} + +Describe 'DSC_AdcsCertificationAuthoritySettings\Convert-StringArrayToAuditFilter' -Tag 'Private' { + Context 'When the string array is empty' { + It 'Should return 0' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Describe 'DSC_AdcsCertificationAuthoritySettings\Convert-StringArrayToAuditFilter' { - Context 'When the string array is empty' { - It 'Should return 0' { - Convert-StringArrayToAuditFilter -StringArray @() | Should -BeExactly 0 - } + Convert-StringArrayToAuditFilter -StringArray @() | Should -BeExactly 0 } + } + } - Context 'When the string array contains StartAndStopADCS and BackupAndRestoreCADatabase' { - It 'Should return 3' { - Convert-StringArrayToAuditFilter -StringArray @('StartAndStopADCS', 'BackupAndRestoreCADatabase') | Should -BeExactly 3 - } + Context 'When the string array contains StartAndStopADCS and BackupAndRestoreCADatabase' { + It 'Should return 3' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Convert-StringArrayToAuditFilter -StringArray @('StartAndStopADCS', 'BackupAndRestoreCADatabase') | Should -BeExactly 3 } + } + } - Context 'When the string array contains all audit filter values' { - It 'Should return 127' { - Convert-StringArrayToAuditFilter -StringArray @( - 'StartAndStopADCS' - 'BackupAndRestoreCADatabase' - 'IssueAndManageCertificateRequests' - 'RevokeCertificatesAndPublishCRLs' - 'ChangeCASecuritySettings' - 'StoreAndRetrieveArchivedKeys' - 'ChangeCAConfiguration' - ) | Should -BeExactly 127 - } + Context 'When the string array contains all audit filter values' { + It 'Should return 127' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + Convert-StringArrayToAuditFilter -StringArray @( + 'StartAndStopADCS' + 'BackupAndRestoreCADatabase' + 'IssueAndManageCertificateRequests' + 'RevokeCertificatesAndPublishCRLs' + 'ChangeCASecuritySettings' + 'StoreAndRetrieveArchivedKeys' + 'ChangeCAConfiguration' + ) | Should -BeExactly 127 } } } } -finally -{ - Invoke-TestCleanup -} diff --git a/tests/Unit/DSC_AdcsEnrollmentPolicyWebService.Tests.ps1 b/tests/Unit/DSC_AdcsEnrollmentPolicyWebService.Tests.ps1 index 274ca1f..f6edb1e 100644 --- a/tests/Unit/DSC_AdcsEnrollmentPolicyWebService.Tests.ps1 +++ b/tests/Unit/DSC_AdcsEnrollmentPolicyWebService.Tests.ps1 @@ -1,16 +1,39 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsEnrollmentPolicyWebService' +<# + .SYNOPSIS + Unit test for DSC_AdcsEnrollmentPolicyWebService DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceName = 'DSC_AdcsEnrollmentPolicyWebService' $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` @@ -19,66 +42,60 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') -} - -function Invoke-TestCleanup -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force -} + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsDeploymentStub.psm1') -Invoke-TestSetup + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Commands.CEP.EnrollmentPolicyServiceSetupException').Type) - { - <# + # Add Custom Type + if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Commands.CEP.EnrollmentPolicyServiceSetupException').Type) + { + <# Define the exception class: Microsoft.CertificateServices.Deployment.Commands.CEP.EnrollmentPolicyServiceSetupException so that unit tests can be run without ADCS being installed. #> - $ExceptionDefinition = @' + $ExceptionDefinition = @' namespace Microsoft.CertificateServices.Deployment.Commands.CEP { public class EnrollmentPolicyServiceSetupException: System.Exception { } } '@ - Add-Type -TypeDefinition $ExceptionDefinition - } + Add-Type -TypeDefinition $ExceptionDefinition + } + # Test Data + InModuleScope -ScriptBlock { $dummyCredential = New-Object ` -TypeName System.Management.Automation.PSCredential ` -ArgumentList ('Administrator', (New-Object -TypeName SecureString)) - $testParametersPresent = @{ + $script:testParametersPresent = @{ AuthenticationType = 'Certificate' SslCertThumbprint = 'B2E43FF3E02D1EE767C06BD905F292E33BD14C1A' Credential = $dummyCredential KeyBasedRenewal = $true Ensure = 'Present' - Verbose = $true + Verbose = $false } - $testParametersAbsent = $testParametersPresent.Clone() - $testParametersAbsent.Ensure = 'Absent' + $script:testParametersAbsent = $testParametersPresent.Clone() + $script:testParametersAbsent.Ensure = 'Absent' - $testParametersGet = @{ + $script:testParametersGet = @{ AuthenticationType = 'Certificate' SslCertThumbprint = 'B2E43FF3E02D1EE767C06BD905F292E33BD14C1A' Credential = $dummyCredential KeyBasedRenewal = $true - Verbose = $true + Verbose = $false } - $invalidThumbprint = 'Zebra' + $script:invalidThumbprint = 'Zebra' # This thumbprint is valid (but not FIPS valid) - $validThumbprint = ( + $script:validThumbprint = ( [System.AppDomain]::CurrentDomain.GetAssemblies().GetTypes() | Where-Object { $_.BaseType.BaseType -eq [System.Security.Cryptography.HashAlgorithm] -and ($_.Name -cmatch 'Managed$' -or $_.Name -cmatch 'Provider$') @@ -90,7 +107,7 @@ namespace Microsoft.CertificateServices.Deployment.Commands.CEP { ) -join '' # This thumbprint is valid for FIPS - $validFipsThumbprint = ( + $script:validFipsThumbprint = ( [System.AppDomain]::CurrentDomain.GetAssemblies().GetTypes() | Where-Object { $_.BaseType.BaseType -eq [System.Security.Cryptography.HashAlgorithm] -and ($_.Name -cmatch 'Provider$' -and $_.Name -cnotmatch 'MD5') @@ -100,488 +117,538 @@ namespace Microsoft.CertificateServices.Deployment.Commands.CEP { } } ) -join '' - -function Install-AdcsEnrollmentPolicyWebService -{ - [CmdletBinding()] - param - ( - [Parameter()] - [ValidateSet('Certificate', 'Kerberos', 'UserName')] - [System.String] - $AuthenticationType, - - [Parameter()] - [System.String] - $SslCertThumbprint, - - [Parameter()] - [System.Management.Automation.PSCredential] - $Credential, - - [Parameter()] - [System.Boolean] - $KeyBasedRenewal = $false, - - [Parameter()] - [Switch] - $Force, - - [Parameter()] - [Switch] - $WhatIf - ) + } } -function Uninstall-AdcsEnrollmentPolicyWebService -{ - [CmdletBinding()] - param - ( - [ValidateSet('Certificate', 'Kerberos', 'UserName')] - [String] - $AuthenticationType, - - [Parameter()] - [System.Boolean] - $KeyBasedRenewal, - - [Parameter()] - [Switch] - $Force - ) -} +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') - Describe 'DSC_AdcsEnrollmentPolicyWebService\Get-TargetResource' { - Context 'When the Enrollment Policy Web Service is installed' { - Mock ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -MockWith { $true } + Restore-TestEnvironment -TestEnvironment $script:testEnvironment - $result = Get-TargetResource @testParametersGet + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force - It 'Should return Ensure set to Present' { - $result.Ensure | Should -Be 'Present' - } + Remove-Module -Name AdcsDeploymentStub -Force - It 'Should call expected mocks' { - Assert-VerifiableMock + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} - Assert-MockCalled ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -Exactly ` - -Times 1 - } - } +Describe 'DSC_AdcsEnrollmentPolicyWebService\Get-TargetResource' -Tag 'Get' { + Context 'When the Enrollment Policy Web Service is installed' { + BeforeAll { + Mock ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -MockWith { $true } + } - Context 'When the Enrollment Policy Web Service is not installed' { - Mock ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -MockWith { $false } + + It 'Should return Ensure set to Present' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 $result = Get-TargetResource @testParametersGet + $result.Ensure | Should -Be 'Present' + } + } - It 'Should return Ensure set to Absent' { - $result.Ensure | Should -Be 'Absent' - } + It 'Should call expected mocks' { + Should -InvokeVerifiable - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -Exactly ` - -Times 1 - } + Should -Invoke ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Enrollment Policy Web Service is not installed' { + BeforeAll { + Mock ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -MockWith { $false } + } + + + It 'Should return Ensure set to Absent' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource @testParametersGet + $result.Ensure | Should -Be 'Absent' } } - Describe 'DSC_AdcsEnrollmentPolicyWebService\Set-TargetResource' { - Context 'When the Enrollment Policy Web Service is not installed but should be' { - Mock -CommandName Install-AdcsEnrollmentPolicyWebService - Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -Exactly ` + -Times 1 -Scope Context + } + } +} - It 'Should not throw an exception' { - { Set-TargetResource @testParametersPresent } | Should -Not -Throw - } +Describe 'DSC_AdcsEnrollmentPolicyWebService\Set-TargetResource' -Tag 'Set' { + Context 'When the Enrollment Policy Web Service is not installed but should be' { + BeforeAll { + Mock -CommandName Install-AdcsEnrollmentPolicyWebService + Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 1 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 0 - } + { Set-TargetResource @testParametersPresent } | Should -Not -Throw } + } - Context 'When the Enrollment Policy Web Service is not installed but should be but an error string is returned installing it' { - Mock -CommandName Install-AdcsEnrollmentPolicyWebService ` - -MockWith { - [PSObject] @{ ErrorString = 'Something went wrong' } - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 1 -Scope Context - Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + Should -Invoke ` + -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 0 -Scope Context + } + } - It 'Should not throw an exception' { - $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + Context 'When the Enrollment Policy Web Service is not installed but should be but an error string is returned installing it' { + BeforeAll { + Mock -CommandName Install-AdcsEnrollmentPolicyWebService ` + -MockWith { + [PSObject] @{ ErrorString = 'Something went wrong' } + } - { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord - } + Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 1 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 0 - } + $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + + { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord } + } - Context 'When the Enrollment Policy Web Service is not installed but should be but an exception is thrown installing it' { - Mock -CommandName Install-AdcsEnrollmentPolicyWebService ` - -MockWith { throw 'Something went wrong' } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 1 -Scope Context - Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + Should -Invoke ` + -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 0 -Scope Context + } + } - It 'Should not throw an exception' { - $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + Context 'When the Enrollment Policy Web Service is not installed but should be but an exception is thrown installing it' { + BeforeAll { + Mock -CommandName Install-AdcsEnrollmentPolicyWebService ` + -MockWith { throw 'Something went wrong' } - { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord - } + Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 1 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 0 - } + $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + + { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord } + } - Context 'When the Enrollment Policy Web Service is installed but should not be' { - Mock -CommandName Install-AdcsEnrollmentPolicyWebService - Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 1 -Scope Context - It 'Should not throw an exception' { - { Set-TargetResource @testParametersAbsent } | Should -Not -Throw - } + Should -Invoke ` + -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 0 -Scope Context + } + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 0 + Context 'When the Enrollment Policy Web Service is installed but should not be' { + BeforeAll { + Mock -CommandName Install-AdcsEnrollmentPolicyWebService + Mock -CommandName Uninstall-AdcsEnrollmentPolicyWebService + } - Assert-MockCalled ` - -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` - -Exactly ` - -Times 1 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Set-TargetResource @testParametersAbsent } | Should -Not -Throw } } - Describe 'DSC_AdcsEnrollmentPolicyWebService\Test-TargetResource' { - Context 'When the Enrollment Policy Web Service is installed' { - Context 'When the Enrollment Policy Web Service should be installed' { - Mock ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -MockWith { $true } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 0 -Scope Context - $result = Test-TargetResource @testParametersPresent + Should -Invoke ` + -CommandName Uninstall-AdcsEnrollmentPolicyWebService ` + -Exactly ` + -Times 1 -Scope Context + } + } +} + +Describe 'DSC_AdcsEnrollmentPolicyWebService\Test-TargetResource' -Tag 'Test' { + Context 'When the Enrollment Policy Web Service is installed' { + Context 'When the Enrollment Policy Web Service should be installed' { + BeforeAll { + Mock ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -MockWith { $true } + } - It 'Should return true' { - $result | Should -BeTrue - } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -Exactly ` - -Times 1 - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Test-TargetResource @testParametersPresent + $result | Should -BeTrue } + } - Context 'When the Enrollment Policy Web Service should not be installed' { - Mock ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -MockWith { $true } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Enrollment Policy Web Service should not be installed' { + BeforeAll { + Mock ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -MockWith { $true } + } - $result = Test-TargetResource @testParametersAbsent - It 'Should return false' { - $result | Should -BeFalse - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersAbsent + $result | Should -BeFalse } } - Context 'When the Enrollment Policy Web Service is not installed' { - Context 'When the Enrollment Policy Web Service should be installed' { - Mock ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -MockWith { $false } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -Exactly ` + -Times 1 -Scope Context + } + } + } + + Context 'When the Enrollment Policy Web Service is not installed' { + Context 'When the Enrollment Policy Web Service should be installed' { + BeforeAll { + Mock ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -MockWith { $false } + } - $result = Test-TargetResource @testParametersPresent - It 'Should return false' { - $result | Should -BeFalse - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersPresent + $result | Should -BeFalse } + } - Context 'When the Enrollment Policy Web Service should not be installed' { - Mock ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -MockWith { $false } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -Exactly ` + -Times 1 -Scope Context + } + } - $result = Test-TargetResource @testParametersAbsent + Context 'When the Enrollment Policy Web Service should not be installed' { + BeforeAll { + Mock ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -MockWith { $false } + } - It 'Should return true' { - $result | Should -BeTrue - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersAbsent + $result | Should -BeTrue } } - } - Describe 'DSC_AdcsEnrollmentPolicyWebService\Test-AdcsEnrollmentPolicyWebServiceInstallState' { - $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases = @( - @{ - AuthenticationType = 'Certificate' - KeyBasedRenewal = $false - WebAppName = 'ADPolicyProvider_CEP_Certificate' - Applicationpool = 'WSEnrollmentPolicyServer' - PhysicalPath = "C:\Windows\SystemData\CEP\ADPolicyProvider_CEP_Certificate" - }, - @{ - AuthenticationType = 'Certificate' - KeyBasedRenewal = $true - WebAppName = 'KeyBasedRenewal_ADPolicyProvider_CEP_Certificate' - Applicationpool = 'WSEnrollmentPolicyServer' - PhysicalPath = "C:\Windows\SystemData\CEP\KeyBasedRenewal_ADPolicyProvider_CEP_Certificate" - }, - @{ - AuthenticationType = 'Kerberos' - KeyBasedRenewal = $false - WebAppName = 'ADPolicyProvider_CEP_Kerberos' - Applicationpool = 'WSEnrollmentPolicyServer' - PhysicalPath = "C:\Windows\SystemData\CEP\ADPolicyProvider_CEP_Kerberos" - }, - @{ - AuthenticationType = 'UserName' - KeyBasedRenewal = $false - WebAppName = 'ADPolicyProvider_CEP_UsernamePassword' - Applicationpool = 'WSEnrollmentPolicyServer' - PhysicalPath = "C:\Windows\SystemData\CEP\ADPolicyProvider_CEP_UsernamePassword" - }, - @{ - AuthenticationType = 'UserName' - KeyBasedRenewal = $true - WebAppName = 'KeyBasedRenewal_ADPolicyProvider_CEP_UsernamePassword' - Applicationpool = 'WSEnrollmentPolicyServer' - PhysicalPath = "C:\Windows\SystemData\CEP\KeyBasedRenewal_ADPolicyProvider_CEP_UsernamePassword" - } - ) - $mockAdcsEnrollmentPolicyWebServiceInstallStateAllInstalled = { - $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -Exactly ` + -Times 1 -Scope Context } - $mockAdcsEnrollmentPolicyWebServiceInstallStateNoneInstalled = { - @() + } + } +} + +Describe 'DSC_AdcsEnrollmentPolicyWebService\Test-AdcsEnrollmentPolicyWebServiceInstallState' -Tag 'Private' { + BeforeDiscovery { + $script:testAdcsEnrollmentPolicyWebServiceInstallStateTestCases = @( + @{ + AuthenticationType = 'Certificate' + KeyBasedRenewal = $false + WebAppName = 'ADPolicyProvider_CEP_Certificate' + Applicationpool = 'WSEnrollmentPolicyServer' + PhysicalPath = 'C:\Windows\SystemData\CEP\ADPolicyProvider_CEP_Certificate' + }, + @{ + AuthenticationType = 'Certificate' + KeyBasedRenewal = $true + WebAppName = 'KeyBasedRenewal_ADPolicyProvider_CEP_Certificate' + Applicationpool = 'WSEnrollmentPolicyServer' + PhysicalPath = 'C:\Windows\SystemData\CEP\KeyBasedRenewal_ADPolicyProvider_CEP_Certificate' + }, + @{ + AuthenticationType = 'Kerberos' + KeyBasedRenewal = $false + WebAppName = 'ADPolicyProvider_CEP_Kerberos' + Applicationpool = 'WSEnrollmentPolicyServer' + PhysicalPath = 'C:\Windows\SystemData\CEP\ADPolicyProvider_CEP_Kerberos' + }, + @{ + AuthenticationType = 'UserName' + KeyBasedRenewal = $false + WebAppName = 'ADPolicyProvider_CEP_UsernamePassword' + Applicationpool = 'WSEnrollmentPolicyServer' + PhysicalPath = 'C:\Windows\SystemData\CEP\ADPolicyProvider_CEP_UsernamePassword' + }, + @{ + AuthenticationType = 'UserName' + KeyBasedRenewal = $true + WebAppName = 'KeyBasedRenewal_ADPolicyProvider_CEP_UsernamePassword' + Applicationpool = 'WSEnrollmentPolicyServer' + PhysicalPath = 'C:\Windows\SystemData\CEP\KeyBasedRenewal_ADPolicyProvider_CEP_UsernamePassword' } + ) + } + BeforeAll { + $script:mockAdcsEnrollmentPolicyWebServiceInstallStateAllInstalled = { $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases } - Context 'When matching Enrollment Policy Web Service is installed' { - BeforeEach { - Mock ` - -CommandName Get-WebApplication ` - -MockWith $mockAdcsEnrollmentPolicyWebServiceInstallStateAllInstalled - } + $script:mockAdcsEnrollmentPolicyWebServiceInstallStateNoneInstalled = { @() } + } - It 'Given AuthenticationType and KeyBasedRenewal it should return $true' -TestCases $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases { - param ( - [Parameter()] - $AuthenticationType, + Context 'When matching Enrollment Policy Web Service is installed' { + BeforeEach { + Mock ` + -CommandName Get-WebApplication ` + -MockWith $mockAdcsEnrollmentPolicyWebServiceInstallStateAllInstalled + } - [Parameter()] - $KeyBasedRenewal, + It 'Given AuthenticationType and KeyBasedRenewal it should return $true' -ForEach $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 - [Parameter()] - $WebAppName, + $result = Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -AuthenticationType $AuthenticationType ` + -KeyBasedRenewal:$KeyBasedRenewal - [Parameter()] - $Applicationpool, + $result | Should -BeTrue + } - [Parameter()] - $PhysicalPath - ) - $result = Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -AuthenticationType $AuthenticationType ` - -KeyBasedRenewal:$KeyBasedRenewal ` - -Verbose + Should -Invoke -CommandName Get-WebApplication -Exactly -Times 1 + } - $result | Should -BeTrue - } - } + } - Context 'When matching Enrollment Policy Web Service is not installed' { - BeforeEach { - Mock ` - -CommandName Get-WebApplication ` - -MockWith $mockAdcsEnrollmentPolicyWebServiceInstallStateNoneInstalled - } + Context 'When matching Enrollment Policy Web Service is not installed' { + BeforeEach { + Mock ` + -CommandName Get-WebApplication ` + -MockWith $mockAdcsEnrollmentPolicyWebServiceInstallStateNoneInstalled + } - It 'Given AuthenticationType and KeyBasedRenewal it should return $false' -TestCases $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases { - param ( - [Parameter()] - $AuthenticationType, + It 'Given AuthenticationType and KeyBasedRenewal it should return $false' -ForEach $testAdcsEnrollmentPolicyWebServiceInstallStateTestCases { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 - [Parameter()] - $KeyBasedRenewal, + $result = Test-AdcsEnrollmentPolicyWebServiceInstallState ` + -AuthenticationType $AuthenticationType ` + -KeyBasedRenewal:$KeyBasedRenewal - [Parameter()] - $WebAppName, + $result | Should -BeFalse + } - [Parameter()] - $Applicationpool, + Should -Invoke -CommandName Get-WebApplication -Exactly -Times 1 + } + } +} - [Parameter()] - $PhysicalPath - ) - $result = Test-AdcsEnrollmentPolicyWebServiceInstallState ` - -AuthenticationType $AuthenticationType ` - -KeyBasedRenewal:$KeyBasedRenewal ` - -Verbose +Describe 'DSC_AdcsEnrollmentPolicyWebService\Test-Thumbprint' -Tag 'Private' { + Context 'When FIPS not set' { + Context 'When a single valid thumbrpint by parameter is passed' { + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - $result | Should -BeFalse + $result = Test-Thumbprint -Thumbprint $validThumbprint + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue } } } - Describe 'DSC_AdcsEnrollmentPolicyWebService\Test-Thumbprint' { - Context 'When FIPS not set' { - Context 'When a single valid thumbrpint by parameter is passed' { - $result = Test-Thumbprint -Thumbprint $validThumbprint - It 'Should return true' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeTrue - } - } + Context 'When a single invalid thumbprint by parameter is passed' { + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single invalid thumbprint by parameter is passed' { - It 'Should throw an exception' { - { Test-Thumbprint -Thumbprint $invalidThumbprint } | Should -Throw - } + { Test-Thumbprint -Thumbprint $invalidThumbprint } | Should -Throw } + } + } + + Context 'When a single invalid thumbprint by parameter with -Quiet is passed' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single invalid thumbprint by parameter with -Quiet is passed' { $result = Test-Thumbprint $invalidThumbprint -Quiet - It 'Should return false' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeFalse - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeFalse } + } + } + + Context 'When a single valid thumbprint by pipeline is passed' { + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single valid thumbprint by pipeline is passed' { $result = $validThumbprint | Test-Thumbprint - It 'Should return true' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeTrue - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue } + } + } - Context 'When a single invalid thumbprint by pipeline is passed' { - It 'Should throw an exception' { - { $invalidThumbprint | Test-Thumbprint } | Should -Throw - } + Context 'When a single invalid thumbprint by pipeline is passed' { + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { $invalidThumbprint | Test-Thumbprint } | Should -Throw } + } + } + + Context 'When a single invalid thumbprint by pipeline with -Quiet is passed' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single invalid thumbprint by pipeline with -Quiet is passed' { $result = $invalidThumbprint | Test-Thumbprint -Quiet - It 'Should return false' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeFalse - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeFalse } } + } + } + + Context 'When FIPS is enabled' { + BeforeAll { + Mock -CommandName Get-ItemProperty -MockWith { @{ Enabled = 1 } } + } - Context 'When FIPS is enabled' { - Mock -CommandName Get-ItemProperty -MockWith { @{ Enabled = 1 } } + Context 'When a single valid FIPS thumbrpint by parameter is passed' { + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single valid FIPS thumbrpint by parameter is passed' { $result = Test-Thumbprint -Thumbprint $validFipsThumbprint - It 'Should return true' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeTrue - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue } + } + } - Context 'When a single invalid FIPS thumbprint by parameter is passed' { - It 'Should throw an exception' { - { Test-Thumbprint -Thumbprint $validThumbprint } | Should -Throw - } + Context 'When a single invalid FIPS thumbprint by parameter is passed' { + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Test-Thumbprint -Thumbprint $validThumbprint } | Should -Throw } + } + } + + Context 'When a single invalid FIPS thumbprint by parameter with -Quiet is passed' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single invalid FIPS thumbprint by parameter with -Quiet is passed' { $result = Test-Thumbprint $validThumbprint -Quiet - It 'Should return false' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeFalse - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeFalse } + } + } + + Context 'When a single valid FIPS thumbprint by pipeline is passed' { + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single valid FIPS thumbprint by pipeline is passed' { $result = $validFipsThumbprint | Test-Thumbprint - It 'Should return true' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeTrue - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue } + } + } + + Context 'When a single invalid FIPS thumbprint by pipeline is passed' { + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single invalid FIPS thumbprint by pipeline is passed' { - It 'Should throw an exception' { - { $validThumbprint | Test-Thumbprint } | Should -Throw - } + { $validThumbprint | Test-Thumbprint } | Should -Throw } + } + } + + Context 'When a single invalid FIPS thumbprint by pipeline with -Quiet is passed' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When a single invalid FIPS thumbprint by pipeline with -Quiet is passed' { $result = $validThumbprint | Test-Thumbprint -Quiet - It 'Should return false' { - $result | Should -BeOfType [System.Boolean] - $result | Should -BeFalse - } + $result | Should -BeOfType [System.Boolean] + $result | Should -BeFalse } } } } } -finally -{ - Invoke-TestCleanup -} diff --git a/tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1 b/tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1 index 809c6ef..8a92e80 100644 --- a/tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1 +++ b/tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1 @@ -1,16 +1,39 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsOnlineResponder' +<# + .SYNOPSIS + Unit test for DSC_AdcsOnlineResponder DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceName = 'DSC_AdcsOnlineResponder' $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` @@ -19,316 +42,357 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') -} - -function Invoke-TestCleanup -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force -} + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsDeploymentStub.psm1') -Invoke-TestSetup + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException').Type) - { - <# + # Add Custom Type + if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException').Type) + { + <# Define the exception class: Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException so that unit tests can be run without ADCS being installed. #> - $ExceptionDefinition = @' + $ExceptionDefinition = @' namespace Microsoft.CertificateServices.Deployment.Common.OCSP { public class OnlineResponderSetupException: System.Exception { } } '@ - Add-Type -TypeDefinition $ExceptionDefinition - } + Add-Type -TypeDefinition $ExceptionDefinition + } - $DummyCredential = New-Object System.Management.Automation.PSCredential ("Administrator", (New-Object -Type SecureString)) + # Add Test Data + InModuleScope -ScriptBlock { + $DummyCredential = New-Object System.Management.Automation.PSCredential ('Administrator', (New-Object -Type SecureString)) - $testParametersPresent = @{ + $script:testParametersPresent = @{ IsSingleInstance = 'Yes' Ensure = 'Present' Credential = $DummyCredential - Verbose = $true + Verbose = $false } - $TestParametersAbsent = @{ + $script:TestParametersAbsent = @{ IsSingleInstance = 'Yes' Ensure = 'Absent' Credential = $DummyCredential - Verbose = $true + Verbose = $false } + } +} - function Install-AdcsOnlineResponder - { - [CmdletBinding()] - param - ( - [Parameter()] - [System.Management.Automation.PSCredential] - $Credential, - - [Parameter()] - [Switch] - $Force, - - [Parameter()] - [Switch] - $WhatIf - ) - } +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') - function Uninstall-AdcsOnlineResponder - { - [CmdletBinding()] - param - ( - [Parameter()] - [Switch] - $Force - ) - } + Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Describe 'DSC_AdcsOnlineResponder\Get-TargetResource' { - Context 'When the Online Responder is installed' { - Mock ` - -CommandName Install-AdcsOnlineResponder ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException') } ` - -Verifiable + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force - $result = Get-TargetResource @testParametersPresent + Remove-Module -Name AdcsDeploymentStub -Force - It 'Should return Ensure set to Present' { - $result.Ensure | Should -Be 'Present' - } + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } +Describe 'DSC_AdcsOnlineResponder\Get-TargetResource' -Tag 'Get' { + Context 'When the Online Responder is installed' { + BeforeAll { + Mock ` + -CommandName Install-AdcsOnlineResponder ` + -MockWith { + Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException') + } -Verifiable + } + + + It 'Should return Ensure set to Present' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getTargetResourceResult = Get-TargetResource @testParametersPresent + $getTargetResourceResult.Ensure | Should -Be 'Present' } + } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } - Context 'When the Online Responder is not installed' { - Mock -CommandName Install-AdcsOnlineResponder + Context 'When the Online Responder is not installed' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder + } - $result = Get-TargetResource @testParametersPresent - It 'Should return Ensure set to Absent' { - $result.Ensure | Should -Be 'Absent' - } + It 'Should return Ensure set to Absent' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } + $getTargetResourceResult = Get-TargetResource @testParametersPresent + $getTargetResourceResult.Ensure | Should -Be 'Absent' } + } - Context 'When there is an unexpected error' { - Mock ` - -CommandName Install-AdcsOnlineResponder ` - -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` - -Verifiable + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } - It 'Should throw an exception' { - { Get-TargetResource @testParametersPresent } | Should Throw - } + Context 'When there is an unexpected error' { + BeforeAll { + Mock ` + -CommandName Install-AdcsOnlineResponder ` + -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` + -Verifiable + } - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Get-TargetResource @testParametersPresent } | Should -Throw } } - Describe 'DSC_AdcsOnlineResponder\Set-TargetResource' { - Context 'When the Online Responder is not installed but should be' { - Mock -CommandName Install-AdcsOnlineResponder - Mock -CommandName Uninstall-AdcsOnlineResponder + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } +} - It 'Should not throw an exception' { - { Set-TargetResource @testParametersPresent } | Should Not Throw - } +Describe 'DSC_AdcsOnlineResponder\Set-TargetResource' -Tag 'Set' { + Context 'When the Online Responder is not installed but should be' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder + Mock -CommandName Uninstall-AdcsOnlineResponder + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsOnlineResponder ` - -Exactly ` - -Times 0 - } + { Set-TargetResource @testParametersPresent } | Should -Not -Throw } + } - Context 'When the Online Responder is not installed but should be but an error is thrown installing it' { - Mock -CommandName Install-AdcsOnlineResponder ` - -MockWith { [PSObject] @{ ErrorString = 'Something went wrong' } } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context - Mock -CommandName Uninstall-AdcsOnlineResponder + Should -Invoke ` + -CommandName Uninstall-AdcsOnlineResponder ` + -Exactly ` + -Times 0 -Scope Context + } + } - It 'Should throw an exception' { - $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + Context 'When the Online Responder is not installed but should be but an error is thrown installing it' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder ` + -MockWith { [PSObject] @{ ErrorString = 'Something went wrong' } } - { Set-TargetResource @testParametersPresent } | Should Throw $errorRecord - } + Mock -CommandName Uninstall-AdcsOnlineResponder + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsOnlineResponder ` - -Exactly ` - -Times 0 - } + $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + + { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord } + } - Context 'When the Online Responder is installed but should not be' { - Mock -CommandName Install-AdcsOnlineResponder - Mock -CommandName Uninstall-AdcsOnlineResponder + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context - It 'Should not throw an exception' { - { Set-TargetResource @TestParametersAbsent } | Should Not Throw - } + Should -Invoke ` + -CommandName Uninstall-AdcsOnlineResponder ` + -Exactly ` + -Times 0 -Scope Context + } + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 0 + Context 'When the Online Responder is installed but should not be' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder + Mock -CommandName Uninstall-AdcsOnlineResponder + } - Assert-MockCalled ` - -CommandName Uninstall-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Set-TargetResource @TestParametersAbsent } | Should -Not -Throw } } - Describe 'DSC_AdcsOnlineResponder\Test-TargetResource' { - Context 'When the Online Responder is installed' { - Context 'When the Online Responder should be installed' { - Mock -CommandName Install-AdcsOnlineResponder ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException') } ` - -Verifiable - - $result = Test-TargetResource @testParametersPresent - - It 'Should return true' { - $result | Should -BeTrue - } - - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } - } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 0 -Scope Context - Context 'When the Online Responder should not be installed' { - Mock -CommandName Install-AdcsOnlineResponder ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException') } ` - -Verifiable + Should -Invoke ` + -CommandName Uninstall-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } +} - $result = Test-TargetResource @TestParametersAbsent +Describe 'DSC_AdcsOnlineResponder\Test-TargetResource' -Tag 'Test' { + Context 'When the Online Responder is installed' { + Context 'When the Online Responder should be installed' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException') } ` + -Verifiable + } - It 'Should return false' { - $result | Should -BeFalse - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } + $testTargetResourceResult = Test-TargetResource @testParametersPresent + $testTargetResourceResult | Should -BeTrue } } - Context 'When the Online Responder is not installed' { - Context 'When the Online Responder should be installed' { - Mock -CommandName Install-AdcsOnlineResponder ` - -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Online Responder should not be installed' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException') } ` + -Verifiable + } - $result = Test-TargetResource @testParametersPresent - It 'Should return false' { - $result | Should -BeFalse - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } + $testTargetResourceResult = Test-TargetResource @TestParametersAbsent + $testTargetResourceResult | Should -BeFalse } + } - Context 'When the Online Responder should not be installed' { - Mock -CommandName Install-AdcsOnlineResponder ` - -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } + } - $result = Test-TargetResource @TestParametersAbsent + Context 'When the Online Responder is not installed' { + Context 'When the Online Responder should be installed' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder ` + -Verifiable + } - It 'Should return true' { - $result | Should -BeTrue - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 - } + $testTargetResourceResult = Test-TargetResource @testParametersPresent + $testTargetResourceResult | Should -BeFalse } } - Context 'Should throw on any other error' { + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Online Responder should not be installed' { + BeforeAll { Mock -CommandName Install-AdcsOnlineResponder ` - -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` -Verifiable + } - It 'Should throw an exception' { - { Test-TargetResource @testParametersPresent } | Should Throw - } - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsOnlineResponder ` - -Exactly ` - -Times 1 + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceResult = Test-TargetResource @TestParametersAbsent + $testTargetResourceResult | Should -BeTrue } } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context + } + } + } + + Context 'Should throw on any other error' { + BeforeAll { + Mock -CommandName Install-AdcsOnlineResponder ` + -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` + -Verifiable + } + + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { Test-TargetResource @testParametersPresent } | Should -Throw + } + } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke ` + -CommandName Install-AdcsOnlineResponder ` + -Exactly ` + -Times 1 -Scope Context } } -} -finally -{ - Invoke-TestCleanup } diff --git a/tests/Unit/DSC_AdcsTemplate.Tests.ps1 b/tests/Unit/DSC_AdcsTemplate.Tests.ps1 index bffff11..9948f96 100644 --- a/tests/Unit/DSC_AdcsTemplate.Tests.ps1 +++ b/tests/Unit/DSC_AdcsTemplate.Tests.ps1 @@ -1,16 +1,39 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsTemplate' +<# + .SYNOPSIS + Unit test for DSC_AdcsTemplate DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceName = 'DSC_AdcsTemplate' $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` @@ -19,268 +42,303 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') -} + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsAdministrationStub.psm1') -function Invoke-TestCleanup -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force -} -Invoke-TestSetup + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - $mockTemplateList = @( - @{ - Name = 'User' - Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.1' - } - @{ - Name = 'DirectoryEmailReplication' - Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.29' - } - @{ - Name = 'DomainControllerAuthentication' - Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.28' - } - @{ - Name = 'KerberosAuthentication' - Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.33' - } - ) + # Test Data + $script:mockTemplateList = @( + @{ + Name = 'User' + Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.1' + } + @{ + Name = 'DirectoryEmailReplication' + Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.29' + } + @{ + Name = 'DomainControllerAuthentication' + Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.28' + } + @{ + Name = 'KerberosAuthentication' + Oid = '1.3.6.1.4.1.311.21.8.8499410.11380151.15942274.9578998.10586356.49.1.33' + } + ) - $testTemplatePresent = @{ + InModuleScope -ScriptBlock { + $script:testTemplatePresent = @{ Name = 'User' } - $testTemplateNotPresent = @{ + $script:testTemplateNotPresent = @{ Name = 'EFS' } + } + + $script:mockGetTemplatePresent = @{ + Name = 'User' + Ensure = 'Present' + } + + $script:mockGetTemplateNotPresent = @{ + Name = 'EFS' + Ensure = 'Absent' + } +} + - $mockGetTemplatePresent = @{ - Name = 'User' - Ensure = 'Present' +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force + + Remove-Module -Name AdcsAdministrationStub -Force + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} + +Describe 'DSC_AdcsTemplate\Get-TargetResource' -Tag 'Get' { + Context 'When the template is installed' { + BeforeAll { + Mock -CommandName Get-CATemplate -MockWith { $mockTemplateList } -Verifiable } - $mockGetTemplateNotPresent = @{ - Name = 'EFS' - Ensure = 'Absent' + It 'Should return Ensure set to Present' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource @testTemplatePresent + $result.Ensure | Should -Be 'Present' + } } - function Get-CATemplate - { - [CmdletBinding()] - param () + It 'Should call expected mocks' { + Should -InvokeVerifiable + Should -Invoke -CommandName Get-CATemplate -Exactly -Times 1 -Scope Context } + } - function Add-CATemplate - { - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [String] - $Name - ) + Context 'When the template is not installed' { + BeforeAll { + Mock -CommandName Get-CATemplate -MockWith { $mockTemplateList } } - function Remove-CATemplate - { - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [String] - $Name, + It 'Should return Ensure set to Absent' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - [Parameter()] - [switch] - $Force - ) + $result = Get-TargetResource @testTemplateNotPresent + $result.Ensure | Should -Be 'Absent' + } } - Describe 'DSC_AdcsTemplate\Get-TargetResource' { - Context 'When the template is installed' { - Mock -CommandName Get-CATemplate -MockWith { $mockTemplateList } + It 'Should call expected mocks' { + #Should -InvokeVerifiable + Should -Invoke -CommandName Get-CATemplate -Exactly -Times 1 -Scope Context + } + } - $result = Get-TargetResource @testTemplatePresent + Context 'When Get-CATemplate throws an exception' { + BeforeAll { + Mock -CommandName Get-CATemplate -MockWith { throw } + } - It 'Should return Ensure set to Present' { - $result.Ensure | Should -Be 'Present' - } + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mocks' { - Assert-VerifiableMock + $mockErrorRecord = Get-InvalidOperationRecord ` + -Message $script:localizedData.InvalidOperationGettingAdcsTemplateMessage - Assert-MockCalled ` - -CommandName Get-CATemplate ` - -Exactly ` - -Times 1 - } + { Get-TargetResource @testTemplatePresent } | Should -Throw -ExpectedMessage ($mockErrorRecord.Exception.Message + '*') } + } + } +} - Context 'When the template is not installed' { - Mock -CommandName Get-CATemplate -MockWith { $mockTemplateList } +Describe 'DSC_AdcsTemplate\Set-TargetResource' -Tag 'Set' { + Context 'When the template is not added but should be' { + BeforeAll { + Mock -CommandName Add-CATemplate + } - $result = Get-TargetResource @testTemplateNotPresent + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should return Ensure set to Absent' { - $result.Ensure | Should -Be 'Absent' - } + { Set-TargetResource @testTemplateNotPresent } | Should -Not -Throw + } + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Get-CATemplate ` - -Exactly ` - -Times 1 - } + It 'Should call expected mock' { + Should -Invoke -CommandName Add-CATemplate ` + -ParameterFilter { + $Name -eq 'EFS' + } -Exactly -Times 1 -Scope Context + } + + Context 'When Add-CATemplate throws an exception' { + BeforeAll { + Mock -CommandName Add-CATemplate -MockWith { throw } } - Context 'When Get-CATemplate throws an exception' { - Mock -CommandName Get-CATemplate -MockWith { throw } + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should throw the correct error' { - $errorRecord = Get-InvalidOperationRecord ` - -Message $script:localizedData.InvalidOperationGettingAdcsTemplateMessage - { Get-TargetResource @testTemplatePresent } | Should -Throw $errorRecord + $mockErrorRecord = Get-InvalidOperationRecord ` + -Message ($script:localizedData.InvalidOperationAddingAdcsTemplateMessage -f $testTemplateNotPresent.Name) + + { Set-TargetResource @testTemplateNotPresent } | Should -Throw -ExpectedMessage ($mockErrorRecord.Exception.Message + '*') } } } - Describe 'DSC_AdcsTemplate\Set-TargetResource' { - Context 'When the template is not added but should be' { - Mock -CommandName Add-CATemplate + Context 'When the template is added but should not be' { + BeforeAll { + Mock -CommandName Remove-CATemplate + } - It 'Should not throw an exception' { - { Set-TargetResource @testTemplateNotPresent } | Should Not Throw - } + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mock' { - Assert-MockCalled ` - -CommandName Add-CATemplate ` - -ParameterFilter { $Name -eq $testTemplateNotPresent.Name } ` - -Exactly ` - -Times 1 + { Set-TargetResource @testTemplatePresent -Ensure 'Absent' } | Should -Not -Throw } + } - Context 'When Add-CATemplate throws an exception' { - Mock -CommandName Add-CATemplate -MockWith { throw } - - It 'Should throw the correct error' { - $errorRecord = Get-InvalidOperationRecord ` - -Message ($script:localizedData.InvalidOperationAddingAdcsTemplateMessage -f $testTemplateNotPresent.Name) - { Set-TargetResource @testTemplateNotPresent } | Should -Throw $errorRecord - } - } + It 'Should call expected mock' { + Should -Invoke ` + -CommandName Remove-CATemplate ` + -ParameterFilter { + $Name -eq 'User' + } -Exactly -Times 1 -Scope Context - Context 'When the template is added but should not be' { - Mock -CommandName Remove-CATemplate + } + } - It 'Should not throw an exception' { - { Set-TargetResource @testTemplatePresent -Ensure 'Absent' } | Should Not Throw - } + Context 'When Remove-CATemplate throws an exception' { + BeforeAll { + Mock -CommandName Remove-CATemplate -MockWith { throw } + } - It 'Should call expected mock' { - Assert-MockCalled ` - -CommandName Remove-CATemplate ` - -ParameterFilter { $Name -eq $testTemplatePresent.Name } ` - -Exactly ` - -Times 1 - } - } + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Context 'When Remove-CATemplate throws an exception' { - Mock -CommandName Remove-CATemplate -MockWith { throw } + $mockErrorRecord = Get-InvalidOperationRecord ` + -Message ($script:localizedData.InvalidOperationRemovingAdcsTemplateMessage -f $testTemplatePresent.Name) - It 'Should throw the correct error' { - $errorRecord = Get-InvalidOperationRecord ` - -Message ($script:localizedData.InvalidOperationRemovingAdcsTemplateMessage -f $testTemplatePresent.Name) - { Set-TargetResource @testTemplatePresent -Ensure 'Absent' } | Should -Throw $errorRecord - } + { Set-TargetResource @testTemplatePresent -Ensure 'Absent' } | Should -Throw -ExpectedMessage ($mockErrorRecord.Exception.Message + '*') } } } + } +} - Describe 'DSC_AdcsTemplate\Test-TargetResource' { - Context 'When the template is added and should be' { - Mock -CommandName Get-TargetResource -MockWith { $mockGetTemplatePresent } +Describe 'DSC_AdcsTemplate\Test-TargetResource' -Tag 'Test' { + Context 'When the template is added and should be' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { $mockGetTemplatePresent } + } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 $result = Test-TargetResource @testTemplatePresent -Ensure 'Present' - - It 'Should return true' { - $result | Should -BeTrue - } - - It 'Should call expected mock' { - Assert-MockCalled ` - -CommandName Get-TargetResource ` - -ParameterFilter { $Name -eq $testTemplatePresent.Name } ` - -Exactly ` - -Times 1 - } + $result | Should -BeTrue } + } + + It 'Should call expected mock' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -ParameterFilter { + $Name -eq 'User' + } -Exactly -Times 1 -Scope Context + } + } - Context 'When the template is added and should not be' { - Mock -CommandName Get-TargetResource -MockWith { $mockGetTemplatePresent } + Context 'When the template is added and should not be' { + BeforeAll { + Mock -CommandName Get-TargetResource ` + -MockWith { $mockGetTemplatePresent } - $result = Test-TargetResource @testTemplatePresent -Ensure 'Absent' + } - It 'Should return false' { - $result | Should -BeFalse - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mock' { - Assert-MockCalled ` - -CommandName Get-TargetResource ` - -ParameterFilter { $Name -eq $testTemplatePresent.Name } ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testTemplateNotPresent -Ensure 'Absent' + $result | Should -BeFalse } + } - Context 'When the template is not added and should be' { - Mock -CommandName Get-TargetResource -MockWith { $mockGetTemplateNotPresent } + It 'Should call expected mock' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -ParameterFilter { + $Name -eq 'EFS' + } -Exactly -Times 1 -Scope Context + } + } - $result = Test-TargetResource @testTemplateNotPresent -Ensure 'Present' + Context 'When the template is not added and should be' { + BeforeAll { + Mock -CommandName Get-TargetResource ` + -MockWith { $mockGetTemplateNotPresent } + } - It 'Should return false' { - $result | Should -BeFalse - } + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - It 'Should call expected mock' { - Assert-MockCalled ` - -CommandName Get-TargetResource ` - -ParameterFilter { $Name -eq $testTemplateNotPresent.Name } ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testTemplateNotPresent -Ensure 'Present' + $result | Should -BeFalse } + } - Context 'When the template is not added and should not be' { - Mock -CommandName Get-TargetResource -MockWith { $MockGetTemplateNotPresent } + It 'Should call expected mock' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -ParameterFilter { + $Name -eq 'EFS' + } -Exactly -Times 1 -Scope Context + } + } - $result = Test-TargetResource @testTemplateNotPresent -Ensure 'Absent' + Context 'When the template is not added and should not be' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { $MockGetTemplateNotPresent } - It 'Should return true' { - $result | Should -BeTrue - } + } - It 'Should call expected mock' { - Assert-MockCalled ` - -CommandName Get-TargetResource ` - -ParameterFilter { $Name -eq $testTemplateNotPresent.Name } ` - -Exactly ` - -Times 1 - } + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Test-TargetResource @testTemplateNotPresent -Ensure 'Absent' + $result | Should -BeTrue } } + + It 'Should call expected mock' { + Should -Invoke ` + -CommandName Get-TargetResource ` + -ParameterFilter { + $Name -eq 'EFS' + } -Exactly -Times 1 -Scope Context + } } } -finally -{ - Invoke-TestCleanup -} diff --git a/tests/Unit/DSC_AdcsWebEnrollment.Tests.ps1 b/tests/Unit/DSC_AdcsWebEnrollment.Tests.ps1 index b2e3ca5..a6bde1e 100644 --- a/tests/Unit/DSC_AdcsWebEnrollment.Tests.ps1 +++ b/tests/Unit/DSC_AdcsWebEnrollment.Tests.ps1 @@ -1,16 +1,39 @@ -$script:dscModuleName = 'ActiveDirectoryCSDsc' -$script:dscResourceName = 'DSC_AdcsWebEnrollment' +<# + .SYNOPSIS + Unit test for DSC_AdcsOnlineResponder DSC resource. -function Invoke-TestSetup -{ + .NOTES +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { try { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } } catch [System.IO.FileNotFoundException] { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' } +} + +BeforeAll { + $script:dscModuleName = 'ActiveDirectoryCSDsc' + $script:dscResourceName = 'DSC_AdcsWebEnrollment' $script:testEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` @@ -19,330 +42,368 @@ function Invoke-TestSetup -TestType 'Unit' Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\AdcsStub.psm1') -} + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '.\Stubs\AdcsDeploymentStub.psm1') -function Invoke-TestCleanup -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Remove-Module -Name AdcsStub -Force -} + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName -Invoke-TestSetup - -# Begin Testing -try -{ - InModuleScope $script:dscResourceName { - if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException').Type) - { - <# + # Add Custom Type + if (-not ([System.Management.Automation.PSTypeName]'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException').Type) + { + <# Define the exception class: Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException so that unit tests can be run without ADCS being installed. #> - $ExceptionDefinition = @' + $ExceptionDefinition = @' namespace Microsoft.CertificateServices.Deployment.Common.WEP { public class WebEnrollmentSetupException: System.Exception { } } '@ - Add-Type -TypeDefinition $ExceptionDefinition - } + Add-Type -TypeDefinition $ExceptionDefinition -IgnoreWarnings + } - $dummyCredential = New-Object System.Management.Automation.PSCredential ("Administrator", (New-Object -Type SecureString)) + InModuleScope -ScriptBlock { + $dummyCredential = New-Object System.Management.Automation.PSCredential ('Administrator', (New-Object -Type SecureString)) - $testParametersPresent = @{ + $script:testParametersPresent = @{ IsSingleInstance = 'Yes' Ensure = 'Present' CAConfig = 'CAConfig' Credential = $dummyCredential - Verbose = $true + Verbose = $false } - $testParametersAbsent = @{ + $script:testParametersAbsent = @{ IsSingleInstance = 'Yes' Ensure = 'Absent' Credential = $dummyCredential - Verbose = $true + Verbose = $false } + } +} - function Install-AdcsWebEnrollment - { - [CmdletBinding()] - param - ( - [Parameter()] - [String] - $CAConfig, - - [Parameter()] - [System.Management.Automation.PSCredential] - $Credential, - - [Parameter()] - [Switch] - $Force, - - [Parameter()] - [Switch] - $WhatIf - ) - } +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') - function Uninstall-AdcsWebEnrollment - { - [CmdletBinding()] - param - ( - [Parameter()] - [Switch] - $Force - ) - } + Restore-TestEnvironment -TestEnvironment $script:testEnvironment - Describe 'DSC_AdcsWebEnrollment\Get-TargetResource' { - Context 'When the Web Enrollment is installed' { - Mock ` - -CommandName Install-AdcsWebEnrollment ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException') } ` - -Verifiable + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force - $result = Get-TargetResource @testParametersPresent + Remove-Module -Name AdcsDeploymentStub -Force - It 'Should return Ensure set to Present' { - $result.Ensure | Should -Be 'Present' - } + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force +} - It 'Should call expected mocks' { - Assert-VerifiableMock - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } - } - Context 'When the Web Enrollment is not installed' { - Mock ` - -CommandName Install-AdcsWebEnrollment +Describe 'DSC_AdcsWebEnrollment\Get-TargetResource' -Tag 'Get' { + Context 'When the Web Enrollment is installed' { + BeforeAll { + Mock ` + -CommandName Install-AdcsWebEnrollment ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException') } ` + -Verifiable + } + + + It 'Should return Ensure set to Present' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 $result = Get-TargetResource @testParametersPresent + $result.Ensure | Should -Be 'Present' + } + } - It 'Should return Ensure set to Absent' { - $result.Ensure | Should -Be 'Absent' - } + It 'Should call expected mocks' { + Should -InvokeVerifiable - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Web Enrollment is not installed' { + BeforeAll { + Mock ` + -CommandName Install-AdcsWebEnrollment + } + + It 'Should return Ensure set to Absent' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource @testParametersPresent + $result.Ensure | Should -Be 'Absent' } + } - Context 'When there is an unexpected error' { - Mock ` - -CommandName Install-AdcsWebEnrollment ` - -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` - -Verifiable + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } - It 'Should throw an exception' { - { Get-TargetResource @testParametersPresent } | Should Throw - } + Context 'When there is an unexpected error' { + BeforeAll { + Mock ` + -CommandName Install-AdcsWebEnrollment ` + -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` + -Verifiable + } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + { Get-TargetResource @testParametersPresent } | Should -Throw } } - Describe 'DSC_AdcsWebEnrollment\Set-TargetResource' { - Context 'When the Web Enrollment is not installed but should be' { - Mock -CommandName Install-AdcsWebEnrollment - Mock -CommandName Uninstall-AdcsWebEnrollment + It 'Should call expected mocks' { + Should -InvokeVerifiable - It 'Should not throw an exception' { - { Set-TargetResource @testParametersPresent } | Should Not Throw - } + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } +} + +Describe 'DSC_AdcsWebEnrollment\Set-TargetResource' -Tag 'Set' { + Context 'When the Web Enrollment is not installed but should be' { + BeforeAll { + Mock -CommandName Install-AdcsWebEnrollment + Mock -CommandName Uninstall-AdcsWebEnrollment + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsWebEnrollment ` - -Exactly ` - -Times 0 - } + { Set-TargetResource @testParametersPresent } | Should -Not -Throw } + } - Context 'When the Web Enrollment is not installed but should be but an error is thrown installing it' { - Mock -CommandName Install-AdcsWebEnrollment ` - -MockWith { [PSObject] @{ ErrorString = 'Something went wrong' } } + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context - Mock -CommandName Uninstall-AdcsWebEnrollment + Should -Invoke ` + -CommandName Uninstall-AdcsWebEnrollment ` + -Exactly ` + -Times 0 -Scope Context + } + } - It 'Should not throw an exception' { - $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + Context 'When the Web Enrollment is not installed but should be but an error is thrown installing it' { + BeforeAll { + Mock -CommandName Install-AdcsWebEnrollment ` + -MockWith { [PSObject] @{ ErrorString = 'Something went wrong' } } - { Set-TargetResource @testParametersPresent } | Should Throw $errorRecord - } + Mock -CommandName Uninstall-AdcsWebEnrollment + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsWebEnrollment ` - -Exactly ` - -Times 0 - } + $errorRecord = Get-InvalidOperationRecord -Message 'Something went wrong' + + { Set-TargetResource @testParametersPresent } | Should -Throw $errorRecord } + } - Context 'When the Web Enrollment is installed but should not be' { - Mock -CommandName Install-AdcsWebEnrollment - Mock -CommandName Uninstall-AdcsWebEnrollment + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context - It 'Should not throw an exception' { - { Set-TargetResource @TestParametersAbsent } | Should Not Throw - } + Should -Invoke ` + -CommandName Uninstall-AdcsWebEnrollment ` + -Exactly ` + -Times 0 -Scope Context + } + } + + Context 'When the Web Enrollment is installed but should not be' { + BeforeAll { + Mock -CommandName Install-AdcsWebEnrollment + Mock -CommandName Uninstall-AdcsWebEnrollment + } - It 'Should call expected mocks' { - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 0 + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Uninstall-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + { Set-TargetResource @TestParametersAbsent } | Should -Not -Throw } } - Describe 'DSC_AdcsWebEnrollment\Test-TargetResource' { - Context 'When the Web Enrollment is installed' { - Context 'When the Web Enrollment should be installed' { - Mock ` - -CommandName Install-AdcsWebEnrollment ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException') } ` - -Verifiable + It 'Should call expected mocks' { + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 0 -Scope Context - $result = Test-TargetResource @testParametersPresent + Should -Invoke ` + -CommandName Uninstall-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } +} + +Describe 'DSC_AdcsWebEnrollment\Test-TargetResource' -Tag 'Test' { + Context 'When the Web Enrollment is installed' { + Context 'When the Web Enrollment should be installed' { + BeforeAll { + Mock ` + -CommandName Install-AdcsWebEnrollment ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException') } ` + -Verifiable + } - It 'Should return true' { - $result | Should -BeTrue - } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersPresent + $result | Should -BeTrue } + } - Context 'When the Web Enrollment should not be installed' { - Mock ` - -CommandName Install-AdcsWebEnrollment ` - -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException') } ` - -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable - $result = Test-TargetResource @testParametersAbsent + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Web Enrollment should not be installed' { + BeforeAll { + Mock ` + -CommandName Install-AdcsWebEnrollment ` + -MockWith { Throw (New-Object -TypeName 'Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentSetupException') } ` + -Verifiable + } - It 'Should return false' { - $result | Should -BeFalse - } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersAbsent + $result | Should -BeFalse } } - Context 'When the Web Enrollment is not installed' { - Context 'When the Web Enrollment should be installed' { - Mock -CommandName Install-AdcsWebEnrollment -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable - $result = Test-TargetResource @testParametersPresent + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } + } + + Context 'When the Web Enrollment is not installed' { + Context 'When the Web Enrollment should be installed' { + BeforeAll { + Mock -CommandName Install-AdcsWebEnrollment -Verifiable + } - It 'Should return false' { - $result | Should -BeFalse - } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersPresent + $result | Should -BeFalse } + } - Context 'When the Web Enrollment should not be installed' { - Mock -CommandName Install-AdcsWebEnrollment -Verifiable + It 'Should call expected mocks' { + Should -InvokeVerifiable - $result = Test-TargetResource @testParametersAbsent + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } + } + + Context 'When the Web Enrollment should not be installed' { + BeforeAll { + Mock -CommandName Install-AdcsWebEnrollment -Verifiable + } - It 'Should return true' { - $result | Should -BeTrue - } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + $result = Test-TargetResource @testParametersAbsent + $result | Should -BeTrue } } - Context 'Should throw on any other error' { - Mock ` + It 'Should call expected mocks' { + Should -InvokeVerifiable + + Should -Invoke ` -CommandName Install-AdcsWebEnrollment ` - -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` - -Verifiable + -Exactly ` + -Times 1 -Scope Context + } + } + } - It 'Should throw an exception' { - { Test-TargetResource @testParametersPresent } | Should Throw - } + Context 'Should throw on any other error' { + BeforeAll { + Mock ` + -CommandName Install-AdcsWebEnrollment ` + -MockWith { Throw (New-Object -TypeName 'System.Exception') } ` + -Verifiable + } - It 'Should call expected mocks' { - Assert-VerifiableMock + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 - Assert-MockCalled ` - -CommandName Install-AdcsWebEnrollment ` - -Exactly ` - -Times 1 - } + { Test-TargetResource @testParametersPresent } | Should -Throw } } + + It 'Should call expected mocks' { + Should -InvokeVerifiable + + Should -Invoke ` + -CommandName Install-AdcsWebEnrollment ` + -Exactly ` + -Times 1 -Scope Context + } } } -finally -{ - Invoke-TestCleanup -} diff --git a/tests/Unit/Stubs/AdcsAdministrationStub.psm1 b/tests/Unit/Stubs/AdcsAdministrationStub.psm1 new file mode 100644 index 0000000..7d7dafa --- /dev/null +++ b/tests/Unit/Stubs/AdcsAdministrationStub.psm1 @@ -0,0 +1,529 @@ +# This section suppresses rules PsScriptAnalyzer may catch in stub functions. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')] + +# Name: ADCSAdministration +# Version: 2.0.0.0 + +[CmdletBinding()] +param () + +function Add-CAAuthorityInformationAccess +{ + <# + .SYNOPSIS + Add-CAAuthorityInformationAccess [-InputObject] [-Force] [-WhatIf] [-Confirm] [] + +Add-CAAuthorityInformationAccess [-Uri] -AddToCertificateOcsp [-Force] [-WhatIf] [-Confirm] [] + +Add-CAAuthorityInformationAccess [-Uri] -AddToCertificateAia [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.CA.AuthorityInformationAccessResult])] + [OutputType([System.Object])] + param ( + [Parameter(ParameterSetName = 'AddAsInputObject', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + #[Microsoft.CertificateServices.Administration.Commands.CA.AuthorityInformationAccess] + [System.Object] + ${InputObject}, + + [Parameter(ParameterSetName = 'AddAsOCSP', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'AddAsAIA', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Uri}, + + [Parameter(ParameterSetName = 'AddAsAIA', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCertificateAia}, + + [Parameter(ParameterSetName = 'AddAsOCSP', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCertificateOcsp}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Add-CACrlDistributionPoint +{ + <# + .SYNOPSIS + Add-CACrlDistributionPoint [-Uri] [-AddToCertificateCdp] [-AddToFreshestCrl] [-AddToCrlCdp] [-AddToCrlIdp] [-PublishToServer] [-PublishDeltaToServer] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.CA.CrlDistributionPointResult])] + [OutputType([System.Object])] + param ( + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Uri}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCertificateCdp}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToFreshestCrl}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCrlCdp}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCrlIdp}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${PublishToServer}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${PublishDeltaToServer}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Add-CATemplate +{ + <# + .SYNOPSIS + Add-CATemplate [-Name] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Name}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Backup-CARoleService +{ + <# + .SYNOPSIS + Backup-CARoleService [-Path] -KeyOnly [-Force] [-Password ] [] + +Backup-CARoleService [-Path] -DatabaseOnly [-Force] [-Incremental] [-KeepLog] [] + +Backup-CARoleService [-Path] [-Force] [-Password ] [-Incremental] [-KeepLog] [] + #> + + [CmdletBinding()] + [OutputType([System.Void])] + param ( + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Path}, + + [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${Force}, + + [Parameter(ParameterSetName = 'Key', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${KeyOnly}, + + [Parameter(ParameterSetName = 'Database', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${DatabaseOnly}, + + [Parameter(ParameterSetName = 'All', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'Key', ValueFromPipelineByPropertyName = $true)] + [securestring] + ${Password}, + + [Parameter(ParameterSetName = 'Database', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'All', ValueFromPipelineByPropertyName = $true)] + [switch] + ${Incremental}, + + [Parameter(ParameterSetName = 'Database', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'All', ValueFromPipelineByPropertyName = $true)] + [switch] + ${KeepLog} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Confirm-CAAttestationIdentityKeyInfo +{ + <# + .SYNOPSIS + Confirm-CAAttestationIdentityKeyInfo [-PublicKeyHash] [] + +Confirm-CAAttestationIdentityKeyInfo [-Certificate] [] + #> + + [CmdletBinding()] + [OutputType([System.Boolean])] + param ( + [Parameter(ParameterSetName = 'PublicKeyHash', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidatePattern('^[0-9a-fA-F]{64}$')] + [string] + ${PublicKeyHash}, + + [Parameter(ParameterSetName = 'Certificate', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNull()] + [System.Security.Cryptography.X509Certificates.X509Certificate2] + ${Certificate} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Confirm-CAEndorsementKeyInfo +{ + <# + .SYNOPSIS + Confirm-CAEndorsementKeyInfo [-PublicKeyHash] [] + +Confirm-CAEndorsementKeyInfo [-Certificate] [] + #> + + [CmdletBinding()] + [OutputType([System.Boolean])] + param ( + [Parameter(ParameterSetName = 'PublicKeyHash', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidatePattern('^[0-9a-fA-F]{64}$')] + [string] + ${PublicKeyHash}, + + [Parameter(ParameterSetName = 'Certificate', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNull()] + [System.Security.Cryptography.X509Certificates.X509Certificate2] + ${Certificate} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Get-CAAuthorityInformationAccess +{ + <# + .SYNOPSIS + Get-CAAuthorityInformationAccess [] + #> + + [CmdletBinding()] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.CA.AuthorityInformationAccess])] + [OutputType([System.Object])] + param ( ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Get-CACrlDistributionPoint +{ + <# + .SYNOPSIS + Get-CACrlDistributionPoint [] + #> + + [CmdletBinding()] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.CA.CrlDistributionPoint])] + [OutputType([System.Object])] + param ( ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Get-CATemplate +{ + <# + .SYNOPSIS + Get-CATemplate [] + #> + + [CmdletBinding()] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.Common.CertificateTemplate])] + [OutputType([System.Object])] + param ( ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Remove-CAAuthorityInformationAccess +{ + <# + .SYNOPSIS + Remove-CAAuthorityInformationAccess [-Uri] [-AddToCertificateAia] [-Force] [-WhatIf] [-Confirm] [] + +Remove-CAAuthorityInformationAccess [-Uri] [-AddToCertificateOcsp] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'RemoveAsAIA', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.CA.AuthorityInformationAccessResult])] + [OutputType([System.Object])] + param ( + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Uri}, + + [Parameter(ParameterSetName = 'RemoveAsAIA', ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCertificateAia}, + + [Parameter(ParameterSetName = 'RemoveAsOCSP', ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCertificateOcsp}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Remove-CACrlDistributionPoint +{ + <# + .SYNOPSIS + Remove-CACrlDistributionPoint [-Uri] [-AddToCertificateCdp] [-AddToFreshestCrl] [-AddToCrlCdp] [-AddToCrlIdp] [-PublishToServer] [-PublishDeltaToServer] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Administration.Commands.CA.CrlDistributionPointResult])] + [OutputType([System.Object])] + param ( + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Uri}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCertificateCdp}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToFreshestCrl}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCrlCdp}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AddToCrlIdp}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${PublishToServer}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${PublishDeltaToServer}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Remove-CATemplate +{ + <# + .SYNOPSIS + Remove-CATemplate [-Name] [-Force] [-WhatIf] [-Confirm] [] + +Remove-CATemplate -AllTemplates [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + param ( + [Parameter(ParameterSetName = 'Default', Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Name}, + + [Parameter(ParameterSetName = 'AllTemplates', Mandatory = $true)] + [switch] + ${AllTemplates}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Restore-CARoleService +{ + <# + .SYNOPSIS + Restore-CARoleService [-Path] -KeyOnly [-Force] [-Password ] [-WhatIf] [-Confirm] [] + +Restore-CARoleService [-Path] -DatabaseOnly [-Force] [-WhatIf] [-Confirm] [] + +Restore-CARoleService [-Path] [-Force] [-Password ] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] + [OutputType([System.Void])] + param ( + [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${Path}, + + [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${Force}, + + [Parameter(ParameterSetName = 'Key', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${KeyOnly}, + + [Parameter(ParameterSetName = 'Database', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [switch] + ${DatabaseOnly}, + + [Parameter(ParameterSetName = 'Key', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'All', ValueFromPipelineByPropertyName = $true)] + [securestring] + ${Password} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} diff --git a/tests/Unit/Stubs/AdcsDeploymentStub.psm1 b/tests/Unit/Stubs/AdcsDeploymentStub.psm1 new file mode 100644 index 0000000..f6724b5 --- /dev/null +++ b/tests/Unit/Stubs/AdcsDeploymentStub.psm1 @@ -0,0 +1,626 @@ +# This section suppresses rules PsScriptAnalyzer may catch in stub functions. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')] + +# Name: adcsdeployment +# Version: 1.0.0.0 + +[CmdletBinding()] +param () + +function Install-AdcsCertificationAuthority +{ + <# + .SYNOPSIS + Install-AdcsCertificationAuthority [-AllowAdministratorInteraction] [-ValidityPeriod ] [-ValidityPeriodUnits ] [-CACommonName ] [-CADistinguishedNameSuffix ] [-CAType ] [-CryptoProviderName ] [-DatabaseDirectory ] [-HashAlgorithmName ] [-IgnoreUnicode] [-KeyLength ] [-LogDirectory ] [-OutputCertRequestFile ] [-OverwriteExistingCAinDS] [-OverwriteExistingKey] [-ParentCA ] [-OverwriteExistingDatabase] [-Credential ] [-Force] [-WhatIf] [-Confirm] [] + +Install-AdcsCertificationAuthority [-AllowAdministratorInteraction] [-CertFilePassword ] [-CertFile ] [-CAType ] [-CertificateID ] [-DatabaseDirectory ] [-LogDirectory ] [-OverwriteExistingKey] [-OverwriteExistingDatabase] [-Credential ] [-Force] [-WhatIf] [-Confirm] [] + +Install-AdcsCertificationAuthority [-AllowAdministratorInteraction] [-ValidityPeriod ] [-ValidityPeriodUnits ] [-CADistinguishedNameSuffix ] [-CAType ] [-CryptoProviderName ] [-DatabaseDirectory ] [-HashAlgorithmName ] [-IgnoreUnicode] [-KeyContainerName ] [-LogDirectory ] [-OutputCertRequestFile ] [-OverwriteExistingCAinDS] [-ParentCA ] [-OverwriteExistingDatabase] [-Credential ] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'NewKeyParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupResult])] + [OutputType([System.Object])] + param ( + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AllowAdministratorInteraction}, + + [Parameter(ParameterSetName = 'ExistingCertificateParameterSet', ValueFromPipelineByPropertyName = $true)] + [securestring] + ${CertFilePassword}, + + [Parameter(ParameterSetName = 'ExistingCertificateParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CertFile}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [System.String] + ${ValidityPeriod}, + + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateRange(1, 4294967295)] + [System.UInt32] + ${ValidityPeriodUnits}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CACommonName}, + + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CADistinguishedNameSuffix}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [System.String] + ${CAType}, + + [Parameter(ParameterSetName = 'ExistingCertificateParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CertificateID}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CryptoProviderName}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${DatabaseDirectory}, + + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${HashAlgorithmName}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [switch] + ${IgnoreUnicode}, + + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${KeyContainerName}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateRange(1, 4294967295)] + [System.UInt32] + ${KeyLength}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${LogDirectory}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${OutputCertRequestFile}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [switch] + ${OverwriteExistingCAinDS}, + + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'ExistingCertificateParameterSet', ValueFromPipelineByPropertyName = $true)] + [switch] + ${OverwriteExistingKey}, + + [Parameter(ParameterSetName = 'ExistingKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [Parameter(ParameterSetName = 'NewKeyParameterSet', ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${ParentCA}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${OverwriteExistingDatabase}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [pscredential] + ${Credential}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Install-AdcsEnrollmentPolicyWebService +{ + <# + .SYNOPSIS + Install-AdcsEnrollmentPolicyWebService [-AuthenticationType ] [-SSLCertThumbprint ] [-KeyBasedRenewal] [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.CEP.EnrollmentPolicyServiceResult])] + [OutputType([System.Object])] + param ( + [Parameter(ValueFromPipelineByPropertyName = $true)] + [System.String] + ${AuthenticationType}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${SSLCertThumbprint}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${KeyBasedRenewal}, + + [switch] + ${Force}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [pscredential] + ${Credential} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Install-AdcsEnrollmentWebService +{ + <# + .SYNOPSIS + Install-AdcsEnrollmentWebService [-CAConfig ] [-ApplicationPoolIdentity] [-AuthenticationType ] [-SSLCertThumbprint ] [-RenewalOnly] [-AllowKeyBasedRenewal] [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + +Install-AdcsEnrollmentWebService -ServiceAccountName -ServiceAccountPassword [-CAConfig ] [-AuthenticationType ] [-SSLCertThumbprint ] [-RenewalOnly] [-AllowKeyBasedRenewal] [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.CES.EnrollmentServiceResult])] + [OutputType([System.Object])] + param ( + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CAConfig}, + + [Parameter(ParameterSetName = 'ServiceAccountParameterSet', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${ServiceAccountName}, + + [Parameter(ParameterSetName = 'ServiceAccountParameterSet', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [securestring] + ${ServiceAccountPassword}, + + [Parameter(ParameterSetName = 'DefaultParameterSet', ValueFromPipelineByPropertyName = $true)] + [switch] + ${ApplicationPoolIdentity}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [System.String] + ${AuthenticationType}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${SSLCertThumbprint}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${RenewalOnly}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + ${AllowKeyBasedRenewal}, + + [switch] + ${Force}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [pscredential] + ${Credential} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Install-AdcsNetworkDeviceEnrollmentService +{ + <# + .SYNOPSIS + Install-AdcsNetworkDeviceEnrollmentService [-ApplicationPoolIdentity] [-RAName ] [-RAEmail ] [-RACompany ] [-RADepartment ] [-RACity ] [-RAState ] [-RACountry ] [-SigningProviderName ] [-SigningKeyLength ] [-EncryptionProviderName ] [-EncryptionKeyLength ] [-CAConfig ] [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + +Install-AdcsNetworkDeviceEnrollmentService -ServiceAccountName -ServiceAccountPassword [-RAName ] [-RAEmail ] [-RACompany ] [-RADepartment ] [-RACity ] [-RAState ] [-RACountry ] [-SigningProviderName ] [-SigningKeyLength ] [-EncryptionProviderName ] [-EncryptionKeyLength ] [-CAConfig ] [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.NDES.NetworkDeviceEnrollmentServiceResult])] + [OutputType([System.Object])] + param ( + [Parameter(ParameterSetName = 'DefaultParameterSet', ValueFromPipelineByPropertyName = $true)] + [switch] + ${ApplicationPoolIdentity}, + + [Parameter(ParameterSetName = 'ServiceAccountParameterSet', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${ServiceAccountName}, + + [Parameter(ParameterSetName = 'ServiceAccountParameterSet', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [securestring] + ${ServiceAccountPassword}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RAName}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RAEmail}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RACompany}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RADepartment}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RACity}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RAState}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${RACountry}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${SigningProviderName}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateRange(1, 4294967295)] + [int] + ${SigningKeyLength}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${EncryptionProviderName}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateRange(1, 4294967295)] + [int] + ${EncryptionKeyLength}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CAConfig}, + + [switch] + ${Force}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [pscredential] + ${Credential} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Install-AdcsOnlineResponder +{ + <# + .SYNOPSIS + Install-AdcsOnlineResponder [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderResult])] + [OutputType([System.Object])] + param ( + [switch] + ${Force}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [pscredential] + ${Credential} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Install-AdcsWebEnrollment +{ + <# + .SYNOPSIS + Install-AdcsWebEnrollment [-CAConfig ] [-Force] [-Credential ] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentResult])] + [OutputType([System.Object])] + param ( + [Parameter(ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CAConfig}, + + [switch] + ${Force}, + + [Parameter(ValueFromPipelineByPropertyName = $true)] + [pscredential] + ${Credential} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Uninstall-AdcsCertificationAuthority +{ + <# + .SYNOPSIS + Uninstall-AdcsCertificationAuthority [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.CA.CertificationAuthoritySetupResult])] + [OutputType([System.Object])] + param ( + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Uninstall-AdcsEnrollmentPolicyWebService +{ + <# + .SYNOPSIS + Uninstall-AdcsEnrollmentPolicyWebService -AuthenticationType [-KeyBasedRenewal] [-Force] [-WhatIf] [-Confirm] [] + +Uninstall-AdcsEnrollmentPolicyWebService [-AllPolicyServers] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'UninstallSingleInstance', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.CEP.EnrollmentPolicyServiceResult])] + [OutputType([System.Object])] + param ( + [Parameter(ParameterSetName = 'UninstallAll', ValueFromPipelineByPropertyName = $true)] + [switch] + ${AllPolicyServers}, + + [Parameter(ParameterSetName = 'UninstallSingleInstance', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [System.String] + ${AuthenticationType}, + + [Parameter(ParameterSetName = 'UninstallSingleInstance', ValueFromPipelineByPropertyName = $true)] + [switch] + ${KeyBasedRenewal}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Uninstall-AdcsEnrollmentWebService +{ + <# + .SYNOPSIS + Uninstall-AdcsEnrollmentWebService -CAConfig -AuthenticationType [-Force] [-WhatIf] [-Confirm] [] + +Uninstall-AdcsEnrollmentWebService [-AllEnrollmentServices] [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'UninstallSingleInstance', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.CES.EnrollmentServiceResult])] + [OutputType([System.Object])] + param ( + [Parameter(ParameterSetName = 'UninstallSingleInstance', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string] + ${CAConfig}, + + [Parameter(ParameterSetName = 'UninstallSingleInstance', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [System.String] + ${AuthenticationType}, + + [Parameter(ParameterSetName = 'UninstallAll', ValueFromPipelineByPropertyName = $true)] + [switch] + ${AllEnrollmentServices}, + + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Uninstall-AdcsNetworkDeviceEnrollmentService +{ + <# + .SYNOPSIS + Uninstall-AdcsNetworkDeviceEnrollmentService [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.NDES.NetworkDeviceEnrollmentServiceResult])] + [OutputType([System.Object])] + param ( + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Uninstall-AdcsOnlineResponder +{ + <# + .SYNOPSIS + Uninstall-AdcsOnlineResponder [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderResult])] + [OutputType([System.Object])] + param ( + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +} + +function Uninstall-AdcsWebEnrollment +{ + <# + .SYNOPSIS + Uninstall-AdcsWebEnrollment [-Force] [-WhatIf] [-Confirm] [] + #> + + [CmdletBinding(DefaultParameterSetName = 'DefaultParameterSet', SupportsShouldProcess = $true, ConfirmImpact = 'High')] + #[OutputType([Microsoft.CertificateServices.Deployment.Common.WEP.WebEnrollmentResult])] + [OutputType([System.Object])] + param ( + [switch] + ${Force} + ) + end + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } +}