$global:config = @{}

function log($msg) {

$timestamp = Get-Date -Format "[yyyy-MM-dd hh:mm:ss]"
add-content "$($config['CHEF_PS_LOG'])" "$timestamp $msg"

}

function msi_url() {

$machine_os = $config['CHEF_MACHINE_OS']
$machine_arch = $config['CHEF_MACHINE_ARCH']
$download_context = $config['CHEF_DOWNLOAD_CONTEXT']
$version = $config['CHEF_VERSION']
$msi_url = $config['CHEF_REMOTE_SOURCE_MSI_URL']

if ($version -eq $null) { $version = '&v=latest' }

if ($msi_url.length -gt 4) {
  $msi_url
} else {
  $url = "https://www.chef.io/chef/download?p=windows"
  if ($machine_os -ne $null) { $url += "&pv=$($machine_os)" }
  if ($machine_arch -ne $null) { $url += "&m=$($machine_arch)" }
  if ($download_context -ne $null) { $url += "&DownloadContext=$($download_context)" }
  $url += $version
  $url
}

}

function report_status($exitcode) {

set-content "$($config['CHEF_PS_EXITCODE'])" "$exitcode"

}

function ps_exit() {

Start-Sleep 5
while (Test-Path "$($config['CHEF_PS_LOG'])") { Remove-Item "$($config['CHEF_PS_LOG'])" -Force -ErrorAction SilentlyContinue }
exit 99

}

function cleanup() {

Remove-Item "$($config['CHEF_LOCAL_MSI_PATH'])" -Force -ErrorAction SilentlyContinue
Remove-Item "$($config['CHEF_CLIENT_MSI_LOG_PATH'])" -Force -ErrorAction SilentlyContinue

}

# Windows 2008 compatible way of loading config: $shell_variables = Get-ItemProperty 'HKLM:SYSTEMCurrentControlSetControlSession ManagerEnvironment'

$cmd_input_variables = @(“CHEF_PS_LOG”, “CHEF_PS_EXITCODE”, “CHEF_REMOTE_SOURCE_MSI_URL”, “CHEF_LOCAL_MSI_PATH”, “CHEF_http_proxy”,“CHEF_CLIENT_MSI_LOG_PATH”,“CHEF_ENVIRONMENT_OPTION”,“CHEF_BOOTSTRAP_DIRECTORY”,“CHEF_CUSTOM_INSTALL_COMMAND”,“CHEF_CUSTOM_RUN_COMMAND”,“CHEF_EXTRA_MSI_PARAMETERS”,“CHEF_MACHINE_OS”,“CHEF_MACHINE_ARCH”,“CHEF_DOWNLOAD_CONTEXT”,“CHEF_VERSION”) $cmd_input_variables | ForEach-Object {

$config[$_] = $shell_variables.$($_)

} log “`nConfig loaded from environment:$($config | Out-String -Width 150)”

log “Removing bootstrap files left by potential earlier run” cleanup

log “Setting up Webclient” $webClient = new-object System.Net.WebClient; if ($config -ne '') {

log "Configuring proxy $($config['CHEF_http_proxy']) in Webclient"
$WebProxy = New-Object System.Net.WebProxy($config['CHEF_http_proxy'],$true)
$WebClient.Proxy = $WebProxy

}

log “Testing for existing Chef client install” if (Test-Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes\C58A706DAFDB80F438DEE2BCD4DCB65C) {

log "Existing install detected. Skipping Chef-client download and install"

} else {

log "No Chef client install detected."
$download_link = msi_url
log "Starting download from $($download_link) to $( $config['CHEF_LOCAL_MSI_PATH'] )"
$webClient.DownloadFile($download_link, $config['CHEF_LOCAL_MSI_PATH'] );

log "Download done. Checking local file."
if (!(Test-Path "$($config['CHEF_LOCAL_MSI_PATH'])")) {
  log "Download failed. Local MSI not found."
  report_status 3; ps_exit
}
$filesize = (Get-Item "$($config['CHEF_LOCAL_MSI_PATH'])").length
if ($filesize -eq 0) {
  log "DOWNLOAD FAILED - Filesize is 0."
  report_status 2; ps_exit
}
log "Download filesize is $filesize"

log "Starting Chef client install"
if ($config['CHEF_CUSTOM_INSTALL_COMMAND'] ) {
  log "Running custom install command $($config['CHEF_CUSTOM_INSTALL_COMMAND'])"
  $install_process = Start-Process -PassThru -Wait "$env:comspec" -ArgumentList "/v /e /c`"start /wait cmd /c %CHEF_CUSTOM_INSTALL_COMMAND% & exit !errorlevel!;`""
} else {
  log "msiexec.exe /qn /log `"$($config['CHEF_CLIENT_MSI_LOG_PATH'])`" /i `"$($config['CHEF_LOCAL_MSI_PATH'])`" $($config['CHEF_EXTRA_MSI_PARAMETERS'])"
  $install_process = Start-Process -PassThru -Wait msiexec.exe -ArgumentList "/qn /log `"$($config['CHEF_CLIENT_MSI_LOG_PATH'])`" /i `"$($config['CHEF_LOCAL_MSI_PATH'])`" $($config['CHEF_EXTRA_MSI_PARAMETERS'])"
}
$install_exitcode = $install_process.ExitCode

log "MSI install returned exit code $install_exitcode"
if ($install_exitcode -ne 0) { report_status 36512; ps_exit }

}

log “Cleaning up Chef bootstrap environment variables” $cmd_input_variables | ForEach-Object {

REG delete "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /F /V $_

}

log “Cleaning up Powershell logfile and starting first Chef run” report_status 0 Start-Sleep 1 while (Test-Path “$($config)”) { Remove-Item “$($config)” -Force -ErrorAction SilentlyContinue }

if ($config) {

# Default to successful run of custom command
$chefrun_exitcode = 0
Try {
  Invoke-Expression $config['CHEF_CUSTOM_RUN_COMMAND']
} catch {
  $chefrun_exitcode = $_.FullyQualifiedErrorId
}

} else {

$chefrun_process = Start-Process -PassThru -Wait c:/opscode/chef/bin/chef-client.bat -ArgumentList "-c `"$($config['CHEF_BOOTSTRAP_DIRECTORY'])/client.rb`" -j `"$($config['CHEF_BOOTSTRAP_DIRECTORY'])/first-boot.json`" $($config['CHEF_ENVIRONMENT_OPTION']) -L `"$($config['CHEF_BOOTSTRAP_DIRECTORY'])/firstrun.log`""
$chefrun_exitcode = [int]$chefrun_process.ExitCode

}

log “Chef run done. Cleaning up Chef firstrun logfile to get control back to bootstrap cmd” While (Test-Path “$($config)/firstrun.log”) { Remove-Item “$($config)/firstrun.log” -Force -ErrorAction SilentlyContinue }

log “First Chef run returned exit code $chefrun_exitcode. We're done.” if ($chefrun_exitcode -ne 0) {

report_status $chefrun_exitcode; ps_exit

}

log “Cleaning up” report_status 0 c:/windows/system32/schtasks.exe /F /delete /tn Chef_bootstrap cleanup ps_exit