Forked from masterzen/Bootstrap-EC2-Windows-CloudInit.ps1
Last active
December 2, 2015 20:15
-
-
Save ramarnat/9059306 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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