Configuration.ps1
Set-StrictMode -Version 2 function Test-TelligentPath { <# .SYNOPSIS Tests if a SQL Server exists and can be connected to. Optonally checks for a specific database or table. .PARAMETER Path The path to test for a Teligent Community .PARAMETER AllowEmpty Specifies that an empty path should be considered as valid .PARAMETER IsValid Only test if the path is syntaticly valid, not that it actually contains a valid Telligent Community instance .PARAMETER Web Only pass if the path contains a Telligent Community website, not a Job Server .PARAMETER JobScheduler Only pass if the path contains a Telligent Community Job Server, not a website #> [CmdletBinding(DefaultParameterSetName='Either')] param( [parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [AllowEmptyString()] [string]$Path, [switch]$AllowEmpty, [parameter(ParameterSetName='Valid', Mandatory=$true)] [switch]$IsValid, [parameter(ParameterSetName='Web', Mandatory=$true)] [switch]$Web, [parameter(ParameterSetName='JobScheduler', Mandatory=$true)] [switch]$JobScheduler ) if(!($Path)) { if(!$AllowEmpty) { throw 'Argument must not be null' } } elseif ($IsValid) { if (!(Test-Path $Path -PathType Container -IsValid -ErrorAction SilentlyContinue)) { throw "'$Path' is not a valid path" } } else { if (!(Test-Path $Path -PathType Container -ErrorAction SilentlyContinue)) { throw "'$Path' does not exist" } if (!(Join-Path $Path communityserver.config | Test-Path -ErrorAction SilentlyContinue)) { throw "'$Path' does not contain a valid Telligent Community community" } if ($Web -and !(Join-Path $Path web.config | Test-Path -ErrorAction SilentlyContinue)) { throw "'$Path' does not contain a valid Telligent Community website" } elseif ($JobScheduler -and !((Join-Path $Path Telligent.JobScheduler.Service.exe | Test-Path) -or (Join-Path $Path Telligent.Jobs.Server.exe | Test-Path))) { throw "'$Path' does not contain a valid Telligent Community Job Server" } } return $true } function Set-ConnectionString { <# .SYNOPSIS Sets the Connection Strings in the .net configurationf ile .PARAMETER WebsitePath The path to the application you want to set connection strings for .PARAMETER Server The SQL Server the connection string will point to .PARAMETER Database The database to use .PARAMETER SqlCredentials If using SQL Authenticaiton, specifies the username nad password to use in the connection string. If not specified, the connection string uses Integrated Security. .PARAMETER ConfigurationFile The configuration file to set the connection strings in. .PARAMETER ConnectionStringName The name of the connection string to set. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true)] [string]$Name, [Parameter(Mandatory=$true)] [string]$Value, [string]$ConfigurationFile = 'connectionstrings.config' ) $path = Join-Path $WebsitePath $ConfigurationFile | Resolve-Path | select -ExpandProperty ProviderPath $connectionStrings = [xml](gc $path) $connectionStrings.connectionStrings.add | ? { $_.name -eq $Name} | % { $_.connectionString = $Value} $connectionStrings.Save($path) } function Set-DatabaseConnectionString { <# .SYNOPSIS Sets the Connection Strings in the .net configurationf ile .PARAMETER WebsitePath The path to the application you want to set connection strings for .PARAMETER Server The SQL Server the connection string will point to .PARAMETER Database The database to use .PARAMETER SqlCredentials If using SQL Authenticaiton, specifies the username nad password to use in the connection string. If not specified, the connection string uses Integrated Security. .PARAMETER ConfigurationFile The configuration file to set the connection strings in. .PARAMETER ConnectionStringName The name of the connection string to set. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [alias('ServerInstance')] [string]$Server, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Database, [PSCredential]$SqlCredentials ) if ($SqlCredentials){ $connectionString = "Server=$Server;Database=$Database;uid=$($SqlCredentials.UserName);pwd=$($SqlCredentials.Password);" } else { $connectionString = "Server=$Server;Database=$Database;Trusted_Connection=yes;" } Set-ConnectionString $WebsitePath -Name 'SiteSqlServer' -Value $connectionString } function Get-ConnectionString { <# .SYNOPSIS Sets the Connection Strings in the .net configurationf ile .PARAMETER Database The database .PARAMETER Server The SQL Server the connection string will point to .PARAMETER SqlCredentials If using SQL Authenticaiton, specifies the username nad password to use in the connection string. If not specified, the connection string uses Integrated Security. .PARAMETER ConfigurationFile The configuration file containing the connection string to read. .PARAMETER ConnectionStringName The name of the connection string to set. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$Directory, [ValidateScript({Test-Path $_ -PathType Leaf})] [string]$ConfigurationFile = 'connectionStrings.Config', [string]$ConnectionStringName = 'SiteSqlServer' ) #Load connection string info $connectionStrings = [xml](get-content (Join-Path $Directory $ConfigurationFile) -ErrorAction SilentlyContinue) $siteSqlConnectionString = $connectionStrings.connectionStrings.add | ? name -eq $ConnectionStringName | select -ExpandProperty connectionString if(!$siteSqlConnectionString) { Write-Error "'$ConnectionStringName' connection string not found in $ConfigFile" } try { $connectionString = New-Object System.Data.SqlClient.SqlConnectionStringBuilder $siteSqlConnectionString -EA SilentlyContinue } catch{} $connectionInfo = @{ ServerInstance = $connectionString.DataSource Database = $connectionString.InitialCatalog } if(!$connectionString.IntegratedSecurity) { $connectionInfo.Username = $connectionString.UserID $connectionInfo.Password = $connectionString.Password } $connectionInfo } function Get-ConnectionStrings { <# .SYNOPSIS Gets the values from the ConnectionStrings file for a community. .PARAMETER Path The path to the community's Website or Job Scheduler. .PARAMETER FileName The name of the connection strings file to open #> param( [ValidateNotNullOrEmpty()] [string]$Path, [string]$ConfigurationFile = 'connectionstrings.config' ) $config = @{} ([xml](Get-Content (Join-Path $Path "$ConfigurationFile"))).connectionStrings.add |% { $config[$_.name] = $_.connectionString } $config } function New-CommunityApiKey { <# .SYNOPSIS Creates a new REST API Key .PARAMETER ApiKey The API Key to Create .PARAMETER Name The name for the API Key. .PARAMETER UserId The User to create the API Key for .PARAMETER WebsitePath The path of the Telligent Community website. If not specified, defaults to the current directory. #> [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true)] [ValidatePattern('^[a-z0-9]+$')] [string]$ApiKey, [ValidateNotNullOrEmpty()] [string]$Name = 'Auto Generated', [ValidatePattern('^[a-z0-9\-\._ ]+$')] [int]$UserId= 2100 ) $createApiKey = "INSERT INTO [dbo].[cs_ApiKeys] ([UserID],[Value],[Name],[DateCreated],[Enabled]) VALUES ($UserId,'$ApiKey','$Name',GETDATE(), 1)" Invoke-TelligentSqlCmd $WebsitePath -Query $createApiKey } function Add-TelligentOverrideChangeAttribute { <# .SYNOPSIS Adds a Change entry to the communityserver_override.config .PARAMETER XPath The XPath for the element containing the attribute to manipulate .PARAMETER Name The Name of the node to modify .PARAMETER Value The new value of the node .PARAMETER WebsitePath The path of the Telligent Community website. If not specified, defaults to the current directory. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$XPath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Name, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Value ) #TODO: Look at original config file to ensure XPath & Node exist $overridePath = join-path $WebsitePath communityserver_override.config if (!(test-path $overridePath)) { '<?xml version="1.0" ?><Overrides />' |out-file $overridePath } $overrides = [xml](gc $overridePath) $override = $overrides.CreateElement('Override') $override.SetAttribute('xpath', $XPath) $override.SetAttribute('mode', 'change') $override.SetAttribute('name', $Name) $override.SetAttribute('value', $Value) $overrides.DocumentElement.AppendChild($override) |out-null $overrides.Save(($overridePath | Resolve-Path).ProviderPath) } function Set-TelligentFilestorage { <# .SYNOPSIS Sets the Filestorage location for a Telligent Community .PARAMETER WebsitePath The path of the Telligent Community website. .PARAMETER FilestoragePath The Filestorage Location to use. The Filestorage should already have been moved to this location. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_ -PathType Container})] [string]$FilestoragePath ) $version = Get-TelligentCommunity $WebsitePath | select -ExpandProperty PlatformVersion if ($Version.Major -ge 10) { Set-ConnectionString $WebsitePath -Name FileStorage -Value $FilestoragePath } else { Add-TelligentOverrideChangeAttribute $WebsitePath ` -XPath "/CommunityServer/CentralizedFileStorage/fileStoreGroup[@name='default']" ` -Name basePath ` -Value $FilestoragePath } } function Set-TelligentSolrUrl { <# .SYNOPSIS Updates the Search Url used by the Telligent Community in the current directory .PARAMETER Url The url of the Solr instance to use .PARAMETER WebsitePath The path of the Telligent Community website. If not specified, defaults to the current directory. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true, ValueFromPipeline=$true)] ##No longer works for solr 4.0 #[ValidateScript({Invoke-WebRequest ($_.AbsoluteUri.TrimEnd('/') + "/admin/") -Method HEAD -UseBasicParsing})] [ValidateNotNullOrEmpty()] [uri]$Url ) $version = Get-TelligentCommunity $WebsitePath | select -ExpandProperty PlatformVersion Write-Progress "Configuration" "Updating Solr Url" if ($Version.Major -ge 10) { Set-ConnectionString $WebsitePath -Name SearchContentUrl -Value $Url Set-ConnectionString $WebsitePath -Name SearchConversationsUrl -Value $Url } else{ Add-TelligentOverrideChangeAttribute ` -XPath /CommunityServer/Search/Solr ` -Name host ` -Value $Url ` -WebsitePath $WebsitePath } } function Install-TelligentLicense { <# .SYNOPSIS Installs a License file into a Telligent Community .PARAMETER LicenseFile The XML License file .PARAMETER WebsitePath The path of the Telligent Community website. If not specified, defaults to the current directory. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_ -PathType Leaf})] [string]$LicenseFile ) $LicenseContent = (gc $LicenseFile) -join [Environment]::NewLine $LicenseId = ([xml]$LicenseContent).document.licenseId $sql = @" delete from cs_Licenses GO insert into cs_Licenses (LicenseID, LicenseValue, InstallDate) values ('$LicenseId', N'$LicenseContent', getdate()) "@ Invoke-TelligentSqlCmd -WebsitePath $WebsitePath -Query $sql } function Disable-CustomErrors { <# .SYNOPSIS Disables Custom Errors for the ASP.Net website in the specified directory .PARAMETER WebsitePath The path of the ASP.Net Web Application. If not specified, defaults to the current directory. .EXAMPLE Disable-CustomErrors #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath ) Write-Warning 'Disabling Custom Errors poses a security risk. Only do this in non production environments' $configPath = Join-Path $WebsitePath web.config | Resolve-Path $webConfig = [xml] (get-content $configPath ) $webConfig.configuration.{system.web}.customErrors.mode = 'Off' $webConfig.Save($configPath) } function Enable-DeveloperMode { <# .SYNOPSIS Enables developer mode for Telligent Community 9.x and above .PARAMETER WebsitePath The path of the ASP.Net Web Application. If not specified, defaults to the current directory. .EXAMPLE Enable-DeveloperMode #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath ) $configPath = Join-Path $WebsitePath web.config | Resolve-Path $webConfig = [xml] (Get-Content $configPath ) $webConfig.configuration.appSettings.add | ? { $_.key -eq 'EnableDeveloperMode'} | % { $_.value = 'true'} $webConfig.Save($configPath) } function Enable-InternalJobs { <# .SYNOPSIS Enables job server to run as an internal process of the website. .PARAMETER WebsitePath The path of the ASP.Net Web Application. If not specified, defaults to the current directory. .EXAMPLE Enable-InternalJobs #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath ) $configPath = Join-Path $WebsitePath web.config | Resolve-Path $webConfig = [xml] (Get-Content $configPath ) $jobSection = [xml]'<add key="RunJobsInternally" value="true" />' $webConfig.configuration.appSettings.AppendChild($webConfig.ImportNode($jobSection.DocumentElement, $true)) | out-null $webConfig.Save($configPath) } function Enable-TelligentWindowsAuth { <# .SYNOPSIS Configures IIS to use Windows Authentication for the ASP.Net website in the current directory .PARAMETER AdminWindowsGroup The name of the windows group who should be automatically made Administrators in the community. Defaults to the local Administrators group. .PARAMETER EmailDomain The email domain to append to a user's username to get their email address if it's not found in Active Directory (USERNAME@EmailDomain). .PARAMETER ProfileRefreshInterval The interval (in days) at which a user's profile should be updated. .PARAMETER WebsitePath The path of the Telligent Community website. If not specified, defaults to the current directory. #> [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [ValidateNotNullOrEmpty()] [string]$AdminWindowsGroup = "$env:ComputerName\Administrators", [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$EmailDomain, [ValidateNotNullOrEmpty()] [byte]$ProfileRefreshInterval = 7 ) $configPath = Join-Path $WebsitePath web.config | resolve-path $webConfig = [xml] (get-content $configPath ) $webConfig.configuration.{system.web}.authentication.mode = 'Windows' $webConfig.Save($configPath) Add-TelligentOverrideChangeAttribute $WebsitePath ` -XPath /CommunityServer/Core/extensionModules ` -Name enabled ` -Value true @{ adminWindowsGroup = $AdminWindowsGroup; emailDomain = "@$($EmailDomain.TrimStart('@'))"; profileRefreshInterval = $ProfileRefreshInterval }.GetEnumerator() |%{ Add-TelligentOverrideChangeAttribute $WebsitePath ` -XPath "/CommunityServer/Core/extensionModules/add[@name='WindowsAuthentication']" ` -Name $_.Key ` -Value $_.Value } #If the following fails, ensure default .net version in IIS is set to 4.0 Get-IISWebsite $WebsitePath |% { Set-WebConfigurationProperty -Filter /system.webServer/security/authentication/* ` -Name enabled ` -Value false ` -PSPath IIS:\ ` -Location $_.Name Set-WebConfigurationProperty -Filter /system.webServer/security/authentication/windowsAuthentication ` -Name enabled ` -Value true ` -PSPath IIS:\ ` -Location $_.Name } } function Enable-TelligentLdap { <# .SYNOPSIS Enables LDAP integration in a Telligent Community .PARAMETER WebsitePath The path of the Telligent Community website. If not specified, defaults to the current directory. .PARAMETER Server The server to use for LDAP. Defaults to the Global Catalog of the AD Forest the server is in. .PARAMETER AuthenticationType The email domain to append to a user's username to get their email address if it's not found in Active Directory (USERNAME@EmailDomain). .PARAMETER Port The port to connect to ldap. Defaults to the Global Catalog port. .PARAMETER Username The username port to connect to ldap with . Defaults to the credntials of Application Pool Identiy. .PARAMETER Password The password port to connect to ldap with . Defaults to the credntials of Application Pool Identiy. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-TelligentPath $_ })] [string]$WebsitePath, [string]$Server = 'GC://', [string]$AuthenticationType = 'Secure', [int]$Port = 3268, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Username, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Password ) #Install Package $packagesPath = join-Path $WebsitePath packages.config | Resolve-Path $packages = [xml](gc $packagesPath) $date = get-date -format yyyy-MM-dd $package = [xml]"<Package Name=""Ldap"" Version=""1.0"" DateInstalled=""$date"" Id=""4BF1091D-376C-42b2-B375-E2FE9480E845"" />" $packages.DocumentElement.AppendChild($packages.ImportNode($package.DocumentElement, $true)) | out-null $packages.Save($packagesPath) #Configure Web.config $webConfigPath = Join-Path $WebsitePath web.config | resolve-path $webConfig = [xml] (get-content $webConfigPath ) $ldapSection = [xml]'<section name="LdapConnection" type="System.Configuration.NameValueSectionHandler" />' $webConfig.configuration.configSections.AppendChild($webConfig.ImportNode($ldapSection.DocumentElement, $true)) | out-null $ldapConfiguration= $webConfig.CreateElement("LdapConnection") @{ Server=$Server Port=$Port UserDN=$Username Password = $Password Authentication = $AuthenticationType }.GetEnumerator() |% { $add = $ldapConfiguration.OwnerDocument.CreateElement("add") $add.SetAttribute('key', $_.Key) $add.SetAttribute('value', $_.Value) $ldapConfiguration.AppendChild($add) | out-null } $webConfig.configuration.AppendChild($ldapConfiguration) | out-null $webConfig.Save($webConfigPath) } |