Created
September 26, 2016 11:36
-
-
Save JanLenoch/57fc76ab68478fa529e0805646e0b7ee to your computer and use it in GitHub Desktop.
Get Near-Zero Load Time in Both Development and Production
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$Paths = @("C:\inetpub\wwwroot\Kentico9InVirtualApplication\CMS\;1;/Kentico9App", "C:\inetpub\Kentico9InSite\CMS\;2") | |
$ScriptBlockBase = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe -m LM/W3SVC/" | |
$JobNamePrefix = "KenticoPrecompilationJob" | |
$ConfirmPreference = "none" | |
# The self-elevaing logic was developed by Jonathan Bennett: https://www.autoitscript.com/forum/topic/174609-powershell-script-to-self-elevate/ | |
# Test if admin | |
function Test-IsAdmin() | |
{ | |
# Get the current ID and its security principal | |
$windowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent() | |
$windowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($windowsID) | |
# Get the Admin role security principal | |
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator | |
# Are we an admin role? | |
if ($windowsPrincipal.IsInRole($adminRole)) | |
{ | |
$true | |
} | |
else | |
{ | |
$false | |
} | |
} | |
# Get UNC path from mapped drive | |
function Get-UNCFromPath | |
{ | |
Param( | |
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] | |
[String] | |
$Path) | |
if ($Path.Contains([io.path]::VolumeSeparatorChar)) | |
{ | |
$psdrive = Get-PSDrive -Name $Path.Substring(0, 1) -PSProvider 'FileSystem' | |
# Is it a mapped drive? | |
if ($psdrive.DisplayRoot) | |
{ | |
$Path = $Path.Replace($psdrive.Name + [io.path]::VolumeSeparatorChar, $psdrive.DisplayRoot) | |
} | |
} | |
return $Path | |
} | |
# Relaunch the script if not admin | |
function Invoke-RequireAdmin | |
{ | |
Param( | |
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] | |
[System.Management.Automation.InvocationInfo] | |
$MyInvocation) | |
if (-not (Test-IsAdmin)) | |
{ | |
# Get the script path | |
$scriptPath = $MyInvocation.MyCommand.Path | |
if ($scriptPath -eq "" -or $scriptPath -eq $null) | |
{ | |
$scriptPath = (Get-Location).Path | |
} | |
$scriptPath = Get-UNCFromPath -Path $scriptPath | |
# Need to quote the paths in case of spaces | |
$scriptPath = '"' + $scriptPath + '"' | |
# Build base arguments for powershell.exe | |
[string[]]$argList = @('-NoLogo -NoProfile', '-ExecutionPolicy Bypass', '-File', $scriptPath) | |
# Add | |
$argList += $MyInvocation.BoundParameters.GetEnumerator() | Foreach {"-$($_.Key)", "$($_.Value)"} | |
$argList += $MyInvocation.UnboundArguments | |
try | |
{ | |
$process = Start-Process PowerShell.exe -PassThru -Verb Runas -Wait -WorkingDirectory $pwd -ArgumentList $argList | |
exit $process.ExitCode | |
} | |
catch {} | |
# Generic failure code | |
exit 1 | |
} | |
} | |
# Relaunch if not admin | |
Invoke-RequireAdmin $script:MyInvocation | |
# Here comes the precompilation logic | |
$Jobs = @() | |
function Build-MetabasePath($P) | |
{ | |
$Split = $Path -split ";" | |
if ($Split[2] -eq $null) | |
{ | |
return $Split[1] + "/ROOT" | |
} | |
else | |
{ | |
return $Split[1] + "/ROOT" + $Split[2] | |
} | |
} | |
$PathsArrayList = New-Object System.Collections.ArrayList | |
foreach ($Path in $Paths) | |
{ | |
$PathsArrayList.Add($Path) | |
$PathSplit = Build-MetabasePath($Path) | |
Write-Host "" | |
Write-Host ("Starting a precompilation job for the IIS metabase path: LM/W3SVC/" + $PathSplit) -ForegroundColor Cyan | |
Write-Host "" | |
$PhysicalPath = $Path -split ";" | Select-Object -First 1 | |
[ScriptBlock]$ScriptBlock = [ScriptBlock]::Create($ScriptBlockBase + $PathSplit) | |
Start-Job -ScriptBlock $ScriptBlock -Name ($JobNamePrefix + $PathSplit.Replace("/", "-")) | |
} | |
Start-Sleep -Seconds 5 | |
while (Get-Job | ? {$_.Name.Contains($JobNamePrefix)}) | |
{ | |
Get-Job | ? {$_.Name.Contains($JobNamePrefix) -and $_.State -eq "Completed"} | Remove-Job | |
if (Get-Job | ? {$_.Name.Contains($JobNamePrefix) -and ($_.State -eq "NotStarted" -or $_.State -eq "Running") -or $_.State -eq "Completed"}) | |
{ | |
Start-Sleep -Seconds 1 | |
continue | |
} | |
elseif (Get-Job | ? {$_.Name.Contains($JobNamePrefix) -and $_.State -ne "NotStarted" -and $_.State -ne "Running" -and $_.State -ne "Completed"}) | |
{ | |
for ($X = $PathsArrayList.Count - 1; $X -ge 0; $X--) | |
{ | |
$PathSplit = Build-MetabasePath($PathsArrayList[$X]) | |
$JobName = ($JobNamePrefix + $PathSplit.Replace("/", "-")) | |
Write-Host "" | |
Write-Host ("Collecting the output of a precompilation job" + $JobName + " (IIS metabase path: LM/W3SVC/" + $PathSplit + "):") -ForegroundColor Gray | |
Receive-Job -Name $JobName | |
$CurrentJob = Get-Job -Name $JobName | |
if ($CurrentJob.State -ne "Completed") | |
{ | |
Write-Host "" | |
Write-Host "The job" $JobName "hasn't probably finished correctly. Do you wish to delete the job?" -ForegroundColor Yellow | |
$Answer = Read-Host "If not, you can restart the job using the Start-Job cmdlet, press 'n' and hit Enter. If you wish to delete it, press 'y' and hit Enter" | |
if ($Answer -eq "y") | |
{ | |
Remove-Job -Name $JobName | |
$PathsArrayList.Remove($PathsArrayList[$X]) | |
} | |
else | |
{ | |
Write-Host "You've chosen not to delete the" $JobName "job. If the job doesn't finish correctly, you will be able to remove it once it fails or using the Remove-Job cmdlet." -ForegroundColor Gray | |
} | |
} | |
else | |
{ | |
Remove-Job -Name $JobName | |
} | |
} | |
} | |
else | |
{ | |
# Handling undesired infinite looping here | |
break | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment