ps/Modules/Alkami.PowerShell.IIS/Public/Install-Provider.ps1

331 lines
15 KiB
PowerShell
Raw Permalink Normal View History

2023-05-30 22:51:22 -07:00
function Install-Provider {
<#
.SYNOPSIS
This function is used in conjunction with Alkami.Installer.Provider to install legacy providers to the appropriate locations.
.DESCRIPTION
This function is used in conjunction with Alkami.Installer.Provider to install legacy providers to the appropriate locations.
It will stop the following services and restart them if they were running at the time of install:
* BankService - WCF Service
* SchedulerService - WCF Service
* CoreService - WCF Service
* SecurityManagementService - WCF Service
* NagConfigurationService - WCF Service
* Nag - Windows Service
* Radium - Windows Service
.PARAMETER ProviderAssemblyInfo
The provider's configured assembly info.
.PARAMETER SourcePath
This is the path to the source containing folder. Typically this is a chocolatey folder.
.PARAMETER ProviderName
The provider's configured name. This is not required, it will be used for display purposes only as of Alkami.PowerShell.IIS v3.1.1
.PARAMETER ProviderTargets
Names of services that the Provider will be installed to
.PARAMETER NoSymlink
Force installation using File Copy operations, omitting a call to Test-InstallerUseSymlinkStrategy, even on hosts with the ENVIRONMENT VARIABLE 'Alkami.Installer.UseSymlink' set
.LINK
Test-InstallerUseSymlinkStrategy
.OUTPUTS
This function will only Write-Information, but also show the files that will be tentatively copied over
.EXAMPLE
Install-Provider -ProviderAssemblyInfo Alkami.App.Providers.Core.Dynamic -SourcePath C:\ProgramData\chocolatey\lib\Alkami.App.Providers.Core.Dynamic
Install-Provider output may be verbose from the underlying calls being made.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[AllowNull()]
[string]$ProviderAssemblyInfo,
[Parameter(Mandatory = $true)]
[ValidateScript( { Test-Path (Resolve-Path $_) })]
[string]$SourcePath,
[Parameter(Mandatory = $false)]
[AllowNull()]
[string]$ProviderName = $null,
[Parameter(Mandatory = $false)]
[AllowNull()]
[string[]]$ProviderTargets = @('BankService', 'CoreService', 'NotificationService', 'SecurityManagementService', 'Radium', 'Nag', 'NagConfigurationService', 'SchedulerService'),
[Parameter(Mandatory = $false)]
[switch]$NoSymlink
)
process {
$loglead = Get-LogLeadName
Write-Host "$loglead : $ProviderName being installed by $($env:USERNAME) on $($env:COMPUTERNAME) at $(Get-Date)"
## If it's a developer machine we can install anything
## Don't install on MIC or WEB servers, only APP servers.
if ( -not (Test-IsDeveloperMachine) -and -not (Test-IsAppServer)) {
Write-Warning "$loglead : Can ONLY install providers on APP machines or DEVELOPER machines"
return
}
if ( -not (Test-IsAdmin)) {
throw "You are not running as administrator. Can not continue."
}
# See if there is an override
if ($NoSymlink) {
Write-Host "$loglead : Override provided! Using Legacy non-Symlink Installer Strategy"
$usingSymlinkStrategy = $false
} else {
$usingSymlinkStrategy = Test-InstallerUseSymlinkStrategy
if ($usingSymlinkStrategy) {
Write-Host "$loglead : Using Symlink Installer Strategy."
} else {
Write-Host "$loglead : Using Legacy non-Symlink Installer Strategy"
}
}
$copyScriptBlock = {
param($sbSourcePath, $sbTargetPath, $sbUseSymlinkStrategy, $sbLoglead)
$sbloglead = "$sbLoglead (copyScriptBlock)"
$sbTargetFilename = Split-Path -Path $sbSourcePath -Leaf
$sbTargetDestination = Join-Path -Path $sbTargetPath -ChildPath $sbTargetFilename
#If sbTargetPath exists, delete it
#NOTE - the Symlink codepath SPECIFICALLY DOES NOT DELETE
if (Test-Path -Path $sbTargetDestination) {
Write-Host "$sbloglead : Removing non-symlinked file at destination $sbTargetDestination"
# This is to remove legacy files when upgrading to new Symlink Strategy.
Remove-FileSystemItem -Path $sbTargetDestination -Force -SkipSymlinks
}
if ($sbUseSymlinkStrategy) {
Write-Host "$sbloglead : Symlinking file $sbSourcePath into Destination $sbTargetPath"
New-Symlink -Path $sbSourcePath -Destination $sbTargetDestination
} else {
Write-Host "$sbloglead : Copying file $sbSourcePath into Destination $sbTargetPath"
Copy-Item -Path $sbSourcePath -Destination $sbTargetPath -Force | Out-Null
}
}
if ( -not (Test-Path -Path $SourcePath)) {
throw "Could not find the source path specified at $SourcePath"
}
$libSourcePath = Join-Path -Path $SourcePath -ChildPath "lib"
## We aren't in a valid Alkami choco package if this is the case.
if ( -not (Test-Path -Path $libSourcePath)) {
throw "Could not find the lib folder path specified at $libSourcePath"
}
$libSourceFSOFolder = (Get-ChildItem $libSourcePath -Directory) | Sort-Object -Descending | Select-Object -First 1
# SRE-16977 - following line should be this
# $libSourceFolderPath = $libSourceFSOFolder.FullName
# However, developers implemented packages that UNINTENTIONALLY took advantage of this bug
# We must reintroduce this bug in order to not break the deployment of malformed packages
# This allows for the preceding Get-ChildItem to return $null and the following line to return
# the path it was trying to Get-ChildItem from without problem, instead of $null
$libSourceFolderPath = Join-Path -Path $libSourcePath -ChildPath $libSourceFSOFolder.Name
#TODO: Get these only once for the $childFiles array below
if ((Get-ChildItem -Path $libSourceFolderPath -Filter "*.dll").Count -eq 0 -and (Get-ChildItem -Path $libSourceFolderPath -Filter "*.exe").Count -eq 0) {
throw "Could not find any dll or exe files under $libSourceFolderPath"
}
if ( -not (Get-ChildItem $libSourceFolderPath -Filter "$ProviderAssemblyInfo.dll")) {
$message = "The folder $libSourceFolderPath does not have a $ProviderAssemblyInfo dll file. This is in violation of package structuring. The Dev team must fix this so the $ProviderAssemblyInfo package id matches the principal dll of the package."
Write-Error $message
throw $message
}
$folderTargets = @()
$orbPath = Get-OrbPath
## If the following services are in any status other than Stopped, we want to stop, then restart them when on a NON-PROD machine.
## Production servers are always deployed to when out-of-pool, so the services are already, in theory, stopped.
$isRadiumRunning = $false
$radiumServiceName = @(Get-ServiceNamesByFragment -Name "Radium")[0]
if ($ProviderTargets -contains "Radium") {
if ($radiumServiceName -ne "Not installed") {
$isRadiumRunning = (Get-Service -Name $radiumServiceName).Status -ne "Stopped"
if (Test-Path -Path (Join-Path -Path (Get-OrbPath) -ChildPath 'Radium')) {
$folderTargets += Join-Path -Path $orbPath -ChildPath "Radium"
}
}
}
$isNagRunning = $false
$nagServiceName = @(Get-ServiceNamesByFragment -Name "Alkami Nag")[0]
if ($ProviderTargets -contains "Nag") {
if ($nagServiceName -ne "Not installed") {
$isNagRunning = (Get-Service -Name $nagServiceName).Status -ne "Stopped"
if (Test-Path -Path (Join-Path -Path (Get-OrbPath) -ChildPath 'Nag')) {
$folderTargets += Join-Path -Path $orbPath -ChildPath "Nag"
}
}
}
$isBankRunning = $false
if ($ProviderTargets -contains "BankService") {
$isBankRunning = Test-IISAppPoolByName -Name "BankService"
$bankServicePath = Join-Path -Path $orbPath -ChildPath "BankService"
$bankServiceBinPath = Join-Path -Path $bankServicePath -ChildPath "bin"
if (Test-Path -Path $bankServiceBinPath) {
$folderTargets += $bankServiceBinPath
}
}
$isSchedulerRunning = $false
if ($ProviderTargets -contains "SchedulerService") {
$isSchedulerRunning = Test-IISAppPoolByName -Name "SchedulerService"
$SchedulerServicePath = Join-Path -Path $orbPath -ChildPath "SchedulerService"
$SchedulerServiceBinPath = Join-Path -Path $SchedulerServicePath -ChildPath "bin"
if (Test-Path -Path $SchedulerServiceBinPath) {
$folderTargets += $SchedulerServiceBinPath
}
}
$isCoreRunning = $false
if ($ProviderTargets -contains 'CoreService') {
$isCoreRunning = Test-IISAppPoolByName -Name "CoreService"
## CoreService is included because occasionally it may use other providers.
$coreServicePath = Join-Path -Path $orbPath -ChildPath "CoreService"
$coreServiceBinPath = Join-Path -Path $coreServicePath -ChildPath "bin"
if (Test-Path -Path $coreServiceBinPath) {
$folderTargets += $coreServiceBinPath
}
}
$isNagConfigRunning = $false
if ($ProviderTargets -contains 'NagConfigurationService') {
$isNagConfigRunning = Test-IISAppPoolByName -Name "NagConfigurationService"
$nagConfigurationServicePath = Join-Path -Path $orbPath -ChildPath "NagConfigurationService"
$nagConfigurationServiceBinPath = Join-Path -Path $nagConfigurationServicePath -ChildPath "bin"
if (Test-Path -Path $nagConfigurationServiceBinPath) {
$folderTargets += $nagConfigurationServiceBinPath
}
}
$isNotifyRunning = $false
if ($ProviderTargets -contains 'NotificationService') {
$isNotifyRunning = Test-IISAppPoolByName -Name "NotificationService"
$notificationServicePath = Join-Path -Path $orbPath -ChildPath "NotificationService"
$notificationServiceBinPath = Join-Path -Path $notificationServicePath -ChildPath "bin"
if (Test-Path -Path $notificationServiceBinPath) {
$folderTargets += $notificationServiceBinPath
}
}
$isSecMgmtRunning = $false
if ($ProviderTargets -contains 'SecurityManagementService') {
$isSecMgmtRunning = Test-IISAppPoolByName -Name "SecurityManagementService"
$securityManagementServicePath = Join-Path -Path $orbPath -ChildPath "SecurityManagementService"
$securityManagementServiceBinPath = Join-Path -Path $securityManagementServicePath -ChildPath "bin"
if (Test-Path -Path $securityManagementServiceBinPath) {
$folderTargets += $securityManagementServiceBinPath
}
}
if ($isRadiumRunning) {
Stop-AlkamiService -ServiceName $radiumServiceName
}
if ($isNagRunning) {
Stop-AlkamiService -ServiceName $nagServiceName
}
if ($isBankRunning) {
Stop-IISAppPoolByName -Name "BankService"
Remove-DotNetTemporaryFiles -Name "Bank"
}
if ($isSchedulerRunning) {
Stop-IISAppPoolByName -Name "SchedulerService"
Remove-DotNetTemporaryFiles -Name "SchedulerService"
}
if ($isCoreRunning) {
Stop-IISAppPoolByName -Name "CoreService"
Remove-DotNetTemporaryFiles -Name "CoreService"
}
if ($isNagConfigRunning) {
Stop-IISAppPoolByName -Name "NagConfigurationService"
Remove-DotNetTemporaryFiles -Name "NagConfigurationService"
}
if ($isNotifyRunning) {
Stop-IISAppPoolByName -Name "NotificationService"
Remove-DotNetTemporaryFiles -Name "NotificationService"
}
if ($isSecMgmtRunning) {
Stop-IISAppPoolByName -Name "SecurityManagementService"
Remove-DotNetTemporaryFiles -Name "securityManagement"
}
if ($isBankRunning -or $isCoreRunning -or $isNagConfigRunning -or $isNotifyRunning -or $isSecMgmtRunning -or $isRadiumRunning -or $isNagRunning -or $isSchedulerRunning) {
Start-Sleep -Seconds 30
}
$childFiles = @()
$childFiles += @(Get-ChildItem -Path $libSourceFolderPath -Filter "*.dll")
$childFiles += @(Get-ChildItem -Path $libSourceFolderPath -Filter "*.exe")
foreach ($childFile in $childFiles) {
$pdbPath = $file.FullName -replace $file.Extension, ".pdb"
if (Test-Path -Path $pdbPath) {
$childFiles += $pdbPath
}
}
Write-Host "$loglead : Files to copy or link: "
Write-Host ("$loglead : `n`t{0}" -f ($childFiles.FullName -join "`n`t"))
## THIS COMMENT APPLIES TO THE SCRIPTBLOCK BEING CALLED BY Invoke-CommandWithRetry
## As we've already checked the files against the shared folder in ORB, let's now check each individual service
## bin folder for the pared-down list of files from the package.
## If the file in the bin folder already exists and matches/wins, we don't need to do anything.
## The anticipation is that the list of files to be checked here is approximately 5-8, or less.
## That's 40 potential file comparisons across five services, so it should be relatively fast.
foreach($targetFolder in $folderTargets) {
foreach($filePath in $childFiles.FullName) {
Write-Host "$loglead : Copying file $filePath into Destination $targetFolder with -Force"
Write-Information '.'
Invoke-CommandWithRetry -MaxRetries 3 -SecondsDelay 1 -Arguments @($filePath, $targetFolder, $usingSymlinkStrategy, $loglead) -ScriptBlock $copyScriptBlock
}
}
if ($isBankRunning) {
Start-IISAppPoolByName -Name "BankService"
}
if ($isSchedulerRunning) {
Start-IISAppPoolByName -Name "SchedulerService"
}
if ($isCoreRunning) {
Start-IISAppPoolByName -Name "CoreService"
}
if ($isNagConfigRunning) {
Start-IISAppPoolByName -Name "NagConfigurationService"
}
if ($isNotifyRunning) {
Start-IISAppPoolByName -Name "NotificationService"
}
if ($isSecMgmtRunning) {
Start-IISAppPoolByName -Name "SecurityManagementService"
}
if ($isRadiumRunning) {
Start-Service -Name $radiumServiceName
}
if ($isNagRunning) {
Start-Service -Name $nagServiceName
}
}
}