$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