Skip to content

Instantly share code, notes, and snippets.

@JanLenoch
Created September 26, 2016 11:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JanLenoch/57fc76ab68478fa529e0805646e0b7ee to your computer and use it in GitHub Desktop.
Save JanLenoch/57fc76ab68478fa529e0805646e0b7ee to your computer and use it in GitHub Desktop.
Get Near-Zero Load Time in Both Development and Production
$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