diff --git a/Set-SslSecurity.ps1 b/Set-SslSecurity.ps1 index 70c569b..19ea9c3 100644 --- a/Set-SslSecurity.ps1 +++ b/Set-SslSecurity.ps1 @@ -227,37 +227,13 @@ process { $ClientSaltValue = New-CCMSalt $ServiceSaltValue = New-CCMSalt - $ScriptBlock = @" -`$ClientCommunicationSalt = '$ClientSaltValue' -`$ServiceCommunicationSalt = '$ServiceSaltValue' -`$FQDN = '$SubjectWithoutCN' -`$NexusUserPW = '$NexusPw' - -# Touch NOTHING below this line -`$User = 'chocouser' -`$SecurePassword = `$NexusUserPW | ConvertTo-SecureString -AsPlainText -Force -`$RepositoryUrl = "https://`$(`$fqdn):8443/repository/ChocolateyInternal/index.json" - -`$credential = [pscredential]::new(`$user, `$securePassword) - -`$downloader = [System.Net.WebClient]::new() -`$downloader.Credentials = `$credential - -`$script = `$downloader.DownloadString("https://`$(`$FQDN):8443/repository/choco-install/ClientSetup.ps1") - -`$params = @{ - Credential = `$Credential - ClientSalt = `$ClientCommunicationSalt - ServiceSalt = `$ServiceCommunicationSalt - InternetEnabled = `$true - RepositoryUrl = `$RepositoryUrl -} - -& ([scriptblock]::Create(`$script)) @params -"@ - - $ScriptBlock | Set-Content -Path $EndpointScript + Invoke-TextReplacementInFile -Path $EndpointScript -Replacement @{ + "{{ ClientSaltValue }}" = $ClientSaltValue + "{{ ServiceSaltValue }}" = $ServiceSaltValue + "{{ FQDN }}" = $SubjectWithoutCn + } + # Agent Setup $agentArgs = @{ CentralManagementServiceUrl = "https://$($SubjectWithoutCn):24020/ChocolateyManagementService" diff --git a/modules/C4B-Environment/C4B-Environment.psm1 b/modules/C4B-Environment/C4B-Environment.psm1 index 04ff72e..dbbfee6 100644 --- a/modules/C4B-Environment/C4B-Environment.psm1 +++ b/modules/C4B-Environment/C4B-Environment.psm1 @@ -2262,6 +2262,10 @@ The host name of the C4B instance. "{{ jenkins_fqdn .*?}}" = ([uri]$Data.JenkinsUri).DnsSafeHost "{{ jenkins_port .*?}}" = ([uri]$Data.JenkinsUri).Port "{{ jenkins_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($Data.JenkinsCredential.Password.ToPlainText()) + + # Nexus Chocolatey Source Credential values + "{{ nexus_client_username .*?}}" = 'chocouser' + "{{ nexus_client_password .*?}}" = $Data.ChocoUserPassword } } } diff --git a/modules/C4B-Environment/ReadmeTemplate.html.j2 b/modules/C4B-Environment/ReadmeTemplate.html.j2 index 624eb71..d43a8fa 100644 --- a/modules/C4B-Environment/ReadmeTemplate.html.j2 +++ b/modules/C4B-Environment/ReadmeTemplate.html.j2 @@ -199,6 +199,15 @@ function CopyToClipboard(id)
📝 Note
diff --git a/scripts/ClientSetup.ps1 b/scripts/ClientSetup.ps1 index 9b12a73..30e7018 100644 --- a/scripts/ClientSetup.ps1 +++ b/scripts/ClientSetup.ps1 @@ -14,7 +14,7 @@ param( # The credential necessary to access the internal Nexus repository. This can # be ignored if Anonymous authentication is enabled. # This parameter will be necessary if your C4B server is web-enabled. - [Parameter()] + [Parameter(Mandatory)] [pscredential] $Credential, @@ -41,19 +41,43 @@ param( # Client salt value used to populate the centralManagementClientCommunicationSaltAdditivePassword # value in the Chocolatey config file - [Parameter()] + [Parameter(Mandatory)] [string] $ClientSalt, # Server salt value used to populate the centralManagementServiceCommunicationSaltAdditivePassword # value in the Chocolatey config file - [Parameter()] + [Parameter(Mandatory)] [string] $ServiceSalt, + #Install the Chocolatey Licensed Extension with right-click context menus available [Parameter()] [Switch] - $InternetEnabled + $IncludePackageTools, + + # Allows for the application of user-defined configuration that is applied after the base configuration. + # Can override base configuration with this parameter + [Parameter()] + [Hashtable] + $AdditionalConfiguration, + + # Allows for the toggling of additonal features that is applied after the base configuration. + # Can override base configuration with this parameter + [Parameter()] + [Hashtable] + $AdditionalFeatures, + + # Allows for the installation of additional packages after the system base packages have been installed. + [Parameter()] + [Hashtable[]] + $AdditionalPackages, + + # Allows for the addition of alternative sources after the base conifguration has been applied. + # Can override base configuration with this parameter + [Parameter()] + [Hashtable[]] + $AdditionalSources ) Set-ExecutionPolicy Bypass -Scope Process -Force @@ -69,11 +93,14 @@ $params = @{ if (-not $IgnoreProxy) { if ($ProxyUrl) { + $proxy = [System.Net.WebProxy]::new($ProxyUrl, $true <#bypass on local#>) $params.Add('ProxyUrl', $ProxyUrl) } if ($ProxyCredential) { $params.Add('ProxyCredential', $ProxyCredential) + $proxy.Credentials = $ProxyCredential + } } @@ -87,7 +114,8 @@ $NupkgUrl = if (-not $ChocolateyVersion) { $QueryUrl = ($RepositoryUrl.TrimEnd('/index.json'), "v3/registration/Chocolatey/index.json") -join '/' $Result = $webClient.DownloadString($QueryUrl) | ConvertFrom-Json $Result.items.items[-1].packageContent -} else { +} +else { # Otherwise, assume the URL "$($RepositoryUrl.TrimEnd('/index.json'))/v3/content/chocolatey/$($ChocolateyVersion)/chocolatey.$($ChocolateyVersion).nupkg" } @@ -118,18 +146,19 @@ choco config set commandExecutionTimeoutSeconds 14400 # Nexus NuGet V3 Compatibility choco feature disable --name="'usePackageRepositoryOptimizations'" -if ($InternetEnabled) { - choco source add --name="'ChocolateyInternal'" --source="'$RepositoryUrl'" --allow-self-service --user="'$($Credential.UserName)'" --password="'$($Credential.GetNetworkCredential().Password)'" --priority=1 -} -else { - choco source add --name="'ChocolateyInternal'" --source="'$RepositoryUrl'" --allow-self-service --priority=1 -} - +#Environment base Source configuration +choco source add --name="'ChocolateyInternal'" --source="'$RepositoryUrl'" --allow-self-service --user="'$($Credential.UserName)'" --password="'$($Credential.GetNetworkCredential().Password)'" --priority=1 choco source disable --name="'Chocolatey'" choco source disable --name="'chocolatey.licensed'" choco upgrade chocolatey-license -y --source="'ChocolateyInternal'" -choco upgrade chocolatey.extension -y --params="'/NoContextMenu'" --source="'ChocolateyInternal'" --no-progress +if (-not $IncludePackageTools) { + choco upgrade chocolatey.extension -y --params="'/NoContextMenu'" --source="'ChocolateyInternal'" --no-progress +} +else { + Write-Warning "IncludePackageTools was passed. Right-Click context menus will be available for installers, .nupkg, and .nuspec file types!" + choco upgrade chocolatey.extension -y --source="'ChocolateyInternal'" --no-progress +} choco upgrade chocolateygui -y --source="'ChocolateyInternal'" --no-progress choco upgrade chocolateygui.extension -y --source="'ChocolateyInternal'" --no-progress @@ -158,3 +187,128 @@ if ($ServiceSalt) { } choco feature enable --name="'useChocolateyCentralManagement'" choco feature enable --name="'useChocolateyCentralManagementDeployments'" + + +Write-Host "Applying user supplied configuration" -ForegroundColor Cyan +#How we call choco from here changes as we need to be more dynamic with thingsii . +if ($AdditionalConfiguration) { + <# + We expect to pass in a hashtable with configuration information with the following shape: + + @{ + Name = BackgroundServiceAllowedCommands + Value = 'install,upgrade,uninstall' + } + #> + + $AdditionalConfiguration.GetEnumerator() | ForEach-Object { + $c = [System.Collections.Generic.list[string]]::new() + $c.Add('config') + $c.Add('set') + $c.Add("--name='$($_.Key)'") + $c.Add("--value='$($_.Value)'") + + & choco @c + } +} + +if ($AdditionalFeatures) { + <# + We expect to pass in feature information as a hashtable with the following shape: + + @{ + Name = useBackgroundservice + State = 'Enabled' + } + #> + $AdditionalFeatures.GetEnumerator() | ForEach-Object { + + $c = [System.Collections.Generic.list[string]]::new() + $c.Add('feature') + + $state = switch ($_.Value) { + 'Enabled' { 'enable' } + 'Disabled' { 'disable' } + default { Write-Error 'State must be either Enabled or Disabled' } + } + + $c.Add($state) + $c.add("--name='$($_.Key)'") + & choco @c + } +} + +if ($AdditionalSources) { + + <# + We expect a user to pass in a hashtable with source information with the folllowing shape: + @{ + Name = 'MySource' + Source = 'https://nexus.fabrikam.com/repository/MyChocolateySource' + #Optional items + Credentials = $MySourceCredential + AllowSelfService = $true + AdminOnly = $true + BypassProxy = $true + Priority = 10 + Certificate = 'C:\cert.pfx' + CertificatePassword = 's0mepa$$' + } +#> + Foreach ($a in $AdditionalSources) { + $c = [System.Collections.Generic.List[string]]::new() + #Required items + $c.Add('source') + $c.Add('add') + $c.Add("--name='$($a.Name)'") + $c.Add("--source='$($a.Source)'") + + #Add credentials if source has them + if ($a.ContainsKey('Credentials')) { + $c.Add("--user='$($a.Credentials.Username)'") + $c.Add("--password='$($a.Credentials.GetNetworkCredential().Password)'") + } + + switch ($true) { + $a['AllowSelfService'] { $c.add('--allow-self-service') } + $a['AdminOnly'] { $c.Add('--admin-only') } + $a['BypassProxy'] { $c.Add('--bypass-proxy') } + $a.ContainsKey('Priority') { $c.Add("--priority='$($a.Priority)'") } + $a.ContainsKey('Certificate') { $c.Add("--cert='$($a.Certificate)'") } + $a.ContainsKey('CerfificatePassword') { $c.Add("--certpassword='$($a.CertificatePassword)'") } + } + } + + & choco @c +} + +if ($AdditionalPackages) { + + <# + We expect to pass in a hashtable with package information with the following shape: + + @{ + Id = 'firefox' + #Optional + Version = 123.4.56 + Pin = $true + } + #> + foreach ($package in $AdditionalPackages.GetEnumerator()) { + + $c = [System.Collections.Generic.list[string]]::new() + $c.add('install') + $c.add($package['Id']) + + switch ($true) { + $package.ContainsKey('Version') { $c.Add("--version='$($package.version)'") } + $package.ContainsKey('Pin') { $c.Add('--pin') } + } + + #Ensure packages install and they don't flood the console output + $c.Add('-y') + $c.Add('--no-progress') + + & choco @c + } +} \ No newline at end of file diff --git a/scripts/New-IISCertificateHost.ps1 b/scripts/New-IISCertificateHost.ps1 index 6998813..5b10a42 100644 --- a/scripts/New-IISCertificateHost.ps1 +++ b/scripts/New-IISCertificateHost.ps1 @@ -49,12 +49,6 @@ if (-not (Get-Website -Name $siteName)) { Write-Host "Website for hosting certificate import already created" -ForegroundColor Green } -if ((Get-Website -Name 'Default Web Site')) { - Get-Website -Name 'Default Web Site' | Remove-Website -} else { - Write-Host "Default website already removed" -ForegroundColor Green -} - Write-Host "Restarting IIS to refresh bindings" -ForegroundColor Green $null = iisreset diff --git a/scripts/Register-C4bEndpoint.ps1 b/scripts/Register-C4bEndpoint.ps1 index dee0459..0ee94c4 100644 --- a/scripts/Register-C4bEndpoint.ps1 +++ b/scripts/Register-C4bEndpoint.ps1 @@ -1,12 +1,129 @@ -# Here is a script you can run to setup your endpoints to connect to the C4B Server. -# This includes: -# - Installing Chocolatey -# - Installing your chocolatey-license -# - Running the Client Setup, which sets up Nexus repo and CCM acccess +[CmdletBinding()] +Param( + # The DNS name of the server that hosts your repository, Jenkins, and Chocolatey Central Management + [Parameter()] + [String] + $Fqdn = '{{ FQDN }}', -$HostName = {{hostname}} #This needs to be the same hostname as the CN/Subject of your SSL cert + # Client salt value used to populate the centralManagementClientCommunicationSaltAdditivePassword + # value in the Chocolatey config file + [Parameter()] + [String] + $ClientCommunicationSalt = '{{ ClientSaltValue }}', -# placeholder if using a self-signed cert + # Server salt value used to populate the centralManagementServiceCommunicationSaltAdditivePassword + # value in the Chocolatey config file + [Parameter()] + [String] + $ServiceCommunicationSalt = '{{ ServiceSaltValue }}', -$downloader = New-Object -TypeName System.Net.WebClient -Invoke-Expression ($downloader.DownloadString("https://$($HostName):8443/repository/choco-install/ClientSetup.ps1")) \ No newline at end of file + [Parameter(Mandatory)] + [PSCredential] + $RepositoryCredential, + + # The URL of a proxy server to use for connecting to the repository. + [Parameter()] + [String] + $ProxyUrl, + # The credentials, if required, to connect to the proxy server. + [Parameter()] + [PSCredential] + $ProxyCredential, + + #Install the Chocolatey Licensed Extension with right-click context menus available + [Parameter()] + [Switch] + $IncludePackageTools, + + # Allows for the application of user-defined configuration that is applied after the base configuration. + # Can override base configuration with this parameter + [Parameter()] + [Hashtable] + $AdditionalConfiguration, + + # Allows for the toggling of additonal features that is applied after the base configuration. + # Can override base configuration with this parameter + [Parameter()] + [Hashtable] + $AdditionalFeatures, + + # Allows for the installation of additional packages after the system base packages have been installed. + [Parameter()] + [Hashtable[]] + $AdditionalPackages, + + # Allows for the addition of alternative sources after the base conifguration has been applied. + # Can override base configuration with this parameter + [Parameter()] + [Hashtable[]] + $AdditionalSources, + + [Parameter()] + [Switch] + $TrustCertificate +) + +# Touch NOTHING below this line +begin { + # Set up our downloader + $downloader = [System.Net.WebClient]::new() + + #setup proxy if required + if ($ProxyUrl) { + $params.add('ProxyUrl', $ProxyUrl) + $proxy = [System.Net.WebProxy]::new($ProxyUrl, $true <#bypass on local#>) + + if ($ProxyCredential) { + $params.Add('ProxyCredential', $ProxyCredential) + $proxy.Credentials = $ProxyCredential + } + + $downloader.Proxy = $proxy + } + + $downloader.Credentials = $RepositoryCredential + +} + +process { + #If we use a Self-Signed certificate, we need to explicity trust it + + if ($TrustCertificate) { + Invoke-Expression ($downloader.DownloadString("http://$($Fqdn):80/Import-ChocoServerCertificate.ps1")) + } + #Once we trust the SSL certificate, we can start onboarding + $RepositoryUrl = "https://$($fqdn):8443/repository/ChocolateyInternal/index.json" + + #Initialize params hashtable so we can add to it if needed later + $params = @{ + Credential = $RepositoryCredential + ClientSalt = $ClientCommunicationSalt + ServiceSalt = $ServiceCommunicationSalt + RepositoryUrl = $RepositoryUrl + } + + switch ($true) { + $PSBoundParameters.ContainsKey('AdditionalConfiguration') { + $params.Add('AdditionalConfiguration', $AdditionalConfiguration) + } + $PSBoundParameters.ContainsKey('AdditionalFeatures') { + $params.add('AdditionalFeatures', $AdditionalFeatures) + } + + $PSBoundParameters.ContainsKey('AdditionalPackages') { + $params.Add('AdditionalPackages', $AdditionalPackages) + } + + $PSBoundParameters.ContainsKey('AdditionalSources') { + $params.Add('AdditionalSources', $AdditionalSources) + } + + $PSBoundParameters.ContainsKey('IncludePackageTools') { + $params.Add('IncludePackageTools', $IncludePackageTools) + } + } + + $script = $downloader.DownloadString("https://$($FQDN):8443/repository/choco-install/ClientSetup.ps1") + + & ([scriptblock]::Create($script)) @params +} \ No newline at end of file