Files
sql-scripts/TPDT-268 - ACP in task sequence/acp_auto.ps1
Thierry Schork 230e7c05d7 tpdt-283
Corrected had coded path from testing
2024-03-18 09:29:12 +01:00

553 lines
20 KiB
PowerShell

<#
TPDT-268
Finalize the database setup after staging a new pharmacy
This script re-implements the autoConfigPharmacy of the DBA in an automated way with interactions with a keyvault to fetch secrets and certificate
TSC 08.02.2024 Creation
#>
# param (
# #[Parameter(Position=0,mandatory=$true)]
# [string] $SqlInstance ="SSUNB008VM01\APSSQL"
# )
#if ran from TSC computer, execute on sun008, otherwise execute locally
if($env:COMPUTERNAME -ne "CGAL41556"){
$SqlInstance = "$($env:COMPUTERNAME)\APSSQL"
if (test-path "C:\Program Files\PackageManagement\Az.Accounts") {Import-Module "C:\Program Files\PackageManagement\Az.Accounts"}else{exit 42101}
if (test-path "C:\Program Files\PackageManagement\Az.keyvault") {Import-Module "C:\Program Files\PackageManagement\Az.keyvault"}else{exit 42101}
if (test-path "C:\Program Files\PackageManagement\Az.compute") {Import-Module "C:\Program Files\PackageManagement\Az.compute"}else{exit 42101}
}
else
{
$SqlInstance ="SSUNB008VM01\APSSQL"
Import-Module Az.Accounts
Import-Module Az.keyvault
Import-Module Az.compute
}
#Import-Module SqlServer
<#
.SYNOPSIS
Executes a T-SQL script on a SQL Server database without trying to parse variables.
.DESCRIPTION
This function executes a T-SQL script on a specified SQL Server database.
The script is split into batches based on the GO statements and each batch is executed separately.
SQLCMD type variables like $(ESCAPE_SQUOTE(WMI(DatabaseName))) are NOT parsed and do not cause errors if they are present in dynamic sql
.PARAMETER Server
The name of the SQL Server instance to connect to.
.PARAMETER Database
The name of the database on the SQL Server instance to execute the script against.
.PARAMETER ScriptPath
The file path of the T-SQL script to execute.
.EXAMPLE
Invoke-SqlScript -Server "YourServer" -Database "YourDatabase" -ScriptPath "YourScript.sql"
Executes the T-SQL script "YourScript.sql" on the "YourDatabase" database of the "YourServer" SQL Server instance.
.NOTES
Author: Thierry Schork
Date: 2024-02-13
#>
function Invoke-SqlScript {
param(
[string]$Server,
[string]$Database,
[string]$ScriptPath,
[string]$script
)
# Load the assembly containing the SqlCommand class
Add-Type -AssemblyName System.Data
# Create a connection string
$connectionString = "Server=$Server;Database=$Database;Integrated Security=True"
# Create a SqlConnection object
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
# Open the connection
$connection.Open()
# Read the content of the script file
if('' -ne $ScriptPath){
$scriptContent = Get-Content -Path $ScriptPath -Raw
}
if('' -ne $script){
$scriptContent = $script
}
# Split the script into batches based on the GO statements
$scriptBatches = $scriptContent -split [regex]'(?smi)^[\s]*GO[\s]*$' | Where-Object { $_.Trim() -ne '' }
# Create a SqlCommand object
$command = $connection.CreateCommand()
foreach ($batch in $scriptBatches) {
#$batch = $batch.Trim()
#$batch = $batch -replace '(?m)^GO\s*', ''
if ($batch.ToLower() -ne "go"){
try {
# Set the command text for the batch
$command.CommandText = $batch
# Execute the command
$null = $command.ExecuteNonQuery()
}
catch {
Write-Error "Error in the file $fileShort"
Write-Error $_.Exception.Message
Write-Error "-------------------"
Write-Error $batch
}
}
}
# Close the connection
$connection.Close()
}
$ErrorActionPreference = "Stop"
$DebugPreference = 'SilentlyContinue'
#overrides
#$ErrorActionPreference = "continue"
#$DebugPreference = 'Continue'
$rootFS = Get-Location
#do we want to execute jobs from TiaPharm. No, because the package
#should have deployed them just before this script
$exec_triapharm = $false
# Replace these values with your Azure AD service principal details
$clientId = "65d289fd-4bea-464f-a1cd-417f74d26888" #pcpl-ApoLsPoc-setupDataEncryptionwithKeyVault
$clientSecret = "dPQ8Q~N5btnUb7cj~H4YZaDDQo7kJNZlpxbRua2a"
$tenantId = "7844775a-a9cc-4c33-a5ae-36dcf6660f45" #galenica
# Replace these values with your Azure Key Vault details
#$resourceGroupName = "rg-ApoLsPoc-Keyvault"
$keyVaultName = "kv-ApoLsPoc-Tde"
#secret to fetch from the key vault
$secretFtpPassword ="centralinfra---svc-APH-trans"
$secretMasterKey ="MasterKey"
$secretTriaPharmSQLCert = "TriaPharmSQLCert"
$secretSqlAzureMigration = "sqlAzureMigration"
# Convert the client secret to a secure string
$securePassword = ConvertTo-SecureString -String $clientSecret -AsPlainText -Force
# Create a PSCredential object
$psCred = New-Object System.Management.Automation.PSCredential -ArgumentList $clientId, $securePassword
# Authenticate using the service principal
$null = Connect-AzAccount -ServicePrincipal -Credential $psCred -TenantId $tenantId
# Get the login for sqlAzureMigration from Azure Key Vault
$secret_central = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretSqlAzureMigration
$login_central = "sqlAzureMigration"
$psCredCentral = New-Object System.Management.Automation.PSCredential($login_central, $secret_central.SecretValue)
# Display the secret value
#Write-Host "Secret Value: $($secret.SecretValue | ConvertFrom-SecureString -AsPlainText)"
##region derive alias from hostname
$hostname = $SqlInstance
$position = $hostname.IndexOf("\")
if ($position -gt 0){
#remove instance name
$hostname = $hostname.SubString(0,$position)
}
$ou = $null
$customer = $null
$clientpath = $null
$format = 'GCM'
if ($hostname.IndexOf("NB") -gt 0){
#old hostname, like SSUNB661VM01
$ou = $hostname.Substring(5,3)
if($hostname -like "SSUNB*"){
$customer="SUN"
}
if($hostname -like "SAMNB*"){
$customer="AMA"
}
if($hostname -like "SCVNB*"){
$customer="CVI"
}
}
else{
#new$customer, like SWAMA701VM23
$ou = $hostname.Substring(5,3)
if($hostname -like "SWSUN*"){
$customer="SUN"
}
if($hostname -like "SWAMA*"){
$customer="AMA"
}
if($hostname -like "SWCVI*"){
$customer="CVI"
}
}
#used to map jobs scripts subfolders when executing scripts with customer abbreviation
switch ($Customer){
'AMA'{ $clientpath = 'AMAVITA' }
'SUN'{ $clientpath = 'SUNSTORE' }
'CVI'{ $clientpath = 'CVI' }
}
if($null -eq $format){
Write-Error "Format could not be derived from hostname $hostname"
}
if($null -eq $customer){
Write-Error "Customer could not be derived from hostname $hostname"
}
if ($null -eq $ou){
Write-Error "OU could not be derived from hostname $hostname"
}
$alias = "$($customer)$($ou)APS"
#region Server DEV/TEST/PROD
$PharmacyShortName = $customer + $ou
$PharmaciesDEV = "SUN007","SUN008","CVI506","AMA704"
$PharmaciesVALI = "SUN004","SUN006","CVI503","CVI504","AMA705","AMA707","AMA888","CVI888","SUN888"
$PharmaciesACCE = "SUN001","SUN002","CVI501","CVI502","AMA701","AMA702","AMA703","CVI505","SUN003"
$PharmaciesTRAINING = "SUN011","CVI507","CVI508","AMA988","AMA989"
if ($PharmaciesDEV -match $PharmacyShortName)
{
$ContextType = 'DEVE'
$CentraleServer = "SWINTDB01"
}
elseif ($PharmaciesVALI -match $PharmacyShortName)
{
$ContextType = 'VALI'
$CentraleServer = "SWTSTDB01"
}
elseif ($PharmaciesACCE -match $PharmacyShortName)
{
$ContextType = 'ACCE'
$CentraleServer = "SWPRDDB01"
}
elseif ($PharmaciesTRAINING -match $PharmacyShortName)
{
$ContextType = 'FORM'
$CentraleServer = "SWPRDDB01"
}
else
{
$ContextType = 'PROD'
$CentraleServer = "SWPRDDB01"
}
#endregion
#endregion
#define a db credential, for testing without hte service principal
#$DBpassword = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name "ua208700"
#$dbCred = New-Object System.Management.Automation.PSCredential -ArgumentList 'ua208700@centralinfra.net', $DBpassword.SecretValue
#$dbCred = Get-SqlCredential -Name "centralinfra\ua208700" -Identity "centralinfra\ua208700" -Secret $DBpassword.SecretValue
##Check if instance is reachable
$instanceReachable=$false
try {
$null = Invoke-Sqlcmd -ServerInstance $SqlInstance -Query "select 1" -QueryTimeout 5 -Database master
$instanceReachable=$true
Write-Debug "Connection to the SQL instance ok"
}
catch {
Write-Error "SQL instance '$($SqlInstance)' is not reachable or the principal doesn't have permissions to connect"
}
##region check out triaOne release
$checkoutGit = $false
if($true -eq $checkoutGit){
$FolderPath = "triaOne_jobs"
if (Test-Path -Path $FolderPath) {
# If the folder exists, remove its contents
Get-ChildItem -Path $FolderPath | Remove-Item -Force -Recurse
Write-Host "Cleaned existing folder: $FolderPath"
} else {
# If the folder doesn't exist, create it
New-Item -ItemType Directory -Path $FolderPath | Out-Null
Write-Host "Created new folder: $FolderPath"
}
# Define the URL of the Git repository and the subfolder you want to check out
$repositoryUrl = "http://shcnbtfs01.hcisolutions.ch:8080/tfs/TriaPharmCollection/_git/TriaOne"
$subfolderPath = "SQL\Jobs"
$localRepo = "triaOne_repo"
# Clone the Git repository without fetching files on the selected branch
git clone -n -b rel/23.6 $repositoryUrl $localRepo
# Move to the cloned repository directory
Set-Location $localRepo
git checkout HEAD $subfolderPath
git pull
# Move the subfolder to the desired location
$destination = Join-Path -Path $rootFS -ChildPath $FolderPath
Move-Item -Path $subfolderPath -Destination $destination -Force -Recurse
Set-Location $rootFS
#Remove-Item $localRepo -Force
}
#endregion
#$instanceReachable = $false
if($true -eq $instanceReachable){
$dbacc = New-Object psobject
$dbacc | Add-Member -MemberType NoteProperty -Name "context" -Value $ContextType
$dbacc | Add-Member -MemberType NoteProperty -Name "customer" -Value $customer
$dbacc | Add-Member -MemberType NoteProperty -Name "version" -Value -1
$dbacc | Add-Member -MemberType NoteProperty -Name "SE_DNS" -Value $hostname
$dbacc | Add-Member -MemberType NoteProperty -Name "aliasInstance" -Value $sqlVariables
##step 1: configure SQL instance max memory
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\1_Configure_InstanceMemory.sql
Write-Output "Executed 1_Configure_InstanceMemory.sql"
##step 2: set db identities
[string]$query = Get-Content -Path .\2_Set_Identity.sql
$query = $query.Replace("`$format", $format)
$query = $query.Replace("`$fqdn", $alias)
$query = $query.Replace("`$customer", $customer)
$query = $query.Replace("`$context", $dbacc.context) # ['context'])
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -Query $query
Write-Output "Executed 2_Set_Identity.sql"
##step 3: activate clr
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\3_Execute_CLR.sql
Write-Output "Executed 3_Execute_CLR.sql"
##step 4: map sql users
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\6_Map_SQLUsers.sql
Write-Output "Executed 6_Map_SQLUsers.sql"
##step 4: remove orphaned users
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\8_Remove_OrphanedSQLUsers.sql
$orphans | Format-Table
Write-Output "Executed 8_Remove_OrphanedSQLUsers.sql"
##step 5: FTP password modification on central server
$ftpPassword = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretFtpPassword
$query = Get-Content -Path .\9_Update_FTPLogin_Central.sql
$query = $query.Replace("`$ftppass", $($ftpPassword.SecretValue | ConvertFrom-SecureString )) ####################################### -AsPlainText))
$query = $query.Replace("`$fqdn", $alias)
#Invoke-Sqlcmd -ServerInstance gcmPrdCent -Database arizona -Query $query
Invoke-Sqlcmd -ServerInstance $CentraleServer -Database arizona -Query $query -Credential $psCredCentral
Write-Output "Executed 9_Update_FTPLogin_Central.sql"
##step 6: execute all DBA packages
$LogFile = "C:\Temp\DBApackagesCLA.log"
try{
Get-ChildItem -path .\dba_packages -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA package file $fileShort"
}
}
catch
{
$file | out-file -FilePath $LogFile -Append -Encoding utf8
$_ | out-file -FilePath $LogFile -Append -Encoding utf8
}
##step 7: execute all DBA structure scripts
Get-ChildItem -path .\dba_structure -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA structure file $fileShort"
}
##step 8: execute all DBA stored procedures scripts
Get-ChildItem -path .\dba_storedProcedures -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA stored procedure file $fileShort"
}
##region triaOne jobs
if($true -eq $exec_triapharm){
##step 9: execute triaOne pharmacy jobs scripts
Get-ChildItem -path .\cp_triaOne_jobs\pharmacy -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed triaOne pharmacy job file $fileShort"
}
##step 10: execute triaOne pharmacy customer jobs scripts
Get-ChildItem -path .\cp_triaOne_jobs\pharmacy\$clientpath -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed triaOne pharmacy customer job file $fileShort"
}
}
#endregion
##region DBA jobs
##step 11: execute all DBA global jobs scripts
Get-ChildItem -path .\dba_jobs\ -Filter *.sql | Where-Object {$_.Name -NotMatch "several"} | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA global job file $fileShort"
}
##step 12: execute all DBA pharmacy jobs scripts
Get-ChildItem -path .\dba_jobs\Pharmacy -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA pharmacy job file $fileShort"
}
##step 13: execute all DBA customer specific pharmacy jobs scripts
Get-ChildItem -path .\dba_jobs\Pharmacy\$clientpath -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA pharmacy $clientpath job file $fileShort"
}
#endregion
##step 14: execute all DBA alerts scripts
Get-ChildItem -path .\dba_alerts -Filter *.sql | ForEach-Object {
$file = $_
$fileShort = Split-Path -Path $file -Leaf
Invoke-SqlScript -Server $SqlInstance -Database master -ScriptPath $file.FullName
Write-Output "executed DBA alert file $fileShort"
}
##step 15: execute schedule shuffle script
$null = Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\10_Change_Schedules_Subscriptions.sql
Write-Output "Executed 10_Change_Schedules_Subscriptions.sql"
##step 16: execute schedule shuffle script
$null = Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\11_Run_Job_CheckReplications.sql
Write-Output "Executed 11_Run_Job_CheckReplications.sql"
##step 17: Atlas configuration
$masterKey = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretMasterKey
$triapharmSqlCert = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretTriaPharmSQLCert
$bckcert = 'D:\SQLDatabaseDump\Certificates\MK\'+$alias.Substring(0,6).toupper()+'_master.bak'
[string]$query = Get-Content -Path .\12_Broker_Config.sql
$query = $query.Replace("`$mk", $($masterKey.SecretValue | ConvertFrom-SecureString )) # -AsPlainText))
$query = $query.Replace("`$cert", $($triapharmSqlCert.SecretValue | ConvertFrom-SecureString )) # -AsPlainText))
$query = $query.Replace("`$bck", $bckcert)
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database arizona -Query $query
Write-Output "Executed 12_Broker_Config.sql"
##step 18: create ad logins
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile .\13_Create_AD_Logins.sql
Write-Output "Executed 13_Create_AD_Logins.sql"
##step 19: final check on pharmacy
#removed because does not brings any value
#in an automated run, as this requires a human to verify and act
#Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -InputFile '.\Check Instance Pharmacy.sql'
#Write-Output "Executed Check Instance Pharmacy.sql"
##step 20: update system_site on the central
$fqdn = [System.Net.Dns]::GetHostByName($alias)
#Get pharmacy OU_id
$query=@"
USE [master];
DECLARE @ou_id INT;
EXECUTE [Arizona].[dbo].[sp_bmc_Bmc_Applic_Default]
@in_job_type = 3,
@in_param_int_1 = NULL, /* Company */
@in_param_int_2 = NULL, /* Subsidiary */
@in_param_varchar_1 = 'cvCurrentOrganizationalUnit',
@out_default_value = @ou_id OUTPUT,
@out_param_int_1 = NULL;
SELECT @ou_id as ou_id
"@
$ou_dataset = Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -Query $query
#update the centrale
$query=Get-Content -Path .\20_update_system_site_centrale.sql
$query = $query.Replace("`$fqdn", $fqdn.HostName)
$query = $query.Replace("`$alias", $alias)
$query = $query.Replace("`$ou_id", $ou_dataset.ou_id)
Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -Query $query
Write-Output "Executed 20_update_system_site_centrale.sql locally"
Invoke-Sqlcmd -ServerInstance $CentraleServer -Database master -Query $query -Credential $psCredCentral
Write-Output "Executed 20_update_system_site_centrale.sql on the central $CentraleServer"
##step 21: update Point_of_sale
#fetch a list of mac adresses
$macs = @{}
$pos = 0
Get-NetAdapter | Where-Object -Property status -eq up | Group-Object -Property MacAddress | ForEach-Object {
$macs.Add($pos, $_.Name)
$pos++
}
if($macs.Count -gt 1){
#we have several mac addresses, unable to define which one should be used in point_of_sale
Write-Error "Several mac addresses are active, no clue which one to save in Point_of_sale"
exit 42102
}
else{
$query=Get-Content -Path .\21_update_point_of_sale_centrale.sql
$query = $query.Replace("`$fqdn", $hostname)
$query = $query.Replace("`$mac", $macs[0])
#Invoke-Sqlcmd -ServerInstance $SqlInstance -Database master -Query $query
Write-Output $query
Write-Output "Executed 21_update_point_of_sale_centrale.sql"
}
}