From f8fadc9030a2bfaf9dab7c179558bd8f9cb9c970 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 11 May 2019 18:43:09 +0200 Subject: [PATCH 01/16] First iteration of documentation --- Assert-TestEnvironment.ps1 | 103 +++++++++++++++++++++++++++++++++++++ Tests/README.md | 49 ++++++++++++++++++ Tests/Tests.depend.psd1 | 42 +++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 Assert-TestEnvironment.ps1 create mode 100644 Tests/README.md create mode 100644 Tests/Tests.depend.psd1 diff --git a/Assert-TestEnvironment.ps1 b/Assert-TestEnvironment.ps1 new file mode 100644 index 000000000..f587014c7 --- /dev/null +++ b/Assert-TestEnvironment.ps1 @@ -0,0 +1,103 @@ +<# + .SYNOPSIS + Assert that the test environment is properly setup and loaded into the + PowerShell session. + + .DESCRIPTION + Assert that the test environment is properly setup and loaded into the + PowerShell session. + + .EXAMPLE + .\Assert-testEnvironment.ps1 + + Will assert that the current PowerShell session is ready to run tests. +#> + +[CmdletBinding(SupportsShouldProcess = $true)] +param +( +) + +#region Verify prerequisites Pester +$pesterModuleName = 'Pester' + +# This is the minimum version that can be used with the tests in this repo. +$pesterModuleMinimumVersion = '4.0.2' + +<# + Pester v4.4.0 has a fix for '-Not -Throw' so it shows the actual error + message if an unexpected exception does occur. It will help when debugging + tests. + If no Pester module exist, then use this as the minimum version. +#> +$pesterModuleRecommendedMinimumVersion = '4.4.0' + +$pesterModule = Get-Module $pesterModuleName -ListAvailable -Verbose:$false | + Where-Object -Property 'Version' -GE -Value $pesterModuleMinimumVersion | + Sort-Object -Property 'Version' -Descending | + Select-Object -First 1 + +if (-not $pesterModule) +{ + <# + Not installing the module here because it's not known what scope the + user want (can) to install the module in. + #> + $message = 'Missing a compatible version of the {0} module. Minimum version of {0} module can be ''{2}'', but the recommended minimum version is ''{1}''.' -f $pesterModuleName, $pesterModuleRecommendedMinimumVersion, $pesterModuleMinimumVersion + Write-Warning -Message $message + $dependencyMissing = $true +} +else +{ + Write-Verbose -Message ('A compatible {0} module is already installed (v{1}). If you want to use a newer version of {0} module, please install it manually.' -f $pesterModule.Name, $pesterModule.Version) +} +#endregion Verify prerequisites Pester + +#region Verify prerequisites PSDepend +$psDependModuleName = 'PSDepend' + +# This is the minimum version that can be used with the tests in this repo. +$psDependModuleMinimumVersion = '0.3.0' +$psDependModuleRecommendedMinimumVersion = 'latest' + +$psDependModule = Get-Module $psDependModuleName -ListAvailable -Verbose:$false | + Where-Object -Property 'Version' -GE -Value $psDependModuleMinimumVersion | + Sort-Object -Property 'Version' -Descending | + Select-Object -First 1 + +if (-not $psDependModule) +{ + <# + Not installing the module here because it's not known what scope the + user want (can) to install the module in. + #> + $message = 'Missing a compatible version of the {0} module. Minimum version of {0} module can be ''{2}'', but the recommended minimum version is ''{1}''. Please install {0} module manually, then run this script again.' -f $psDependModuleName, $psDependModuleRecommendedMinimumVersion, $psDependModuleMinimumVersion + Write-Warning -Message $message + $dependencyMissing = $true +} +else +{ + Write-Verbose -Message ('A compatible {0} module is already installed (v{1}). If you want to use a newer version of {0} module, please install it manually.' -f $psDependModule.Name, $psDependModule.Version) +} +#endregion Verify prerequisites PSDepend + +if ($dependencyMissing) +{ + Write-Output -InputObject 'Please install the necessary dependencies manually, then run this script again.' + return +} + +$dependenciesPath = Join-Path $PSScriptRoot -ChildPath 'Tests' + +Write-Verbose -Message ('Running Invoke-PSDepend using dependencies found under the path ''{0}''.' -f $dependenciesPath) + +if ($PSBoundParameters.ContainsKey('Confirm')) +{ + $invokePSDependConfirmation = $ConfirmPreference +} +else +{ + $invokePSDependConfirmation = $false +} + +Invoke-PSDepend -Path $dependenciesPath -Confirm:$invokePSDependConfirmation diff --git a/Tests/README.md b/Tests/README.md new file mode 100644 index 000000000..d60b2bc55 --- /dev/null +++ b/Tests/README.md @@ -0,0 +1,49 @@ +# Running tests + +## Integration tests in Hyper-V + +The below steps assumes the virtual machines does not have access to the +Internet. + +This requires at least one working domain controller. + + + +1. Copy Pester to a path in `$env:PSModulePath`. +1. Copy PSDepend to a path in `$env:PSModulePath`. +1. Copy resource module code to a local folder, e.g. `C:\source\xActiveDirectory`. + _**NOTE:** Do not copy the resource being tested to a path that exist_ + _in `$env:PSModulePath`, that will generate an error that multiple_ + _modules exist on the node._ +1. Copy the repository [DscResource.Tests](https://github.com/PowerShell/DscResource.Tests) + to the root of the folder where the resource module code was copied, + e.g. `C:\source\xActiveDirectory`. +1. Start a PowerShell prompt with elevated permissions. +1. Run + ```powershell + cd 'c:\source\xActiveDirectory' + .\Assert-TestEnvironment.ps1 -Confirm + ``` +1. **IMPORTANT!** Answer 'No' on the first two questions, and answer + 'Yes' on the third question. + ```plaintext + Processing dependency + Process the dependency 'RemoveTestFramework'? + [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): n + + Processing dependency + Process the dependency 'CloneTestFramework'? + [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): n + + Processing dependency + Process the dependency 'LoadDscResourceKitTypes'? + [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y + ``` +1. Run + ```powershell + Invoke-Pester .\Tests\Integration\MSFT_xADComputer.Integration.Tests.ps1 + ``` diff --git a/Tests/Tests.depend.psd1 b/Tests/Tests.depend.psd1 new file mode 100644 index 000000000..3446741b8 --- /dev/null +++ b/Tests/Tests.depend.psd1 @@ -0,0 +1,42 @@ +<# + .DESCRIPTION + This is the dependency file for use with Assert-TestEnvironment.ps1 and/or + Invoke-PSDepend (PSSDepend). +#> +@{ + RemoveTestFramework = @{ + DependencyType = 'Command' + Source = ' + $testFrameWorkPath = Join-Path -Path $PWD -ChildPath ''DscResource.Tests'' + if (Test-Path -Path $testFrameWorkPath) + { + Write-Verbose -Message ''Removing local test framework repository.'' + Remove-Item -Path (Join-Path -Path $PWD -ChildPath ''DscResource.Tests'') -Recurse -Force + } + ' + } + + 'CloneTestFramework' = @{ + DependencyType = 'Git' + Name = 'https://github.com/PowerShell/DscResource.Tests' + Version = 'dev' + DependsOn = 'RemoveTestFramework' + } + + LoadDscResourceKitTypes = @{ + DependencyType = 'Command' + Source = ' + if (-not (''Microsoft.DscResourceKit.Test'' -as [Type])) + { + Write-Verbose -Message ''Loading the Microsoft.DscResourceKit types into the current session.'' + $typesSourceFile = Join-Path -Path ''$PWD\DscResource.Tests'' -ChildPath ''Microsoft.DscResourceKit.cs'' + Add-Type -Path $typesSourceFile -WarningAction SilentlyContinue + } + else + { + Write-Verbose -Message ''The Microsoft.DscResourceKit types was already loaded into the current session.'' + } + ' + DependsOn = 'CloneTestFramework' + } +} From 5e771200586b3df93e259ca4da61a380fcb40fa9 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 May 2019 19:46:22 +0200 Subject: [PATCH 02/16] Updated steps for base image --- Tests/README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/Tests/README.md b/Tests/README.md index d60b2bc55..3b990f947 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -1,12 +1,79 @@ # Running tests -## Integration tests in Hyper-V +## Run integration tests in Hyper-V (PowerShell Direct) The below steps assumes the virtual machines does not have access to the Internet. This requires at least one working domain controller. +### Create Hyper-V base image template + +There are many blog articles explaining this, just search for +create a hyper-v template" in your favorite search engine. + +The basic steps are + +1. Create VM with Windows Server 2016 or later (Desktop Experience or + Server Core). +1. Export the VM. + +This can be done with these steps. + +>**Note:** All these steps are expected to be run in the same elevated +>PowerShell prompt. + +1. Create a Hyper-VM (Generation 2). In an elevated PowerShell prompt run + this. + ```powershell + $virtualHardDiskPath = Get-VMHost | Select-Object -ExpandProperty 'VirtualHardDiskPath' + $pathWindowsServerIso = 'C:\_images\en_windows_server_2019_x64_dvd_4cb967d8.iso' + + $newVmParameters = @{ + Name = 'DscAD-template' + BootDevice = 'CD' + MemoryStartupBytes = 4GB + NoVHD = $true + Generation = 2 + SwitchName = 'Default Switch' + } + + $vm = New-VM @newVmParameters + Set-VM -VM $vm -AutomaticCheckpointsEnabled $false -DynamicMemory + $vmDiskPath = Join-Path -Path $virtualHardDiskPath -ChildPath 'DscAD-template.vhdx' + $vhd = New-VHD -Path $vmDiskPath -SizeBytes 40GB -Dynamic + Add-VMHardDiskDrive -VM $vm -Path $vhd.Path + Get-VMDvdDrive -VM $vm | Set-VMDvdDrive -Path $pathWindowsServerIso + Start-VM -VM $vm + ``` +1. Continue the installation as normal in the Hyper-V Virtual Machine + Connection. + 1. You don't need to provide a product key. +1. (Optional) Install any updates. +1. (Optional) Make any personal modifications, if they will stick after + a SysPrep. +1. In an elevated PowerShell prompt run this to + [Sysprep generalize](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--generalize--a-windows-installation) + and return the VM (image) to the out-of-the-box-experience. + ```powershell + C:\Windows\System32\SysPrep\sysprep.exe /quiet /generalize /oobe /shutdown + ``` +1. Create the folder where we store the exported image. _This folder can_ + _be located anywhere._ + ```powershell + $templatePath = 'C:\Hyper-V\Templates' + New-Item -Path $templatePath -ItemType 'Directory' -Force + ``` +1. Export the VM base image template. + ```powershell + Export-VM -VM $vm -Path $templatePath + ``` +1. (Optional) This VM can be deleted once we exported the image. + ```powershell + Remove-VM -VM $vm -Force + Remove-Item -Path $vmDiskPath -Force + ``` + 1. Create a Hyper-VM (Generation 2). In an elevated PowerShell prompt run this. ```powershell + $pathWindowsServerIso = 'C:\_images\17763.379.190312-0539.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso' $virtualHardDiskPath = Get-VMHost | Select-Object -ExpandProperty 'VirtualHardDiskPath' - $pathWindowsServerIso = 'C:\_images\en_windows_server_2019_x64_dvd_4cb967d8.iso' $newVmParameters = @{ - Name = 'DscAD-template' + Name = 'DSCAD-template' BootDevice = 'CD' MemoryStartupBytes = 4GB NoVHD = $true @@ -40,7 +39,7 @@ This can be done with these steps. $vm = New-VM @newVmParameters Set-VM -VM $vm -AutomaticCheckpointsEnabled $false -DynamicMemory - $vmDiskPath = Join-Path -Path $virtualHardDiskPath -ChildPath 'DscAD-template.vhdx' + $vmDiskPath = Join-Path -Path $virtualHardDiskPath -ChildPath 'DSCAD-template.vhdx' $vhd = New-VHD -Path $vmDiskPath -SizeBytes 40GB -Dynamic Add-VMHardDiskDrive -VM $vm -Path $vhd.Path Get-VMDvdDrive -VM $vm | Set-VMDvdDrive -Path $pathWindowsServerIso @@ -61,18 +60,77 @@ This can be done with these steps. 1. Create the folder where we store the exported image. _This folder can_ _be located anywhere._ ```powershell - $templatePath = 'C:\Hyper-V\Templates' - New-Item -Path $templatePath -ItemType 'Directory' -Force + $templatesPath = 'C:\Hyper-V\Templates' + New-Item -Path $templatesPath -ItemType 'Directory' -Force ``` 1. Export the VM base image template. ```powershell - Export-VM -VM $vm -Path $templatePath + Export-VM -VM $vm -Path $templatesPath ``` -1. (Optional) This VM can be deleted once we exported the image. +1. (Optional) The exported VM can be deleted once the export is finished. ```powershell Remove-VM -VM $vm -Force Remove-Item -Path $vmDiskPath -Force ``` + + +### Deploy Hyper-V virtual machines + +This will deploy three virtual machines using the virtual machine template +exported in the previous step. These steps assume you have a PC with enough +memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. + +>You can make changes to memory before starting the virtual machines, or +>change the default memory in the template above before exporting the base +>image template. + + +1. Create a Hyper-V virtual switch to use for the private network between + the virtual machines. _**Note:** Running the cmdlet `New-VMSwitch` more_ + _than once will create more than one virtual switch with the same name._ + ```powershell + $virtualSwitchName = 'DSCADLabPrivate' + if ( -not (Get-VMSwitch -Name $virtualSwitchName)) + { + New-VMSwitch -Name $virtualSwitchName -SwitchType 'Private' + } + ``` +1. Deploy three virtual machines that will be used to configure three + domain controllers. + ```powershell + $templateName = 'DSCAD-template' + $templatesPath = 'C:\Hyper-V\Templates' + $virtualMachinesPath = 'C:\Hyper-V\Virtual Machines' + + $vmTemplatePath = (Get-ChildItem -Path (Join-Path -Path $templatesPath -ChildPath $templateName) -Recurse -Filter '*.vmcx').FullName + + $vmNames = @( + 'dc01' + 'dc02' + 'dc03' + ) + + foreach ($vmName in $vmNames) + { + $vmPath = Join-Path -Path $virtualMachinesPath -ChildPath $vmName + $vm = Import-VM -Path $vmTemplatePath -Copy -GenerateNewId -VirtualMachinePath $vmPath -VhdDestinationPath $vmPath -SnapshotFilePath $vmPath -SmartPagingFilePath $vmPath + Set-VM -VM $vm -NewVMName $vmName -DynamicMemory + Set-VM -VM $vm -AutomaticCheckpointsEnabled $false + Get-VMNetworkAdapter -VM $vm | Connect-VMNetworkAdapter -SwitchName $virtualSwitchName + } + + Get-VM -Name $vmnames | Start-VM -Verbose + ``` +1. On each started VM finish the installation by configure the following + in the Hyper-V Virtual Machine Connection. + - Localization + - (Optional) Product key + - Accept license terms + - Set local administrator password to `adminP@ssw0rd1`. _**Note:** This_ + _password must be the same as the one used in the integration test._ + + +### Test prerequisites +The below steps assumes the virtual machines does not have access to the +Internet. + + +1. Install the dependent DSC resource modules on the node that hosts your + virtual machines, the same as from where the integration tests will be run. + ```powershell + $dependentModules = @( + 'PSDscResources', + 'ComputerManagementDsc', + 'NetworkingDsc' + ) + + Install-Module -Name $dependentModules + ``` +1. Open a PowerShell Direct session to each virtual machine. + ```powershell + $localAdminPassword = ConvertTo-SecureString 'adminP@ssw0rd1' -AsPlainText -Force + $localAdminUsername = 'Administrator' + + $newObjectParameters = @{ + TypeName = 'System.Management.Automation.PSCredential' + ArgumentList = @( + $localAdminUsername, + $localAdminPassword + ) + } + + $localAdminCredential = New-Object @newObjectParameters + + $dc01Session = New-PSSession -VMName 'dc01' -Credential $localAdminCredential + $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential + $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential + ``` +1. Copy the dependent modules to each of the virtual machines. + ```powershell + $dependentModule = Get-Module -ListAvailable -Name $dependentModules + foreach ($module in $dependentModule) + { + $sourceModulePath = Split-Path -Path $module.ModuleBase -Parent + $destinationModulePath = Join-Path -Path 'C:\Program Files\WindowsPowerShell\Modules' -ChildPath $module.Name + + Copy-Item -ToSession $dc01Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + Copy-Item -ToSession $dc02Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + Copy-Item -ToSession $dc03Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + } + ``` +1. Create the configuration .mof and the metadata .mof file on the respective + nodes. + ```powershell + Invoke-Command -Session $dc01Session -FilePath '.\Tests\TestHelpers\Prepare-DscLab-dc01.ps1' + Invoke-Command -Session $dc02Session -FilePath '.\Tests\TestHelpers\Prepare-DscLab-dc02.ps1' + Invoke-Command -Session $dc03Session -FilePath '.\Tests\TestHelpers\Prepare-DscLab-dc03.ps1' + ``` +1. Configure the DSC Local Configuration Manager (LCM) on each virtual + machine using the metadata .mof created in previous step. + ```powershell + Invoke-Command -Session $dc01Session,$dc02Session,$dc03Session -ScriptBlock { + Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force + } + ``` +1. Run the configuration on each virtual machine to set up all the + prerequisites. **The virtual machine will reboot during this.** + ```powershell + Invoke-Command -Session $dc01Session,$dc02Session,$dc03Session -ScriptBlock { + Start-DscConfiguration -Path "C:\DSC\Configuration\" -ComputerName 'localhost' -Wait -Force -Verbose + } + ``` +1. Wait until the node has been restarted and the rest of the configuration + has been applied. This should report the status *Success* once the + configuration is finished. _**Note:** Since the virtual machines rebooted_ + _we need to reconnect to the sessions._ + ```powershell + $dc01Session = New-PSSession -VMName 'dc01' -Credential $localAdminCredential + $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential + $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential + + Invoke-Command -Session $dc01Session,$dc02Session,$dc03Session -ScriptBlock { + Get-DscConfigurationStatus + } + ``` +1. At this point it would be good to checkpoint the servers. + ```powershell + Checkpoint-VM -Name 'dc01','dc02','dc03' -SnapshotName 'WithPreReq' + ``` 1. Copy Pester to a path in `$env:PSModulePath`. 1. Copy PSDepend to a path in `$env:PSModulePath`. 1. Copy resource module code to a local folder, e.g. `C:\source\xActiveDirectory`. @@ -114,3 +257,4 @@ This can be done with these steps. ```powershell Invoke-Pester .\Tests\Integration\MSFT_xADComputer.Integration.Tests.ps1 ``` + diff --git a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 new file mode 100644 index 000000000..911751f19 --- /dev/null +++ b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 @@ -0,0 +1,150 @@ +<# + .SYNOPSIS + Prerequisites configuration for running integration tests. + This configuration sets up the prerequisites for the + node dc01.dscadlab.com. +#> + +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) +} + +[DSCLocalConfigurationManager()] +configuration LCMConfig +{ + Node $AllNodes.NodeName + { + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyAndAutoCorrect' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } + } +} + +<# + .SYNOPSIS + Configures the Hyper-V node dc01 with the correct prerequisites. +#> +Configuration DomainController +{ + Import-DSCResource -ModuleName PSDscResources + Import-DSCResource -ModuleName NetworkingDsc + Import-DSCResource -ModuleName ComputerManagementDsc + + + Node 'localhost' + { + Computer NewName + { + Name = 'dc01' + Description = 'First domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.2.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.3.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + } +} + +LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose + +DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose diff --git a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 new file mode 100644 index 000000000..bbb08bc31 --- /dev/null +++ b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 @@ -0,0 +1,150 @@ +<# + .SYNOPSIS + Prerequisites configuration for running integration tests. + This configuration sets up the prerequisites for the + node dc02.dscadlab.com. +#> + +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) +} + +[DSCLocalConfigurationManager()] +configuration LCMConfig +{ + Node $AllNodes.NodeName + { + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyAndAutoCorrect' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } + } +} + +<# + .SYNOPSIS + Configures the Hyper-V node dc02 with the correct prerequisites. +#> +Configuration DomainController +{ + Import-DSCResource -ModuleName PSDscResources + Import-DSCResource -ModuleName NetworkingDsc + Import-DSCResource -ModuleName ComputerManagementDsc + + + Node 'localhost' + { + Computer NewName + { + Name = 'dc02' + Description = 'First domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.3.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.2.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + } +} + +LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose + +DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose diff --git a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 new file mode 100644 index 000000000..efa4e4fa8 --- /dev/null +++ b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 @@ -0,0 +1,150 @@ +<# + .SYNOPSIS + Prerequisites configuration for running integration tests. + This configuration sets up the prerequisites for the + node dc03.dscadlab.com. +#> + +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) +} + +[DSCLocalConfigurationManager()] +configuration LCMConfig +{ + Node $AllNodes.NodeName + { + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyAndAutoCorrect' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } + } +} + +<# + .SYNOPSIS + Configures the Hyper-V node dc02 with the correct prerequisites. +#> +Configuration DomainController +{ + Import-DSCResource -ModuleName PSDscResources + Import-DSCResource -ModuleName NetworkingDsc + Import-DSCResource -ModuleName ComputerManagementDsc + + + Node 'localhost' + { + Computer NewName + { + Name = 'dc03' + Description = 'First domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.4.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.2.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + } +} + +LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose + +DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose From 6a1ee5a15078d2ec4eddb21df60acb433a98d0b6 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Mon, 3 Jun 2019 18:12:57 +0200 Subject: [PATCH 04/16] Added section Running integration tests --- Assert-TestEnvironment.ps1 | 23 +++++++++++- Tests/README.md | 75 ++++++++++++++++++++------------------ Tests/Tests.depend.psd1 | 5 ++- 3 files changed, 66 insertions(+), 37 deletions(-) diff --git a/Assert-TestEnvironment.ps1 b/Assert-TestEnvironment.ps1 index f587014c7..e42a0fc29 100644 --- a/Assert-TestEnvironment.ps1 +++ b/Assert-TestEnvironment.ps1 @@ -7,15 +7,26 @@ Assert that the test environment is properly setup and loaded into the PowerShell session. + .PARAMETER Tags + One or more tags to use for the cmdlet Invoke-PSDepend. + .EXAMPLE .\Assert-testEnvironment.ps1 Will assert that the current PowerShell session is ready to run tests. + + .EXAMPLE + .\Assert-testEnvironment.ps1 -Tags 'LoadDscResourceKitTypes' + + Will only assert that the current PowerShell session has the types loaded. #> [CmdletBinding(SupportsShouldProcess = $true)] param ( + [Parameter()] + [System.String[]] + $Tags ) #region Verify prerequisites Pester @@ -100,4 +111,14 @@ else $invokePSDependConfirmation = $false } -Invoke-PSDepend -Path $dependenciesPath -Confirm:$invokePSDependConfirmation +$invokePSDependParameters = @{ + Path = $dependenciesPath + Confirm = $invokePSDependConfirmation +} + +if ($PSBoundParameters.ContainsKey('Tags')) +{ + $invokePSDependParameters['Tags'] = $Tags +} + +Invoke-PSDepend @invokePSDependParameters diff --git a/Tests/README.md b/Tests/README.md index 0de48a05e..f73d483ae 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -132,12 +132,6 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. ### Test prerequisites - - The below steps assumes the virtual machines does not have access to the Internet. @@ -146,6 +140,8 @@ Internet. virtual machines, the same as from where the integration tests will be run. ```powershell $dependentModules = @( + 'Pester', + 'PSDepend', 'PSDscResources', 'ComputerManagementDsc', 'NetworkingDsc' @@ -174,11 +170,15 @@ Internet. ``` 1. Copy the dependent modules to each of the virtual machines. ```powershell - $dependentModule = Get-Module -ListAvailable -Name $dependentModules + $dependentModule = Get-Module -ListAvailable -Name $dependentModules | + Sort-Object -Property 'Version' | + Sort-Object -Unique + foreach ($module in $dependentModule) { - $sourceModulePath = Split-Path -Path $module.ModuleBase -Parent - $destinationModulePath = Join-Path -Path 'C:\Program Files\WindowsPowerShell\Modules' -ChildPath $module.Name + $sourceModulePath = $module.ModuleBase + $moduleVersionFolder = Split-Path -Path $module.ModuleBase -Leaf + $destinationModulePath = Join-Path -Path (Join-Path -Path 'C:\Program Files\WindowsPowerShell\Modules' -ChildPath $module.Name) -ChildPath $moduleVersionFolder Copy-Item -ToSession $dc01Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force Copy-Item -ToSession $dc02Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force @@ -219,42 +219,47 @@ Internet. Get-DscConfigurationStatus } ``` +1. **Important!** Change to folder to root of your local working repository folder, e.g. + `cd 'c:\source\xActiveDirectory'`. +1. Clone the latest test framework into the local repository folder. _**Note:**_ + _This requires `git`. The test framework will also be cloned when running_ + _a unit test._ + ```powershell + .\Assert-TestEnvironment.ps1 + ``` 1. At this point it would be good to checkpoint the servers. ```powershell Checkpoint-VM -Name 'dc01','dc02','dc03' -SnapshotName 'WithPreReq' ``` -1. Copy Pester to a path in `$env:PSModulePath`. -1. Copy PSDepend to a path in `$env:PSModulePath`. + +### Running the integration tests + +By reverting to the checkpoint created before, these tests can be run +several times. The integration tests that depend on an already existing +domain can be run several times without reverting to the checkpoint. The +resources that need a clean environment are the resources that configures +the domain, e.g. `xADDomain` and `xADDomainController`. + 1. Copy resource module code to a local folder, e.g. `C:\source\xActiveDirectory`. _**NOTE:** Do not copy the resource being tested to a path that exist_ _in `$env:PSModulePath`, that will generate an error that multiple_ _modules exist on the node._ -1. Copy the repository [DscResource.Tests](https://github.com/PowerShell/DscResource.Tests) - to the root of the folder where the resource module code was copied, - e.g. `C:\source\xActiveDirectory`. -1. Start a PowerShell prompt with elevated permissions. -1. Run ```powershell - cd 'c:\source\xActiveDirectory' - .\Assert-TestEnvironment.ps1 -Confirm - ``` -1. **IMPORTANT!** Answer 'No' on the first two questions, and answer - 'Yes' on the third question. - ```plaintext - Processing dependency - Process the dependency 'RemoveTestFramework'? - [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): n - - Processing dependency - Process the dependency 'CloneTestFramework'? - [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): n - - Processing dependency - Process the dependency 'LoadDscResourceKitTypes'? - [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y + $sourceRepositoryPath = '.' + $destinationRepositoryPath = 'C:\Source\xActiveDirectory' + + # This way we skip the hidden folder '.git'. + Get-ChildItem -Path $sourceRepositoryPath | Copy-Item -ToSession $dc01Session -Destination $destinationRepositoryPath -Recurse -Force + Get-ChildItem -Path $sourceRepositoryPath | Copy-Item -ToSession $dc02Session -Destination $destinationRepositoryPath -Recurse -Force + Get-ChildItem -Path $sourceRepositoryPath | Copy-Item -ToSession $dc03Session -Destination $destinationRepositoryPath -Recurse -Force ``` -1. Run +1. This runs the actual integration tests. ```powershell - Invoke-Pester .\Tests\Integration\MSFT_xADComputer.Integration.Tests.ps1 + Invoke-Command -Session $dc01Session -ScriptBlock { + cd 'c:\source\xActiveDirectory' + .\Assert-TestEnvironment.ps1 -Tags 'LoadDscResourceKitTypes' + + Invoke-Pester -Path '.\Tests\Integration\MSFT_xADComputer.Integration.Tests.ps1' + } ``` diff --git a/Tests/Tests.depend.psd1 b/Tests/Tests.depend.psd1 index 3446741b8..36a2eed77 100644 --- a/Tests/Tests.depend.psd1 +++ b/Tests/Tests.depend.psd1 @@ -5,6 +5,7 @@ #> @{ RemoveTestFramework = @{ + Tags = 'RemoveTestFramework' DependencyType = 'Command' Source = ' $testFrameWorkPath = Join-Path -Path $PWD -ChildPath ''DscResource.Tests'' @@ -16,7 +17,8 @@ ' } - 'CloneTestFramework' = @{ + CloneTestFramework = @{ + Tags = 'CloneTestFramework' DependencyType = 'Git' Name = 'https://github.com/PowerShell/DscResource.Tests' Version = 'dev' @@ -24,6 +26,7 @@ } LoadDscResourceKitTypes = @{ + Tags = 'LoadDscResourceKitTypes' DependencyType = 'Command' Source = ' if (-not (''Microsoft.DscResourceKit.Test'' -as [Type])) From 78d1e55ec30e5d346b990b4a284b8b3b653009c5 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Wed, 5 Jun 2019 18:37:42 +0200 Subject: [PATCH 05/16] Reorder steps --- Tests/README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Tests/README.md b/Tests/README.md index f73d483ae..22218910c 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -185,6 +185,8 @@ Internet. Copy-Item -ToSession $dc03Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force } ``` +1. **Important!** Change to folder to root of your local working repository + folder, e.g. cd 'c:\source\xActiveDirectory'. 1. Create the configuration .mof and the metadata .mof file on the respective nodes. ```powershell @@ -219,8 +221,6 @@ Internet. Get-DscConfigurationStatus } ``` -1. **Important!** Change to folder to root of your local working repository folder, e.g. - `cd 'c:\source\xActiveDirectory'`. 1. Clone the latest test framework into the local repository folder. _**Note:**_ _This requires `git`. The test framework will also be cloned when running_ _a unit test._ @@ -240,10 +240,13 @@ domain can be run several times without reverting to the checkpoint. The resources that need a clean environment are the resources that configures the domain, e.g. `xADDomain` and `xADDomainController`. -1. Copy resource module code to a local folder, e.g. `C:\source\xActiveDirectory`. +1. **Important!** Change to folder to root of your local working repository + folder, e.g. cd 'c:\source\xActiveDirectory'. +1. Copy resource module code to a local folder on each virtual machine, + e.g. `C:\source\xActiveDirectory`. _**NOTE:** Do not copy the resource being tested to a path that exist_ _in `$env:PSModulePath`, that will generate an error that multiple_ - _modules exist on the node._ + _modules exist on the node when running the integration tests._ ```powershell $sourceRepositoryPath = '.' $destinationRepositoryPath = 'C:\Source\xActiveDirectory' From 44923a29365137813bae0b56486e431817b4b5cd Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Wed, 5 Jun 2019 18:43:27 +0200 Subject: [PATCH 06/16] FIx typo --- Tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/README.md b/Tests/README.md index 22218910c..9e633d16e 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -90,7 +90,7 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. _than once will create more than one virtual switch with the same name._ ```powershell $virtualSwitchName = 'DSCADLabPrivate' - if ( -not (Get-VMSwitch -Name $virtualSwitchName)) + if (-not (Get-VMSwitch -Name $virtualSwitchName)) { New-VMSwitch -Name $virtualSwitchName -SwitchType 'Private' } From f862acef8080b9e5edb4572f6414a5cbf520f7ce Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Fri, 10 Apr 2020 21:48:28 +0200 Subject: [PATCH 07/16] Update README.md --- DscResource.Tests | 1 + Tests/README.md | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) create mode 160000 DscResource.Tests diff --git a/DscResource.Tests b/DscResource.Tests new file mode 160000 index 000000000..9c3c40618 --- /dev/null +++ b/DscResource.Tests @@ -0,0 +1 @@ +Subproject commit 9c3c40618b3ccb25e560a2e5fd2e346fbfb830cb diff --git a/Tests/README.md b/Tests/README.md index 9e633d16e..a2007c812 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -19,13 +19,19 @@ used to create the one or more servers to run tests on. >**Note:** All these steps are expected to be run in the same elevated >PowerShell prompt. It also expect that you have downloaded the appropriate ->installation media, for example from [Windows Server Evaluations](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019). +>installation media, for example from [Windows Server Evaluations](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019) +>or the [direct link to the ISO](https://software-download.microsoft.com/download/pr/17763.737.190906-2324.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us_1.iso). 1. Create a Hyper-VM (Generation 2). In an elevated PowerShell prompt run this. ```powershell - $pathWindowsServerIso = 'C:\_images\17763.379.190312-0539.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso' + $windowsServerIsoPath = 'C:\_images\17763.737.190906-2324.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso' + if (-not (Test-Path -Path $windowsServerIsoPath)) + { + throw 'ISO path cannot be found.' + } + $virtualHardDiskPath = Get-VMHost | Select-Object -ExpandProperty 'VirtualHardDiskPath' $newVmParameters = @{ @@ -42,15 +48,17 @@ used to create the one or more servers to run tests on. $vmDiskPath = Join-Path -Path $virtualHardDiskPath -ChildPath 'DSCAD-template.vhdx' $vhd = New-VHD -Path $vmDiskPath -SizeBytes 40GB -Dynamic Add-VMHardDiskDrive -VM $vm -Path $vhd.Path - Get-VMDvdDrive -VM $vm | Set-VMDvdDrive -Path $pathWindowsServerIso + Get-VMDvdDrive -VM $vm | Set-VMDvdDrive -Path $windowsServerIsoPath Start-VM -VM $vm ``` 1. Continue the installation as normal in the Hyper-V Virtual Machine Connection. - 1. You don't need to provide a product key. + - You don't need to provide a product key. + - You can set any password you like for the template, it will be re-set + for each new VM that is deployed later. 1. (Optional) Install any updates. -1. (Optional) Make any personal modifications, if they will stick after - a SysPrep. +1. (Optional) Make any personal modifications (if they will stick after + the SysPrep we will do next). 1. In an elevated PowerShell prompt run this to [Sysprep generalize](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--generalize--a-windows-installation) and return the VM (image) to the out-of-the-box-experience. @@ -90,7 +98,7 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. _than once will create more than one virtual switch with the same name._ ```powershell $virtualSwitchName = 'DSCADLabPrivate' - if (-not (Get-VMSwitch -Name $virtualSwitchName)) + if (-not (Get-VMSwitch -Name $virtualSwitchName -ErrorAction 'SilentlyContinue')) { New-VMSwitch -Name $virtualSwitchName -SwitchType 'Private' } @@ -119,7 +127,7 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. Get-VMNetworkAdapter -VM $vm | Connect-VMNetworkAdapter -SwitchName $virtualSwitchName } - Get-VM -Name $vmnames | Start-VM -Verbose + Get-VM -Name $vmNames | Start-VM -Verbose ``` 1. On each started VM finish the installation by configure the following in the Hyper-V Virtual Machine Connection. @@ -127,7 +135,7 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. - (Optional) Product key - Accept license terms - Set local administrator password to `adminP@ssw0rd1`. _**Note:** This_ - _password must be the same as the one used in the integration test._ + _password **must** be the same as the one used in the integration test._ ### Test prerequisites From 92558783b4e18a472b7c4926fc3956ba9a9ad43e Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 11 Apr 2020 14:24:37 +0200 Subject: [PATCH 08/16] Update --- Assert-TestEnvironment.ps1 | 124 --------- DscResource.Tests | 1 - REMOVE.md | 30 +++ RequiredModules.psd1 | 5 + Tests/README.md | 103 +++++--- Tests/TestHelpers/Prepare-DscLab-dc01.ps1 | 283 +++++++++++---------- Tests/TestHelpers/Prepare-DscLab-dc02.ps1 | 290 ++++++++++++---------- Tests/TestHelpers/Prepare-DscLab-dc03.ps1 | 290 ++++++++++++---------- Tests/Tests.depend.psd1 | 45 ---- 9 files changed, 576 insertions(+), 595 deletions(-) delete mode 100644 Assert-TestEnvironment.ps1 delete mode 160000 DscResource.Tests create mode 100644 REMOVE.md delete mode 100644 Tests/Tests.depend.psd1 diff --git a/Assert-TestEnvironment.ps1 b/Assert-TestEnvironment.ps1 deleted file mode 100644 index e42a0fc29..000000000 --- a/Assert-TestEnvironment.ps1 +++ /dev/null @@ -1,124 +0,0 @@ -<# - .SYNOPSIS - Assert that the test environment is properly setup and loaded into the - PowerShell session. - - .DESCRIPTION - Assert that the test environment is properly setup and loaded into the - PowerShell session. - - .PARAMETER Tags - One or more tags to use for the cmdlet Invoke-PSDepend. - - .EXAMPLE - .\Assert-testEnvironment.ps1 - - Will assert that the current PowerShell session is ready to run tests. - - .EXAMPLE - .\Assert-testEnvironment.ps1 -Tags 'LoadDscResourceKitTypes' - - Will only assert that the current PowerShell session has the types loaded. -#> - -[CmdletBinding(SupportsShouldProcess = $true)] -param -( - [Parameter()] - [System.String[]] - $Tags -) - -#region Verify prerequisites Pester -$pesterModuleName = 'Pester' - -# This is the minimum version that can be used with the tests in this repo. -$pesterModuleMinimumVersion = '4.0.2' - -<# - Pester v4.4.0 has a fix for '-Not -Throw' so it shows the actual error - message if an unexpected exception does occur. It will help when debugging - tests. - If no Pester module exist, then use this as the minimum version. -#> -$pesterModuleRecommendedMinimumVersion = '4.4.0' - -$pesterModule = Get-Module $pesterModuleName -ListAvailable -Verbose:$false | - Where-Object -Property 'Version' -GE -Value $pesterModuleMinimumVersion | - Sort-Object -Property 'Version' -Descending | - Select-Object -First 1 - -if (-not $pesterModule) -{ - <# - Not installing the module here because it's not known what scope the - user want (can) to install the module in. - #> - $message = 'Missing a compatible version of the {0} module. Minimum version of {0} module can be ''{2}'', but the recommended minimum version is ''{1}''.' -f $pesterModuleName, $pesterModuleRecommendedMinimumVersion, $pesterModuleMinimumVersion - Write-Warning -Message $message - $dependencyMissing = $true -} -else -{ - Write-Verbose -Message ('A compatible {0} module is already installed (v{1}). If you want to use a newer version of {0} module, please install it manually.' -f $pesterModule.Name, $pesterModule.Version) -} -#endregion Verify prerequisites Pester - -#region Verify prerequisites PSDepend -$psDependModuleName = 'PSDepend' - -# This is the minimum version that can be used with the tests in this repo. -$psDependModuleMinimumVersion = '0.3.0' -$psDependModuleRecommendedMinimumVersion = 'latest' - -$psDependModule = Get-Module $psDependModuleName -ListAvailable -Verbose:$false | - Where-Object -Property 'Version' -GE -Value $psDependModuleMinimumVersion | - Sort-Object -Property 'Version' -Descending | - Select-Object -First 1 - -if (-not $psDependModule) -{ - <# - Not installing the module here because it's not known what scope the - user want (can) to install the module in. - #> - $message = 'Missing a compatible version of the {0} module. Minimum version of {0} module can be ''{2}'', but the recommended minimum version is ''{1}''. Please install {0} module manually, then run this script again.' -f $psDependModuleName, $psDependModuleRecommendedMinimumVersion, $psDependModuleMinimumVersion - Write-Warning -Message $message - $dependencyMissing = $true -} -else -{ - Write-Verbose -Message ('A compatible {0} module is already installed (v{1}). If you want to use a newer version of {0} module, please install it manually.' -f $psDependModule.Name, $psDependModule.Version) -} -#endregion Verify prerequisites PSDepend - -if ($dependencyMissing) -{ - Write-Output -InputObject 'Please install the necessary dependencies manually, then run this script again.' - return -} - -$dependenciesPath = Join-Path $PSScriptRoot -ChildPath 'Tests' - -Write-Verbose -Message ('Running Invoke-PSDepend using dependencies found under the path ''{0}''.' -f $dependenciesPath) - -if ($PSBoundParameters.ContainsKey('Confirm')) -{ - $invokePSDependConfirmation = $ConfirmPreference -} -else -{ - $invokePSDependConfirmation = $false -} - -$invokePSDependParameters = @{ - Path = $dependenciesPath - Confirm = $invokePSDependConfirmation -} - -if ($PSBoundParameters.ContainsKey('Tags')) -{ - $invokePSDependParameters['Tags'] = $Tags -} - -Invoke-PSDepend @invokePSDependParameters diff --git a/DscResource.Tests b/DscResource.Tests deleted file mode 160000 index 9c3c40618..000000000 --- a/DscResource.Tests +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9c3c40618b3ccb25e560a2e5fd2e346fbfb830cb diff --git a/REMOVE.md b/REMOVE.md new file mode 100644 index 000000000..aa645f9f1 --- /dev/null +++ b/REMOVE.md @@ -0,0 +1,30 @@ +1. Install the dependent DSC resource modules on the node that hosts your + virtual machines, the same as from where the integration tests will be run. + ```powershell + $dependentModules = @( + 'Pester', + 'PSDepend', + 'PSDscResources', + 'ComputerManagementDsc', + 'NetworkingDsc' + ) + + Install-Module -Name $dependentModules + ``` +1. Copy the dependent modules to each of the virtual machines. + ```powershell + $dependentModule = Get-Module -ListAvailable -Name $dependentModules | + Sort-Object -Property 'Version' | + Sort-Object -Unique + + foreach ($module in $dependentModule) + { + $sourceModulePath = $module.ModuleBase + $moduleVersionFolder = Split-Path -Path $module.ModuleBase -Leaf + $destinationModulePath = Join-Path -Path (Join-Path -Path 'C:\Program Files\WindowsPowerShell\Modules' -ChildPath $module.Name) -ChildPath $moduleVersionFolder + + Copy-Item -ToSession $dc01Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + Copy-Item -ToSession $dc02Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + Copy-Item -ToSession $dc03Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + } + ``` diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index 0deb4a26e..7bd321d46 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -24,4 +24,9 @@ # Prerequisites modules needed for examples or integration tests xFailoverCluster = '1.14.1' + + # Modules required to run integration tests in local lab environment. + PSDscResources = '2.12.0.0' + NetworkingDsc = '7.4.0.0' + ComputerManagementDsc = '8.1.0' } diff --git a/Tests/README.md b/Tests/README.md index a2007c812..7bd5f4693 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -109,6 +109,7 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. $templateName = 'DSCAD-template' $templatesPath = 'C:\Hyper-V\Templates' $virtualMachinesPath = 'C:\Hyper-V\Virtual Machines' + $virtualSwitchName = 'DSCADLabPrivate' $vmTemplatePath = (Get-ChildItem -Path (Join-Path -Path $templatesPath -ChildPath $templateName) -Recurse -Filter '*.vmcx').FullName @@ -124,6 +125,8 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. $vm = Import-VM -Path $vmTemplatePath -Copy -GenerateNewId -VirtualMachinePath $vmPath -VhdDestinationPath $vmPath -SnapshotFilePath $vmPath -SmartPagingFilePath $vmPath Set-VM -VM $vm -NewVMName $vmName -DynamicMemory Set-VM -VM $vm -AutomaticCheckpointsEnabled $false + # TODO: This can be resolved by removing the ISO prior to exporting the template + Get-VMDvdDrive -VM $vm | Set-VMDvdDrive -Path $null Get-VMNetworkAdapter -VM $vm | Connect-VMNetworkAdapter -SwitchName $virtualSwitchName } @@ -140,22 +143,22 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. ### Test prerequisites -The below steps assumes the virtual machines does not have access to the -Internet. +The host for the virtual machines must have access to Internet. The +below steps assumes the virtual machines that should run the integration +test are only connect to a private virtual switch and does not have access +to the Internet. + +The blow steps *must* be run in a elevated PowerShell console. -1. Install the dependent DSC resource modules on the node that hosts your - virtual machines, the same as from where the integration tests will be run. +1. Change to folder to root of your local working repository + folder, e.g. cd 'c:\source\ActiveDirectoryDsc'. ```powershell - $dependentModules = @( - 'Pester', - 'PSDepend', - 'PSDscResources', - 'ComputerManagementDsc', - 'NetworkingDsc' - ) - - Install-Module -Name $dependentModules + cd c:\source\ActiveDirectoryDsc + ``` +1. Resolve dependencies and build the repository. + ```powershell + .\build.ps1 -ResolveDependency -Tasks build ``` 1. Open a PowerShell Direct session to each virtual machine. ```powershell @@ -176,43 +179,63 @@ Internet. $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential ``` -1. Copy the dependent modules to each of the virtual machines. +1. Copy the tests and the output folder to each of the virtual machines. ```powershell - $dependentModule = Get-Module -ListAvailable -Name $dependentModules | - Sort-Object -Property 'Version' | - Sort-Object -Unique - - foreach ($module in $dependentModule) - { - $sourceModulePath = $module.ModuleBase - $moduleVersionFolder = Split-Path -Path $module.ModuleBase -Leaf - $destinationModulePath = Join-Path -Path (Join-Path -Path 'C:\Program Files\WindowsPowerShell\Modules' -ChildPath $module.Name) -ChildPath $moduleVersionFolder + $destinationPath = 'c:\projects' - Copy-Item -ToSession $dc01Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force - Copy-Item -ToSession $dc02Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force - Copy-Item -ToSession $dc03Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force + Copy-Item -ToSession $dc01Session -Path '.' -Destination $destinationPath -Recurse -Force + Copy-Item -ToSession $dc02Session -Path '.' -Destination $destinationPath -Recurse -Force + Copy-Item -ToSession $dc03Session -Path '.' -Destination $destinationPath -Recurse -Force + ``` +1. Prepare the test environment in the remote session by running `build.ps1` + with the task `noop` against each of the virtual machines. + ```powershell + $scriptBlock = { + cd c:\projects\ActiveDirectoryDsc + .\build.ps1 -Tasks noop + #Write-Verbose -Message ('PSModulePath is now set to: ''{0}''' -f $env:PSModulePath) -Verbose } + + Invoke-Command -Session $dc01Session -ScriptBlock $scriptBlock + Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock + Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock ``` -1. **Important!** Change to folder to root of your local working repository - folder, e.g. cd 'c:\source\xActiveDirectory'. -1. Create the configuration .mof and the metadata .mof file on the respective - nodes. +1. Configure prerequisites like computer name, IP address, and Windows features + that is needed to promote a node to a domain controller. This creates + the configuration .mof and the metadata .mof file on the respective + nodes which will be executed in next steps. ```powershell - Invoke-Command -Session $dc01Session -FilePath '.\Tests\TestHelpers\Prepare-DscLab-dc01.ps1' - Invoke-Command -Session $dc02Session -FilePath '.\Tests\TestHelpers\Prepare-DscLab-dc02.ps1' - Invoke-Command -Session $dc03Session -FilePath '.\Tests\TestHelpers\Prepare-DscLab-dc03.ps1' + $dc01ScriptBlock = { + .\tests\TestHelpers\Prepare-DscLab-dc01.ps1 + } + + Invoke-Command -Session $dc01Session -ScriptBlock $dc01ScriptBlock + Invoke-Command -Session $dc02Session -FilePath '.\tests\TestHelpers\Prepare-DscLab-dc02.ps1' + Invoke-Command -Session $dc03Session -FilePath '.\tests\TestHelpers\Prepare-DscLab-dc03.ps1' ``` 1. Configure the DSC Local Configuration Manager (LCM) on each virtual machine using the metadata .mof created in previous step. ```powershell - Invoke-Command -Session $dc01Session,$dc02Session,$dc03Session -ScriptBlock { - Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force + $vmPSSessions = @( + $dc01Session + #$dc02Session + #$dc03Session + ) + Invoke-Command -Session $vmPSSessions -ScriptBlock { + Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force } ``` 1. Run the configuration on each virtual machine to set up all the prerequisites. **The virtual machine will reboot during this.** ```powershell - Invoke-Command -Session $dc01Session,$dc02Session,$dc03Session -ScriptBlock { + $vmPSSessions = @( + $dc01Session + #$dc02Session + #$dc03Session + ) + Invoke-Command -Session $vmPSSessions -ScriptBlock { + $env:PSModulePath + [System.Environment]::GetEnvironmentVariable('PSModulePath', [System.EnvironmentVariableTarget]::Machine) Start-DscConfiguration -Path "C:\DSC\Configuration\" -ComputerName 'localhost' -Wait -Force -Verbose } ``` @@ -225,7 +248,13 @@ Internet. $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential - Invoke-Command -Session $dc01Session,$dc02Session,$dc03Session -ScriptBlock { + $vmPSSessions = @( + $dc01Session + #$dc02Session + #$dc03Session + ) + + Invoke-Command -Session $vmPSSessions -ScriptBlock { Get-DscConfigurationStatus } ``` diff --git a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 index 911751f19..888d1678a 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 @@ -3,148 +3,179 @@ Prerequisites configuration for running integration tests. This configuration sets up the prerequisites for the node dc01.dscadlab.com. + + .NOTES + This must initialize the test environment prior running so + that the configuration can find the required modules. #> -$ConfigurationData = @{ - AllNodes = @( - @{ - NodeName= '*' - PSDscAllowDomainUser = $true - PsDscAllowPlainTextPassword = $true - }, - @{ - NodeName = 'localhost' - } - ) -} +$script:dscModuleName = 'ActiveDirectoryDsc' +$script:dscResourceName = 'None' -[DSCLocalConfigurationManager()] -configuration LCMConfig +try { - Node $AllNodes.NodeName - { - Settings - { - RefreshMode = 'Push' - RebootNodeIfNeeded = $true - ConfigurationMode = 'ApplyAndAutoCorrect' - CertificateId = $node.Thumbprint - AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' - } - } + Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' } - -<# - .SYNOPSIS - Configures the Hyper-V node dc01 with the correct prerequisites. -#> -Configuration DomainController +catch [System.IO.FileNotFoundException] { - Import-DSCResource -ModuleName PSDscResources - Import-DSCResource -ModuleName NetworkingDsc - Import-DSCResource -ModuleName ComputerManagementDsc - - - Node 'localhost' - { - Computer NewName - { - Name = 'dc01' - Description = 'First domain controller' - } - - DnsClientGlobalSetting ConfigureSuffixSearchListSingle - { - IsSingleInstance = 'Yes' - SuffixSearchList = 'dscadlab.com' - } - - NetAdapterName 'RenameNetAdapter' - { - NewName = 'dscadlab.com' - Status = 'Up' - } - - NetIPInterface 'DisableDhcp' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Dhcp = 'Disabled' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - IPAddress NewIPv4Address - { - IPAddress = '10.0.2.4/8' - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPV4' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' +} - DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Address = @('127.0.0.1', '10.0.3.4') - Validate = $false +$script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' - DependsOn = '[NetAdapterName]RenameNetAdapter' - } +try +{ + $ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) + } - Firewall 'AllowICMP' + [DSCLocalConfigurationManager()] + configuration LCMConfig + { + Node $AllNodes.NodeName { - Ensure = 'Present' - Enabled = 'True' - Name = 'dscadlab-allow-icmp' - DisplayName = 'DSC AD Lab - Allow ICMP' - Group = 'DSC AD Lab' - Profile = @('Domain', 'Private', 'Public') - Direction = 'InBound' - Protocol = 'ICMPv4' - Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyAndAutoCorrect' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } } + } - WindowsFeature 'DNS' - { - Ensure = 'Present' - Name = 'DNS' - } + <# + .SYNOPSIS + Configures the Hyper-V node dc01 with the correct prerequisites. + #> + Configuration DomainController + { + Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' + Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' + Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' - WindowsFeature 'AD-Domain-Services' + Node 'localhost' { - Ensure = 'Present' - Name = 'AD-Domain-Services' - - DependsOn = '[WindowsFeature]DNS' + Computer NewName + { + Name = 'dc01' + Description = 'First domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.2.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.3.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } } + } - WindowsFeature 'RSAT-AD-PowerShell' - { - Ensure = 'Present' - Name = 'RSAT-AD-PowerShell' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } + LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose - WindowsFeature 'RSAT-ADDS' - { - Ensure = 'Present' - Name = 'RSAT-ADDS' + DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose - DependsOn = '[WindowsFeature]AD-Domain-Services' - } - } + Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force + Start-DscConfiguration -Path "C:\DSC\Configuration\" -ComputerName 'localhost' -Wait -Force -Verbose +} +finally +{ + Restore-TestEnvironment -TestEnvironment $script:testEnvironment } - -LCMConfig ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose - -DomainController ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose diff --git a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 index bbb08bc31..38b446ea2 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 @@ -3,148 +3,176 @@ Prerequisites configuration for running integration tests. This configuration sets up the prerequisites for the node dc02.dscadlab.com. + + .NOTES + This must initialize the test environment prior running so + that the configuration can find the required modules. #> -$ConfigurationData = @{ - AllNodes = @( - @{ - NodeName= '*' - PSDscAllowDomainUser = $true - PsDscAllowPlainTextPassword = $true - }, - @{ - NodeName = 'localhost' - } - ) -} +# $script:dscModuleName = 'ActiveDirectoryDsc' +# $script:dscResourceName = 'None' + +# 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' + +# try +# { + $ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) + } -[DSCLocalConfigurationManager()] -configuration LCMConfig -{ - Node $AllNodes.NodeName + [DSCLocalConfigurationManager()] + configuration LCMConfig { - Settings + Node $AllNodes.NodeName { - RefreshMode = 'Push' - RebootNodeIfNeeded = $true - ConfigurationMode = 'ApplyAndAutoCorrect' - CertificateId = $node.Thumbprint - AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyAndAutoCorrect' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } } } -} -<# - .SYNOPSIS - Configures the Hyper-V node dc02 with the correct prerequisites. -#> -Configuration DomainController -{ - Import-DSCResource -ModuleName PSDscResources - Import-DSCResource -ModuleName NetworkingDsc - Import-DSCResource -ModuleName ComputerManagementDsc - - - Node 'localhost' + <# + .SYNOPSIS + Configures the Hyper-V node dc02 with the correct prerequisites. + #> + Configuration DomainController { - Computer NewName - { - Name = 'dc02' - Description = 'First domain controller' - } - - DnsClientGlobalSetting ConfigureSuffixSearchListSingle - { - IsSingleInstance = 'Yes' - SuffixSearchList = 'dscadlab.com' - } - - NetAdapterName 'RenameNetAdapter' - { - NewName = 'dscadlab.com' - Status = 'Up' - } - - NetIPInterface 'DisableDhcp' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Dhcp = 'Disabled' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - IPAddress NewIPv4Address - { - IPAddress = '10.0.3.4/8' - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPV4' + Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' + Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' + Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Address = @('127.0.0.1', '10.0.2.4') - Validate = $false - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - Firewall 'AllowICMP' - { - Ensure = 'Present' - Enabled = 'True' - Name = 'dscadlab-allow-icmp' - DisplayName = 'DSC AD Lab - Allow ICMP' - Group = 'DSC AD Lab' - Profile = @('Domain', 'Private', 'Public') - Direction = 'InBound' - Protocol = 'ICMPv4' - Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' - } - - WindowsFeature 'DNS' - { - Ensure = 'Present' - Name = 'DNS' - } - - WindowsFeature 'AD-Domain-Services' - { - Ensure = 'Present' - Name = 'AD-Domain-Services' - - DependsOn = '[WindowsFeature]DNS' - } - - WindowsFeature 'RSAT-AD-PowerShell' + Node 'localhost' { - Ensure = 'Present' - Name = 'RSAT-AD-PowerShell' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } - - WindowsFeature 'RSAT-ADDS' - { - Ensure = 'Present' - Name = 'RSAT-ADDS' - - DependsOn = '[WindowsFeature]AD-Domain-Services' + Computer NewName + { + Name = 'dc02' + Description = 'Second domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.3.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.2.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } } } -} - -LCMConfig ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose -DomainController ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose + LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose + + DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose +# } +# finally +# { +# Restore-TestEnvironment -TestEnvironment $script:testEnvironment +# } diff --git a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 index efa4e4fa8..0a14196d8 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 @@ -3,148 +3,176 @@ Prerequisites configuration for running integration tests. This configuration sets up the prerequisites for the node dc03.dscadlab.com. + + .NOTES + This must initialize the test environment prior running so + that the configuration can find the required modules. #> -$ConfigurationData = @{ - AllNodes = @( - @{ - NodeName= '*' - PSDscAllowDomainUser = $true - PsDscAllowPlainTextPassword = $true - }, - @{ - NodeName = 'localhost' - } - ) -} +# $script:dscModuleName = 'ActiveDirectoryDsc' +# $script:dscResourceName = 'None' + +# 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' + +# try +# { + $ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) + } -[DSCLocalConfigurationManager()] -configuration LCMConfig -{ - Node $AllNodes.NodeName + [DSCLocalConfigurationManager()] + configuration LCMConfig { - Settings + Node $AllNodes.NodeName { - RefreshMode = 'Push' - RebootNodeIfNeeded = $true - ConfigurationMode = 'ApplyAndAutoCorrect' - CertificateId = $node.Thumbprint - AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyAndAutoCorrect' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } } } -} -<# - .SYNOPSIS - Configures the Hyper-V node dc02 with the correct prerequisites. -#> -Configuration DomainController -{ - Import-DSCResource -ModuleName PSDscResources - Import-DSCResource -ModuleName NetworkingDsc - Import-DSCResource -ModuleName ComputerManagementDsc - - - Node 'localhost' + <# + .SYNOPSIS + Configures the Hyper-V node dc02 with the correct prerequisites. + #> + Configuration DomainController { - Computer NewName - { - Name = 'dc03' - Description = 'First domain controller' - } - - DnsClientGlobalSetting ConfigureSuffixSearchListSingle - { - IsSingleInstance = 'Yes' - SuffixSearchList = 'dscadlab.com' - } - - NetAdapterName 'RenameNetAdapter' - { - NewName = 'dscadlab.com' - Status = 'Up' - } - - NetIPInterface 'DisableDhcp' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Dhcp = 'Disabled' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - IPAddress NewIPv4Address - { - IPAddress = '10.0.4.4/8' - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPV4' + Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' + Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' + Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Address = @('127.0.0.1', '10.0.2.4') - Validate = $false - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - Firewall 'AllowICMP' - { - Ensure = 'Present' - Enabled = 'True' - Name = 'dscadlab-allow-icmp' - DisplayName = 'DSC AD Lab - Allow ICMP' - Group = 'DSC AD Lab' - Profile = @('Domain', 'Private', 'Public') - Direction = 'InBound' - Protocol = 'ICMPv4' - Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' - } - - WindowsFeature 'DNS' - { - Ensure = 'Present' - Name = 'DNS' - } - - WindowsFeature 'AD-Domain-Services' - { - Ensure = 'Present' - Name = 'AD-Domain-Services' - - DependsOn = '[WindowsFeature]DNS' - } - - WindowsFeature 'RSAT-AD-PowerShell' + Node 'localhost' { - Ensure = 'Present' - Name = 'RSAT-AD-PowerShell' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } - - WindowsFeature 'RSAT-ADDS' - { - Ensure = 'Present' - Name = 'RSAT-ADDS' - - DependsOn = '[WindowsFeature]AD-Domain-Services' + Computer NewName + { + Name = 'dc03' + Description = 'Third domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.4.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.2.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } } } -} - -LCMConfig ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose -DomainController ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose + LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose + + DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose +# } +# finally +# { +# Restore-TestEnvironment -TestEnvironment $script:testEnvironment +# } diff --git a/Tests/Tests.depend.psd1 b/Tests/Tests.depend.psd1 deleted file mode 100644 index 36a2eed77..000000000 --- a/Tests/Tests.depend.psd1 +++ /dev/null @@ -1,45 +0,0 @@ -<# - .DESCRIPTION - This is the dependency file for use with Assert-TestEnvironment.ps1 and/or - Invoke-PSDepend (PSSDepend). -#> -@{ - RemoveTestFramework = @{ - Tags = 'RemoveTestFramework' - DependencyType = 'Command' - Source = ' - $testFrameWorkPath = Join-Path -Path $PWD -ChildPath ''DscResource.Tests'' - if (Test-Path -Path $testFrameWorkPath) - { - Write-Verbose -Message ''Removing local test framework repository.'' - Remove-Item -Path (Join-Path -Path $PWD -ChildPath ''DscResource.Tests'') -Recurse -Force - } - ' - } - - CloneTestFramework = @{ - Tags = 'CloneTestFramework' - DependencyType = 'Git' - Name = 'https://github.com/PowerShell/DscResource.Tests' - Version = 'dev' - DependsOn = 'RemoveTestFramework' - } - - LoadDscResourceKitTypes = @{ - Tags = 'LoadDscResourceKitTypes' - DependencyType = 'Command' - Source = ' - if (-not (''Microsoft.DscResourceKit.Test'' -as [Type])) - { - Write-Verbose -Message ''Loading the Microsoft.DscResourceKit types into the current session.'' - $typesSourceFile = Join-Path -Path ''$PWD\DscResource.Tests'' -ChildPath ''Microsoft.DscResourceKit.cs'' - Add-Type -Path $typesSourceFile -WarningAction SilentlyContinue - } - else - { - Write-Verbose -Message ''The Microsoft.DscResourceKit types was already loaded into the current session.'' - } - ' - DependsOn = 'CloneTestFramework' - } -} From 9d4915a1850601145c7cfb0e216f23c86745dbf9 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 11 Apr 2020 15:44:34 +0200 Subject: [PATCH 09/16] Fix steps --- REMOVE.md | 13 + Tests/README.md | 127 +++++--- Tests/TestHelpers/Prepare-DscLab-dc01.ps1 | 278 ++++++++--------- Tests/TestHelpers/Prepare-DscLab-dc02.ps1 | 285 ++++++++---------- Tests/TestHelpers/Prepare-DscLab-dc03.ps1 | 285 ++++++++---------- .../MSFT_ADComputer.Integration.Tests.ps1 | 36 +-- 6 files changed, 500 insertions(+), 524 deletions(-) diff --git a/REMOVE.md b/REMOVE.md index aa645f9f1..180cb28cd 100644 --- a/REMOVE.md +++ b/REMOVE.md @@ -28,3 +28,16 @@ Copy-Item -ToSession $dc03Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force } ``` +1. Prepare the test environment in the remote session by running `build.ps1` + with the task `noop` against each of the virtual machines. + ```powershell + $scriptBlock = { + cd c:\projects\ActiveDirectoryDsc + .\build.ps1 -Tasks noop + #Write-Verbose -Message ('PSModulePath is now set to: ''{0}''' -f $env:PSModulePath) -Verbose + } + + Invoke-Command -Session $dc01Session -ScriptBlock $scriptBlock + Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock + Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock + ``` diff --git a/Tests/README.md b/Tests/README.md index 7bd5f4693..0042d9b58 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -179,26 +179,23 @@ The blow steps *must* be run in a elevated PowerShell console. $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential ``` -1. Copy the tests and the output folder to each of the virtual machines. +1. Copy the required modules to each of the virtual machines. ```powershell - $destinationPath = 'c:\projects' + $dependentModulePaths = @( + '.\output\RequiredModules\Pester' + '.\output\RequiredModules\PSDscResources' + '.\output\RequiredModules\ComputerManagementDsc' + '.\output\RequiredModules\NetworkingDsc' + ) - Copy-Item -ToSession $dc01Session -Path '.' -Destination $destinationPath -Recurse -Force - Copy-Item -ToSession $dc02Session -Path '.' -Destination $destinationPath -Recurse -Force - Copy-Item -ToSession $dc03Session -Path '.' -Destination $destinationPath -Recurse -Force - ``` -1. Prepare the test environment in the remote session by running `build.ps1` - with the task `noop` against each of the virtual machines. - ```powershell - $scriptBlock = { - cd c:\projects\ActiveDirectoryDsc - .\build.ps1 -Tasks noop - #Write-Verbose -Message ('PSModulePath is now set to: ''{0}''' -f $env:PSModulePath) -Verbose - } + $destinationPath = 'C:\Program Files\WindowsPowerShell\Modules' - Invoke-Command -Session $dc01Session -ScriptBlock $scriptBlock - Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock - Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock + foreach ($dependentModulePath in $dependentModulePaths) + { + Copy-Item -ToSession $dc01Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force + #Copy-Item -ToSession $dc02Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force + #Copy-Item -ToSession $dc03Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force + } ``` 1. Configure prerequisites like computer name, IP address, and Windows features that is needed to promote a node to a domain controller. This creates @@ -206,12 +203,25 @@ The blow steps *must* be run in a elevated PowerShell console. nodes which will be executed in next steps. ```powershell $dc01ScriptBlock = { + cd 'c:\projects\ActiveDirectoryDsc' .\tests\TestHelpers\Prepare-DscLab-dc01.ps1 } Invoke-Command -Session $dc01Session -ScriptBlock $dc01ScriptBlock - Invoke-Command -Session $dc02Session -FilePath '.\tests\TestHelpers\Prepare-DscLab-dc02.ps1' - Invoke-Command -Session $dc03Session -FilePath '.\tests\TestHelpers\Prepare-DscLab-dc03.ps1' + + $dc02ScriptBlock = { + cd 'c:\projects\ActiveDirectoryDsc' + .\tests\TestHelpers\Prepare-DscLab-dc02.ps1 + } + + Invoke-Command -Session $dc02Session -ScriptBlock $dc02ScriptBlock + + $dc03ScriptBlock = { + cd 'c:\projects\ActiveDirectoryDsc' + .\tests\TestHelpers\Prepare-DscLab-dc03.ps1 + } + + Invoke-Command -Session $dc03Session -ScriptBlock $dc03ScriptBlock ``` 1. Configure the DSC Local Configuration Manager (LCM) on each virtual machine using the metadata .mof created in previous step. @@ -233,9 +243,8 @@ The blow steps *must* be run in a elevated PowerShell console. #$dc02Session #$dc03Session ) + Invoke-Command -Session $vmPSSessions -ScriptBlock { - $env:PSModulePath - [System.Environment]::GetEnvironmentVariable('PSModulePath', [System.EnvironmentVariableTarget]::Machine) Start-DscConfiguration -Path "C:\DSC\Configuration\" -ComputerName 'localhost' -Wait -Force -Verbose } ``` @@ -258,11 +267,18 @@ The blow steps *must* be run in a elevated PowerShell console. Get-DscConfigurationStatus } ``` -1. Clone the latest test framework into the local repository folder. _**Note:**_ - _This requires `git`. The test framework will also be cloned when running_ - _a unit test._ +1. Set the execution policy to bypass. This makes the script certificate check + faster when running Pester. ```powershell - .\Assert-TestEnvironment.ps1 + $vmPSSessions = @( + $dc01Session + #$dc02Session + #$dc03Session + ) + + Invoke-Command -Session $vmPSSessions -ScriptBlock { + Set-ExecutionPolicy -ExecutionPolicy 'Bypass' -Scope 'LocalMachine' + } ``` 1. At this point it would be good to checkpoint the servers. ```powershell @@ -275,31 +291,56 @@ By reverting to the checkpoint created before, these tests can be run several times. The integration tests that depend on an already existing domain can be run several times without reverting to the checkpoint. The resources that need a clean environment are the resources that configures -the domain, e.g. `xADDomain` and `xADDomainController`. - -1. **Important!** Change to folder to root of your local working repository - folder, e.g. cd 'c:\source\xActiveDirectory'. -1. Copy resource module code to a local folder on each virtual machine, - e.g. `C:\source\xActiveDirectory`. - _**NOTE:** Do not copy the resource being tested to a path that exist_ - _in `$env:PSModulePath`, that will generate an error that multiple_ - _modules exist on the node when running the integration tests._ +the domain, e.g. `ADDomain` and `ADDomainController`. + +1. Change to folder to root of your local working repository + folder, e.g. cd 'c:\source\ActiveDirectoryDsc'. + ```powershell + cd 'c:\source\ActiveDirectoryDsc' + ``` +1. Reconnect the sessions after we created the checkpoint which make the + session to disconnect. + ```powershell + $localAdminPassword = ConvertTo-SecureString 'adminP@ssw0rd1' -AsPlainText -Force + $localAdminUsername = 'Administrator' + + $newObjectParameters = @{ + TypeName = 'System.Management.Automation.PSCredential' + ArgumentList = @( + $localAdminUsername, + $localAdminPassword + ) + } + + $localAdminCredential = New-Object @newObjectParameters + + $dc01Session = New-PSSession -VMName 'dc01' -Credential $localAdminCredential + $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential + $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential + ``` +1. Copy resource module output folder to the system PowerShell modules folder. + ```powershell + cd 'c:\source\ActiveDirectoryDsc' + + $dscModuleOutputPath = '.\output\ActiveDirectoryDsc' + $destinationPath = 'C:\Program Files\WindowsPowerShell\Modules' + + Copy-Item -ToSession $dc01Session -Path $dscModuleOutputPath -Destination $destinationPath -Recurse -Force + ``` +1. Copy the tests and the required modules to each of the virtual machines. ```powershell - $sourceRepositoryPath = '.' - $destinationRepositoryPath = 'C:\Source\xActiveDirectory' + cd 'c:\source\ActiveDirectoryDsc' - # This way we skip the hidden folder '.git'. - Get-ChildItem -Path $sourceRepositoryPath | Copy-Item -ToSession $dc01Session -Destination $destinationRepositoryPath -Recurse -Force - Get-ChildItem -Path $sourceRepositoryPath | Copy-Item -ToSession $dc02Session -Destination $destinationRepositoryPath -Recurse -Force - Get-ChildItem -Path $sourceRepositoryPath | Copy-Item -ToSession $dc03Session -Destination $destinationRepositoryPath -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc01Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + #Copy-Item -ToSession $dc02Session -Path '.\tests' -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + #Copy-Item -ToSession $dc02Session -Path '.\tests' -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force ``` 1. This runs the actual integration tests. ```powershell Invoke-Command -Session $dc01Session -ScriptBlock { - cd 'c:\source\xActiveDirectory' - .\Assert-TestEnvironment.ps1 -Tags 'LoadDscResourceKitTypes' + cd 'c:\projects\ActiveDirectoryDsc' - Invoke-Pester -Path '.\Tests\Integration\MSFT_xADComputer.Integration.Tests.ps1' + Invoke-Pester -Path '.\Tests\Integration\MSFT_ADComputer.Integration.Tests.ps1' } ``` diff --git a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 index 888d1678a..b5adbbe11 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 @@ -9,173 +9,145 @@ that the configuration can find the required modules. #> -$script:dscModuleName = 'ActiveDirectoryDsc' -$script:dscResourceName = 'None' - -try -{ - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) } -catch [System.IO.FileNotFoundException] + +[DSCLocalConfigurationManager()] +configuration LCMConfig { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + Node $AllNodes.NodeName + { + Settings + { + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyOnly' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' + } + } } -$script:testEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:dscModuleName ` - -DSCResourceName $script:dscResourceName ` - -ResourceType 'Mof' ` - -TestType 'Integration' - -try +<# + .SYNOPSIS + Configures the Hyper-V node dc01 with the correct prerequisites. +#> +Configuration DomainController { - $ConfigurationData = @{ - AllNodes = @( - @{ - NodeName= '*' - PSDscAllowDomainUser = $true - PsDscAllowPlainTextPassword = $true - }, - @{ - NodeName = 'localhost' - } - ) - } + Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' + Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' + Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' - [DSCLocalConfigurationManager()] - configuration LCMConfig + Node 'localhost' { - Node $AllNodes.NodeName + Computer NewName { - Settings - { - RefreshMode = 'Push' - RebootNodeIfNeeded = $true - ConfigurationMode = 'ApplyAndAutoCorrect' - CertificateId = $node.Thumbprint - AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' - } + Name = 'dc01' + Description = 'First domain controller' } - } - <# - .SYNOPSIS - Configures the Hyper-V node dc01 with the correct prerequisites. - #> - Configuration DomainController - { - Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' - Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' - Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } - Node 'localhost' + NetAdapterName 'RenameNetAdapter' { - Computer NewName - { - Name = 'dc01' - Description = 'First domain controller' - } - - DnsClientGlobalSetting ConfigureSuffixSearchListSingle - { - IsSingleInstance = 'Yes' - SuffixSearchList = 'dscadlab.com' - } - - NetAdapterName 'RenameNetAdapter' - { - NewName = 'dscadlab.com' - Status = 'Up' - } - - NetIPInterface 'DisableDhcp' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Dhcp = 'Disabled' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - IPAddress NewIPv4Address - { - IPAddress = '10.0.2.4/8' - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPV4' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Address = @('127.0.0.1', '10.0.3.4') - Validate = $false - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - Firewall 'AllowICMP' - { - Ensure = 'Present' - Enabled = 'True' - Name = 'dscadlab-allow-icmp' - DisplayName = 'DSC AD Lab - Allow ICMP' - Group = 'DSC AD Lab' - Profile = @('Domain', 'Private', 'Public') - Direction = 'InBound' - Protocol = 'ICMPv4' - Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' - } - - WindowsFeature 'DNS' - { - Ensure = 'Present' - Name = 'DNS' - } - - WindowsFeature 'AD-Domain-Services' - { - Ensure = 'Present' - Name = 'AD-Domain-Services' - - DependsOn = '[WindowsFeature]DNS' - } - - WindowsFeature 'RSAT-AD-PowerShell' - { - Ensure = 'Present' - Name = 'RSAT-AD-PowerShell' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } - - WindowsFeature 'RSAT-ADDS' - { - Ensure = 'Present' - Name = 'RSAT-ADDS' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } + NewName = 'dscadlab.com' + Status = 'Up' } - } - LCMConfig ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } - DomainController ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose + IPAddress NewIPv4Address + { + IPAddress = '10.0.2.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' - Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force - Start-DscConfiguration -Path "C:\DSC\Configuration\" -ComputerName 'localhost' -Wait -Force -Verbose -} -finally -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.3.4') + Validate = $false + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' + { + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + } } + +LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose + +DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose diff --git a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 index 38b446ea2..abc758838 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 @@ -9,170 +9,145 @@ that the configuration can find the required modules. #> -# $script:dscModuleName = 'ActiveDirectoryDsc' -# $script:dscResourceName = 'None' - -# 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' - -# try -# { - $ConfigurationData = @{ - AllNodes = @( - @{ - NodeName= '*' - PSDscAllowDomainUser = $true - PsDscAllowPlainTextPassword = $true - }, - @{ - NodeName = 'localhost' - } - ) - } +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) +} - [DSCLocalConfigurationManager()] - configuration LCMConfig +[DSCLocalConfigurationManager()] +configuration LCMConfig +{ + Node $AllNodes.NodeName { - Node $AllNodes.NodeName + Settings { - Settings - { - RefreshMode = 'Push' - RebootNodeIfNeeded = $true - ConfigurationMode = 'ApplyAndAutoCorrect' - CertificateId = $node.Thumbprint - AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' - } + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyOnly' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' } } +} + +<# + .SYNOPSIS + Configures the Hyper-V node dc02 with the correct prerequisites. +#> +Configuration DomainController +{ + Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' + Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' + Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' - <# - .SYNOPSIS - Configures the Hyper-V node dc02 with the correct prerequisites. - #> - Configuration DomainController + Node 'localhost' { - Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' - Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' - Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' + Computer NewName + { + Name = 'dc02' + Description = 'Second domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.3.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.2.4') + Validate = $false - Node 'localhost' + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' { - Computer NewName - { - Name = 'dc02' - Description = 'Second domain controller' - } - - DnsClientGlobalSetting ConfigureSuffixSearchListSingle - { - IsSingleInstance = 'Yes' - SuffixSearchList = 'dscadlab.com' - } - - NetAdapterName 'RenameNetAdapter' - { - NewName = 'dscadlab.com' - Status = 'Up' - } - - NetIPInterface 'DisableDhcp' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Dhcp = 'Disabled' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - IPAddress NewIPv4Address - { - IPAddress = '10.0.3.4/8' - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPV4' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Address = @('127.0.0.1', '10.0.2.4') - Validate = $false - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - Firewall 'AllowICMP' - { - Ensure = 'Present' - Enabled = 'True' - Name = 'dscadlab-allow-icmp' - DisplayName = 'DSC AD Lab - Allow ICMP' - Group = 'DSC AD Lab' - Profile = @('Domain', 'Private', 'Public') - Direction = 'InBound' - Protocol = 'ICMPv4' - Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' - } - - WindowsFeature 'DNS' - { - Ensure = 'Present' - Name = 'DNS' - } - - WindowsFeature 'AD-Domain-Services' - { - Ensure = 'Present' - Name = 'AD-Domain-Services' - - DependsOn = '[WindowsFeature]DNS' - } - - WindowsFeature 'RSAT-AD-PowerShell' - { - Ensure = 'Present' - Name = 'RSAT-AD-PowerShell' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } - - WindowsFeature 'RSAT-ADDS' - { - Ensure = 'Present' - Name = 'RSAT-ADDS' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' } } +} + +LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose - LCMConfig ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose - - DomainController ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose -# } -# finally -# { -# Restore-TestEnvironment -TestEnvironment $script:testEnvironment -# } +DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose diff --git a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 index 0a14196d8..2e791689e 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 @@ -9,170 +9,145 @@ that the configuration can find the required modules. #> -# $script:dscModuleName = 'ActiveDirectoryDsc' -# $script:dscResourceName = 'None' - -# 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' - -# try -# { - $ConfigurationData = @{ - AllNodes = @( - @{ - NodeName= '*' - PSDscAllowDomainUser = $true - PsDscAllowPlainTextPassword = $true - }, - @{ - NodeName = 'localhost' - } - ) - } +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName= '*' + PSDscAllowDomainUser = $true + PsDscAllowPlainTextPassword = $true + }, + @{ + NodeName = 'localhost' + } + ) +} - [DSCLocalConfigurationManager()] - configuration LCMConfig +[DSCLocalConfigurationManager()] +configuration LCMConfig +{ + Node $AllNodes.NodeName { - Node $AllNodes.NodeName + Settings { - Settings - { - RefreshMode = 'Push' - RebootNodeIfNeeded = $true - ConfigurationMode = 'ApplyAndAutoCorrect' - CertificateId = $node.Thumbprint - AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' - } + RefreshMode = 'Push' + RebootNodeIfNeeded = $true + ConfigurationMode = 'ApplyOnly' + CertificateId = $node.Thumbprint + AllowModuleOverwrite = $true + DebugMode = 'ForceModuleImport' } } +} + +<# + .SYNOPSIS + Configures the Hyper-V node dc02 with the correct prerequisites. +#> +Configuration DomainController +{ + Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' + Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' + Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' - <# - .SYNOPSIS - Configures the Hyper-V node dc02 with the correct prerequisites. - #> - Configuration DomainController + Node 'localhost' { - Import-DSCResource -ModuleName 'PSDscResources' -ModuleVersion '2.12.0.0' - Import-DSCResource -ModuleName 'NetworkingDsc' -ModuleVersion '7.4.0.0' - Import-DSCResource -ModuleName 'ComputerManagementDsc' -ModuleVersion '8.1.0' + Computer NewName + { + Name = 'dc03' + Description = 'Third domain controller' + } + + DnsClientGlobalSetting ConfigureSuffixSearchListSingle + { + IsSingleInstance = 'Yes' + SuffixSearchList = 'dscadlab.com' + } + + NetAdapterName 'RenameNetAdapter' + { + NewName = 'dscadlab.com' + Status = 'Up' + } + + NetIPInterface 'DisableDhcp' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Dhcp = 'Disabled' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + IPAddress NewIPv4Address + { + IPAddress = '10.0.4.4/8' + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPV4' + + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' + { + InterfaceAlias = 'dscadlab.com' + AddressFamily = 'IPv4' + Address = @('127.0.0.1', '10.0.2.4') + Validate = $false - Node 'localhost' + DependsOn = '[NetAdapterName]RenameNetAdapter' + } + + Firewall 'AllowICMP' { - Computer NewName - { - Name = 'dc03' - Description = 'Third domain controller' - } - - DnsClientGlobalSetting ConfigureSuffixSearchListSingle - { - IsSingleInstance = 'Yes' - SuffixSearchList = 'dscadlab.com' - } - - NetAdapterName 'RenameNetAdapter' - { - NewName = 'dscadlab.com' - Status = 'Up' - } - - NetIPInterface 'DisableDhcp' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Dhcp = 'Disabled' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - IPAddress NewIPv4Address - { - IPAddress = '10.0.4.4/8' - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPV4' - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' - { - InterfaceAlias = 'dscadlab.com' - AddressFamily = 'IPv4' - Address = @('127.0.0.1', '10.0.2.4') - Validate = $false - - DependsOn = '[NetAdapterName]RenameNetAdapter' - } - - Firewall 'AllowICMP' - { - Ensure = 'Present' - Enabled = 'True' - Name = 'dscadlab-allow-icmp' - DisplayName = 'DSC AD Lab - Allow ICMP' - Group = 'DSC AD Lab' - Profile = @('Domain', 'Private', 'Public') - Direction = 'InBound' - Protocol = 'ICMPv4' - Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' - } - - WindowsFeature 'DNS' - { - Ensure = 'Present' - Name = 'DNS' - } - - WindowsFeature 'AD-Domain-Services' - { - Ensure = 'Present' - Name = 'AD-Domain-Services' - - DependsOn = '[WindowsFeature]DNS' - } - - WindowsFeature 'RSAT-AD-PowerShell' - { - Ensure = 'Present' - Name = 'RSAT-AD-PowerShell' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } - - WindowsFeature 'RSAT-ADDS' - { - Ensure = 'Present' - Name = 'RSAT-ADDS' - - DependsOn = '[WindowsFeature]AD-Domain-Services' - } + Ensure = 'Present' + Enabled = 'True' + Name = 'dscadlab-allow-icmp' + DisplayName = 'DSC AD Lab - Allow ICMP' + Group = 'DSC AD Lab' + Profile = @('Domain', 'Private', 'Public') + Direction = 'InBound' + Protocol = 'ICMPv4' + Description = 'This rule will allow all types of the ICMP protcol to allow unrestricted ping' + } + + WindowsFeature 'DNS' + { + Ensure = 'Present' + Name = 'DNS' + } + + WindowsFeature 'AD-Domain-Services' + { + Ensure = 'Present' + Name = 'AD-Domain-Services' + + DependsOn = '[WindowsFeature]DNS' + } + + WindowsFeature 'RSAT-AD-PowerShell' + { + Ensure = 'Present' + Name = 'RSAT-AD-PowerShell' + + DependsOn = '[WindowsFeature]AD-Domain-Services' + } + + WindowsFeature 'RSAT-ADDS' + { + Ensure = 'Present' + Name = 'RSAT-ADDS' + + DependsOn = '[WindowsFeature]AD-Domain-Services' } } +} + +LCMConfig ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose - LCMConfig ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose - - DomainController ` - -ConfigurationData $ConfigurationData ` - -OutputPath 'C:\DSC\Configuration' ` - -Verbose -# } -# finally -# { -# Restore-TestEnvironment -TestEnvironment $script:testEnvironment -# } +DomainController ` + -ConfigurationData $ConfigurationData ` + -OutputPath 'C:\DSC\Configuration' ` + -Verbose diff --git a/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 b/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 index 14a4e1345..b48d5dffc 100644 --- a/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 +++ b/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 @@ -1,21 +1,21 @@ -$script:dscModuleName = 'ActiveDirectoryDsc' +# $script:dscModuleName = 'ActiveDirectoryDsc' $script:dscResourceFriendlyName = 'ADComputer' $script:dscResourceName = "MSFT_$($script:dscResourceFriendlyName)" -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' +# 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' try { @@ -381,7 +381,7 @@ try } finally { - #region FOOTER - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - #endregion + # #region FOOTER + # Restore-TestEnvironment -TestEnvironment $script:testEnvironment + # #endregion } From f2933c836ac9eaa9c4ae6074fe0a0e96dfc6c8dd Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 12 Apr 2020 13:01:35 +0200 Subject: [PATCH 10/16] Update integration tests --- REMOVE.md | 43 -- Tests/README.md | 37 +- Tests/TestHelpers/Prepare-DscLab-dc01.ps1 | 2 +- Tests/TestHelpers/Prepare-DscLab-dc02.ps1 | 2 +- Tests/TestHelpers/Prepare-DscLab-dc03.ps1 | 2 +- .../MSFT_ADComputer.Integration.Tests.ps1 | 634 +++++++++--------- .../MSFT_ADDomain.Root.Integration.Tests.ps1 | 124 ++-- .../Integration/MSFT_ADDomain.Root.config.ps1 | 10 +- ...FT_ADOptionalFeature.Integration.Tests.ps1 | 194 +++--- .../MSFT_ADOptionalFeature.config.ps1 | 4 +- 10 files changed, 483 insertions(+), 569 deletions(-) delete mode 100644 REMOVE.md diff --git a/REMOVE.md b/REMOVE.md deleted file mode 100644 index 180cb28cd..000000000 --- a/REMOVE.md +++ /dev/null @@ -1,43 +0,0 @@ -1. Install the dependent DSC resource modules on the node that hosts your - virtual machines, the same as from where the integration tests will be run. - ```powershell - $dependentModules = @( - 'Pester', - 'PSDepend', - 'PSDscResources', - 'ComputerManagementDsc', - 'NetworkingDsc' - ) - - Install-Module -Name $dependentModules - ``` -1. Copy the dependent modules to each of the virtual machines. - ```powershell - $dependentModule = Get-Module -ListAvailable -Name $dependentModules | - Sort-Object -Property 'Version' | - Sort-Object -Unique - - foreach ($module in $dependentModule) - { - $sourceModulePath = $module.ModuleBase - $moduleVersionFolder = Split-Path -Path $module.ModuleBase -Leaf - $destinationModulePath = Join-Path -Path (Join-Path -Path 'C:\Program Files\WindowsPowerShell\Modules' -ChildPath $module.Name) -ChildPath $moduleVersionFolder - - Copy-Item -ToSession $dc01Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force - Copy-Item -ToSession $dc02Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force - Copy-Item -ToSession $dc03Session -Path $sourceModulePath -Destination $destinationModulePath -Recurse -Force - } - ``` -1. Prepare the test environment in the remote session by running `build.ps1` - with the task `noop` against each of the virtual machines. - ```powershell - $scriptBlock = { - cd c:\projects\ActiveDirectoryDsc - .\build.ps1 -Tasks noop - #Write-Verbose -Message ('PSModulePath is now set to: ''{0}''' -f $env:PSModulePath) -Verbose - } - - Invoke-Command -Session $dc01Session -ScriptBlock $scriptBlock - Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock - Invoke-Command -Session $dc02Session -ScriptBlock $scriptBlock - ``` diff --git a/Tests/README.md b/Tests/README.md index 0042d9b58..539683cf6 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -163,7 +163,7 @@ The blow steps *must* be run in a elevated PowerShell console. 1. Open a PowerShell Direct session to each virtual machine. ```powershell $localAdminPassword = ConvertTo-SecureString 'adminP@ssw0rd1' -AsPlainText -Force - $localAdminUsername = 'Administrator' + $localAdminUsername = '.\Administrator' $newObjectParameters = @{ TypeName = 'System.Management.Automation.PSCredential' @@ -302,7 +302,7 @@ the domain, e.g. `ADDomain` and `ADDomainController`. session to disconnect. ```powershell $localAdminPassword = ConvertTo-SecureString 'adminP@ssw0rd1' -AsPlainText -Force - $localAdminUsername = 'Administrator' + $localAdminUsername = '.\Administrator' $newObjectParameters = @{ TypeName = 'System.Management.Automation.PSCredential' @@ -335,12 +335,41 @@ the domain, e.g. `ADDomain` and `ADDomainController`. #Copy-Item -ToSession $dc02Session -Path '.\tests' -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force #Copy-Item -ToSession $dc02Session -Path '.\tests' -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force ``` -1. This runs the actual integration tests. +1. This runs the tests on the first domain controller. ```powershell Invoke-Command -Session $dc01Session -ScriptBlock { cd 'c:\projects\ActiveDirectoryDsc' - Invoke-Pester -Path '.\Tests\Integration\MSFT_ADComputer.Integration.Tests.ps1' + $testParameters = @{ + Verbose = $true + } + + Invoke-pester -Script @( + @{ + Path = '.\tests\Integration\MSFT_ADDomain.Root.Integration.Tests.ps1' + Parameters = $testParameters + } + @{ + Path = '.\tests\Integration\MSFT_ADOptionalFeature.Integration.Tests.ps1' + Parameters = $testParameters + } + @{ + Path = '.\tests\Integration\MSFT_ADComputer.Integration.Tests.ps1' + Parameters = $testParameters + } + ) } ``` + This test need to run twice because of a required reboot. When the test + finishes it will print a warning message asking for a reboot of the note. + Restart the node manually or use this + ```powershell + Restart-VM -Name 'dc01' -Type Reboot -Wait -For Heartbeat -Force + ``` + After the node has restarted and finished (takes ~a minute), reconnect + the session and then run the integration tests again to verify the + installation. + ```powershell + $dc01Session = New-PSSession -VMName 'dc01' -Credential $localAdminCredential + ``` diff --git a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 index b5adbbe11..47a82f81e 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 @@ -30,7 +30,7 @@ configuration LCMConfig Settings { RefreshMode = 'Push' - RebootNodeIfNeeded = $true + RebootNodeIfNeeded = $false ConfigurationMode = 'ApplyOnly' CertificateId = $node.Thumbprint AllowModuleOverwrite = $true diff --git a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 index abc758838..4eb406cae 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 @@ -30,7 +30,7 @@ configuration LCMConfig Settings { RefreshMode = 'Push' - RebootNodeIfNeeded = $true + RebootNodeIfNeeded = $false ConfigurationMode = 'ApplyOnly' CertificateId = $node.Thumbprint AllowModuleOverwrite = $true diff --git a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 index 2e791689e..4c871887e 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 @@ -30,7 +30,7 @@ configuration LCMConfig Settings { RefreshMode = 'Push' - RebootNodeIfNeeded = $true + RebootNodeIfNeeded = $false ConfigurationMode = 'ApplyOnly' CertificateId = $node.Thumbprint AllowModuleOverwrite = $true diff --git a/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 b/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 index b48d5dffc..bb134258c 100644 --- a/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 +++ b/tests/Integration/MSFT_ADComputer.Integration.Tests.ps1 @@ -1,387 +1,361 @@ -# $script:dscModuleName = 'ActiveDirectoryDsc' $script:dscResourceFriendlyName = 'ADComputer' $script:dscResourceName = "MSFT_$($script:dscResourceFriendlyName)" -# 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' - -try -{ - $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" - . $configFile - - Describe "$($script:dscResourceName)_Integration" { - BeforeAll { - $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" - } +$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" +. $configFile - $configurationName = "$($script:dscResourceName)_CreateComputerAccount1_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } +Describe "$($script:dscResourceName)_Integration" { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } + $configurationName = "$($script:dscResourceName)_CreateComputerAccount1_Config" - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.ComputerName | Should -Be $ConfigurationData.AllNodes.ComputerName1 - $resourceCurrentState.Location | Should -Be 'Old location' - $resourceCurrentState.DnsHostName | Should -BeNullOrEmpty - $resourceCurrentState.ServicePrincipalNames | Should -BeNullOrEmpty - $resourceCurrentState.UserPrincipalName | Should -BeNullOrEmpty - $resourceCurrentState.DisplayName | Should -BeNullOrEmpty - $resourceCurrentState.Path | Should -Match '^CN=Computers' - $resourceCurrentState.Description | Should -BeNullOrEmpty - $resourceCurrentState.Enabled | Should -BeTrue - $resourceCurrentState.EnabledOnCreation | Should -BeFalse - $resourceCurrentState.DomainController | Should -BeNullOrEmpty - $resourceCurrentState.Credential | Should -BeNullOrEmpty - $resourceCurrentState.RequestFile | Should -BeNullOrEmpty - $resourceCurrentState.RestoreFromRecycleBin | Should -BeFalse - $resourceCurrentState.DistinguishedName | Should -Match ('^CN={0}' -f $ConfigurationData.AllNodes.ComputerName1) - $resourceCurrentState.SID | Should -Match '^S-' - $resourceCurrentState.SamAccountName | Should -Be ('{0}$' -f $ConfigurationData.AllNodes.ComputerName1) - } + & $configurationName @configurationParameters - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_RemoveComputerAccount1_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.ComputerName | Should -Be $ConfigurationData.AllNodes.ComputerName1 + $resourceCurrentState.Location | Should -Be 'Old location' + $resourceCurrentState.DnsHostName | Should -BeNullOrEmpty + $resourceCurrentState.ServicePrincipalNames | Should -BeNullOrEmpty + $resourceCurrentState.UserPrincipalName | Should -BeNullOrEmpty + $resourceCurrentState.DisplayName | Should -BeNullOrEmpty + $resourceCurrentState.Path | Should -Match '^CN=Computers' + $resourceCurrentState.Description | Should -BeNullOrEmpty + $resourceCurrentState.Enabled | Should -BeTrue + $resourceCurrentState.EnabledOnCreation | Should -BeFalse + $resourceCurrentState.DomainController | Should -BeNullOrEmpty + $resourceCurrentState.Credential | Should -BeNullOrEmpty + $resourceCurrentState.RequestFile | Should -BeNullOrEmpty + $resourceCurrentState.RestoreFromRecycleBin | Should -BeFalse + $resourceCurrentState.DistinguishedName | Should -Match ('^CN={0}' -f $ConfigurationData.AllNodes.ComputerName1) + $resourceCurrentState.SID | Should -Match '^S-' + $resourceCurrentState.SamAccountName | Should -Be ('{0}$' -f $ConfigurationData.AllNodes.ComputerName1) + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_RemoveComputerAccount1_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.Ensure | Should -Be 'Absent' - $resourceCurrentState.Enabled | Should -BeFalse - } + & $configurationName @configurationParameters - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_RestoreComputerAccount1_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $resourceCurrentState.Ensure | Should -Be 'Absent' + $resourceCurrentState.Enabled | Should -BeFalse + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_RestoreComputerAccount1_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Enabled | Should -BeTrue - $resourceCurrentState.Location | Should -Be 'Old location' - } + & $configurationName @configurationParameters - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_CreateComputerAccount2Disabled_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.Enabled | Should -BeTrue + $resourceCurrentState.Location | Should -Be 'Old location' + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_CreateComputerAccount2Disabled_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Enabled | Should -BeFalse - } + & $configurationName @configurationParameters - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_CreateComputerAccount3WithOfflineDomainJoin_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should have created a Offline Domain Join request file' { - $ConfigurationData.AllNodes.RequestFileName | Should -Exist + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.Enabled | Should -BeFalse + } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_CreateComputerAccount3WithOfflineDomainJoin_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.Enabled | Should -BeTrue - } + & $configurationName @configurationParameters - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_UpdateComputerAccount1_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + It 'Should have created a Offline Domain Join request file' { + $ConfigurationData.AllNodes.RequestFileName | Should -Exist + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.Enabled | Should -BeTrue + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_UpdateComputerAccount1_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.Ensure | Should -Be 'Present' - $resourceCurrentState.ComputerName | Should -Be $ConfigurationData.AllNodes.ComputerName1 - $resourceCurrentState.Location | Should -Be $ConfigurationData.AllNodes.Location - $resourceCurrentState.DnsHostName | Should -Be $ConfigurationData.AllNodes.DnsHostName - $resourceCurrentState.ServicePrincipalNames | Should -Contain 'spn/a' - $resourceCurrentState.ServicePrincipalNames | Should -Contain 'spn/b' - $resourceCurrentState.UserPrincipalName | Should -Be $ConfigurationData.AllNodes.UserPrincipalName - $resourceCurrentState.DisplayName | Should -Be $ConfigurationData.AllNodes.DisplayName - $resourceCurrentState.Path | Should -Be ('OU={0},{1}' -f $ConfigurationData.AllNodes.OrganizationalUnitName, $ConfigurationData.AllNodes.DomainDistinguishedName) - $resourceCurrentState.Description | Should -Be $ConfigurationData.AllNodes.Description - $resourceCurrentState.Enabled | Should -BeTrue - $resourceCurrentState.EnabledOnCreation | Should -BeFalse - $resourceCurrentState.DomainController | Should -BeNullOrEmpty - $resourceCurrentState.Credential | Should -BeNullOrEmpty - $resourceCurrentState.RequestFile | Should -BeNullOrEmpty - $resourceCurrentState.RestoreFromRecycleBin | Should -BeFalse - $resourceCurrentState.DistinguishedName | Should -Match ('^CN={0}' -f $ConfigurationData.AllNodes.ComputerName1) - $resourceCurrentState.SID | Should -Match '^S-' - $resourceCurrentState.SamAccountName | Should -Be ('{0}$' -f $ConfigurationData.AllNodes.ComputerName1) - } + & $configurationName @configurationParameters - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_CleanUp_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.ComputerName | Should -Be $ConfigurationData.AllNodes.ComputerName1 + $resourceCurrentState.Location | Should -Be $ConfigurationData.AllNodes.Location + $resourceCurrentState.DnsHostName | Should -Be $ConfigurationData.AllNodes.DnsHostName + $resourceCurrentState.ServicePrincipalNames | Should -Contain 'spn/a' + $resourceCurrentState.ServicePrincipalNames | Should -Contain 'spn/b' + $resourceCurrentState.UserPrincipalName | Should -Be $ConfigurationData.AllNodes.UserPrincipalName + $resourceCurrentState.DisplayName | Should -Be $ConfigurationData.AllNodes.DisplayName + $resourceCurrentState.Path | Should -Be ('OU={0},{1}' -f $ConfigurationData.AllNodes.OrganizationalUnitName, $ConfigurationData.AllNodes.DomainDistinguishedName) + $resourceCurrentState.Description | Should -Be $ConfigurationData.AllNodes.Description + $resourceCurrentState.Enabled | Should -BeTrue + $resourceCurrentState.EnabledOnCreation | Should -BeFalse + $resourceCurrentState.DomainController | Should -BeNullOrEmpty + $resourceCurrentState.Credential | Should -BeNullOrEmpty + $resourceCurrentState.RequestFile | Should -BeNullOrEmpty + $resourceCurrentState.RestoreFromRecycleBin | Should -BeFalse + $resourceCurrentState.DistinguishedName | Should -Match ('^CN={0}' -f $ConfigurationData.AllNodes.ComputerName1) + $resourceCurrentState.SID | Should -Match '^S-' + $resourceCurrentState.SamAccountName | Should -Be ('{0}$' -f $ConfigurationData.AllNodes.ComputerName1) + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_CleanUp_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' } } -} -finally -{ - # #region FOOTER - # Restore-TestEnvironment -TestEnvironment $script:testEnvironment - # #endregion } diff --git a/tests/Integration/MSFT_ADDomain.Root.Integration.Tests.ps1 b/tests/Integration/MSFT_ADDomain.Root.Integration.Tests.ps1 index 0c8d63937..c19175823 100644 --- a/tests/Integration/MSFT_ADDomain.Root.Integration.Tests.ps1 +++ b/tests/Integration/MSFT_ADDomain.Root.Integration.Tests.ps1 @@ -14,99 +14,73 @@ param () Set-StrictMode -Version 1.0 -$script:dscModuleName = 'ActiveDirectoryDsc' $script:dscResourceFriendlyName = 'ADDomain' $script:dscResourceName = "MSFT_$($script:dscResourceFriendlyName)" $script:subTestName = 'Root' -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' +$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).$($script:subTestName).config.ps1" +. $configFile -try -{ - $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).$($script:subTestName).config.ps1" - . $configFile - - Describe "$($script:dscResourceName).$($script:subTestName)_Integration" { - BeforeAll { - $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" - } +Describe "$($script:dscResourceName).$($script:subTestName)_Integration" { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } + foreach ($testName in $ConfigurationData.AllNodes.Tests.Keys ) + { + $configurationName = "$($script:dscResourceName)_$($testName)_Config" - foreach ($testName in $ConfigurationData.AllNodes.Tests.Keys ) - { - $configurationName = "$($script:dscResourceName)_$($testName)_Config" + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } + & $configurationName @configurationParameters - & $configurationName @configurationParameters + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Force = $true + ErrorAction = 'Stop' + } - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Force = $true - ErrorAction = 'Stop' - } + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + $DscConfigurationStatus = Get-DscConfigurationStatus + if ($DscConfigurationStatus.RebootRequested) + { + Write-Warning 'A Reboot has been requested by the DSC. Please reboot then re-run the test' + Return + } - $DscConfigurationStatus = Get-DscConfigurationStatus - if ($DscConfigurationStatus.RebootRequested) + It 'Should be able to call Get-DscConfiguration without throwing' { { - Write-Warning 'A Reboot has been requested by the DSC. Please reboot then re-run the test' - Return - } + $script:currentConfiguration = Get-DscConfiguration -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -ErrorAction Stop - } | Should -Not -Throw - } + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId - } - - foreach ($property in $ConfigurationData.AllNodes.Tests.$testName.Keys) - { - It "Should have set the correct $property property" { - $resourceCurrentState.$property | Should -Be $ConfigurationData.AllNodes.Tests.$testName.$property - } + foreach ($property in $ConfigurationData.AllNodes.Tests.$testName.Keys) + { + It "Should have set the correct $property property" { + $resourceCurrentState.$property | Should -Be $ConfigurationData.AllNodes.Tests.$testName.$property } + } - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration | Should -Be 'True' - } + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration | Should -Be 'True' } } } } -finally -{ - #region FOOTER - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - #endregion -} diff --git a/tests/Integration/MSFT_ADDomain.Root.config.ps1 b/tests/Integration/MSFT_ADDomain.Root.config.ps1 index a2d8745a1..60b44ac24 100644 --- a/tests/Integration/MSFT_ADDomain.Root.config.ps1 +++ b/tests/Integration/MSFT_ADDomain.Root.config.ps1 @@ -18,14 +18,14 @@ else @{ NodeName = 'localhost' CertificateFile = $env:DscPublicCertificatePath - CredentialUserName = 'administrator' - CredentialPassword = 'ContosoAdmin@1' + CredentialUserName = 'Administrator' + CredentialPassword = 'adminP@ssw0rd1' SafeModePassword = 'SafemodePassword@1' Tests = [Ordered]@{ FeatureInstall = @{ } ForestRootDomain = @{ - DomainName = 'contoso.com' - DomainNetbiosName = 'CONTOSO' + DomainName = 'dscadlab.com' + DomainNetbiosName = 'DSCADLAB' DatabasePath = 'C:\NTDS' LogPath = 'C:\NTDS' SysvolPath = 'C:\SysVol' @@ -33,6 +33,8 @@ else DomainMode = 'WinThreshold' } } + + PsDscAllowPlainTextPassword = $true } ) } diff --git a/tests/Integration/MSFT_ADOptionalFeature.Integration.Tests.ps1 b/tests/Integration/MSFT_ADOptionalFeature.Integration.Tests.ps1 index 7c9268307..6dbf50f77 100644 --- a/tests/Integration/MSFT_ADOptionalFeature.Integration.Tests.ps1 +++ b/tests/Integration/MSFT_ADOptionalFeature.Integration.Tests.ps1 @@ -1,132 +1,108 @@ -$script:dscModuleName = 'ActiveDirectoryDsc' $script:dscResourceFriendlyName = 'ADOptionalFeature' $script:dscResourceName = "MSFT_$($script:dscResourceFriendlyName)" -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.' -} +$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" +. $configFile -$script:testEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:dscModuleName ` - -DSCResourceName $script:dscResourceName ` - -ResourceType 'Mof' ` - -TestType 'Integration' - -try -{ - $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" - . $configFile +Describe "$($script:dscResourceName)_Integration" { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } - Describe "$($script:dscResourceName)_Integration" { - BeforeAll { - $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" - } + $configurationName = "$($script:dscResourceName)_RecycleBinFeature_Config" - $configurationName = "$($script:dscResourceName)_RecycleBinFeature_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } + & $configurationName @configurationParameters - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' } - $resourceCurrentState.FeatureName | Should -Be 'Recycle Bin Feature' - $resourceCurrentState.ForestFQDN | Should -Be $ConfigurationData.AllNodes.ForestFullyQualifiedDomainName - $resourceCurrentState.EnterpriseAdministratorCredential.UserName | Should -Be $ConfigurationData.AllNodes.AdministratorUserName - } + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_PrivilegedAccessManagementFeature_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } + $resourceCurrentState.FeatureName | Should -Be 'Recycle Bin Feature' + $resourceCurrentState.ForestFQDN | Should -Be $ConfigurationData.AllNodes.ForestFullyQualifiedDomainName + $resourceCurrentState.EnterpriseAdministratorCredential.UserName | Should -Be $ConfigurationData.AllNodes.AdministratorUserName + } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_PrivilegedAccessManagementFeature_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.FeatureName | Should -Be 'Privileged Access Management Feature' - $resourceCurrentState.ForestFQDN | Should -Be $ConfigurationData.AllNodes.ForestFullyQualifiedDomainName - $resourceCurrentState.EnterpriseAdministratorCredential.UserName | Should -Be $ConfigurationData.AllNodes.AdministratorUserName - } + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } + + $resourceCurrentState.FeatureName | Should -Be 'Privileged Access Management Feature' + $resourceCurrentState.ForestFQDN | Should -Be $ConfigurationData.AllNodes.ForestFullyQualifiedDomainName + $resourceCurrentState.EnterpriseAdministratorCredential.UserName | Should -Be $ConfigurationData.AllNodes.AdministratorUserName + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' } } } -finally -{ - #region FOOTER - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - #endregion -} + diff --git a/tests/Integration/MSFT_ADOptionalFeature.config.ps1 b/tests/Integration/MSFT_ADOptionalFeature.config.ps1 index f7b2f289f..dde8d796e 100644 --- a/tests/Integration/MSFT_ADOptionalFeature.config.ps1 +++ b/tests/Integration/MSFT_ADOptionalFeature.config.ps1 @@ -26,7 +26,9 @@ else ForestFullyQualifiedDomainName = $ForestFullyQualifiedDomainName AdministratorUserName = ('{0}\Administrator' -f $netBiosDomainName) - AdministratorPassword = 'P@ssw0rd1' + AdministratorPassword = 'adminP@ssw0rd1' + + PsDscAllowPlainTextPassword = $true } ) } From 6d5308caa606527ebc6625da21177c9ade563e3c Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 12 Apr 2020 13:20:11 +0200 Subject: [PATCH 11/16] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60482004a..db881d2ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,9 @@ For older change log history see the [historic changelog](HISTORIC_CHANGELOG.md) ### Added +- ActiveDirectoryDsc + - Documentation and steps to setup a lab in Hyper-V to be able to run + the integration tests. - ADManagedServiceAccount - Added support for setting a common name to a Managed Service Account for a longer more friendly name than the SAM account name which has a 15 character limit. From 91f33d501e990baacf42509954755f8d1402cc22 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 12 Apr 2020 19:47:10 +0200 Subject: [PATCH 12/16] Update steps --- Tests/README.md | 70 ++++--- tests/Integration/MSFT_ADComputer.config.ps1 | 2 +- .../Integration/MSFT_ADDomain.Root.config.ps1 | 2 +- ...ControllerProperties.Integration.Tests.ps1 | 188 ++++++++---------- ...FT_ADDomainControllerProperties.config.ps1 | 2 +- 5 files changed, 124 insertions(+), 140 deletions(-) diff --git a/Tests/README.md b/Tests/README.md index 539683cf6..9514a9a93 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -193,43 +193,42 @@ The blow steps *must* be run in a elevated PowerShell console. foreach ($dependentModulePath in $dependentModulePaths) { Copy-Item -ToSession $dc01Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force - #Copy-Item -ToSession $dc02Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force - #Copy-Item -ToSession $dc03Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force + Copy-Item -ToSession $dc02Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force + Copy-Item -ToSession $dc03Session -Path $dependentModulePath -Destination $destinationPath -Recurse -Force } ``` +1. Copy the tests and the required modules to each of the virtual machines. + ```powershell + cd 'c:\source\ActiveDirectoryDsc' + + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc01Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc02Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc03Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + ``` 1. Configure prerequisites like computer name, IP address, and Windows features that is needed to promote a node to a domain controller. This creates the configuration .mof and the metadata .mof file on the respective nodes which will be executed in next steps. ```powershell - $dc01ScriptBlock = { - cd 'c:\projects\ActiveDirectoryDsc' - .\tests\TestHelpers\Prepare-DscLab-dc01.ps1 + Invoke-Command -Session $dc01Session -ScriptBlock { + c:\projects\ActiveDirectoryDsc\tests\TestHelpers\Prepare-DscLab-dc01.ps1 } - Invoke-Command -Session $dc01Session -ScriptBlock $dc01ScriptBlock - - $dc02ScriptBlock = { - cd 'c:\projects\ActiveDirectoryDsc' - .\tests\TestHelpers\Prepare-DscLab-dc02.ps1 + Invoke-Command -Session $dc02Session -ScriptBlock { + c:\projects\ActiveDirectoryDsc\tests\TestHelpers\Prepare-DscLab-dc02.ps1 } - Invoke-Command -Session $dc02Session -ScriptBlock $dc02ScriptBlock - - $dc03ScriptBlock = { - cd 'c:\projects\ActiveDirectoryDsc' - .\tests\TestHelpers\Prepare-DscLab-dc03.ps1 + Invoke-Command -Session $dc03Session -ScriptBlock { + c:\projects\ActiveDirectoryDsc\tests\TestHelpers\Prepare-DscLab-dc03.ps1 } - - Invoke-Command -Session $dc03Session -ScriptBlock $dc03ScriptBlock ``` 1. Configure the DSC Local Configuration Manager (LCM) on each virtual machine using the metadata .mof created in previous step. ```powershell $vmPSSessions = @( $dc01Session - #$dc02Session - #$dc03Session + $dc02Session + $dc03Session ) Invoke-Command -Session $vmPSSessions -ScriptBlock { Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force @@ -240,15 +239,20 @@ The blow steps *must* be run in a elevated PowerShell console. ```powershell $vmPSSessions = @( $dc01Session - #$dc02Session - #$dc03Session + $dc02Session + $dc03Session ) Invoke-Command -Session $vmPSSessions -ScriptBlock { Start-DscConfiguration -Path "C:\DSC\Configuration\" -ComputerName 'localhost' -Wait -Force -Verbose } ``` -1. Wait until the node has been restarted and the rest of the configuration + A reboot will be required then the same configuration must be run again. + Restart the node manually or use this + ```powershell + Restart-VM -Name 'dc01','dc02','dc03' -Type Reboot -Wait -For Heartbeat -Force + ``` +1. Wait until the node has been restarted and then verify that the configuration has been applied. This should report the status *Success* once the configuration is finished. _**Note:** Since the virtual machines rebooted_ _we need to reconnect to the sessions._ @@ -259,8 +263,8 @@ The blow steps *must* be run in a elevated PowerShell console. $vmPSSessions = @( $dc01Session - #$dc02Session - #$dc03Session + $dc02Session + $dc03Session ) Invoke-Command -Session $vmPSSessions -ScriptBlock { @@ -272,8 +276,8 @@ The blow steps *must* be run in a elevated PowerShell console. ```powershell $vmPSSessions = @( $dc01Session - #$dc02Session - #$dc03Session + $dc02Session + $dc03Session ) Invoke-Command -Session $vmPSSessions -ScriptBlock { @@ -318,7 +322,7 @@ the domain, e.g. `ADDomain` and `ADDomainController`. $dc02Session = New-PSSession -VMName 'dc02' -Credential $localAdminCredential $dc03Session = New-PSSession -VMName 'dc03' -Credential $localAdminCredential ``` -1. Copy resource module output folder to the system PowerShell modules folder. +1. Copy the ActiveDirectoryDsc module to each of the virtual machines. ```powershell cd 'c:\source\ActiveDirectoryDsc' @@ -326,14 +330,16 @@ the domain, e.g. `ADDomain` and `ADDomainController`. $destinationPath = 'C:\Program Files\WindowsPowerShell\Modules' Copy-Item -ToSession $dc01Session -Path $dscModuleOutputPath -Destination $destinationPath -Recurse -Force + Copy-Item -ToSession $dc02Session -Path $dscModuleOutputPath -Destination $destinationPath -Recurse -Force + Copy-Item -ToSession $dc03Session -Path $dscModuleOutputPath -Destination $destinationPath -Recurse -Force ``` -1. Copy the tests and the required modules to each of the virtual machines. +1. Copy the tests to each of the virtual machines. ```powershell cd 'c:\source\ActiveDirectoryDsc' Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc01Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force - #Copy-Item -ToSession $dc02Session -Path '.\tests' -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force - #Copy-Item -ToSession $dc02Session -Path '.\tests' -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc02Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc03Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force ``` 1. This runs the tests on the first domain controller. ```powershell @@ -357,6 +363,10 @@ the domain, e.g. `ADDomain` and `ADDomainController`. Path = '.\tests\Integration\MSFT_ADComputer.Integration.Tests.ps1' Parameters = $testParameters } + @{ + Path = '.\tests\Integration\MSFT_ADDomainControllerProperties.Integration.Tests.ps1' + Parameters = $testParameters + } ) } ``` diff --git a/tests/Integration/MSFT_ADComputer.config.ps1 b/tests/Integration/MSFT_ADComputer.config.ps1 index 52c0e735c..eadd9e427 100644 --- a/tests/Integration/MSFT_ADComputer.config.ps1 +++ b/tests/Integration/MSFT_ADComputer.config.ps1 @@ -21,7 +21,7 @@ else AllNodes = @( @{ NodeName = 'localhost' - CertificateFile = $env:DscPublicCertificatePath + #CertificateFile = $env:DscPublicCertificatePath DomainDistinguishedName = $domainDistinguishedName ComputerName1 = 'DSCINTEGTEST01' diff --git a/tests/Integration/MSFT_ADDomain.Root.config.ps1 b/tests/Integration/MSFT_ADDomain.Root.config.ps1 index 60b44ac24..fb12f1352 100644 --- a/tests/Integration/MSFT_ADDomain.Root.config.ps1 +++ b/tests/Integration/MSFT_ADDomain.Root.config.ps1 @@ -17,7 +17,7 @@ else AllNodes = @( @{ NodeName = 'localhost' - CertificateFile = $env:DscPublicCertificatePath + #CertificateFile = $env:DscPublicCertificatePath CredentialUserName = 'Administrator' CredentialPassword = 'adminP@ssw0rd1' SafeModePassword = 'SafemodePassword@1' diff --git a/tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 b/tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 index e43c2afd5..fd951baa6 100644 --- a/tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 +++ b/tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 @@ -1,130 +1,104 @@ -$script:dscModuleName = 'ActiveDirectoryDsc' $script:dscResourceFriendlyName = 'ADDomainControllerProperties' $script:dscResourceName = "MSFT_$($script:dscResourceFriendlyName)" -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.' -} +$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" +. $configFile -$script:testEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:dscModuleName ` - -DSCResourceName $script:dscResourceName ` - -ResourceType 'Mof' ` - -TestType 'Integration' +Describe "$($script:dscResourceName)_Integration" { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } -try -{ - $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" - . $configFile + $configurationName = "$($script:dscResourceName)_SetPropertyValues_Config" - Describe "$($script:dscResourceName)_Integration" { - BeforeAll { - $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" - } - - $configurationName = "$($script:dscResourceName)_SetPropertyValues_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw - } + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } + & $configurationName @configurationParameters - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Force = $true + ErrorAction = 'Stop' } - $resourceCurrentState.IsSingleInstance | Should -Be 'Yes' - $resourceCurrentState.ContentFreshness | Should -Be 100 - } + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' - } + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw } - $configurationName = "$($script:dscResourceName)_RestoreDefaultValues_Config" - - Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - - & $configurationName @configurationParameters - - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - - Start-DscConfiguration @startDscConfigurationParameters - } | Should -Not -Throw + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } - It 'Should be able to call Get-DscConfiguration without throwing' { - { - $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop - } | Should -Not -Throw - } + $resourceCurrentState.IsSingleInstance | Should -Be 'Yes' + $resourceCurrentState.ContentFreshness | Should -Be 100 + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } - It 'Should have set the resource and all the parameters should match' { - $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { - $_.ConfigurationName -eq $configurationName ` - -and $_.ResourceId -eq $resourceId + $configurationName = "$($script:dscResourceName)_RestoreDefaultValues_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData } - $resourceCurrentState.IsSingleInstance | Should -Be 'Yes' - $resourceCurrentState.ContentFreshness | Should -Be 60 - } + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } - It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId } + + $resourceCurrentState.IsSingleInstance | Should -Be 'Yes' + $resourceCurrentState.ContentFreshness | Should -Be 60 + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' } } } -finally -{ - #region FOOTER - Restore-TestEnvironment -TestEnvironment $script:testEnvironment - #endregion -} diff --git a/tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 b/tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 index 36ff9b3e8..d40413753 100644 --- a/tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 +++ b/tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 @@ -17,7 +17,7 @@ else AllNodes = @( @{ NodeName = 'localhost' - CertificateFile = $env:DscPublicCertificatePath + #CertificateFile = $env:DscPublicCertificatePath } ) } From f24962a37bdbe442bd3297eea52bb5b6de242071 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 12 Apr 2020 20:04:35 +0200 Subject: [PATCH 13/16] Update steps --- Tests/README.md | 45 +++++++++++++------ .../MSFT_ADOptionalFeature.config.ps1 | 2 +- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Tests/README.md b/Tests/README.md index 9514a9a93..1570670b6 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -37,7 +37,7 @@ used to create the one or more servers to run tests on. $newVmParameters = @{ Name = 'DSCAD-template' BootDevice = 'CD' - MemoryStartupBytes = 4GB + MemoryStartupBytes = 2GB NoVHD = $true Generation = 2 SwitchName = 'Default Switch' @@ -46,7 +46,7 @@ used to create the one or more servers to run tests on. $vm = New-VM @newVmParameters Set-VM -VM $vm -AutomaticCheckpointsEnabled $false -DynamicMemory $vmDiskPath = Join-Path -Path $virtualHardDiskPath -ChildPath 'DSCAD-template.vhdx' - $vhd = New-VHD -Path $vmDiskPath -SizeBytes 40GB -Dynamic + $vhd = New-VHD -Path $vmDiskPath -SizeBytes 25GB -Dynamic Add-VMHardDiskDrive -VM $vm -Path $vhd.Path Get-VMDvdDrive -VM $vm | Set-VMDvdDrive -Path $windowsServerIsoPath Start-VM -VM $vm @@ -341,6 +341,35 @@ the domain, e.g. `ADDomain` and `ADDomainController`. Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc02Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc03Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force ``` +1. This runs the tests on the first domain controller. This test need to + run twice because of a required reboot (see next step). + ```powershell + Invoke-Command -Session $dc01Session -ScriptBlock { + cd 'c:\projects\ActiveDirectoryDsc' + + $testParameters = @{ + Verbose = $true + } + + Invoke-pester -Script @( + @{ + Path = '.\tests\Integration\MSFT_ADDomain.Root.Integration.Tests.ps1' + Parameters = $testParameters + } + ) + } + ``` + When the test finishes it will print a warning message asking for a reboot + of the note. Restart the node manually or use this: + ```powershell + Restart-VM -Name 'dc01' -Type Reboot -Wait -For Heartbeat -Force + ``` + After the node has restarted and finished (takes ~a minute), reconnect + the session and then run the integration tests again by running the next + step. + ```powershell + $dc01Session = New-PSSession -VMName 'dc01' -Credential $localAdminCredential + ``` 1. This runs the tests on the first domain controller. ```powershell Invoke-Command -Session $dc01Session -ScriptBlock { @@ -370,16 +399,4 @@ the domain, e.g. `ADDomain` and `ADDomainController`. ) } ``` - This test need to run twice because of a required reboot. When the test - finishes it will print a warning message asking for a reboot of the note. - Restart the node manually or use this - ```powershell - Restart-VM -Name 'dc01' -Type Reboot -Wait -For Heartbeat -Force - ``` - After the node has restarted and finished (takes ~a minute), reconnect - the session and then run the integration tests again to verify the - installation. - ```powershell - $dc01Session = New-PSSession -VMName 'dc01' -Credential $localAdminCredential - ``` diff --git a/tests/Integration/MSFT_ADOptionalFeature.config.ps1 b/tests/Integration/MSFT_ADOptionalFeature.config.ps1 index dde8d796e..3f4872952 100644 --- a/tests/Integration/MSFT_ADOptionalFeature.config.ps1 +++ b/tests/Integration/MSFT_ADOptionalFeature.config.ps1 @@ -21,7 +21,7 @@ else AllNodes = @( @{ NodeName = 'localhost' - CertificateFile = $env:DscPublicCertificatePath + #CertificateFile = $env:DscPublicCertificatePath ForestFullyQualifiedDomainName = $ForestFullyQualifiedDomainName From e33cc2c5f065fdfd360050e806728095ca2cd149 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Mon, 13 Apr 2020 13:38:44 +0200 Subject: [PATCH 14/16] Update with VMware and requirements section --- Tests/README.md | 82 +++++++++++++++++++---- Tests/TestHelpers/Prepare-DscLab-dc01.ps1 | 20 +++--- Tests/TestHelpers/Prepare-DscLab-dc02.ps1 | 20 +++--- Tests/TestHelpers/Prepare-DscLab-dc03.ps1 | 20 +++--- 4 files changed, 100 insertions(+), 42 deletions(-) diff --git a/Tests/README.md b/Tests/README.md index 1570670b6..bca6eab38 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -1,6 +1,64 @@ -# Running tests +# Running Integration Tests -## Run integration tests in Hyper-V (PowerShell Direct) +## VMware ESXi + +_To be enhanced. Might be able to use [Invoke-VMScript](https://www.vmware.com/support/developer/windowstoolkit/wintk40u1/html/Invoke-VMScript.html)_ +_to more resemble the Hyper-V steps._ + +### Requirements + +- This requires a ESXi install on a physical server. + +- The virtual machine should have at least 2GB of memory and 25GB of disk. + +- The host should also have a disk with enough free + space for a virtual machine plus snapshots (~30GB should + suffice). + +- The virtual machine need to have internet connectivity. + +### Deploy VMware ESXi virtual machine + +1. Downloaded the appropriate installation media, for example from + [Windows Server Evaluations](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019). +1. Configure VM on a VMware ESXi host. +1. Install the server operating system using the downloaded media. +1. Make sure to install the necessary tools to be able to clone and build + the repository. See the article [Getting Started as a Contributor](https://dsccommunity.org/guidelines/getting-started/) + for the necessary tools. +1. Clone the repository to the domain controller using `git`. +1. Snapshot the virtual machine so it possible to revert to this state. + +### Running the integration tests + +1. Change location to the local repository folder. +1. Build the module using `.\build.ps1 -ResolveDependency -Tasks build`. +1. Build the first domain controller by running the integration test + `Invoke-Pester .\tests\Integration\MSFT_ADDomain.Root.Integration.Tests.ps1`. + The integration test will require a reboot. +1. Run the any additional integration tests by changing the path to the + integration test in the previous test. + +## Microsoft Hyper-V (PowerShell Direct) + +### Requirements + +- This requires a host that can run Hyper-V. For example Windows 10 + or Windows Server 2019 on either physical hardware with virtualization + enabled (BIOS setting) or in a VM that supports nested virtualization. + + > In Azure (for example) the VM size `Standard E8-4s_v3` supports nested + > virtualization and have 4 vCPUs and 64 GiB memory. + +- The host should have enough memory to be able to run at least 4 VMs with + 2GB each simultaneous. +- The host should also have a disk with enough free + space to hold the template and 4 VM's plus checkpoints (~150GB should + suffice). + +- Internet connectivity is required to create the base VM template (if updates +should be installed), but the lab that runs the integration tests does _not_ +need Internet connectivity. ### Create Hyper-V base image template @@ -18,13 +76,13 @@ The below steps will help to create a base image template that will be used to create the one or more servers to run tests on. >**Note:** All these steps are expected to be run in the same elevated ->PowerShell prompt. It also expect that you have downloaded the appropriate +>PowerShell prompt. It also expects that you have downloaded the appropriate >installation media, for example from [Windows Server Evaluations](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019) >or the [direct link to the ISO](https://software-download.microsoft.com/download/pr/17763.737.190906-2324.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us_1.iso). 1. Create a Hyper-VM (Generation 2). In an elevated PowerShell prompt run - this. + this: ```powershell $windowsServerIsoPath = 'C:\_images\17763.737.190906-2324.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso' if (-not (Test-Path -Path $windowsServerIsoPath)) @@ -65,7 +123,7 @@ used to create the one or more servers to run tests on. ```powershell C:\Windows\System32\SysPrep\sysprep.exe /quiet /generalize /oobe /shutdown ``` -1. Create the folder where we store the exported image. _This folder can_ +1. Create the folder where we will store the exported image. _This folder can_ _be located anywhere._ ```powershell $templatesPath = 'C:\Hyper-V\Templates' @@ -132,7 +190,7 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. Get-VM -Name $vmNames | Start-VM -Verbose ``` -1. On each started VM finish the installation by configure the following +1. On each started VM finish the installation by configuring the following in the Hyper-V Virtual Machine Connection. - Localization - (Optional) Product key @@ -143,15 +201,15 @@ memory (~32GB) and disk (~60GB) on the PC that will host the virtual machines. ### Test prerequisites -The host for the virtual machines must have access to Internet. The +The host for the virtual machines must have access the Internet. The below steps assumes the virtual machines that should run the integration -test are only connect to a private virtual switch and does not have access +test are only connected to a private virtual switch and do not have access to the Internet. -The blow steps *must* be run in a elevated PowerShell console. +The below steps *must* be run in a elevated PowerShell console. -1. Change to folder to root of your local working repository +1. Change directory to the root of your local working repository folder, e.g. cd 'c:\source\ActiveDirectoryDsc'. ```powershell cd c:\source\ActiveDirectoryDsc @@ -294,10 +352,10 @@ The blow steps *must* be run in a elevated PowerShell console. By reverting to the checkpoint created before, these tests can be run several times. The integration tests that depend on an already existing domain can be run several times without reverting to the checkpoint. The -resources that need a clean environment are the resources that configures +resources that need a clean environment are the resources that configure the domain, e.g. `ADDomain` and `ADDomainController`. -1. Change to folder to root of your local working repository +1. Change directory to the root of your local working repository folder, e.g. cd 'c:\source\ActiveDirectoryDsc'. ```powershell cd 'c:\source\ActiveDirectoryDsc' diff --git a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 index 47a82f81e..692db4b05 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc01.ps1 @@ -12,8 +12,8 @@ $ConfigurationData = @{ AllNodes = @( @{ - NodeName= '*' - PSDscAllowDomainUser = $true + NodeName = '*' + PSDscAllowDomainUser = $true PsDscAllowPlainTextPassword = $true }, @{ @@ -29,12 +29,12 @@ configuration LCMConfig { Settings { - RefreshMode = 'Push' - RebootNodeIfNeeded = $false - ConfigurationMode = 'ApplyOnly' - CertificateId = $node.Thumbprint + RefreshMode = 'Push' + RebootNodeIfNeeded = $false + ConfigurationMode = 'ApplyOnly' + CertificateId = $node.Thumbprint AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' + DebugMode = 'ForceModuleImport' } } } @@ -53,7 +53,7 @@ Configuration DomainController { Computer NewName { - Name = 'dc01' + Name = 'dc01' Description = 'First domain controller' } @@ -75,7 +75,7 @@ Configuration DomainController AddressFamily = 'IPv4' Dhcp = 'Disabled' - DependsOn = '[NetAdapterName]RenameNetAdapter' + DependsOn = '[NetAdapterName]RenameNetAdapter' } IPAddress NewIPv4Address @@ -84,7 +84,7 @@ Configuration DomainController InterfaceAlias = 'dscadlab.com' AddressFamily = 'IPV4' - DependsOn = '[NetAdapterName]RenameNetAdapter' + DependsOn = '[NetAdapterName]RenameNetAdapter' } DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' diff --git a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 index 4eb406cae..c942598f7 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc02.ps1 @@ -12,8 +12,8 @@ $ConfigurationData = @{ AllNodes = @( @{ - NodeName= '*' - PSDscAllowDomainUser = $true + NodeName = '*' + PSDscAllowDomainUser = $true PsDscAllowPlainTextPassword = $true }, @{ @@ -29,12 +29,12 @@ configuration LCMConfig { Settings { - RefreshMode = 'Push' - RebootNodeIfNeeded = $false - ConfigurationMode = 'ApplyOnly' - CertificateId = $node.Thumbprint + RefreshMode = 'Push' + RebootNodeIfNeeded = $false + ConfigurationMode = 'ApplyOnly' + CertificateId = $node.Thumbprint AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' + DebugMode = 'ForceModuleImport' } } } @@ -53,7 +53,7 @@ Configuration DomainController { Computer NewName { - Name = 'dc02' + Name = 'dc02' Description = 'Second domain controller' } @@ -75,7 +75,7 @@ Configuration DomainController AddressFamily = 'IPv4' Dhcp = 'Disabled' - DependsOn = '[NetAdapterName]RenameNetAdapter' + DependsOn = '[NetAdapterName]RenameNetAdapter' } IPAddress NewIPv4Address @@ -84,7 +84,7 @@ Configuration DomainController InterfaceAlias = 'dscadlab.com' AddressFamily = 'IPV4' - DependsOn = '[NetAdapterName]RenameNetAdapter' + DependsOn = '[NetAdapterName]RenameNetAdapter' } DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' diff --git a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 index 4c871887e..64d107197 100644 --- a/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 +++ b/Tests/TestHelpers/Prepare-DscLab-dc03.ps1 @@ -12,8 +12,8 @@ $ConfigurationData = @{ AllNodes = @( @{ - NodeName= '*' - PSDscAllowDomainUser = $true + NodeName = '*' + PSDscAllowDomainUser = $true PsDscAllowPlainTextPassword = $true }, @{ @@ -29,12 +29,12 @@ configuration LCMConfig { Settings { - RefreshMode = 'Push' - RebootNodeIfNeeded = $false - ConfigurationMode = 'ApplyOnly' - CertificateId = $node.Thumbprint + RefreshMode = 'Push' + RebootNodeIfNeeded = $false + ConfigurationMode = 'ApplyOnly' + CertificateId = $node.Thumbprint AllowModuleOverwrite = $true - DebugMode = 'ForceModuleImport' + DebugMode = 'ForceModuleImport' } } } @@ -53,7 +53,7 @@ Configuration DomainController { Computer NewName { - Name = 'dc03' + Name = 'dc03' Description = 'Third domain controller' } @@ -75,7 +75,7 @@ Configuration DomainController AddressFamily = 'IPv4' Dhcp = 'Disabled' - DependsOn = '[NetAdapterName]RenameNetAdapter' + DependsOn = '[NetAdapterName]RenameNetAdapter' } IPAddress NewIPv4Address @@ -84,7 +84,7 @@ Configuration DomainController InterfaceAlias = 'dscadlab.com' AddressFamily = 'IPV4' - DependsOn = '[NetAdapterName]RenameNetAdapter' + DependsOn = '[NetAdapterName]RenameNetAdapter' } DNSServerAddress 'SetFirstDomainControllerDNSIPAddresses' From 6fdcf94f573c2899e4898a8c11b03fcbc5ff803f Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 30 Apr 2022 15:49:29 +0200 Subject: [PATCH 15/16] Update README --- Tests/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tests/README.md b/Tests/README.md index bca6eab38..ed7072b7d 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -260,8 +260,8 @@ The below steps *must* be run in a elevated PowerShell console. cd 'c:\source\ActiveDirectoryDsc' Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc01Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force - Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc02Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force - Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc03Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc02Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force + Get-ChildItem -Path '.\tests' | Copy-Item -ToSession $dc03Session -Destination 'c:\projects\ActiveDirectoryDsc\tests' -Recurse -Force ``` 1. Configure prerequisites like computer name, IP address, and Windows features that is needed to promote a node to a domain controller. This creates @@ -288,6 +288,7 @@ The below steps *must* be run in a elevated PowerShell console. $dc02Session $dc03Session ) + Invoke-Command -Session $vmPSSessions -ScriptBlock { Set-DscLocalConfigurationManager -Path 'C:\DSC\Configuration' -ComputerName 'localhost' -Verbose -Force } From 84c9de06ce804790f4f40864cc28a707d0d2b6a6 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 14 Aug 2022 11:43:19 +0200 Subject: [PATCH 16/16] Fix VM host paths --- Tests/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Tests/README.md b/Tests/README.md index ed7072b7d..4696c70d0 100644 --- a/Tests/README.md +++ b/Tests/README.md @@ -60,6 +60,28 @@ _to more resemble the Hyper-V steps._ should be installed), but the lab that runs the integration tests does _not_ need Internet connectivity. +### Setup the Hyper-V host + +Run the following command to get the virtual machine and virtual machine +harddisk location: + +```powershell +Get-VMHost | Select-Object -Property VirtualMachinePath,VirtualHardDiskPath +``` + +Make sure the paths point to a location that has sufficient disk space, +especially the virtual machine harddisk location (`VirtualHardDiskPath`). +If the path need to change then run the below command and change the paths +as needed: + +```powershell +$virtualMachinePath = 'E:\Hyper-V' +$virtualMachineHarddiskPath = 'E:\Hyper-V\Virtual Hard Disks' +New-Item -Path $virtualMachinePath -Type 'Directory' -Force | Out-Null +New-Item -Path $virtualMachineHarddiskPath -Type 'Directory' -Force | Out-Null +Set-VMHost -VirtualMachinePath $virtualMachinePath -VirtualHardDiskPath $virtualMachineHarddiskPath +``` + ### Create Hyper-V base image template There are many blog articles explaining this, just search for