diff --git a/Set-SslSecurity.ps1 b/Set-SslSecurity.ps1 index ccaaa15..81356b4 100644 --- a/Set-SslSecurity.ps1 +++ b/Set-SslSecurity.ps1 @@ -43,7 +43,10 @@ param( [Parameter(ParameterSetName='Subject')] [Parameter(ParameterSetName='Thumbprint')] [string] - $CertificateDnsName, + $CertificateDnsName = $( + if (-not (Get-Command Get-ChocoEnvironmentProperty -ErrorAction SilentlyContinue)) {. $PSScriptRoot\scripts\Get-Helpers.ps1} + Get-ChocoEnvironmentProperty CertSubject + ), # This option security hardens your C4B server, in scenarios where you have a non-self-signed certificate. # It adds a role and user credential to the Nexus server, which is used to authenticate the source setup on a client endpoint. @@ -60,7 +63,10 @@ param( $Hostname = [System.Net.Dns]::GetHostName(), # API key of your Nexus repo, to add to the source setup on C4B Server. - [string]$NuGetApiKey = $(Get-Content "$env:SystemDrive\choco-setup\logs\nexus.json" | ConvertFrom-Json).NuGetApiKey, + [string]$NuGetApiKey = $( + if (-not (Get-Command Get-ChocoEnvironmentProperty -ErrorAction SilentlyContinue)) {. $PSScriptRoot\scripts\Get-Helpers.ps1} + Get-ChocoEnvironmentProperty NuGetApiKey -AsPlainText + ), # If provided, will skip launching the browser [switch]$SkipBrowserLaunch @@ -207,7 +213,7 @@ process { # Reset the NuGet v3 cache, such that it doesn't capture localhost as the FQDN Remove-NexusRepositoryFolder -RepositoryName ChocolateyInternal -Name v3 - Update-JsonFile -Path "$env:SystemDrive\choco-setup\logs\nexus.json" -Properties @{ + Update-Clixml -Properties @{ NexusUri = "https://$($SubjectWithoutCn):8443" NexusRepo = $RepositoryUrl ChocoUserPassword = $NexusPw @@ -227,7 +233,7 @@ process { # Add firewall rule for Jenkins netsh advfirewall firewall add rule name="Jenkins-7443" dir=in action=allow protocol=tcp localport=7443 - Update-JsonFile -Path "$env:SystemDrive\choco-setup\logs\jenkins.json" -Properties @{ + Update-Clixml -Properties @{ JenkinsUri = "https://$($SubjectWithoutCn):7443" } @@ -294,12 +300,9 @@ process { } Install-ChocolateyAgent @agentArgs - } - - else { - - # Agent Setup - $agentArgs = @{ + } else { + # Agent Setup + $agentArgs = @{ CentralManagementServiceUrl = "https://$($SubjectWithoutCn):24020/ChocolateyManagementService" } @@ -316,30 +319,27 @@ Invoke-Expression (`$downloader.DownloadString("http://`$(`$HostName):80/Import- } } - Update-JsonFile -Path "$env:SystemDrive\choco-setup\logs\ccm.json" -Properties @{ + Update-Clixml -Properties @{ CCMWebPortal = "https://$($SubjectWithoutCn)/Account/Login" CCMServiceURL = "https://$($SubjectWithoutCn):24020/ChocolateyManagementService" - ServiceSalt = $ServiceSaltValue - ClientSalt = $ClientSaltValue - } - - # Save useful params to JSON - $SslJson = @{ CertSubject = $SubjectWithoutCn CertThumbprint = $Certificate.Thumbprint CertExpiry = $Certificate.NotAfter IsSelfSigned = $IsSelfSigned } - $SslJson | ConvertTo-Json | Out-File "$env:SystemDrive\choco-setup\logs\ssl.json" + + if ($Hardened) { + Update-Clixml -Properties @{ + ServiceSalt = ConvertTo-SecureString $ServiceSaltValue -AsPlainText -Force + ClientSalt = ConvertTo-SecureString $ClientSaltValue -AsPlainText -Force + } + } } end { Write-Host 'Writing README to Desktop; this file contains login information for all C4B services.' New-QuickstartReadme - Write-Host 'Cleaning up temporary data' - Remove-JsonFiles - if (-not $SkipBrowserLaunch -and $Host.Name -eq 'ConsoleHost') { $Message = 'The CCM, Nexus & Jenkins sites will open in your browser in 10 seconds. Press any key to skip this.' $Timeout = New-TimeSpan -Seconds 10 diff --git a/Start-C4bCcmSetup.ps1 b/Start-C4bCcmSetup.ps1 index ea9eed5..2492b67 100644 --- a/Start-C4bCcmSetup.ps1 +++ b/Start-C4bCcmSetup.ps1 @@ -31,6 +31,8 @@ process { $Packages = (Get-Content $PSScriptRoot\files\chocolatey.json | ConvertFrom-Json).packages + Set-ChocoEnvironmentProperty -Name DatabaseUser -Value $DatabaseCredential + # DB Setup Write-Host "Installing SQL Server Express" $chocoArgs = @('upgrade', 'sql-server-express', '-y', '--no-progress') @@ -147,14 +149,13 @@ process { & choco @chocoArgs $CcmSvcUrl = choco config get centralManagementServiceUrl -r - $CcmJson = @{ + Update-Clixml -Properties @{ CCMServiceURL = $CcmSvcUrl CCMWebPortal = "http://localhost/Account/Login" DefaultUser = "ccmadmin" DefaultPwToBeChanged = "123qwe" CCMDBUser = $DatabaseUser } - $CcmJson | ConvertTo-Json | Out-File "$env:SystemDrive\choco-setup\logs\ccm.json" Write-Host "Chocolatey Central Management Setup has now completed" -ForegroundColor Green diff --git a/Start-C4bJenkinsSetup.ps1 b/Start-C4bJenkinsSetup.ps1 index 2bb7685..76cf5eb 100644 --- a/Start-C4bJenkinsSetup.ps1 +++ b/Start-C4bJenkinsSetup.ps1 @@ -14,7 +14,7 @@ param( [string]$HostName = $env:ComputerName, # API key of your Nexus repo, for Chocolatey Jenkins jobs to use - [string]$NuGetApiKey = $(Get-Content "$env:SystemDrive\choco-setup\logs\nexus.json" | ConvertFrom-Json).NuGetApiKey + [string]$NuGetApiKey = $(Get-ChocoEnvironmentProperty NuGetApiKey -AsPlainText) ) process { $DefaultEap = $ErrorActionPreference @@ -114,13 +114,11 @@ process { Write-Host "Starting Jenkins service back up" -ForegroundColor Green Start-Service -Name Jenkins - # Save useful params to JSON - $JenkinsJson = @{ + # Save useful params + Update-Clixml -Properties @{ JenkinsUri = "http://$($HostName):8080" - JenkinsUser = "admin" - JenkinsPw = $JenkinsCred.GetNetworkCredential().Password + JenkinsCredential = $JenkinsCred } - $JenkinsJson | ConvertTo-Json | Out-File "$env:SystemDrive\choco-setup\logs\jenkins.json" Write-Host 'Jenkins setup complete' -ForegroundColor Green diff --git a/Start-C4bNexusSetup.ps1 b/Start-C4bNexusSetup.ps1 index 90c0ac6..259e48c 100644 --- a/Start-C4bNexusSetup.ps1 +++ b/Start-C4bNexusSetup.ps1 @@ -114,15 +114,13 @@ process { } $null = New-NetFirewallRule @FwRuleParams - # Save useful params to JSON - $NexusJson = @{ + # Save useful params + Update-Clixml -Properties @{ NexusUri = "http://localhost:8081" - NexusUser = "admin" - NexusPw = "$($Credential.GetNetworkCredential().Password)" + NexusCredential = $Credential NexusRepo = "$((Get-NexusRepository -Name 'ChocolateyInternal').url)/index.json" - NuGetApiKey = $NugetApiKey + NuGetApiKey = $NugetApiKey | ConvertTo-SecureString -AsPlainText -Force } - $NexusJson | ConvertTo-Json | Out-File "$env:SystemDrive\choco-setup\logs\nexus.json" $ErrorActionPreference = $DefaultEap Stop-Transcript diff --git a/Start-C4bSetup.ps1 b/Start-C4bSetup.ps1 index d710190..6ea8188 100644 --- a/Start-C4bSetup.ps1 +++ b/Start-C4bSetup.ps1 @@ -102,8 +102,10 @@ try { $PkgsDir = Join-Path $FilesDir "files" $TempDir = Join-Path $ChocoPath "temp" $TestDir = Join-Path $ChocoPath "tests" - @($ChocoPath, $FilesDir, $PkgsDir, $TempDir, $TestDir) | ForEach-Object { - $null = New-Item -Path $_ -ItemType Directory -Force -ErrorAction SilentlyContinue + $xmlDir = Join-Path $ChocoPath "clixml" + + @($ChocoPath, $FilesDir, $PkgsDir, $TempDir, $TestDir,$xmlDir) | ForEach-Object { + $null = New-Item -Path $_ -ItemType Directory -Force -ErrorAction Stop } if (-not $PSScriptRoot -or $PSScriptRoot -ne $FilesDir) { diff --git a/scripts/Get-Helpers.ps1 b/scripts/Get-Helpers.ps1 index 7980705..58d66cd 100644 --- a/scripts/Get-Helpers.ps1 +++ b/scripts/Get-Helpers.ps1 @@ -40,6 +40,10 @@ function Invoke-Choco { } } +Update-TypeData -TypeName SecureString -MemberType ScriptMethod -MemberName ToPlainText -Force -Value { + [System.Net.NetworkCredential]::new("TempCredential", $this).Password +} + #region Package functions (OfflineInstallPreparation.ps1) if (-not ("System.IO.Compression.ZipArchive" -as [type])) { Add-Type -Assembly 'System.IO.Compression' @@ -2056,20 +2060,78 @@ function Invoke-TextReplacementInFile { } } -function Update-JsonFile { +function Update-Clixml { [CmdletBinding()] param( - [Parameter(Mandatory)] - [string]$Path, + [Parameter()] + [string]$Path = "$env:SystemDrive\choco-setup\clixml\chocolatey-for-business.xml", [Parameter(Mandatory)] [hashtable]$Properties ) - $Json = Get-Content -Path $Path | ConvertFrom-Json + $CliXml = if (Test-Path $Path) { + Import-Clixml $Path + } else { + if (-not (Test-Path (Split-Path $Path -Parent))) { + $null = mkdir (Split-Path $Path -Parent) -Force + } + [PSCustomObject]@{} + } + $Properties.GetEnumerator().ForEach{ - Add-Member -InputObject $Json -MemberType NoteProperty -Name $_.Key -Value $_.Value -Force + Add-Member -InputObject $CliXml -MemberType NoteProperty -Name $_.Key -Value $_.Value -Force + } + + $CliXml | Export-Clixml $Path -Force +} + +function Get-ChocoEnvironmentProperty { + [CmdletBinding(DefaultParameterSetName="All")] + param( + [Parameter(ParameterSetName="Specific", Mandatory, ValueFromPipeline, Position=0)] + [string]$Name, + + [Parameter(ParameterSetName="Specific")] + [switch]$AsPlainText + ) + begin { + $Content = Import-Clixml -Path "$env:SystemDrive\choco-setup\clixml\chocolatey-for-business.xml" + } + process { + if ($Name) { + if ($AsPlainText -and $Content.$Name -is [System.Security.SecureString]) { + return $Content.$Name.ToPlainText() + } else { + return $Content.$Name + } + } else { + $Content + } + } +} + +function Set-ChocoEnvironmentProperty { + [CmdletBinding(DefaultParameterSetName="Key")] + param( + [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName="Key", Position=0)] + [Alias('Key')] + [string]$Name, + + [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName="Key", Position=1)] + $Value, + + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName="Hashtable")] + [hashtable]$InputObject = @{} + ) + begin { + $Properties = $InputObject + } + process { + $Properties.$Name = $Value + } + end { + Update-Clixml -Path "$env:SystemDrive\choco-setup\clixml\chocolatey-for-business.xml" -Properties $Properties } - $Json | ConvertTo-Json | Set-Content -Path $Path } function Set-JenkinsCertificate { @@ -2156,32 +2218,6 @@ function Set-JenkinsCertificate { #endregion #region README functions -function Remove-JsonFiles { - <# -.SYNOPSIS -Removes unnecessary json data files from the system upon completion of the Quickstart Guide. -.PARAMETER JsonPath -The path to the JSON data files. Defaults to 'C:\choco-setup\logs'. -.EXAMPLE -./Start-C4bCleanup.ps1 -.EXAMPLE -./Start-C4bCleanup.ps1 -JsonPath C:\Temp\ -#> - - - [CmdletBinding()] - Param( - [Parameter()] - [String] - $JsonPath = "$env:SystemDrive\choco-setup\logs" - ) - - process { - - Get-ChildItem $JsonPath -Filter '*.json' | Foreach-Object { Remove-Item $_.FullName -Force } - } -} - Function New-QuickstartReadme { <# .SYNOPSIS @@ -2197,11 +2233,9 @@ The host name of the C4B instance. param() process { try { - $CCMData = Get-Content "$env:SystemDrive\choco-setup\logs\ccm.json" | ConvertFrom-Json - $NexusData = Get-Content "$env:SystemDrive\choco-setup\logs\nexus.json" | ConvertFrom-Json - $JenkinsData = Get-Content "$env:SystemDrive\choco-setup\logs\jenkins.json" | ConvertFrom-Json + $Data = Get-ChocoEnvironmentProperty } catch { - Write-Error "Unable to read JSON files. Ensure the Quickstart Guide has been completed." + Write-Error "Unable to read stored values. Ensure the Quickstart Guide has been completed." } Copy-Item $PSScriptRoot\ReadmeTemplate.html.j2 -Destination $env:Public\Desktop\Readme.html -Force @@ -2209,26 +2243,26 @@ The host name of the C4B instance. # Working around the existing j2 template, so we can keep them roughly in sync Invoke-TextReplacementInFile -Path $env:Public\Desktop\Readme.html -Replacement @{ # CCM Values - "{{ ccm_fqdn .*?}}" = ([uri]$CCMData.CCMWebPortal).DnsSafeHost - "{{ ccm_port .*?}}" = ([uri]$CCMData.CCMWebPortal).Port - "{{ ccm_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($CCMData.DefaultPwToBeChanged) + "{{ ccm_fqdn .*?}}" = ([uri]$Data.CCMWebPortal).DnsSafeHost + "{{ ccm_port .*?}}" = ([uri]$Data.CCMWebPortal).Port + "{{ ccm_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($Data.DefaultPwToBeChanged) # Chocolatey Configuration Values "{{ ccm_encryption_password .*?}}" = "Requested on first run." - "{{ ccm_client_salt .*?}}" = [System.Web.HttpUtility]::HtmlEncode($CCMData.ClientSalt) - "{{ ccm_service_salt .*?}}" = [System.Web.HttpUtility]::HtmlEncode($CCMData.ServiceSalt) - "{{ chocouser_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($NexusData.ChocoUserPassword) + "{{ ccm_client_salt .*?}}" = [System.Web.HttpUtility]::HtmlEncode((Get-ChocoEnvironmentProperty ClientSalt -AsPlainText)) + "{{ ccm_service_salt .*?}}" = [System.Web.HttpUtility]::HtmlEncode((Get-ChocoEnvironmentProperty ServiceSalt -AsPlainText)) + "{{ chocouser_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($Data.NexusCredential.Password.ToPlainText()) # Nexus Values - "{{ nexus_fqdn .*?}}" = ([uri]$NexusData.NexusUri).DnsSafeHost - "{{ nexus_port .*?}}" = ([uri]$NexusData.NexusUri).Port - "{{ nexus_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($NexusData.NexusPw) - "{{ lookup\('file', 'credentials\/nexus_apikey'\) .*?}}" = $NexusJson.NuGetApiKey + "{{ nexus_fqdn .*?}}" = ([uri]$Data.NexusUri).DnsSafeHost + "{{ nexus_port .*?}}" = ([uri]$Data.NexusUri).Port + "{{ nexus_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($Data.NexusCredential.Password.ToPlainText()) + "{{ lookup\('file', 'credentials\/nexus_apikey'\) .*?}}" = Get-ChocoEnvironmentProperty NugetApiKey -AsPlainText # Jenkins Values - "{{ jenkins_fqdn .*?}}" = ([uri]$JenkinsData.JenkinsUri).DnsSafeHost - "{{ jenkins_port .*?}}" = ([uri]$JenkinsData.JenkinsUri).Port - "{{ jenkins_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($JenkinsData.JenkinsPw) + "{{ jenkins_fqdn .*?}}" = ([uri]$Data.JenkinsUri).DnsSafeHost + "{{ jenkins_port .*?}}" = ([uri]$Data.JenkinsUri).Port + "{{ jenkins_password .*?}}" = [System.Web.HttpUtility]::HtmlEncode($Data.JenkinsCredential.Password.ToPlainText()) } } }