# Params Param ( # Install typical tools [bool] $InstallTools = ##INST_TOOLS, # Install SQL Server Express [bool] $InstallSQLServer = ##INST_SQL ) # Import Modules Import-Module ServerManager # Setup variables $rootUrl = "https://mimsprereqs.sspinnovations.com/lifecycle/2020/" $loggedinuser=$env:username # Gets the Windows Server version Function Get-Windows-Version { $osversion = [Environment]::OSVersion.Version If($osversion.Major -eq 6) { If($osversion.Minor -eq 1) { Return 2008 } If($osversion.Minor -eq 3) { Return 2012 } } ElseIf($osversion.Major -eq 10) { If($osversion.Build -eq 14393) { Return 2016 } If($osversion.Build -eq 17763) { Return 2019 } } Return 0 } # This Lifecycle script only works with Server 2008 and above # check if we have an OS version that or above Function Can-Install-Lifecycle { $osversion = [Environment]::OSVersion.Version Write-Host "OS Full Version is : '$osversion'" If($osversion.Major -lt 6) { Return $False } Return $True } # Determine if .NET 4.5 can be installed as an OS feature # or if we have to download and install it Function Asp-Net45-OS { $osversion = [Environment]::OSVersion.Version If($osversion.Minor -gt 1) { Return $True } Return $False } # Add a path to the system path Function AddTo-SystemPath { Param( [array]$PathToAdd ) $VerifiedPathsToAdd = $Null Foreach($Path in $PathToAdd) { if($env:Path -like "*$Path*") { Write-Host "Current item in path is: $Path" Write-Host "$Path already exists in Path statement" } else { $VerifiedPathsToAdd += ";$Path" Write-Host "`$VerifiedPathsToAdd updated to contain: $Path"} if($VerifiedPathsToAdd -ne $null) { Write-Host "`$VerifiedPathsToAdd contains: $verifiedPathsToAdd" Write-Host "Adding $Path to Path statement now..." [Environment]::SetEnvironmentVariable("Path",$env:Path + $VerifiedPathsToAdd,"Process") } } } # Runs the specified application with the arguments provided # and waits on it to finish Function Run-Application([string]$app, [string]$arglist) { Write-Host "Running '$app' with args '$arglist'..." $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $app #$pinfo.RedirectStandardError = $true #$pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arglist $pinfo.Verb = "runas"; $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() } # Sets the users permissions on the folder so they can write to it Function Set-UserPermissions([string]$folder) { Write-Host "Setting permissions on '$folder'" $acl = Get-Acl $folder $permission = "BUILTIN\Users","FullControl","Allow" $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission $acl.SetAccessRule($accessRule) $acl | Set-Acl $folder } # Add a local group Function Add-LocalGroup([string]$groupName) { net localgroup /add $groupName } # Add a user to a local group Function Add-UserToLocalGroup([string]$groupName, [string]$userDomain, [string]$userName) { Write-Host "Adding user '$userName' of domain '$userDomain' to group '$groupName'" net localgroup "$groupName" "$userDomain\$userName" /add } # Create Lifecycle Database Function Create-LifecycleDatabaseAndUser() { $databaseFile = "C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\lifecycle.mdf" $sqlCommandExe = "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd.exe" If (Test-Path $databasefile) { Write-Host "Lifecycle database already exists at '$databaseFile'" } Else { $tempFile = [IO.Path]::GetTempFileName() add-content -path $tempFile -value ((new-object net.webclient).DownloadString($rootUrl + "create_database_and_user.sql")) Run-Application $sqlCommandExe "-S localhost\SQLEXPRESS -U sa -P 123QWEasd -i $tempFile" Remove-Item $tempFile } } # Create Lifecycle Database Function Download-LifecycleContext() { $programData = $Env:ProgramData $configurationFolder = Join-Path $programData "Lifecycle\Configuration" $connectionFile = Join-Path $configurationFolder "LifecycleContextConnection.xml" $connectionOpenFile = Join-Path $configurationFolder "LifecycleContextOpenConnection.xml" If (Test-Path $connectionFile) { Write-Host "Lifecycle Db context file already exists at '$connectionFile'" } Else { $tempFile = [IO.Path]::GetTempFileName() add-content -path $tempFile -value ((new-object net.webclient).DownloadString($rootUrl + "LifecycleContextOpenConnection.xml")) if (!(Test-Path -path $configurationFolder)) {New-Item $configurationFolder -Type Directory} Copy-Item $tempFile $connectionOpenFile Remove-Item $tempFile Set-UserPermissions $configurationFolder } } # Install the OS required components Function Install-OS-Components([int] $windowsVersion) { If ($windowsVersion -eq 2019) { # Make sure that .NET is installed Install-WindowsFeature NET-HTTP-Activation,NET-WCF-HTTP-Activation45,NET-Framework-45-Core,NET-Framework-45-ASPNET # Make sure that IIS is installed properly Install-WindowsFeature Web-Server,Web-WebServer,Web-Metabase,Web-Performance,Web-Stat-Compression,Web-Dyn-Compression,Web-Windows-Auth,Web-Basic-Auth,Web-Asp-Net45,Web-Asp-Net,Web-Net-Ext45,Web-Net-Ext # Install UI components Install-WindowsFeature Web-Mgmt-Console } ElseIf ($windowsVersion -eq 2016) { # Make sure that .NET is installed Install-WindowsFeature NET-HTTP-Activation,NET-WCF-HTTP-Activation45,NET-Framework-45-Core,NET-Framework-45-ASPNET # Make sure that IIS is installed properly Install-WindowsFeature Web-Server,Web-WebServer,Web-Metabase,Web-Performance,Web-Stat-Compression,Web-Dyn-Compression,Web-Windows-Auth,Web-Basic-Auth,Web-Asp-Net45,Web-Asp-Net,Web-Net-Ext45,Web-Net-Ext # Install UI components Install-WindowsFeature Web-Mgmt-Console } ElseIf($windowsVersion -eq 2012) { # Make sure that .NET is installed Install-WindowsFeature Application-Server,NET-Framework-Core,NET-HTTP-Activation,NET-Non-HTTP-Activ,AS-NET-Framework,AS-WAS-Support,AS-HTTP-Activation # Make sure that IIS is installed properly Install-WindowsFeature Web-Server,Web-WebServer,Web-Mgmt-Console,Web-Metabase,Web-Performance,Web-Stat-Compression,Web-Dyn-Compression,Web-Windows-Auth,Web-Basic-Auth,Web-Asp-Net45,Web-Asp-Net,Web-Net-Ext45,Web-Net-Ext } } # Write out the start time $startdate=Get-Date Write-Host "Starting at '$startdate'" # Write out the configuration we are using Write-Host "Script called with InstallTools='$InstallTools' and InstallSQLServer='$InstallSQLServer'" # Check we are running with elevated permissions $myIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $wp = New-Object Security.Principal.WindowsPrincipal($myIdentity) if (-not $wp.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) { Write-Host "This script requires administrative privileges, please re-launch with elevated credentials" -ForegroundColor Red Return } # Can we install Lifecycle on this OS? $caninstall = Can-Install-Lifecycle If ($caninstall -eq $False) { # Can't install, inform the user and exit Write-Host "Unable to install Lifecycle on this operating system" -ForegroundColor Red Return } #Collection of installed preReqs $installedPreReqs = New-Object 'System.Collections.Generic.List[string]' # Figure out what Windows OS we have $windowsVersion = Get-Windows-Version # Detect if ASP.NET 4.5 is part of the OS features # (regardless if it is installed or not) $net45inos = Asp-Net45-OS # Install OS components (twice to get over some reference bug!) Install-OS-Components $windowsVersion Install-OS-Components $windowsVersion $installedPreReqs.Add("Windows Web Server"); $installedPreReqs.Add("Windows Application Server"); #Download and Install Chocolatey iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) # Setup the paths to chocolatey folders $chocolatey = Join-Path $env:ALLUSERSPROFILE "\chocolatey" $chocolateybin = Join-Path $chocolatey "bin" $chocolateylib = Join-Path $chocolatey "lib" Write-Host "Using $chocolatey for installation..." # Add bin path to system path AddTo-SystemPath($chocolateybin) # Install Helper Apps $chocolateyinst = Join-Path $chocolateybin "cinst.exe" $chocolateyexe = Join-Path $chocolateybin "choco.exe" # Are we installing some standard tools? If ($InstallTools -eq $True) { Run-Application $chocolateyexe "install notepadplusplus.install -y --allow-empty-checksums" $installedPreReqs.Add("Notepad ++"); Run-Application $chocolateyexe "install 7zip.install -y --allow-empty-checksums" $installedPreReqs.Add("7-Zip"); } Run-Application $chocolateyexe "install sqlserver-cmdlineutils -y --allow-empty-checksums " Run-Application $chocolateyexe "install install iisnode --version=0.2.26 -y --allow-empty-checksums" Run-Application $chocolateyexe "install urlrewrite -y --allow-empty-checksums" Run-Application $chocolateyexe "install nodejs -y --allow-empty-checksums" # Install .NET 4.6 Run-Application $chocolateyinst "-y --allow-empty-checksums dotnet4.6" # Are we installing SQL Server? If ($InstallSQLServer -eq $True) { # Install C++ redist Run-Application $chocolateyinst "-y vcredist2008" Run-Application $webpiexe "/Install /Products:SQLExpress /SQLPassword:123QWEasd /AcceptEula" Run-Application $webpiexe "/Install /Products:SQLManagementStudio /AcceptEula" $installedPreReqs.Add("SQL Server Express 2008 R2 and Tools"); Create-LifecycleDatabaseAndUser Download-LifecycleContext } #Download the results template to file $tempFile = [IO.Path]::GetTempFileName() $tempFile = [IO.path]::ChangeExtension($tempFile,".html") add-content -path $tempFile -value ((new-object net.webclient).DownloadString($rootUrl + "results_template.html")) #Update the template with the installed items (and their versions) $template_content = [IO.File]::ReadAllText($tempFile) # Are we installing SQL Server? If ($InstallSQLServer -eq $False) { $template_content = $template_content -replace "sqlserver_installed = true", "sqlserver_installed = false" } #Generate a string for the installed pre-requisites $preReqsString = ""; foreach($prereq in $installedPreReqs) { if($preReqsString -eq "") { $preReqsString = $prereq; } else { $preReqsString = [string]::Format("{0}|{1}", $preReqsString, $prereq); } } $template_content = $template_content -replace "%%INSTALLEDPREREQS%%", $preReqsString set-content $tempFile $template_content $programData = $Env:ProgramData $prerequisitesFolder = Join-Path $programData "Lifecycle\Prerequisites" $prerequisitesFile = Join-Path $prerequisitesFolder "LifecyclePrerequisitesResult.html" if (!(Test-Path -path $prerequisitesFolder)) {New-Item $prerequisitesFolder -Type Directory} Copy-Item $tempFile $prerequisitesFile -Force Remove-Item $tempFile #Show the generated results file Invoke-Item $prerequisitesFile # Write out the start time $enddate = Get-Date $timespan = New-TimeSpan -Start $startdate -End $enddate Write-Host "Complete at '$enddate' and took $timespan" # All done Write-Host "Installation of pre-requisites is complete!" -foregroundcolor Green