299 lines
13 KiB
PowerShell
299 lines
13 KiB
PowerShell
Function Install-Widget {
|
|
<#
|
|
.SYNOPSIS
|
|
Installs a widget either on a server or a developer machine from a choco location, stops and starts IIS if it was running before.
|
|
|
|
.EXAMPLE
|
|
Install-Widget -WidgetName Authentication -SourcePath c:\programdata\chocolatey\lib\alkami.apps.authentication
|
|
|
|
.PARAMETER WidgetName
|
|
The name of the widget to install
|
|
|
|
.PARAMETER SourcePath
|
|
The path to the widget to be installed, usually a chocolatey lib folder
|
|
|
|
.PARAMETER IsAdmin
|
|
Indicate that the base web application name to look in is WebClientAdmin, otherwise is WebClient
|
|
|
|
.PARAMETER RemoveLogs
|
|
Indicating that the ORB logs should be purged
|
|
|
|
.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
|
|
Install-Widget output may be verbose from the underlying calls being made.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
Param(
|
|
[Parameter(Mandatory=$true, Position=0)]
|
|
[string]$WidgetName,
|
|
|
|
[Parameter(Mandatory=$true, Position=1)]
|
|
[string]$SourcePath,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$IsAdmin,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$RemoveLogs,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$NoSymlink
|
|
)
|
|
|
|
$loglead = Get-LogLeadName
|
|
Write-Host "$loglead : $WidgetName being installed by $($env:USERNAME) on $($env:COMPUTERNAME) at $(Get-Date)"
|
|
|
|
if ( -not (Test-IsDeveloperMachine) -and -not (Test-IsWebServer)) {
|
|
Write-Warning "$loglead : Cannot install widgets on the APP tier"
|
|
return
|
|
}
|
|
if ( -not (Test-IsAdmin)) {
|
|
throw "You are NOT running as administrator. Cannot continue."
|
|
}
|
|
|
|
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"
|
|
}
|
|
}
|
|
|
|
if ($usingSymlinkStrategy) {
|
|
$FILE_OPERATION_STRING = "SYMLINKing"
|
|
} else {
|
|
$FILE_OPERATION_STRING = "COPYing"
|
|
}
|
|
|
|
if ( -not (Test-Path -Path $SourcePath)) {
|
|
throw "$loglead : Could not find the source path specified at $SourcePath"
|
|
}
|
|
|
|
$libSourcePath = Join-Path -Path $SourcePath -ChildPath 'lib'
|
|
|
|
if ( -not (Test-Path -Path $libSourcePath)) {
|
|
throw "$loglead : Could not find the lib folder path specified at $libSourcePath"
|
|
}
|
|
|
|
$libSourceFSOFolder = Get-ChildItem -Path $libSourcePath -Directory `
|
|
| Sort-Object -Descending `
|
|
| Where-Object {(Get-ChildItem -Path $_.FullName -filter "*.dll").Count -gt 0 } `
|
|
| Select-Object -First 1
|
|
# This was labeled as part of, and committed against, SRE-16977 but that's the wrong ticket number.
|
|
|
|
# The following line should be this:
|
|
# $libSourceFolderPath = $libSourceFSOFolder.FullName
|
|
# However, developers implemented packages that UNINTENTIONALLY took advantage of a bug where the .net version subfolders didn't exist.
|
|
# We must handle 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
|
|
|
|
# SRE-18955 - Added the Where-Object clause above to handle folders existing with no dlls due to poor choco cleanup.
|
|
# libSourceFSOFolder may be null (and that's acceptable). So .name will be null
|
|
# and $libSourceFolderPath will correctly be $libSourcePath.
|
|
|
|
$libSourceFolderPath = Join-Path -Path $libSourcePath -ChildPath $libSourceFSOFolder.Name
|
|
Write-Host "$loglead : Looking for dll files in $libSourceFolderPath"
|
|
|
|
if ((Get-ChildItem -Path $libSourceFolderPath -Filter *.dll).Count -eq 0) {
|
|
throw "$loglead : Could not find any dll files under $libSourceFolderPath"
|
|
}
|
|
|
|
## Second use-case will be for installing from a project folder and getting this from the bin path of the built solution
|
|
## That above case is to-do for cbrand - 2018-08-16
|
|
$contentTopPath = Join-Path -Path $SourcePath -ChildPath "Content"
|
|
$contentSourcePath = Join-Path -Path $contentTopPath -ChildPath "Areas"
|
|
|
|
$contentSourcePathFound = $true
|
|
|
|
if ( -not (Test-Path -Path $contentSourcePath)) {
|
|
## Don't throw right here because this could be an API widget
|
|
Write-Warning "$loglead : Is this an API style widget? Could not find the content path specified at $contentSourcePath"
|
|
$contentSourcePathFound = $false
|
|
}
|
|
if ($contentSourcePathFound -and (Get-ChildItem $contentSourcePath -Directory).Count -eq 0) {
|
|
## Don't throw right here because this could be an API widget
|
|
Write-Warning "$loglead : Is this an API style widget? Could not find any content folders under $contentSourcePath"
|
|
$contentSourcePathFound = $false
|
|
}
|
|
|
|
$contentSourceFolderPath = ""
|
|
|
|
if ($contentSourcePathFound) {
|
|
$preferredContentSourceFolderPath = Join-Path -Path $contentSourcePath -ChildPath "App"
|
|
$contentSourceFolderPath = $preferredContentSourceFolderPath
|
|
|
|
if ( -not (Test-Path -Path $contentSourceFolderPath)) {
|
|
Write-Host "$loglead : Not able to find the content folder $contentSourceFolderPath looking for another"
|
|
$contentSourceFSOFolder = (Get-ChildItem $contentSourcePath -Directory) | Sort-Object -Descending | Select-Object -First 1
|
|
# SRE-16977 - following line should be this
|
|
# $contentSourceFolderPath = $contentSourceFSOFolder.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
|
|
$contentSourceFolderPath = Join-Path -Path $contentSourcePath -ChildPath $contentSourceFSOFolder.Name
|
|
}
|
|
|
|
Write-Host "$loglead : Found content folder $contentSourceFolderPath"
|
|
}
|
|
|
|
Write-Host "$loglead : Ready to install $WidgetName"
|
|
Write-Host "$loglead : $FILE_OPERATION_STRING DLL/LIB files from $libSourceFolderPath"
|
|
|
|
if ($contentSourcePathFound) {
|
|
Write-Host "$loglead : $FILE_OPERATION_STRING CONTENT files from $contentSourceFolderPath"
|
|
}
|
|
|
|
$appName = "WebClient"
|
|
|
|
if ($IsAdmin) {
|
|
$appName = "WebClientAdmin"
|
|
}
|
|
|
|
## Get the IIS sites by path then get the distinct application pool names for all sites bound to this path.
|
|
$ORB_PATH = Get-OrbPath
|
|
$orbBaseWebclientPath = Join-Path -Path $ORB_PATH -ChildPath $appName
|
|
Write-Host "$loglead : Orb Base webclient path $orbBaseWebclientPath"
|
|
|
|
$iisApplicationPools = @()
|
|
$iisSites = Get-IISSitesByPath -Path $orbBaseWebclientPath
|
|
foreach ($site in $iisSites) {
|
|
if ($site.ApplicationPool -notin $iisApplicationPools) {
|
|
$iisApplicationPools += $site.ApplicationPool
|
|
}
|
|
}
|
|
|
|
$appPathTemp = Join-Path -Path $ORB_PATH -ChildPath $appName
|
|
$orbAreaPath = Join-Path -Path $appPathTemp -ChildPath "Areas"
|
|
$orbAreaWidgetContentPath = Join-Path $orbAreaPath $WidgetName
|
|
$orbAreaBinPath = Join-Path $orbAreaWidgetContentPath "bin"
|
|
|
|
# In the case of using the symlink installer strategy, we just always goto to the app root bin
|
|
# In the non-symlink case, we would send to C:\Orb\WebClientAdmin\bin or C:\Orb\WebClient\Areas\<AreaName>\bin
|
|
if ($IsAdmin -or $usingSymlinkStrategy) {
|
|
$orbAreaBinPath = Join-Path -Path $appPathTemp -ChildPath "bin"
|
|
}
|
|
|
|
## Stop any/all $iisApplicationPools that are running.
|
|
$isRunning = $false
|
|
foreach ($appPool in $iisApplicationPools) {
|
|
Write-Host "$loglead : Test-IISAppPoolByName -Name $appPool"
|
|
$isSiteRunning = Test-IISAppPoolByName -Name $appPool
|
|
if ($isSiteRunning) {
|
|
$isRunning = $true
|
|
}
|
|
|
|
if($isSiteRunning) {
|
|
Write-Host "$loglead : Stopping $appPool"
|
|
(Stop-WebAppPool -Name $appPool) | Out-Null
|
|
Do {
|
|
Start-Sleep -Milliseconds 100
|
|
} Until ((Get-WebAppPoolState -Name $appPool).Value -eq "Stopped" )
|
|
}
|
|
}
|
|
|
|
if ($RemoveLogs -and $isRunning) {
|
|
$logfiles = Get-LogPathsForOrbApplication -AppName $appName
|
|
foreach($logPath in $logfiles) {
|
|
if (Test-Path -Path $logPath) {
|
|
Write-Host "$loglead : Removing $logPath"
|
|
(Remove-FileSystemItem -Path $logPath -ErrorAction Stop) | Out-Null
|
|
}
|
|
}
|
|
}
|
|
|
|
# Remove the folder to the widget areas in Orb before starting.
|
|
$symlinkAreaContentFolderAlreadyCorrect = $false
|
|
if ($usingSymlinkStrategy) {
|
|
$isOrbAreaWidgetPathSymlink = Test-IsSymlink -Path $orbAreaWidgetContentPath
|
|
Write-Host "$loglead : Is the existing ORB Widget Area path already a Symlink? $isOrbAreaWidgetPathSymlink"
|
|
if ($isOrbAreaWidgetPathSymlink) {
|
|
$symlinkAreaContentFolderAlreadyCorrect = Test-PathMatch -FirstPath $orbAreaWidgetContentPath -SecondPath $contentSourceFolderPath
|
|
}
|
|
}
|
|
|
|
if ((Test-Path -Path $orbAreaWidgetContentPath) -and -not $symlinkAreaContentFolderAlreadyCorrect) {
|
|
Write-Host "$loglead : Removing item $orbAreaWidgetContentPath"
|
|
(Remove-FileSystemItem -Path $orbAreaWidgetContentPath -Recurse -ErrorAction Stop) | Out-Null
|
|
}
|
|
|
|
if ($usingSymlinkStrategy) {
|
|
Write-Host "$loglead : $FILE_OPERATION_STRING folder $contentSourceFolderPath into Destination $orbAreaWidgetContentPath"
|
|
if ($contentSourcePathFound) {
|
|
# Link the <widget>\App\ folder to <orb-areas>\<widget-name>
|
|
New-Symlink -Path $contentSourceFolderPath -Destination $orbAreaPath -Name $WidgetName
|
|
}
|
|
Write-Host "$loglead : Get all of the dll, pdb and xml files in $libSourceFolderPath to be symlinked directly to $orbAreaBinPath"
|
|
$filesInlibSourceFolderPath = Get-ChildItem -Path $libSourceFolderPath -Recurse
|
|
$fileTypesToLink = @(".dll",".pdb",".xml")
|
|
|
|
foreach ($file in $filesInlibSourceFolderPath) {
|
|
if ($file.Extension -in $fileTypesToLink) {
|
|
$libFilePath = Join-Path -Path $libSourceFolderPath -ChildPath $file
|
|
$orbAreaBinFilePath = Join-Path -Path $orbAreaBinPath -ChildPath $file
|
|
|
|
if ( -not (Test-IsSymlink -Path $orbAreaBinFilePath)) {
|
|
New-Symlink -Path $libFilePath -Destination $orbAreaBinPath
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
## Legacy filecopy codepath
|
|
foreach ($iisSite in $iisSites) {
|
|
$tempFilePath = Get-SiteTempDirectoryPath -siteOrAppName $($iisSite.Name) ##$appName
|
|
if ($isRunning -and -not ([string]::IsNullOrWhiteSpace($tempFilePath)) -and (Test-Path -Path $tempFilePath)) {
|
|
Write-Host "$loglead : Removing item $tempFilePath"
|
|
(Remove-FileSystemItem -Path $tempFilePath -Recurse -ErrorAction Stop) | Out-Null
|
|
}
|
|
}
|
|
|
|
## Widget CONTENT Directory should never exist because we deleted it but let's make sure it does ...
|
|
if ( -not (Test-Path -Path $orbAreaWidgetContentPath)) {
|
|
Write-Host "$loglead : Creating directory $orbAreaWidgetContentPath"
|
|
(New-Item -Path $orbAreaWidgetContentPath -ItemType Directory) | Out-Null
|
|
}
|
|
if ($contentSourcePathFound) {
|
|
$copyWidgetContentScript = {
|
|
param($sbSourceFolder, $sbOrbPath)
|
|
$sbSourcePath = Join-Path -Path $sbSourceFolder -ChildPath '*'
|
|
(Copy-Item -Path $sbSourcePath -Destination $sbOrbPath -Recurse -Force) | Out-Null
|
|
}
|
|
Write-Host "$loglead : $FILE_OPERATION_STRING CONTENT source folder: $contentSourceFolderPath to CONTENT destination path: $orbAreaWidgetContentPath"
|
|
Invoke-CommandWithRetry -MaxRetries 3 -SecondsDelay 1 -Arguments @($contentSourceFolderPath, $orbAreaWidgetContentPath) -ScriptBlock $copyWidgetContentScript
|
|
}
|
|
|
|
## Widget LIB directory should never exist because we deleted it but let's make sure it does ...
|
|
if ( -not (Test-Path -Path $orbAreaBinPath)) {
|
|
Write-Host "$loglead : Creating directory $orbAreaBinPath"
|
|
(New-Item -Path $orbAreaBinPath -ItemType Directory) | Out-Null
|
|
}
|
|
Write-Host "$loglead : $FILE_OPERATION_STRING LIB source folder: $libSourceFolderPath to LIB destination path: $orbAreaBinPath"
|
|
$copyWidgetLibScript = {
|
|
param($sbSourceFolder, $sbOrbPath)
|
|
$sbSourcePath = Join-Path -Path $sbSourceFolder -ChildPath '*'
|
|
(Copy-Item -Path $sbSourcePath -Destination $sbOrbPath -Recurse -Force) | Out-Null
|
|
}
|
|
Invoke-CommandWithRetry -MaxRetries 3 -SecondsDelay 1 -Arguments @($libSourceFolderPath, $orbAreaBinPath) -ScriptBlock $copyWidgetLibScript
|
|
}
|
|
|
|
|
|
if ($isRunning) {
|
|
foreach ($appPool in $iisApplicationPools) {
|
|
Write-Host "$loglead : Starting App Pool: $appPool"
|
|
(Start-WebAppPool -Name $appPool) | Out-Null
|
|
}
|
|
}
|
|
} |