diff --git a/powershell/Scripts/UserDataScripts/OnrClient.ps1 b/powershell/Scripts/UserDataScripts/OnrClient.ps1 index 27d5ebdc9..651cb688a 100644 --- a/powershell/Scripts/UserDataScripts/OnrClient.ps1 +++ b/powershell/Scripts/UserDataScripts/OnrClient.ps1 @@ -1,63 +1,142 @@ $GlobalConfig = @{ "all" = @{ - "BOEWindowsClientS3Bucket" = "mod-platform-image-artefact-bucket20230203091453221500000001" - "BOEWindowsClientS3Folder" = "hmpps/onr" + "WindowsClientS3Bucket" = "mod-platform-image-artefact-bucket20230203091453221500000001" + "WindowsClientS3Folder" = "hmpps/onr" "BOEWindowsClientS3File" = "51048121.ZIP" + # "Oracle11g32bitClientS3File" = "V20606-01.zip" + "Oracle11g64bitClientS3File" = "V20609-01.zip" + "Oracle19c64bitClientS3File" = "WINDOWS.X64_193000_client.zip" # Oracle 19c client SW, install 1st" + "ORACLE_19C_HOME" = "C:\app\oracle\product\19.0.0\client_1" + "ORACLE_11G_HOME" = "C:\app\oracle\product\11.2.0\client_1" + "ORACLE_BASE" = "C:\app\oracle" "RegistryPath" = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\winlogon" "LegalNoticeCaption" = "IMPORTANT" "LegalNoticeText" = "This system is restricted to authorized users only. Individuals who attempt unauthorized access will be prosecuted. If you are unauthorized terminate access now. Click OK to indicate your acceptance of this information" } + "oasys-national-reporting-dev" = @{ + "OnrShortcuts" = @{ + } + } "oasys-national-reporting-test" = @{ + "serviceUser" = "svc_nart" + "nartComputersOU" = "OU=Nart,OU=MODERNISATION_PLATFORM_SERVERS,DC=AZURE,DC=NOMS,DC=ROOT" + "domain" = "AZURE" "OnrShortcuts" = @{ "Onr CmcApp" = "http://t2-onr-web-1-a.oasys-national-reporting.hmpps-test.modernisation-platform.service.justice.gov.uk:7777/CmcApp" - } } "oasys-national-reporting-preproduction" = @{ - "OnrShortcuts" = @{ - + "serviceUser" = "svc_nart" + "nartComputersOU" = "OU=Nart,OU=MODERNISATION_PLATFORM_SERVERS,DC=AZURE,DC=HMPP,DC=ROOT" + "domain" = "HMPP" + "OnrShortcuts" = @{ } } "oasys-national-reporting-production" = @{ - "OnrShortcuts" = @{ - + "serviceUser" = "svc_nart" + "nartComputersOU" = "OU=Nart,OU=MODERNISATION_PLATFORM_SERVERS,DC=AZURE,DC=HMPP,DC=ROOT" + "domain" = "HMPP" + "OnrShortcuts" = @{ } - } - } - - function Get-Config { - $Token = Invoke-RestMethod -TimeoutSec 10 -Headers @{"X-aws-ec2-metadata-token-ttl-seconds"=3600} -Method PUT -Uri http://169.254.169.254/latest/api/token - $InstanceId = Invoke-RestMethod -TimeoutSec 10 -Headers @{"X-aws-ec2-metadata-token" = $Token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-id - $TagsRaw = aws ec2 describe-tags --filters "Name=resource-id,Values=$InstanceId" - $Tags = "$TagsRaw" | ConvertFrom-Json - $EnvironmentNameTag = ($Tags.Tags | Where-Object {$_.Key -eq "environment-name"}).Value - - if (-not $GlobalConfig.Contains($EnvironmentNameTag)) { - Write-Error "Unexpected environment-name tag value $EnvironmentNameTag" - } - Return $GlobalConfig.all + $GlobalConfig[$EnvironmentNameTag] + } } - + + $tempPath = ([System.IO.Path]::GetTempPath()) + + $ConfigurationManagementRepo = "$tempPath\modernisation-platform-configuration-management" + $ModulesRepo = "$ConfigurationManagementRepo\powershell\Modules" + $ErrorActionPreference = "Stop" + $WorkingDirectory = "C:\Software" + $AppDirectory = "C:\App" + + New-Item -ItemType Directory -Path $WorkingDirectory -Force + New-Item -ItemType Directory -Path $AppDirectory -Force + +# {{{ functions + +function Get-Config { + $tokenParams = @{ + TimeoutSec = 10 + Headers = @{"X-aws-ec2-metadata-token-ttl-seconds" = 3600} + Method = 'PUT' + Uri = 'http://169.254.169.254/latest/api/token' + } + $Token = Invoke-RestMethod @tokenParams + + $instanceIdParams = @{ + TimeoutSec = 10 + Headers = @{"X-aws-ec2-metadata-token" = $Token} + Method = 'GET' + Uri = 'http://169.254.169.254/latest/meta-data/instance-id' + } + $InstanceId = Invoke-RestMethod @instanceIdParams + + $awsParams = @( + 'ec2', + 'describe-tags', + '--filters', + "Name=resource-id,Values=$InstanceId" + ) + + $TagsRaw = & aws @awsParams + + $Tags = $TagsRaw | ConvertFrom-Json + $EnvironmentNameTag = ($Tags.Tags | Where-Object { $_.Key -eq "environment-name" }).Value + + if (-not $GlobalConfig.Contains($EnvironmentNameTag)) { + Write-Error "Unexpected environment-name tag value $EnvironmentNameTag" + } + + Return $GlobalConfig.all + $GlobalConfig[$EnvironmentNameTag] +} + +function Get-InstanceTags { + $Token = Invoke-RestMethod -TimeoutSec 10 -Headers @{"X-aws-ec2-metadata-token-ttl-seconds"=3600} -Method PUT -Uri http://169.254.169.254/latest/api/token + $InstanceId = Invoke-RestMethod -TimeoutSec 10 -Headers @{"X-aws-ec2-metadata-token" = $Token} -Method GET -Uri http://169.254.169.254/latest/meta-data/instance-id + $TagsRaw = aws ec2 describe-tags --filters "Name=resource-id,Values=$InstanceId" + $Tags = $TagsRaw | ConvertFrom-Json + $Tags.Tags +} + +function Get-Installer { + param ( + [Parameter(Mandatory)] + [string]$Key, + + [Parameter(Mandatory)] + [string]$Destination + ) + + $s3Params = @{ + BucketName = $Config.WindowsClientS3Bucket + Key = ($Config.WindowsClientS3Folder + "/" + $Key) + File = $Destination + Verbose = $true + } + + Read-S3Object @s3Params +} + function Add-BOEWindowsClient { [CmdletBinding()] param ( [hashtable]$Config ) - + $ErrorActionPreference = "Stop" if (Test-Path (([System.IO.Path]::GetTempPath()) + "\BOE\setup.exe")) { Write-Output "BOE Windows Client already installed" } else { Write-Output "Add BOE Windows Client" Set-Location -Path ([System.IO.Path]::GetTempPath()) - Read-S3Object -BucketName $Config.BOEWindowsClientS3Bucket -Key ($Config.BOEWindowsClientS3Folder + "/" + $Config.BOEWindowsClientS3File) -File (".\" + $Config.BOEWindowsClientS3File) -Verbose | Out-Null - + Read-S3Object -BucketName $Config.WindowsClientS3Bucket -Key ($Config.WindowsClientS3Folder + "/" + $Config.BOEWindowsClientS3File) -File (".\" + $Config.BOEWindowsClientS3File) -Verbose | Out-Null + # Extract BOE Client Installer - there is no installer for this application Expand-Archive -Path (".\" + $Config.BOEWindowsClientS3File) -DestinationPath (([System.IO.Path]::GetTempPath()) + "\BOE") -Force | Out-Null # Install BOE Windows Client - Start-Process -FilePath (([System.IO.Path]::GetTempPath()) + "\BOE\setup.exe") -ArgumentList "-r", "C:\Users\Administrator\AppData\Local\Temp\modernisation-platform-configuration-management\powershell\Configs\OnrClientResponse.ini" -Wait -NoNewWindow - + Start-Process -FilePath (([System.IO.Path]::GetTempPath()) + "\BOE\setup.exe") -ArgumentList "-r", "$ConfigurationManagementRepo\powershell\Configs\OnrClientResponse.ini" -Wait -NoNewWindow + # Create a desktop shortcut for BOE Client Tools $WScriptShell = New-Object -ComObject WScript.Shell $targetPath = [System.IO.Path]::Combine([environment]::GetFolderPath("CommonStartMenu"), "Programs\BusinessObjects XI 3.1\BusinessObjects Enterprise Client Tools") @@ -70,6 +149,37 @@ $GlobalConfig = @{ } } + function Get-SecretValue { + param ( + [Parameter(Mandatory)] + [string]$SecretId, + [Parameter(Mandatory)] + [string]$SecretKey + ) + + try { + $secretJson = aws secretsmanager get-secret-value --secret-id $SecretId --query SecretString --output text + + if ($null -eq $secretJson -or $secretJson -eq '') { + Write-Host "The SecretId '$SecretId' does not exist or returned no value." + return $null + } + + $secretObject = $secretJson | ConvertFrom-Json + + if (-not $secretObject.PSObject.Properties.Name -contains $SecretKey) { + Write-Host "The SecretKey '$SecretKey' does not exist in the secret." + return $null + } + + return $secretObject.$SecretKey + } + catch { + Write-Host "An error occurred while retrieving the secret: $_" + return $null + } + } + function Add-Shortcuts { [CmdletBinding()] param ( @@ -93,43 +203,293 @@ $GlobalConfig = @{ } } -# Apply to all environments that aren't on the domain -function Add-LoginText { - [CmdletBinding()] - param ( - [hashtable]$Config - ) +function Clear-PendingFileRenameOperations { + $regPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" + $regKey = "PendingFileRenameOperations" - $ErrorActionPreference = "Stop" - Write-Output "Add Legal Notice" - - if (-NOT (Test-Path $Config.RegistryPath)) { - Write-Output " - Registry path does not exist, creating" - New-Item -Path $Config.RegistryPath -Force | Out-Null + if (Get-ItemProperty -Path $regPath -Name $regKey -ErrorAction SilentlyContinue) { + try { + Remove-ItemProperty -Path $regPath -Name $regKey -Force -ErrorAction Stop + Write-Host "Successfully removed $regKey from the registry." + } + catch { + Write-Warning "Failed to remove $regKey. Error: $_" + } + } + else { + Write-Host "$regKey does not exist in the registry. No action needed." + } +} + +function Move-ModPlatformADComputer { + [CmdletBinding()] + param ( + [Parameter(Mandatory=$true)][System.Management.Automation.PSCredential]$ModPlatformADCredential, + [Parameter(Mandatory=$true)][string]$NewOU + ) + + $ErrorActionPreference = "Stop" + + # Do nothing if host not part of domain + if (-not (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain) { + Return $false } - $RegistryPath = $Config.RegistryPath - $LegalNoticeCaption = $Config.LegalNoticeCaption - $LegalNoticeText = $Config.LegalNoticeText + # Install powershell features if missing + if (-not (Get-Module -ListAvailable -Name "ActiveDirectory")) { + Write-Host "INFO: Installing RSAT-AD-PowerShell feature" + Install-WindowsFeature -Name "RSAT-AD-PowerShell" -IncludeAllSubFeature + } - Write-Output " - Set Legal Notice Caption" - New-ItemProperty -Path $RegistryPath -Name LegalNoticeCaption -Value $LegalNoticeCaption -PropertyType String -Force + # Move the computer to the new OU + (Get-ADComputer -Credential $ModPlatformADCredential -Identity $env:COMPUTERNAME).objectGUID | Move-ADObject -TargetPath $NewOU -Credential $ModPlatformADCredential +} - Write-Output " - Set Legal Notice Text" - New-ItemProperty -Path $RegistryPath -Name LegalNoticeText -Value $LegalNoticeText -PropertyType String -Force +# function Add-OracleClient { +# [CmdletBinding()] +# params( +# [string]$OracleClientPath, +# [hashtable]$Config +# ) +# } + +# }}} end of functions + +# {{{ Prep the server for installation +# Install PowerShell 5.1 if running on PowerShell 4 or below +if ( $PSVersionTable.PSVersion.Major -le 4 ) { + choco install powershell -y + # reboot when run from ssm doc + exit 3010 } - # Install PowerShell 5.1 if running on PowerShell 4 or below - if ( $PSVersionTable.PSVersion.Major -le 4 ) { - choco install powershell -y - # reboot when run from ssm doc - exit 3010 - } +# Set the registry key to prefer IPv4 over IPv6 +Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters" -Name "DisabledComponents" -Value 0x20 -Type DWord + +# Output a message to confirm the change +Write-Host "Registry updated to prefer IPv4 over IPv6. A system restart is required for changes to take effect." + +# Turn off the firewall as this will possibly interfere with Sia Node creation +# Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False + +# Disable antivirus and other security during installation + +function Test-WindowsServer2012R2 { + $osVersion = (Get-WmiObject -Class Win32_OperatingSystem).Version + return $osVersion -like "6.3*" +} + +if (-not (Test-WindowsServer2012R2)) { + # Disable real-time monitoring + Set-MpPreference -DisableRealtimeMonitoring $true + + # Disable intrusion prevention system + Set-MpPreference -DisableIntrusionPreventionSystem $true + + # Disable script scanning + Set-MpPreference -DisableScriptScanning $true + + # Disable behavior monitoring + Set-MpPreference -DisableBehaviorMonitoring $true + + Write-Host "Windows Security antivirus has been disabled. Please re-enable it as soon as possible for security reasons." +} else { + Write-Host "Running on Windows Server 2012 R2. Skipping antivirus configuration." +} + +# Set local time zone to UK although this should now be set by Group Policy objects +Set-TimeZone -Name "GMT Standard Time" + +# }}} complete - add prerequisites to server +# +$Config = Get-Config +$Tags = Get-InstanceTags +# {{{ join domain if domain-name tag is set +# Join domain and reboot is needed before installers run +$env:PSModulePath = "$ModulesRepo;$env:PSModulePath" +$ErrorActionPreference = "Continue" +Import-Module ModPlatformAD -Force +$ADConfig = Get-ModPlatformADConfig +if ($null -ne $ADConfig) { + $ADCredential = Get-ModPlatformADJoinCredential -ModPlatformADConfig $ADConfig + if (Add-ModPlatformADComputer -ModPlatformADConfig $ADConfig -ModPlatformADCredential $ADCredential) { + # Get the AD Admin credentials + $ADAdminCredential = Get-ModPlatformADAdminCredential -ModPlatformADConfig $ADConfig + # Move the computer to the correct OU + Move-ModPlatformADComputer -ModPlatformADCredential $ADAdminCredential -NewOU $($Config.nartComputersOU) + Exit 3010 # triggers reboot if running from SSM Doc + } +} else { + Write-Output "No domain-name tag found so apply Local Group Policy" + . .\LocalGroupPolicy.ps1 +} +# }}} + +# {{{ Get the config and tags for the instance +$Config = Get-Config +$Tags = Get-InstanceTags +# }}} + + +# {{{ Add computer to the correct OU +# $env:PSModulePath = "$ModulesRepo;$env:PSModulePath" +# +# Import-Module ModPlatformAD -Force +# $ADConfig = Get-ModPlatformADConfig + +# Get the AD Admin credentials +# $ADAdminCredential = Get-ModPlatformADAdminCredential -ModPlatformADConfig $ADConfig + +# Move the computer to the correct OU +# Move-ModPlatformADComputer -ModPlatformADCredential $ADAdminCredential -NewOU $($Config.nartComputersOU) + +# ensure computer is in the correct OU +Start-Process -FilePath "gpupdate.exe" -ArgumentList "/force" -Wait -NoNewWindow + +Start-Process -FilePath "gpresult.exe" -ArgumentList "/f /h","$WorkingDirectory\gpresult.html" -Wait -Verb "RunAs" + +# }}} + +# {{{ prepare assets +Set-Location -Path $WorkingDirectory +Get-Installer -Key $Config.Oracle11g64bitClientS3File -Destination (".\" + $Config.Oracle11g64bitClientS3File) +Get-Installer -Key $Config.Oracle19c64bitClientS3File -Destination (".\" + $Config.Oracle19c64bitClientS3File) + +Expand-Archive ( ".\" + $Config.Oracle11g64bitClientS3File) -Destination ".\Oracle11g64bitClient" +Expand-Archive ( ".\" + $Config.Oracle19c64bitClientS3File) -Destination ".\Oracle19c64bitClient" +# }}} + +# {{{ Install Oracle 11g and 19c 64-bit clients +# +# Create svc_nart credential object +$dbenv = ($Tags | Where-Object { $_.Key -eq "oasys-national-reporting-environment" }).Value +$bodsSecretName = "/sap/bods/$dbenv/passwords" + +$service_user_password = Get-SecretValue -SecretId $bodsSecretName -SecretKey "svc_nart" -ErrorAction SilentlyContinue + +if ([string]::IsNullOrEmpty($service_user_password)) { + Write-Host "Failed to retrieve svc_nart password from Secrets Manager. Exiting." + exit 1 +} + +$DomainName = (Get-WmiObject -Class Win32_ComputerSystem).Domain + +$11gResponseFileContent = @" +oracle.install.responseFileVersion=http://www.oracle.com/2007/install/rspfmt_clientinstall_response_schema_v11_2_0 +ORACLE_HOSTNAME=$($env:COMPUTERNAME).$DomainName +INVENTORY_LOCATION=C:\Program Files\Oracle\Inventory +SELECTED_LANGUAGES=en +ORACLE_HOME=$($Config.ORACLE_11G_HOME) +ORACLE_BASE=$($Config.ORACLE_BASE) +oracle.install.client.installType=Administrator +oracle.install.client.oramtsPortNumber=49157 +"@ + +$11gResponseFileContent | Out-File -FilePath "$WorkingDirectory\Oracle11g64bitClient\11gClient64bitinstall.rsp" -Force -Encoding ascii + +$19cResponseFileContent = @" +oracle.install.responseFileVersion=/oracle/install/rspfmt_clientinstall_response_schema_v19.0.0 +ORACLE_HOME=$($Config.ORACLE_19C_HOME) +ORACLE_BASE=$($Config.ORACLE_BASE) +oracle.install.IsBuiltInAccount=false +oracle.install.OracleHomeUserName=$($Config.domain)\$($Config.serviceUser) +oracle.install.OracleHomeUserPassword=$service_user_password +oracle.install.client.installType=Administrator +"@ + +$19cResponseFileContent | Out-File -FilePath "$WorkingDirectory\Oracle19c64bitClient\19cClient64bitinstall.rsp" -Force -Encoding ascii + +$logFile11g = "$WorkingDirectory\Oracle11g64bitClient\install.log" +New-Item -ItemType File -Path $logFile11g -Force + +$11gClientParams = @{ + FilePath = "$WorkingDirectory\Oracle11g64bitClient\client\setup.exe" + WorkingDirectory = "$WorkingDirectory\Oracle11g64bitClient\client" + ArgumentList = "-silent","-nowelcome","-nowait","-noconfig","-responseFile $WorkingDirectory\Oracle11g64bitClient\11gClient64bitinstall.rsp" + Wait = $true + NoNewWindow = $true +} + +try { + "Starting Oracle 11g 64-bit client installation at $(Get-Date)" | Out-File -FilePath $logFile11g -Append + Start-Process @11gClientParams + "Ended Oracle 11g 64-bit client installation at $(Get-Date)" | Out-File -FilePath $logFile11g -Append + # create shortcut for sqlplus on the desktop for all users + $WScriptShell = New-Object -ComObject WScript.Shell + $targetPath = [System.IO.Path]::Combine($($Config.ORACLE_11G_HOME), "BIN\sqlplus.exe") + $shortcutPath = [System.IO.Path]::Combine([environment]::GetFolderPath("CommonDesktopDirectory"), "sqlplus11g.lnk") + $shortcut = $WScriptShell.CreateShortcut($shortcutPath) + $shortcut.TargetPath = $targetPath + $shortcut.Save() | Out-Null + "Shortcut created at $shortcutPath" | Out-File -FilePath $logFile11g -Append +} +catch { + $exception = $_.Exception + $exception.Message | Out-File -FilePath $logFile11g -Append + Write-Host "Failed to install Oracle 11g 64-bit client. Error: $_" +} + +$logFile19c = "$WorkingDirectory\Oracle19c64bitClient\install.log" +New-Item -ItemType File -Path $logFile19c -Force + +$19cClientParams = @{ + FilePath = "$WorkingDirectory\Oracle19c64bitClient\client\setup.exe" + WorkingDirectory = "$WorkingDirectory\Oracle19c64bitClient\client" + ArgumentList = "-silent","-noconfig","-nowait","-responseFile $WorkingDirectory\Oracle19c64bitClient\19cClient64bitinstall.rsp" + Wait = $true + NoNewWindow = $true +} + +try { + "Starting Oracle 19c 64-bit client installation at $(Get-Date)" | Out-File -FilePath $logFile19c -Append + Start-Process @19cClientParams + "Ended Oracle 19c 64-bit client installation at $(Get-Date)" | Out-File -FilePath $logFile19c -Append + # create shortcut for sqlplus on the desktop for all users + $WScriptShell = New-Object -ComObject WScript.Shell + $targetPath = [System.IO.Path]::Combine($($Config.ORACLE_19C_HOME), "bin\sqlplus.exe") + $shortcutPath = [System.IO.Path]::Combine([environment]::GetFolderPath("CommonDesktopDirectory"), "sqlplus19c.lnk") + $shortcut = $WScriptShell.CreateShortcut($shortcutPath) + $shortcut.TargetPath = $targetPath + $shortcut.Save() | Out-Null + "Shortcut created at $shortcutPath" | Out-File -FilePath $logFile19c -Append +} catch { + $exception = $_.Exception + $exception.Message | Out-File -FilePath $logFile19c -Append + Write-Host "Failed to install Oracle 19c 64-bit client. Error $_" +} + + + +# }}} choco install winscp.install -y - + $ErrorActionPreference = "Stop" $Config = Get-Config - Add-LoginText $Config Add-BOEWindowsClient $Config Add-Shortcuts $Config + + # Re-enable antivirus settings if not Windows Server 2012 R2 + if (-not (Test-WindowsServer2012R2)) { + # Re-enable real-time monitoring + Set-MpPreference -DisableRealtimeMonitoring $false + + # Re-enable intrusion prevention system + Set-MpPreference -DisableIntrusionPreventionSystem $false + + # Re-enable script scanning + Set-MpPreference -DisableScriptScanning $false + + # Re-enable behavior monitoring + Set-MpPreference -DisableBehaviorMonitoring $false + + Write-Host "Windows Security antivirus has been re-enabled." + } else { + Write-Host "Running on Windows Server 2012 R2. Antivirus configuration was not changed." + } + +$content = Get-Content "$WorkingDirectory\Oracle19c64bitClient\19cClient64bitinstall.rsp" + +$modifycontent = $content -replace '(?i)(Password=)(.*)', '$1********' + +$modifycontent | Set-Content "$WorkingDirectory\Oracle19c64bitClient\19cClient64bitinstall.rsp" \ No newline at end of file