Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save ramarnat/9059306 to your computer and use it in GitHub Desktop.

Select an option

Save ramarnat/9059306 to your computer and use it in GitHub Desktop.
# Windows AMIs don't have WinRM enabled by default -- this script will enable WinRM
# AND install 7-zip, curl and .NET 4 if its missing.
# Then use the EC2 tools to create a new AMI from the result, and you have a system
# that will execute user-data as a PowerShell script after the instance fires up!
# This has been tested on Windows 2008 SP2 64bits AMIs provided by Amazon
#
# Inject this as user-data of a Windows 2008 AMI, like this (edit the adminPassword to your needs):
#
# <powershell>
# $log = 'c:\bootstrap_output.txt'
# Set-ExecutionPolicy Unrestricted
# icm $executioncontext.InvokeCommand.NewScriptBlock((New-Object Net.WebClient).DownloadString('https://gist.github.com/ramarnat/9059306/raw')) -ArgumentList "adminPassword" | Add-Content $log
# </powershell>
#
param(
[Parameter(Mandatory=$true)]
[string]$AdminPassword,
[string]$BootstrapScript,
[string]$Bootstrapbucket
)
Start-Transcript -Path 'c:\bootstrap-transcript.txt' -Force
Set-StrictMode -Version Latest
Set-ExecutionPolicy Unrestricted
$log = 'c:\Bootstrap.txt'
while (($AdminPassword -eq $null) -or ($AdminPassword -eq ''))
{
$AdminPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((Read-Host "Enter a non-null / non-empty Administrator password" -AsSecureString)))
Write-Host 'Password set.'
}
$systemPath = [Environment]::GetFolderPath([Environment+SpecialFolder]::System)
$sysNative = [IO.Path]::Combine($env:windir, "sysnative")
#http://blogs.msdn.com/b/david.wang/archive/2006/03/26/howto-detect-process-bitness.aspx
$Is32Bit = (($Env:PROCESSOR_ARCHITECTURE -eq 'x86') -and ($Env:PROCESSOR_ARCHITEW6432 -eq $null))
Add-Content $log -value "Is 32-bit [$Is32Bit]"
#http://msdn.microsoft.com/en-us/library/ms724358.aspx
$coreEditions = @(0x0c,0x27,0x0e,0x29,0x2a,0x0d,0x28,0x1d)
$IsCore = $coreEditions -contains (Get-WmiObject -Query "Select OperatingSystemSKU from Win32_OperatingSystem" | Select -ExpandProperty OperatingSystemSKU)
Add-Content $log -value "Is Core [$IsCore]"
# move to home, PS is incredibly complex :)
cd $Env:USERPROFILE
Set-Location -Path $Env:USERPROFILE
[Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath
#change admin password
net user Administrator $AdminPassword
Add-Content $log -value "Changed Administrator password"
$client = new-object System.Net.WebClient
#.net 4
if ((Test-Path "${Env:windir}\Microsoft.NET\Framework\v4.0.30319") -eq $false)
{
$netUrl = if ($IsCore) {'http://download.microsoft.com/download/3/6/1/361DAE4E-E5B9-4824-B47F-6421A6C59227/dotNetFx40_Full_x86_x64_SC.exe' } `
else { 'http://download.microsoft.com/download/9/5/A/95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE/dotNetFx40_Full_x86_x64.exe' }
$client.DownloadFile( $netUrl, 'dotNetFx40_Full.exe')
Start-Process -FilePath 'C:\Users\Administrator\dotNetFx40_Full.exe' -ArgumentList '/norestart /q /ChainingPackage ADMINDEPLOYMENT' -Wait -NoNewWindow
del dotNetFx40_Full.exe
Add-Content $log -value "Found that .NET4 was not installed and downloaded / installed"
}
#configure powershell to use .net 4
$config = @'
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- http://msdn.microsoft.com/en-us/library/w4atty68.aspx -->
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
<supportedRuntime version="v2.0.50727" />
</startup>
</configuration>
'@
if (Test-Path "${Env:windir}\SysWOW64\WindowsPowerShell\v1.0\powershell.exe")
{
$config | Set-Content "${Env:windir}\SysWOW64\WindowsPowerShell\v1.0\powershell.exe.config"
Add-Content $log -value "Configured 32-bit Powershell on x64 OS to use .NET 4"
}
if (Test-Path "${Env:windir}\system32\WindowsPowerShell\v1.0\powershell.exe")
{
$config | Set-Content "${Env:windir}\system32\WindowsPowerShell\v1.0\powershell.exe.config"
Add-Content $log -value "Configured host OS specific Powershell at ${Env:windir}\system32\ to use .NET 4"
}
#check winrm id, if it's not valid and LocalAccountTokenFilterPolicy isn't established, do it
$id = &winrm id
if (($id -eq $null) -and (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -name LocalAccountTokenFilterPolicy -ErrorAction SilentlyContinue) -eq $null)
{
New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -name LocalAccountTokenFilterPolicy -value 1 -propertyType dword
Add-Content $log -value "Added LocalAccountTokenFilterPolicy since winrm id could not be executed"
}
#enable powershell servermanager cmdlets (only for 2008 r2 + above)
if ($IsCore)
{
DISM /Online /Enable-Feature /FeatureName:MicrosoftWindowsPowerShell /FeatureName:ServerManager-PSH-Cmdlets /FeatureName:BestPractices-PSH-Cmdlets
Add-Content $log -value "Enabled ServerManager and BestPractices Cmdlets"
#enable .NET flavors - on server core only -- errors on regular 2008
DISM /Online /Enable-Feature /FeatureName:NetFx2-ServerCore /FeatureName:NetFx2-ServerCore-WOW64 /FeatureName:NetFx3-ServerCore /FeatureName:NetFx3-ServerCore-WOW64
Add-Content $log -value "Enabled .NET frameworks 2 and 3 for x86 and x64"
}
#install choclatey
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
SetX Path "${Env:Path};%systemdrive%\chocolatey\bin" /m
$Env:Path += ';C:\chocolatey\bin'
$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -Path 'c:\bootstrap-transcript.txt' -append
chocolatey feature enable -n allowGlobalConfirmation
#vc 2010 redstributable
cinst -y vcredist2010
Add-Content $log -value "Installed VC+Redistributable 2010"
#vc 2008 redstributable
cinst -y vcredist2008
Add-Content $log -value "Installed VC+Redistributable 2008"
# Cygwin
choco install cygwin -debug -overrideArgs -force -installArgs '-q -R C:\tools\cygwin -l C:\tools\cygwin\packages -s http://cygwin.mirror.constant.com/'
SetX Path "${Env:Path};%systemdrive%\Cygwin\bin" /m
$Env:Path += ';C:\Cygwin;C:\Cygwin\bin'
Add-Content $log -value "Installed Cygwin"
[Console]::Out.Flush()
CINST -y Boxstarter
cinst -y boxstarter.chocolatey
Add-Content $log -value "Installed Boxstarter"
CINST -y Atom
Add-Content $log -value "Installed Atom"
choco install -y cyg-get
Add-Content $log -value "Installed Cyg-Get"
choco install -y consul
Add-Content $log -value "Installed Consul"
# Patch cyg-get to use gatech mirror
(Get-Content C:\ProgramData\chocolatey\lib\cyg-get\tools\cyg-get.ps1) |
Foreach-Object {$_ -replace "ftp://mirrors.kernel.org/sourceware/cygwin", "http://cygwin.mirror.constant.com/"} |
Set-Content C:\ProgramData\chocolatey\lib\cyg-get\tools\cyg-get.ps1
Add-Content $log -value "Patched Cyg-Get"
cyg-get rsync
cyg-get curl
cyg-get wget
cyg-get 7zip
Add-Content $log -value "Installed Cygwin and Packages"
C:\tools\cygwin\bin\bash --login -c "mkpasswd -l > /etc/passwd"
C:\tools\cygwin\bin\bash --login -c "mkgroup -l > /etc/group"
cyg-get openssh
C:\tools\cygwin\bin\bash --login -c "/usr/bin/ssh-host-config --yes --pwd [$AdminPassword]"
C:\tools\cygwin\bin\bash --login -c "/usr/bin/ssh-user-config -y -p [$AdminPassword]"
C:\tools\cygwin\bin\bash --login -c "curl http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > ./.ssh/authorized_keys"
C:\tools\cygwin\bin\bash --login -c "sed -i.bak 's/#.*PasswordAuthentication.*yes/PasswordAuthentication no/' /etc/sshd_config"
net localgroup Administrators sshd /ADD
wmic useraccount where "Name='sshd'" set PasswordExpires=FALSE
wmic useraccount where "Name='cyg_server'" set PasswordExpires=FALSE
# Add the ssh port to the firewall
netsh advfirewall firewall add rule name=SSH dir=in action=allow protocol=tcp localport=22
Add-Content $log -value "Opened SSH Port"
# Start SSH
# OpenSSH ssh-host-config does not setup the service correctly
C:\tools\cygwin\bin\bash --login -c "cygrunsrv --stop sshd"
C:\tools\cygwin\bin\bash --login -c "cygrunsrv --remove sshd"
C:\tools\cygwin\bin\bash --login -c "mkpasswd -l > /etc/passwd"
C:\tools\cygwin\bin\bash --login -c "chown cyg_server /var/empty"
# make sure the rights for cyg_server are set
C:\tools\cygwin\bin\bash --login -c "editrights -u cyg_server -a SeAssignPrimaryTokenPrivilege"
C:\tools\cygwin\bin\bash --login -c "editrights -u cyg_server -a SeCreateTokenPrivilege"
C:\tools\cygwin\bin\bash --login -c "editrights -u cyg_server -a SeTcbPrivilege"
C:\tools\cygwin\bin\bash --login -c "editrights -u cyg_server -a SeServiceLogonRight"
C:\tools\cygwin\bin\bash --login -c "editrights -u cyg_server -a SeIncreaseQuotaPrivilege"
# install service with cyg_server user manually
C:\tools\cygwin\bin\bash --login -c "cygrunsrv -I sshd -d 'CYGWIN sshd' -p /usr/sbin/sshd -a '-D' -y tcpip -e 'CYGWIN=ntsec' -u cyg_server -w [$AdminPassword]"
net start sshd
Add-Content $log -value "Started SSH"
# create a tmp folder on C: and point the cygwin temp over there
# Chef/Vagrant-windows plugin uses winrm which will use C:/tmp
# but rsync running under ssh will use /tmp which is C:/Cygwin/tmp
mkdir "c:\\tmp"
C:\tools\cygwin\bin\bash --login -c "rm -rf /tmp && ln -s /cygdrive/c/tmp /tmp"
# run SMRemoting script to enable event log management, etc - available only on R2
# this script turns encryption back on.
$remotingScript = [IO.Path]::Combine($systemPath, 'Configure-SMRemoting.ps1')
if (-not (Test-Path $remotingScript)) { $remotingScript = [IO.Path]::Combine($sysNative, 'Configure-SMRemoting.ps1') }
Add-Content $log -value "Found Remoting Script: [$(Test-Path $remotingScript)] at $remotingScript"
if (Test-Path $remotingScript)
{
. $remotingScript -force -enable
Add-Content $log -value 'Ran Configure-SMRemoting.ps1'
}
# clamav
#cinst clamwin
#Add-Content $log -value "Installed Clamav"
cinst conemu
Add-Content $log -value "Installed ConEmu"
# cinst sqlserver2008r2express-managementstudio
# cinst chef-client
# Add-Content $log -value "Installed Chef Client"
&winrm set winrm/config/client/auth '@{Basic="true"}'
&winrm set winrm/config/service '@{AllowUnencrypted="true"}'
&winrm set winrm/config '@{MaxTimeoutms="36000000"}'
&winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="8096"}'
&winrm set winrm/config/service/auth '@{Basic="true"}'
# restart winrm (so it pickup the unencrypted setting)
net stop winrm
net start winrm
Add-Content $log -value "Started WinRM"
# Stop Transcript here so that Boxstarter/Chocolatey can start its own
Stop-Transcript
# Load Boxstarter
. C:\Users\Administrator\AppData\Roaming\Boxstarter\BoxstarterShell.ps1
# Boxstarter options
$Boxstarter.RebootOk=$true # Allow reboots?
$Boxstarter.NoPassword=$false # Is this a machine with no login password?
$Boxstarter.AutoLogin=$true # Save my password securely and auto-login after a reboot
$BoxstarterPassword=ConvertTo-SecureString $AdminPassword -asplaintext -force
# Save Credentials
$cred = new-object System.Management.Automation.PSCredential ("Administrator", $BoxstarterPassword)
# Setup Chef
$TARGETDIR = 'C:/chef'
Try
{
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
};
Write-Host "Created Chef Folder"
cinst -y chef-client
Write-Host "Installed chef-client"
$TARGETDIR='C:\chef\ohai\hints'
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
ni $TARGETDIR\ec2.json -type file
}
Write-Host "Set OHAI hints"
iex "$env:SystemDrive\opscode\chef\embedded\bin\gem.bat install --no-ri --no-rdoc chef-sugar chef-rewind diplomat" | Add-Content $log
Write-Host "Installed Chef Gems"
}
Catch
{
"ERROR setting up Chef: $_" | Add-Content $log
}
# EPM Bootstrap
Try
{
Add-Content $log -value "starting installer $Bootstrapbucket/$BootstrapScript"
Install-BoxstarterPackage -PackageName $Bootstrapbucket/$BootstrapScript -Credential $cred | Add-Content $log
Add-Content $log -value "finished installer"
}
Catch
{
"ERROR executing bootstrap $BootstrapScript.txt: $_" | Add-Content $log
}
# Change the Windows Settings
Try
{
Disable-InternetExplorerESC
Add-Content $log -value "Disabled IE ESC"
Set-WindowsExplorerOptions -EnableShowHiddenFilesFoldersDrives -EnableShowFileExtensions
Add-Content $log -value "Set Windows Explore Options"
Set-TaskbarOptions -Size Small
Add-Content $log -value "Set Task Bar Options"
}
Catch
{
"ERROR executing boxcutter: $_" | Add-Content $log
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment