Skip to content

Instantly share code, notes, and snippets.

@pstephens
Last active December 28, 2015 06:59
Show Gist options
  • Save pstephens/7460763 to your computer and use it in GitHub Desktop.
Save pstephens/7460763 to your computer and use it in GitHub Desktop.
Node.js bootstrapper in PowerShell.
$nodeUrl = "http://nodejs.org/dist/v0.10.22/x64/node-v0.10.22-x64.msi"
$nodeSha = "c3c169304c6371ee7bd119151bcbced61a322394"
function DownloadIt($url, $path)
{
Start-BitsTransfer -Source $url -Destination $path
}
function TestHash($path, $sha)
{
$bytes = [System.IO.File]::ReadAllBytes($path)
$hasher = [System.Security.Cryptography.SHA1]::Create()
$hash = $hasher.ComputeHash($bytes)
$hasher.Dispose()
$hashAsHex = ($hash.GetEnumerator() | Foreach-Object { "{0:x2}" -f $_ }) -Join ""
if($hashAsHex -ne $sha) {
throw "Hash for '$path' is incorrect. Was '$hashAsHex' but should be '$sha'."
}
}
function IsElevated()
{
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).
IsInRole([Security.Principal.WIndowsBuiltInRole]::Administrator)
}
function ElevateIfNecessary([ScriptBlock]$script, $workingDirectory)
{
if(!(IsElevated)) {
Write-Host "Elevating..."
Start-Process "$PSHome\powershell" `
-Verb runAs `
-Wait `
-ArgumentList "-ExecutionPolicy unrestricted -NoProfile -Command & { Set-Location $workingDirectory; $script }"
}
else
{
Push-Location $workingDirectory
try
{
& $script
}
finally
{
Pop-Location
}
}
}
function FindPath($paths)
{
foreach($path in $paths)
{
if(Test-Path $path)
{
$resolvedPaths = @(Resolve-Path $path)
if($resolvedPaths.Length -gt 1)
{
throw "Too many files match '$path'."
}
return $resolvedPaths[0]
}
}
throw "Failed to find a match for paths '$($paths -join ", ")'."
}
function RunNPM($cmdline)
{
$npmPath = FindPath "$env:ProgramFiles\nodejs\npm.cmd"
$p = (Start-Process $npmPath -ArgumentList $cmdline -NoNewWindow -Wait -PassThru)
if($p.ExitCode -ne 0)
{
throw "NPM returned nonzero exit code: $($p.ExitCode)"
}
}
function FixupEnvironment
{
$pathParts = $env:Path -split ";"
$pathParts += [System.Environment]::GetEnvironmentVariable("Path", "Machine") -split ";"
$pathParts += [System.Environment]::GetEnvironmentVariable("Path", "User") -split ";"
$pathParts = $pathParts | Where { ![string]::IsNullOrWhitespace($_) } | Select-Object -Unique
$env:Path = $pathParts -join ";"
}
try
{
# Configure directories and paths
$thisScript = $MyInvocation.MyCommand.Path
$curDir = Split-Path $thisScript
$tempDir = Join-Path $curDir NodeTemp
$nodeMsi = Join-Path $tempDir "node.msi"
if(!(Test-Path $tempDir)) {
New-Item $tempDir -ItemType Directory | Out-Null
}
Get-ChildItem $tempDir -exclude node.msi | Remove-Item
if(!(Test-Path $nodeMsi))
{
Write-Host "Downloading Node.js..."
DownloadIt $nodeUrl $nodeMsi
}
Write-Host "Verifying Node.js installer hash..."
TestHash $nodeMsi $nodeSha
ElevateIfNecessary {
try {
Write-Host 'Uninstalling Node.js (if needed)...'
Start-Process msiexec -ArgumentList '/x Node.msi /quiet /l* uninstall.log' -NoNewWindow -Wait
Write-Host 'Installing Node.js...'
$p = (Start-Process msiexec -ArgumentList '/i Node.msi /quiet /l* install.log' -NoNewWindow -Wait -PassThru)
$p.ExitCode | Set-Content MsiExecExitCode.txt
} catch {
$_ | Set-Content ElevatedError.txt
$_
}
} $tempDir
# Check the results from msiexec
$elevatedErrorPath = Join-Path $tempDir ElevatedError.txt
if(Test-Path $elevatedErrorPath) {
throw "Failed in elevated shell: $(Get-Content $elevatedErrorPath)"
}
$msiExecExitCode = [int](Get-Content (Join-Path $tempDir MsiExecExitCode.txt))
if($msiExecExitCode -ne 0)
{
throw "Failed while running msiexec with exit code $msiExecExitCode."
}
Write-Host "Installing jslint..."
RunNPM "install jslint"
Write-Host "Fixing up local environment Path..."
FixupEnvironment
Write-Host "Successfully installed Node.js."
}
catch
{
throw $_
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment