DSC PullServer automation with GitLab
Prerequisites
- Install a Pullserver 1
- Install GitLab runner on the Pullserver with the "shell" executor and tags "shell", "powershell5", "windows" and "pullserver".
- Create a gitlab project where the Project Name is the name of your intended DSC config. e.g. "Finance", omitting spaces and punctuation.
- Register the Gitlab runner with your DSC configuration project in GitLab.
- Stop the Gitlab Runner service and open c:\Gitlab-Runner\config.toml in a text editor.
- Change the
[[runners]]
>shell
setting from "pwsh" to "powershell" and restart the Gitlab Runner service. - Add a .gitignore file with contents
[PROJECT TITLE]/
to ignore the compiled mof. - Add .gitlab-ci.yml file to your project with the following contents
stages: - dependencies - test - run manage_dependencies: stage: dependencies tags: - shell # <-- executor, must change config.toml shell from "pwsh" to "powershell" - powershell5 # <-- only use runner with powershell 5 - windows # <-- only use windows runner - pullserver # <-- only use runner with Pullserver installed script: | # Configure Environment $ErrorActionPreference = 'Stop' Set-Location -Path $env:CI_PROJECT_DIR # Initialize variables [string[]]$detectedmodules = @() [string[]]$stagedmodules = @() [string[]]$ignoremodules = "PSDesiredStateConfiguration" [string]$modulespath = 'C:\Program Files\WindowsPowerShell\DscService\Modules' write-warning -Message "This script does not upgrade existing modules. Please test your scripts with modules already installed on the pull server." write-output "Setting PSModulePath..." $env:PSModulePath = 'C:\Program Files\WindowsPowerShell\Modules;C:\Program Files (x86)\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules' Write-Output "Detecting required modules..." Get-Content -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE).ps1" | Where-Object {$_ -match '(import-dscresource\s+)'} | ForEach-Object { $detectedmodules += $_.ToString().Trim().Split(" ") | Select-Object -Last 1 } $detectedmodules = $detectedmodules | Where-Object{$_ -notcontains $ignoremodules} Write-Output "Getting currently staged modules..." Get-ChildItem -Path $modulespath -Filter *.zip | ForEach-Object { $stagedmodules += $_.Name.ToString().Trim().Split("_")[0] } Write-Output "Checking for modules in the runners's powershell library..." foreach($detectedmodule In $detectedmodules){ write-output "Checking for $detectedmodule..." $checkmod = Get-DscResource -Module $detectedmodule -WarningAction SilentlyContinue If($checkmod){ write-output "$detectedmodule already installed." }else{ Write-Output "Installing $detectedmodule..." Install-Module -Name $detectedmodule } } Write-Output "Identifying modules missing from the pullserver repository..." $missingmodules = $detectedmodules | Where {$stagedmodules -NotContains $_} foreach($missingmodule In $missingmodules){ Write-Output "Downloading $missingmodule..." Save-Module -Name $missingmodule -Path . Write-Output "Unhiding files to enable compression..." Get-ChildItem -path ".\$missingmodule\$version\*" -force -Recurse | where{$_.Attributes -match "hidden"} | foreach{$_.Attributes=""} Write-Output "Compressing module..." $version = (Get-ChildItem -Path ".\$missingmodule").Name $archive = '.\' + $missingmodule + '_' + $version + '.zip' Compress-Archive -Path ".\$missingmodule\$version\*" -DestinationPath $archive Write-Output "Creating checksum..." New-DscChecksum -Path $archive -OutPath . write-output "Copying modules to module share..." Copy-Item -Path $archive -Destination $modulespath write-output "Copying checksum to module share..." Copy-Item -Path "$archive.checksum" -Destination $modulespath } only: - pushes test_dsc: stage: test tags: - shell - powershell5 - windows - pullserver script: | BeforeAll { . "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE).ps1" } Describe 'Pester-Test' { It 'Passes Script Analyzer' { Invoke-ScriptAnalyzer -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE).ps1" -Severity Error | Should -BeNullOrEmpty } It 'Generated MOF' { "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\localhost.mof" | Should -Exist } } AfterAll { If(Test-Path -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\localhost.mof"){Remove-Item -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\localhost.mof"} } only: - pushes run_dsc: stage: run tags: - shell - powershell5 - windows - pullserver script: | # Configure Environment $ErrorActionPreference = 'Stop' Set-Location -Path $env:CI_PROJECT_DIR # Initialize variables [string]$configpath = 'C:\Program Files\WindowsPowerShell\DscService\Configuration' write-output "Setting PSModulePath..." $env:PSModulePath = 'C:\Program Files\WindowsPowerShell\Modules;C:\Program Files (x86)\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules' Write-Output "Writing MOF..." Try{ & "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE).ps1" -Verbose }Catch{ Throw $_.Exception.Message } Write-Output "Creating Checksum..." New-DscChecksum -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\localhost.mof" Write-Output "Renaming MOF file..." Rename-Item -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\localhost.mof" -NewName "$($env:CI_PROJECT_TITLE).mof" Write-Output "Renaming checksum file..." Rename-Item -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\localhost.mof.checksum" -NewName "$($env:CI_PROJECT_TITLE).mof.checksum" Write-Output "Copying MOF to $configpath..." Copy-Item -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\$($env:CI_PROJECT_TITLE).mof" -Destination $configpath Write-Output "Copying checksum to $configpath..." Copy-Item -Path "$($env:CI_PROJECT_DIR)\$($env:CI_PROJECT_TITLE)\$($env:CI_PROJECT_TITLE).mof.checksum" -Destination $configpath only: - master
1 If your Pullserver cannot reach the internet, consider creating a local Nuget server to host required modules and add a Register-PSrepository command to the Configure Environment section of the Dependencies stage to register your internal Nuget server. You will need to upload all required modules and resources to the internal Nuget Server.
Document Actions