Unpacking Software Livestream

Join our monthly Unpacking Software livestream to hear about the latest news, chat and opinion on packaging, software deployment and lifecycle management!

Learn More

Chocolatey Product Spotlight

Join the Chocolatey Team on our regular monthly stream where we put a spotlight on the most recent Chocolatey product releases. You'll have a chance to have your questions answered in a live Ask Me Anything format.

Learn More

Chocolatey Coding Livestream

Join us for the Chocolatey Coding Livestream, where members of our team dive into the heart of open source development by coding live on various Chocolatey projects. Tune in to witness real-time coding, ask questions, and gain insights into the world of package management. Don't miss this opportunity to engage with our team and contribute to the future of Chocolatey!

Learn More

Calling All Chocolatiers! Whipping Up Windows Automation with Chocolatey Central Management

Webinar from
Wednesday, 17 January 2024

We are delighted to announce the release of Chocolatey Central Management v0.12.0, featuring seamless Deployment Plan creation, time-saving duplications, insightful Group Details, an upgraded Dashboard, bug fixes, user interface polishing, and refined documentation. As an added bonus we'll have members of our Solutions Engineering team on-hand to dive into some interesting ways you can leverage the new features available!

Watch On-Demand
Chocolatey Community Coffee Break

Join the Chocolatey Team as we discuss all things Community, what we do, how you can get involved and answer your Chocolatey questions.

Watch The Replays
Chocolatey and Intune Overview

Webinar Replay from
Wednesday, 30 March 2022

At Chocolatey Software we strive for simple, and teaching others. Let us teach you just how simple it could be to keep your 3rd party applications updated across your devices, all with Intune!

Watch On-Demand
Chocolatey For Business. In Azure. In One Click.

Livestream from
Thursday, 9 June 2022

Join James and Josh to show you how you can get the Chocolatey For Business recommended infrastructure and workflow, created, in Azure, in around 20 minutes.

Watch On-Demand
The Future of Chocolatey CLI

Livestream from
Thursday, 04 August 2022

Join Paul and Gary to hear more about the plans for the Chocolatey CLI in the not so distant future. We'll talk about some cool new features, long term asks from Customers and Community and how you can get involved!

Watch On-Demand
Hacktoberfest Tuesdays 2022

Livestreams from
October 2022

For Hacktoberfest, Chocolatey ran a livestream every Tuesday! Re-watch Cory, James, Gary, and Rain as they share knowledge on how to contribute to open-source projects such as Chocolatey CLI.

Watch On-Demand

Downloads:

1,053,490

Downloads of v 2.4.209:

4,542

Last Update:

26 Apr 2015

Package Maintainer(s):

Software Author(s):

  • Matt Wrock

Tags:

boxstarter chocolatey environment setup

Boxstarter Chocolatey Module

This is not the latest version of Boxstarter Chocolatey Module available.

  • 1
  • 2
  • 3

2.4.209 | Updated: 26 Apr 2015

Downloads:

1,053,490

Downloads of v 2.4.209:

4,542

Software Author(s):

  • Matt Wrock

Boxstarter Chocolatey Module 2.4.209

This is not the latest version of Boxstarter Chocolatey Module available.

  • 1
  • 2
  • 3

Some Checks Have Failed or Are Not Yet Complete

Not All Tests Have Passed


Validation Testing Unknown


Verification Testing Unknown


Scan Testing Resulted in Investigate

Details
Learn More

Deployment Method: Individual Install, Upgrade, & Uninstall

To install Boxstarter Chocolatey Module, run the following command from the command line or from PowerShell:

>

To upgrade Boxstarter Chocolatey Module, run the following command from the command line or from PowerShell:

>

To uninstall Boxstarter Chocolatey Module, run the following command from the command line or from PowerShell:

>

Deployment Method:

NOTE

This applies to both open source and commercial editions of Chocolatey.

1. Enter Your Internal Repository Url

(this should look similar to https://community.chocolatey.org/api/v2/)


2. Setup Your Environment

1. Ensure you are set for organizational deployment

Please see the organizational deployment guide

2. Get the package into your environment

  • Open Source or Commercial:
    • Proxy Repository - Create a proxy nuget repository on Nexus, Artifactory Pro, or a proxy Chocolatey repository on ProGet. Point your upstream to https://community.chocolatey.org/api/v2/. Packages cache on first access automatically. Make sure your choco clients are using your proxy repository as a source and NOT the default community repository. See source command for more information.
    • You can also just download the package and push it to a repository Download

3. Copy Your Script

choco upgrade boxstarter.chocolatey -y --source="'INTERNAL REPO URL'" --version="'2.4.209'" [other options]

See options you can pass to upgrade.

See best practices for scripting.

Add this to a PowerShell script or use a Batch script with tools and in places where you are calling directly to Chocolatey. If you are integrating, keep in mind enhanced exit codes.

If you do use a PowerShell script, use the following to ensure bad exit codes are shown as failures:


choco upgrade boxstarter.chocolatey -y --source="'INTERNAL REPO URL'" --version="'2.4.209'" 
$exitCode = $LASTEXITCODE

Write-Verbose "Exit code was $exitCode"
$validExitCodes = @(0, 1605, 1614, 1641, 3010)
if ($validExitCodes -contains $exitCode) {
  Exit 0
}

Exit $exitCode

- name: Install boxstarter.chocolatey
  win_chocolatey:
    name: boxstarter.chocolatey
    version: '2.4.209'
    source: INTERNAL REPO URL
    state: present

See docs at https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html.


chocolatey_package 'boxstarter.chocolatey' do
  action    :install
  source   'INTERNAL REPO URL'
  version  '2.4.209'
end

See docs at https://docs.chef.io/resource_chocolatey_package.html.


cChocoPackageInstaller boxstarter.chocolatey
{
    Name     = "boxstarter.chocolatey"
    Version  = "2.4.209"
    Source   = "INTERNAL REPO URL"
}

Requires cChoco DSC Resource. See docs at https://github.com/chocolatey/cChoco.


package { 'boxstarter.chocolatey':
  ensure   => '2.4.209',
  provider => 'chocolatey',
  source   => 'INTERNAL REPO URL',
}

Requires Puppet Chocolatey Provider module. See docs at https://forge.puppet.com/puppetlabs/chocolatey.


4. If applicable - Chocolatey configuration/installation

See infrastructure management matrix for Chocolatey configuration elements and examples.

Package Approved

This package was approved as a trusted package on 26 Apr 2015.

Description

Creates a fresh developer (or non developer) environment from a bare OS utilizing powershell and chocolatey. Installs chocolatey, cutomizes windows settings, installs windows updates, handles reboots, installs windows features and your favorite applications.


tools\boxlogo.ico
 
tools\BoxStarter.bat
@echo off
  
powershell -NoProfile -ExecutionPolicy bypass -command "Import-Module '%~dp0Boxstarter.Chocolatey\Boxstarter.Chocolatey.psd1';Invoke-ChocolateyBoxstarter %*"
tools\Boxstarter.Chocolatey\Boxstarter.Chocolatey.psd1
 
tools\Boxstarter.Chocolatey\Boxstarter.Chocolatey.psm1
$unNormalized=(Get-Item "$PSScriptRoot\..\Boxstarter.Bootstrapper\Boxstarter.Bootstrapper.psd1")
Import-Module $unNormalized.FullName -global -DisableNameChecking -Force
Resolve-Path $PSScriptRoot\*.ps1 | 
    % { . $_.ProviderPath }

Check-Chocolatey -ShouldIntercept

Export-ModuleMember Invoke-ChocolateyBoxstarter, New-BoxstarterPackage, Invoke-BoxstarterBuild, Get-PackageRoot, Set-BoxstarterShare, Get-BoxstarterConfig, Set-BoxstarterConfig, Install-BoxstarterPackage, New-PackageFromScript, Enable-BoxstarterClientRemoting, Enable-BoxstarterCredSSP, Resolve-VMPlugin

Export-ModuleMember Install-ChocolateyInstallPackageOverride,
                    Write-HostOverride
Export-ModuleMember -alias Install-ChocolateyInstallPackage, Write-Host, Enable-BoxstarterVM
tools\Boxstarter.Chocolatey\Boxstarter.Chocolatey.pssproj
 
tools\Boxstarter.Chocolatey\Boxstarter.Chocolatey.pssproj.user
 
tools\Boxstarter.Chocolatey\Boxstarter.zip
 
tools\Boxstarter.Chocolatey\BoxstarterConnectionConfig.ps1
$source = @"
public class BoxstarterConnectionConfig {
    public BoxstarterConnectionConfig(System.Uri connectionURI, System.Management.Automation.PSCredential credential, System.Management.Automation.Remoting.PSSessionOption psSessionOption) {
        ConnectionURI=connectionURI;
        Credential=credential;
        PSSessionOption=psSessionOption;
    }
    public System.Uri ConnectionURI;
    public System.Management.Automation.PSCredential Credential;
    public System.Management.Automation.Remoting.PSSessionOption PSSessionOption;
}
"@
Add-Type -TypeDefinition $source
tools\Boxstarter.Chocolatey\Check-Chocolatey.ps1
function Check-Chocolatey ([switch]$ShouldIntercept){
    Enable-Net40
    $mod_install = "$env:ChocolateyInstall\chocolateyinstall\helpers\chocolateyInstaller.psm1"
    if(-not $env:ChocolateyInstall -or -not (Test-Path $mod_install)){
        Write-BoxstarterMessage "Chocolatey not installed. Downloading and installing..."
        $env:ChocolateyInstall = "$env:programdata\chocolatey"
        New-Item $env:ChocolateyInstall -Force -type directory | Out-Null
        $config = Get-BoxstarterConfig
        $url=$config.ChocolateyPackage
        Enter-BoxstarterLogable {
            $currentLogging=$Boxstarter.Suppresslogging
            if($VerbosePreference -eq "SilentlyContinue"){$Boxstarter.Suppresslogging=$true}
            Install-Chocolatey $url
            if($global:error[0].CategoryInfo.Activity -eq 'Remove-Module'){ $global:error.RemoveAt(0) } #this is so terrible
            $Boxstarter.SuppressLogging = $currentLogging
        }

        if(Test-Path $mod_install) {
            Write-BoxstarterMessage "Importing Chocolatey module from $mod_install" -Verbose
            Import-Module $mod_install -Global -Force
        }
    }
    if(!$BoxstarterIntrercepting)
    {
        Write-BoxstarterMessage "Chocolatey installed, setting up interception of Chocolatey methods." -Verbose
        if($ShouldIntercept){Intercept-Chocolatey}
    }
}

function Is64Bit {  [IntPtr]::Size -eq 8  }

function Enable-Net40 {
    if(Is64Bit) {$fx="framework64"} else {$fx="framework"}
    if(!(test-path "$env:windir\Microsoft.Net\$fx\v4.0.30319")) {
        if((Test-PendingReboot) -and $Boxstarter.RebootOk) {return Invoke-Reboot}
        Write-BoxstarterMessage "Downloading .net 4.5..."
        Get-HttpToFile "http://download.microsoft.com/download/b/a/4/ba4a7e71-2906-4b2d-a0e1-80cf16844f5f/dotnetfx45_full_x86_x64.exe" "$env:temp\net45.exe"
        Write-BoxstarterMessage "Installing .net 4.5..."
        if(Get-IsRemote) {
            Invoke-FromTask @"
Start-Process "$env:temp\net45.exe" -verb runas -wait -argumentList "/quiet /norestart /log $env:temp\net45.log"
"@
        }
        else {
            $proc = Start-Process "$env:temp\net45.exe" -verb runas -argumentList "/quiet /norestart /log $env:temp\net45.log" -PassThru 
            while(!$proc.HasExited){ sleep -Seconds 1 }
        }
    }
}

function Get-HttpToFile ($url, $file){
    Write-BoxstarterMessage "Downloading $url to $file" -Verbose
    Invoke-RetriableScript -RetryScript {
        if(Test-Path $args[1]){Remove-Item $args[1] -Force}
        $downloader=new-object net.webclient
        $wp=[system.net.WebProxy]::GetDefaultProxy()
        $wp.UseDefaultCredentials=$true
        $downloader.Proxy=$wp
        try {
            $downloader.DownloadFile($args[0], $args[1])
        }
        catch{
            if($VerbosePreference -eq "Continue"){
                Write-Error $($_.Exception | fl * -Force | Out-String)
            }
            throw $_
        }
    } $url $file
}
tools\Boxstarter.Chocolatey\Chocolatey.ps1
function Install-ChocolateyInstallPackageOverride {
param(
  [string] $packageName, 
  [string] $fileType = 'exe',
  [string] $silentArgs = '',
  [string] $file,
  $validExitCodes = @(0)
)    
    Wait-ForMSIEXEC
    if(Get-IsRemote){
        Invoke-FromTask @"
Import-Module $env:ChocolateyInstall\chocolateyinstall\helpers\chocolateyInstaller.psm1 -Global
Install-ChocolateyInstallPackage $(Expand-Splat $PSBoundParameters)
"@
    }
    else{
        chocolateyInstaller\Install-ChocolateyInstallPackage @PSBoundParameters
    }
}

function Write-HostOverride {
param(
  [Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true, ValueFromRemainingArguments=$true)][object] $Object,
  [Parameter()][switch] $NoNewLine, 
  [Parameter(Mandatory=$false)][ConsoleColor] $ForegroundColor, 
  [Parameter(Mandatory=$false)][ConsoleColor] $BackgroundColor,
  [Parameter(Mandatory=$false)][Object] $Separator
)
    if($Boxstarter.ScriptToCall -ne $null) { Log-BoxStarterMessage $object }

    if($Boxstarter.SuppressLogging){
        $caller = (Get-Variable MyInvocation -Scope 1).Value.MyCommand.Name
        if("Describe","Context","write-PesterResult" -contains $caller) {
            Microsoft.PowerShell.Utility\Write-Host @PSBoundParameters
        }
        return;
    }
    $chocoWriteHost = Get-Command -Module chocolateyInstaller | ? { $_.Name -eq "Write-Host" }
    if($chocoWriteHost){
        &($chocoWriteHost) @PSBoundParameters
    }
    else {
        Microsoft.PowerShell.Utility\Write-Host @PSBoundParameters
    }
}

new-alias Install-ChocolateyInstallPackage Install-ChocolateyInstallPackageOverride -force
new-alias Write-Host Write-HostOverride -force

function cinst {
<#
.SYNOPSIS
Intercepts Chocolatey call to check for reboots

#>    
    param([int[]]$RebootCodes=@())
    chocolatey Install @PSBoundParameters
}

function choco {
<#
.SYNOPSIS
Intercepts Chocolatey call to check for reboots

#>    
    param([int[]]$RebootCodes=@())
    chocolatey @PSBoundParameters
}

function cup {
<#
.SYNOPSIS
Intercepts Chocolatey call to check for reboots

#>    
    param([int[]]$RebootCodes=@())
    chocolatey Update @PSBoundParameters
}

function cinstm {
<#
.SYNOPSIS
Intercepts Chocolatey call to check for reboots

#>    
    param([int[]]$RebootCodes=@())
    chocolatey InstallMissing @PSBoundParameters
}

function chocolatey {
<#
.SYNOPSIS
Intercepts Chocolatey call to check for reboots

#>  
    param([int[]]$RebootCodes=@())
    $RebootCodes=Add-DefaultRebootCodes $RebootCodes
    $PSBoundParameters.Remove("RebootCodes") | Out-Null
    $packageNames=-split $packageNames
    Write-BoxstarterMessage "Installing $($packageNames.Count) packages" -Verbose
    #backwards compatibility for Chocolatey versions prior to 0.9.8.21
    if(!$packageNames){$packageNames=$packageName}
    if($Script:NewChoco) {
        $PSBoundParameters.yes = $true
    }
    
    foreach($packageName in $packageNames){
        $PSBoundParameters.packageNames = $packageName
        if($source -eq "WindowsFeatures"){
            $dismInfo=(DISM /Online /Get-FeatureInfo /FeatureName:$packageName)
            if($dismInfo -contains "State : Enabled" -or $dismInfo -contains "State : Enable Pending") {
                Write-BoxstarterMessage "$packageName is already installed"
                return
            }
            else{
                $winFeature=$true
            }
        }
        if(((Test-PendingReboot) -or $Boxstarter.IsRebooting) -and $Boxstarter.RebootOk) {return Invoke-Reboot}
        $session=Start-TimedSection "Calling Chocolatey to install $packageName. This may take several minutes to complete..."
        $currentErrorCount = $global:error.Count
        $rebootable = $false
        try {
            if($winFeature -eq $true -and (Get-IsRemote)){
                #DISM Output is more confusing than helpful.
                $currentLogging=$Boxstarter.Suppresslogging
                if($VerbosePreference -eq "SilentlyContinue"){$Boxstarter.Suppresslogging=$true}
                Invoke-FromTask @"
."$env:ChocolateyInstall\chocolateyinstall\chocolatey.ps1" $(Expand-Splat $PSBoundParameters)
"@
                $Boxstarter.SuppressLogging = $currentLogging
            }
            else{
                Call-Chocolatey @PSBoundParameters

                # chocolatey reassembles environment variables after an install
                # but does not add the machine PSModule value to the user Online
                $machineModPath = [System.Environment]::GetEnvironmentVariable("PSModulePath","Machine")
                if(!$env:PSModulePath.EndsWith($machineModPath)) {
                    $env:PSModulePath += ";" + $machineModPath
                }

                Write-BoxstarterMessage "Exit Code: $LastExitCode" -Verbose
                if($LastExitCode -ne 0) {
                    Write-Error "Chocolatey reported an unsuccessful exit code of $LastExitCode"
                }
            }
        }
        catch { 
            #Only write the error to the error stream if it was not previously
            #written by chocolatey
            $chocoErrors = $global:error.Count - $currentErrorCount
            if($chocoErrors -gt 0){
                $idx = 0
                $errorWritten = $false
                while($idx -lt $chocoErrors){
                    if(($global:error[$idx].Exception.Message | Out-String).Contains($_.Exception.Message)){
                        $errorWritten = $true
                    }
                    if(!$errorWritten){
                        Write-Error $_
                    }
                    $idx += 1
                }
            }
        }
        $chocoErrors = $global:error.Count - $currentErrorCount
        if($chocoErrors -gt 0){
            Write-BoxstarterMessage "There was an error calling chocolatey" -Verbose
            $idx = 0
            while($idx -lt $chocoErrors){
                Log-BoxstarterMessage "Error from chocolatey: $($global:error[$idx].Exception | fl * -Force | Out-String)"
                if($global:error[$idx] -match "code was '(-?\d+)'") {
                    $errorCode=$matches[1]
                    if($RebootCodes -contains $errorCode) {
                       $rebootable = $true
                    }
                }
                $idx += 1
            }
        }
        Stop-Timedsection $session
        if(!$Boxstarter.rebootOk) {continue}
        if($Boxstarter.IsRebooting){
            Remove-ChocolateyPackageInProgress $packageName
            return
        }
        if($rebootable) {
            Write-BoxstarterMessage "Chocolatey Install returned a reboot-able exit code"
            Remove-ChocolateyPackageInProgress $packageName
            Invoke-Reboot
        }
    }
}

function Call-Chocolatey {
    if($PSBoundParameters.Keys -notcontains "Source"){
        $PSBoundParameters.Source = "$($Boxstarter.LocalRepo);$((Get-BoxstarterConfig).NugetSources)"
    }
    ."$env:ChocolateyInstall\chocolateyinstall\chocolatey.ps1" @PSBoundParameters
}

function Intercept-Command {
    param(
        $commandName, 
        $targetCommand = "$env:ChocolateyInstall\chocolateyinstall\chocolatey.ps1",
        [switch]$omitCommandParam
    )
    $metadata=Get-MetaData $targetCommand
    $srcMetadata=Get-MetaData $commandName
    if($commandName.Split("\").Length -eq 2){
        $commandName = $commandName.Substring($commandName.IndexOf("\")+1)
    }
    $metadata.Parameters.Remove("Verbose") | out-null
    $metadata.Parameters.Remove("Debug") | out-null
    $metadata.Parameters.Remove("ErrorAction") | out-null
    $metadata.Parameters.Remove("WarningAction") | out-null
    $metadata.Parameters.Remove("ErrorVariable") | out-null
    $metadata.Parameters.Remove("WarningVariable") | out-null
    $metadata.Parameters.Remove("OutVariable") | out-null
    $metadata.Parameters.Remove("OutBuffer") | out-null
    if($metadata.Parameters.ContainsKey("yes")){
        $Script:NewChoco=$true
    }
    if($omitCommandParam) {
        $metadata.Parameters.Remove("command") | out-null
    }
    $params = [Management.Automation.ProxyCommand]::GetParamBlock($metadata)    
    if($srcMetadata.Parameters.count -gt 0) {
        $srcParams = [Management.Automation.ProxyCommand]::GetParamBlock($srcMetadata)    
        $params += ",`r`n" + $srcParams
    }
    $cmdLetBinding = [Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($metadata)
    $strContent = (Get-Content function:\$commandName).ToString()
    if($strContent -match "param\(.+\)") {
        $strContent = $strContent.Replace($matches[0],"")
    }
    Set-Item Function:\$commandName -value "$cmdLetBinding `r`n param ( $params )Process{ `r`n$strContent}" -force
}

function Get-MetaData ($command){
    $cmdDef = Get-Command $command | ? {$_.CommandType -ne "Application"}
    return New-Object System.Management.Automation.CommandMetaData ($cmdDef)
}
function Intercept-Chocolatey {
    if($Script:BoxstarterIntrercepting){return}
    Intercept-Command cinst -omitCommandParam
    Intercept-Command cup -omitCommandParam
    Intercept-Command cinstm -omitCommandParam
    Intercept-Command chocolatey
    Intercept-Command choco
    Intercept-Command call-chocolatey
    $Script:BoxstarterIntrercepting=$true
}

function Add-DefaultRebootCodes($codes) {
    if($codes -eq $null){$codes=@()}
    $codes += 3010 #common MSI reboot needed code
    $codes += -2067919934 #returned by SQL Server when it needs a reboot
    return $codes
}

function Remove-ChocolateyPackageInProgress($packageName) {
    $pkgDir = (dir $env:ChocolateyInstall\lib\$packageName.*)
    if($pkgDir.length -gt 0) {$pkgDir = $pkgDir[-1]}
    if($pkgDir -ne $null) {
        remove-item $pkgDir -Recurse -Force -ErrorAction SilentlyContinue  
    }
}

function Expand-Splat($splat){
    $ret=""
    ForEach($item in $splat.KEYS.GetEnumerator()) {
        $ret += "-$item$(Resolve-SplatValue $splat[$item]) " 
    }
    return $ret
}

function Resolve-SplatValue($val){
    if($val -is [switch]){
        if($val.IsPresent){
            return ":`$True"
        }
        else{
            return ":`$False"
        }
    }
    if($val -is [Array]){
        $ret=" @("
        $firstVal=$False
        foreach($arrayVal in $val){
            if($firstVal){$ret+=","}
            if($arrayVal -is [int]){
                $ret += "$arrayVal"
            }
            else{
                $ret += "`"$arrayVal`""
            }

            $firstVal=$true
        }
        $ret += ")"
        return $ret
    }
    $ret = " `"$($val.Replace('"','`' + '"'))`""
    return $ret
}

function Wait-ForMSIEXEC{
    Do{
        Get-Process | ? {$_.Name -eq "MSIEXEC"} | % {
            if(!($_.HasExited)){
                $proc=Get-WmiObject -Class Win32_Process -Filter "ProcessID=$($_.Id)"
                if($proc.CommandLine -ne $null -and $proc.CommandLine.EndsWith(" /V")){ break }
                Write-BoxstarterMessage "Another installer is running: $($proc.CommandLine). Waiting for it to complete..."
                $_.WaitForExit()
            }
        }
    } Until ((Get-Process | ? {$_.Name -eq "MSIEXEC"} ) -eq $null)
}
tools\Boxstarter.Chocolatey\en-US\about_boxstarter_chocolatey.help.txt
TOPIC
	About_Boxstarter_Chocolatey

SYNOPSIS
	Describes how to use Boxstarter's Chocolatey module to setup a new 
	environment with your favorite Chocolatey packages.

DESCRIPTION
	Boxstarter's Chocolatey module compliments the Boxstarter Bootstrap 
	module by augmenting its unattended script execution environment 
	with Chocolatey goodness making it easy to setup a new box with 
	Chocolatey packages.

Installing Chocolatey
	Boxstarter will check to ensure if Chocolatey is installed. If 
	Chocolatey is not installed it will install it before running any 
	Chocolatey commands. Boxstarter will also check to see if the .Net 
	4.5 Framework is installed before installing Chocolatey since the 
	.Net 4 runtime is a prerequisite.

Chocolatey Boxstarter Packages
	When calling Install-BoxstarterPackage or just Boxstarter, a 
	Package name must be passed to the command. This is a 
	special Chocolatey package provided by the user that boxstarter asks 
	Chocolatey to install and it contains the script that is intended to 
	install all the applications and settings the user wants setup on the 
	target machine.

	This package script has access to all of the Chocolatey helper 
	functions as well as all Boxstarter logging, WinConfig and 
	Bootstrapper commands. See About_Boxstarter_Bootstrapper and 
	About_Boxstarter_Logging for information regarding those comands.

	This can also be a script file containing the chocolatey install 
	script. If the package name provided is a URL or resolves to a file. 
	Then it is assumed that this contains the chocolatey install 
	script and a .nupkg file will be created using the script.

Creating Packages
	Boxstarter provides some functions to make creation and deployment of 
	packages easy. Use New-BoxstarterPackage to either create a skeleton 
	package with a minimal nuspec and ChocolateyInstall.ps1 or to import an 
	existing package into boxstarter. This will put the package source files
	in $($Boxstarter.LocalRepo)\<package name>. To pack these source files
	use Invoke-BoxstarterBuild <package name>. You may also pack all 
	package	in your repo with Invoke-BoxstarterBuild -all. If you would like 
	to make	your local repo a network share, use Set-BoxstarterShare. 

Consuming Boxstarter Packages
	The primary gateway to kicking off a Boxstarter.Chocolatey installation 
	session is Install-BoxstarterPackage. While you may use this 
	powershell function, you can also call Boxstarter.bat which takes the 
	exact same parameters as Invoke-CocolateyBoxstarter. If you installed 
	Boxstarter.Chocolatey via Chocolatey or the setup.bat installer, 
	boxstarter.bat is placed in your path. Boxstarter.bat will import the 
	Boxstarter.Chocolatey module and create a powershell session bypassing 
	ExecutionPolicy. Boxstarter.bat is ideal for calling Boxstarter 
	remotely. Simply share the Boxstarter base directory and you can access 
	it via \\serverName\Boxstarter\Boxstarter.bat.

Package Sources
	Install-BoxstarterPackage (or Boxstarter) expects just the name of the
	bootstrapping package - just like CINST or Nuget. Boxstarter will search
	the following locations in this order:

	- $Boxstarter.LocalRepo: This is the local repository that by default is
	in the BuildPackages directory in the Boxstarter Base Boxstarter Module 
	directory ($Boxstarter.BaseDir). You can change the default by using the
	Set-BoxstarterConfig function with the -LocalRepo argument.

	- Chocolatey.org: The public chocolatey feed at http://chocolatey.org/api/v2

	- Myget: The Boxstarter Community Feed at http://www.myget.org/F/boxstarter/api/v2

	The last two remote sources can be configured by editing 
	$($Boxstarter.BaseDir)\Boxstarter.Config.

Running Boxstarter Remotely
	When using the Computername, ConnectionURI or Session parameters of
	Install-BoxstarterPackage, Boxstarter will attempt to install the package
	the the remote maching it is directed at. Boxstarter will check to ensure
	that all necessary client side Powershell Remoting settings are correctly
	configured. If they are not, Boxstarter will prompt to confirm whether it 
	should enable them unless the -Force parameter is used. The -Force 
	parameter will suppress prompts. As part of this configuration, Boxstarter 
	will enable CredSSP authentication to ensure that any network connection 
	that the package may try to establish will pass the users credentials.

	Boxstarter will also attempt to enable Powershell remoting on the target 
	machine if it is not already installed. Boxstarter can only do this if the
	WMI firewall ports are open on the target computer. If they are not and 
	powershell remoting is not enabled on the target machine, the installation 
	will fail. Users can easily enable powershell remoting manually on the 
	target machine by opening an administrative powershell console on the remote
	computer and then issuing 'Enable-PSRemoting -Force'.

Reboot detection
	Perhaps the most compelling feature of Boxstarter is its way to handle 
	reboots during an involved environment setup package. Especially when 
	you are running patches, installing services and downloading complex 
	applications. Boxstarter intercepts all calls to Chocolatey install 
	commands and checks for pending reboots prior to calling Chocolatey. If 
	a pending reboot exists, Boxstarter reboots the machine and automatically
	logs on with the credentials you provided providing an unattended 
	installation session. After the Chocolatey package completes, if the 
	package fails and returns the common MSI reboot needed exit code of 
	3010, Boxstarter will reboot which will likely cause the package to 
	succeed on the next run. See about_boxstarter_bootstrapper for more 
	details about the rebooting logic and how you can disable or manually 
	invoke them.

Package Authoring Considerations
	Boxstarter can run any Chocolatey package and any valid powershell 
	inside that package. However, there are a few things to consider 
	that may make a Boxstarter Chocolatey package a better installation 
	experience.

	- Boxstarter Chocolatey packages should be repeatable. This is 
	especially true if you anticipate the need to reboot. When Boxstarter 
	reboots, it starts running the package from the beginning. So ensure 
	that there is nothing that would cause the package to break if run 
	twice.

	- If you have several Chocolatey packages that you want to install 
	during the Boxstarter session, it is preferable to call CINST 
	directly from inside your ChocolateyInstall instead of declaring 
	them as dependencies. This is because Boxstarter cannot intercept 
	Chocolatey dependencies so those packages will not have any reboot 
	protections.

SEE ALSO

	http://boxstarter.org
	Install-BoxstarterPackage
	Invoke-ChocolateyBoxstarter
	about_boxstarter_logging
	Invoke-Boxstarter
	Invoke-Reboot
	New-BoxstarterPackage
	Invoke-BoxstarterBuild
	Set-BoxstarterShare
	about_boxstarter_variable_in_bootstrapper
	about_boxstarter_logging
	about_boxstarter_variable_in_chocolatey
	Set-BoxstarterConfig
tools\Boxstarter.Chocolatey\en-US\About_Boxstarter_Variable_In_Chocolatey.help.txt
TOPIC
	About_Boxstarter_Variable_In_Chocolatey

SYNOPSIS
	A Hashtable for persisting Boxstarter settings.

DESCRIPTION	
	The Boxstarter variable is a hashtable that is globaly accesible. 
	Different Boxstarter modules may store different settings.
	Some of the Chocolatey module settings available from the 
	Boxstarter variable can also be set from the 
	Invoke-ChocolateyBoxstarter Command.

BOXSTARTER VARIABLE SETTINGS
	ProgramFiles86
		Unless the environment has been specilly conficured, this 
		points to the 'Program Files' folder in the system drive on 
		x86 machines and the 'Program Files (x86)' folder in the 
		system drive on 64 bit machines.

	ChocolateyBin
		This points to the path of the chocolatey bin directory which 
		by default is c:\chocolatey\bin.

	Package
		The name of the bootstrapper package running in Boxstarter.

	LocalRepo
		Path to the local directory containing packages that 
		boxstarter will scan when looking for a package. By default 
		this is the BuildPackeged directory under the base Boxstarter 
		directory usually in the user's AppData directory. The 
		default can be changed by using the	Set-BoxstarterConfig 
		function with the -LocalRepo argument.

	NugetSources
		The Nuget feeds that Boxstarter checks for the Boxstarter 
		Bootstrap package. By default this is the chocolatey and 
		Myget Boxstarter community feed. This can be changed by 
		using the Set-BoxstarterConfig function with the -NugetSources 
		argument.

SEE ALSO
	http://boxstarter.org
	About_Boxstarter_Variable_In_Bootstrapper
	Invoke-ChocolateyBoxstarter
	Set-BoxstarterConfig
tools\Boxstarter.Chocolatey\Enable-BoxstarterClientRemoting.ps1
function Enable-BoxstarterClientRemoting {
<#
.SYNOPSIS
Enables and configures PowerShell remoting from the client

.DESCRIPTION
Enable-BoxstarterClientRemoting will check if PowerShell Remoting is enabled on the local 
machine. If not, it will enable it and it will also add all remote hosts to trust to the 
WSMAN trusted hosts list. The original trusted host list will be returned. When running 
Install-BoxstarterPackage, Boxstarter will roll back to the original trusted hosts when 
the package install is complete.

.PARAMETER RemoteHostsToTrust
A list of ComputerNames to add to the WSMAN Trusted hosts list.

.OUTPUTS
A list of the original trusted hosts on the local machine as well as a bool indicating 
if PowerShell Remoting was successfully completed.

.EXAMPLE
Enable-BoxstarterClientRemoting box1,box2

.LINK
http://boxstarter.org
Install-BoxstarterPackage

#>
    param(
    [string[]] $RemoteHostsToTrust
    )
    if(Test-Admin) { $elevated = $true }

    $Result=@{    
        Success=$False;
        PreviousTrustedHosts=$null;
    }
    Write-BoxstarterMessage "Configuring local PowerShell Remoting settings..."
    
    if(!(Get-Command Test-WSMan -ErrorAction SilentlyContinue)) {
        #I have only seen this on VisualStudio.Com Hosted build servers
        $Result.Success=$True
        return $Result
    }

    try { $wsman = Test-WSMan -ErrorAction Stop } catch { $credssp = $_}
    if($credssp.Exception -ne $null){
        Write-BoxstarterMessage "Local PowerShell Remoting is not enabled" -Verbose
        Write-BoxstarterMessage "Error returned $($credssp.ToString())" -Verbose
        if($elevated -and ($Force -or (Confirm-Choice "PowerShell remoting is not enabled locally. Should Boxstarter enable PowerShell remoting?")))
        {
            Write-BoxstarterMessage "Enabling PowerShell Remoting on local machine"
            $enableArgs=@{Force=$true}
            $command=Get-Command Enable-PSRemoting
            if($command.Parameters.Keys -contains "skipnetworkprofilecheck"){
                $enableArgs.skipnetworkprofilecheck=$true
            }
            Enable-PSRemoting @enableArgs | Out-Null
        }else {
            Write-BoxstarterMessage "Not enabling local PowerShell Remoting aborting package install"
            return $Result
        }
    }

    $newHosts = @()
    $Result.PreviousTrustedHosts=(Get-Item "wsman:\localhost\client\trustedhosts").Value
    $hostArray=$Result.PreviousTrustedHosts.Split(",")
    if($hostArray -contains "*") {
        $Result.PreviousTrustedHosts = $null
    }
    else {
        $RemoteHostsToTrust | ? { $hostArray -NotContains $_ } | % { $newHosts += $_ }
        if($newHosts.Count -gt 0) {
            $strNewHosts = $newHosts -join ","
            if($Result.PreviousTrustedHosts.Length -gt 0){
                $strNewHosts = $Result.PreviousTrustedHosts + "," + $strNewHosts
            }
            Write-BoxstarterMessage "Adding $strNewHosts to allowed wsman hosts" -Verbose
            Set-Item "wsman:\localhost\client\trustedhosts" -Value $strNewHosts -Force
        }
    }

    $Result.Success=$True
    return $Result
}
tools\Boxstarter.Chocolatey\Enable-BoxstarterCredSSP.ps1
function Enable-BoxstarterCredSSP {
<#
.SYNOPSIS
Enables and configures CredSSP Authentication to be used in PowerShell remoting sessions

.DESCRIPTION
Enabling CredSSP allows a caller from one remote session to authenticate on other remote 
resources. This is known as credential delegation. By default, PowerShell sessions do not 
use credSSP and therefore cannot bake a "second hop" to use other remote resources that 
require their authentication token.

Enable-BoxstarterCredSSP allows remote boxstarter installs to use credential delegation 
in the case where one might keep some resources on another remote machine that need to be 
installed into their current remote session.

This command will enable CredSSP and add all RemoteHostsToTrust to the CredSSP trusted 
hosts list. It will also edit the users group policy to allow Fresh Credential Delegation.

.PARAMETER RemoteHostsToTrust
A list of ComputerNames to add to the CredSSP Trusted hosts list.

.OUTPUTS
A list of the original trusted hosts on the local machine.

.EXAMPLE
Enable-BoxstarterCredSSP box1,box2

.LINK
http://boxstarter.org
Install-BoxstarterPackage

#>
    param(
    [string[]] $RemoteHostsToTrust
    )
    $Result=@{    
        Success=$False;
        PreviousCSSPTrustedHosts=$null;
        PreviousFreshCredDelegationHostCount=0
    }
    if(!(Test-Admin)) {
        return $result
    }
    Write-BoxstarterMessage "Configuring CredSSP settings..."
    $credssp = Get-WSManCredSSP

    $ComputersToAdd = @()
    $idxHosts=$credssp[0].IndexOf(": ")
    if($idxHosts -gt -1){
        $credsspEnabled=$True
        $Result.PreviousCSSPTrustedHosts=$credssp[0].substring($idxHosts+2)
        $hostArray=$Result.PreviousCSSPTrustedHosts.Split(",")
        $RemoteHostsToTrust | ? { $hostArray -notcontains "wsman/$_" } | % { $ComputersToAdd += $_ }
    }
    else {
        $ComputersToAdd = $RemoteHostsToTrust
    }

    if($ComputersToAdd.Count -gt 0){
        Write-BoxstarterMessage "Adding $($ComputersToAdd -join ',') to allowed credSSP hosts" -Verbose
        try {
            Enable-WSManCredSSP -DelegateComputer $ComputersToAdd -Role Client -Force -ErrorAction Stop | Out-Null
        } 
        catch {
            Write-BoxstarterMessage "Enable-WSManCredSSP failed with: $_" -Verbose
            return $result
        }
    }

    $key = Get-CredentialDelegationKey
    if (!(Test-Path "$key\CredentialsDelegation")) {
        New-Item $key -Name CredentialsDelegation | Out-Null
    }
    $key = Join-Path $key "CredentialsDelegation"
    New-ItemProperty -Path "$key" -Name "ConcatenateDefaults_AllowFresh" -Value 1 -PropertyType Dword -Force | Out-Null
    New-ItemProperty -Path "$key" -Name "ConcatenateDefaults_AllowFreshNTLMOnly" -Value 1 -PropertyType Dword -Force | Out-Null

    $result.PreviousFreshNTLMCredDelegationHostCount = Set-CredentialDelegation $key 'AllowFreshCredentialsWhenNTLMOnly' $RemoteHostsToTrust
    $result.PreviousFreshCredDelegationHostCount = Set-CredentialDelegation $key 'AllowFreshCredentials' $RemoteHostsToTrust

    $Result.Success=$True
    return $Result
}

function Set-CredentialDelegation($key, $subKey, $allowed){
    New-ItemProperty -Path "$key" -Name $subKey -Value 1 -PropertyType Dword -Force | Out-Null
    $policyNode = Join-Path $key $subKey
    if (!(Test-Path $policyNode)) {
        md $policyNode | Out-Null
    }
    $currentHostProps=@()
    (Get-Item $policyNode).Property | % {
        $currentHostProps += (Get-ItemProperty -Path $policyNode -Name $_).($_)
    }
    $currentLength = $currentHostProps.Length
    $idx=$currentLength
    $allowed | ? { $currentHostProps -notcontains "wsman/$_"} | % {
        ++$idx
        New-ItemProperty -Path $policyNode -Name "$idx" -Value "wsman/$_" -PropertyType String -Force | Out-Null
    }

    return $currentLength
}

function Get-CredentialDelegationKey {
    return "HKLM:\SOFTWARE\Policies\Microsoft\Windows"
}
tools\Boxstarter.Chocolatey\Enable-RemotePsRemoting.ps1
function Enable-RemotePsRemoting {
##############################################################################
##
## Enable-RemotePsRemoting
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################

<#

.SYNOPSIS

Enables PowerShell Remoting on a remote computer. Requires that the machine
responds to WMI requests, and that its operating system is Windows Vista or
later.

.EXAMPLE

Enable-RemotePsRemoting <Computer>

#>

param(
    ## The computer on which to enable remoting
    $Computername,

    ## The credential to use when connecting
    [Management.Automation.PsCredential]$Credential
)

    $credential = Get-Credential $credential
    $username = $credential.Username
    $password = $credential.GetNetworkCredential().Password

    $script = @"

    `$log = Join-Path `$env:TEMP Enable-RemotePsRemoting.output.txt
    Remove-Item -Force `$log -ErrorAction SilentlyContinue
    Start-Transcript -Path `$log

    if(!(1,3,4,5 -contains (Get-WmiObject win32_computersystem).DomainRole)) { 
        `$networkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')) 
        `$connections = `$networkListManager.GetNetworkConnections() 

        `$connections | % {`$_.GetNetwork().SetCategory(1)}
    } 

    ## Create a task that will run with full network privileges.
    ## In this task, we call Enable-PsRemoting
    schtasks /CREATE /TN 'Temp Enable Remoting' /SC WEEKLY /RL HIGHEST ``
        /RU $username /RP "$password" ``
        /TR "powershell -noprofile -command Enable-PsRemoting -Force | Out-File (Join-Path `$env:TEMP Enable-PSRemoting.txt)" /F |
        Out-String

    ##Give task a normal priority
    `$taskFile = Join-Path `$env:TEMP RemotingTask.txt
    [xml]`$xml = schtasks /QUERY /TN 'Temp Enable Remoting' /XML
    `$xml.Task.Settings.Priority="4"
    `$xml.Save(`$taskFile)
    schtasks /CREATE /TN 'Enable Remoting' /RU $username /RP "$password" /XML "`$taskFile" /F | Out-String
    schtasks /DELETE /TN 'Temp Enable Remoting' /F | Out-String

    schtasks /RUN /TN 'Enable Remoting' | Out-String

    `$securePass = ConvertTo-SecureString "$password" -AsPlainText -Force
    `$credential =
        New-Object Management.Automation.PsCredential $username,`$securepass

    ## Wait for the remoting changes to come into effect
    for(`$count = 1; `$count -le 10; `$count++)
    {
        `$output = Invoke-Command localhost { 1 } -Cred `$credential ``
            -ErrorAction SilentlyContinue
        if(`$output -eq 1) { break; }

        "Attempt `$count : Not ready yet."
        Sleep 5
    }

    ## Delete the temporary task
    schtasks /DELETE /TN 'Enable Remoting' /F | Out-String
    Stop-Transcript

"@

    $commandBytes = [System.Text.Encoding]::Unicode.GetBytes($script)
    $encoded = [Convert]::ToBase64String($commandBytes)

    Write-BoxstarterMessage "Configuring $computername" -Verbose
    $command = "powershell -NoProfile -EncodedCommand $encoded"
    $null = Invoke-WmiMethod -Computer $computername -Credential $credential `
        Win32_Process Create -Args $command
    Sleep 10
    Write-BoxstarterMessage "Testing connection" -Verbose
    for($count = 1; $count -le 100; $count++) {
        $wmiResult = Invoke-Command $computername {
            Get-WmiObject Win32_ComputerSystem } -Credential $credential -ErrorAction SilentlyContinue
        if($wmiResult -ne $Null){
            Write-BoxstarterMessage "PowerShell Remoting enabled successfully"
            break
        }
        else {
            Write-BoxstarterMessage "Attempt $count failed." -Verbose
        }
        if($global:Error.Count -gt 0){
            Write-BoxstarterMessage "$($global:Error[0])" -Verbose
            $global:Error.RemoveAt(0)
        }
    }
}
tools\Boxstarter.Chocolatey\Get-BoxstarterConfig.ps1
function Get-BoxStarterConfig {
<#
.SYNOPSIS
Retrieves persisted Boxstarter configuration settings.

.DESCRIPTION
Boxstarter stores configuration data in an xml file in the Boxstarter base
directory. The Get-BoxstarterConfig function is a convenience function
for reading those settings.

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
about_boxstarter_variable_in_chocolatey
Set-BoxstarterConfig
#>    
    [xml]$configXml = Get-Content (Join-Path $Boxstarter.BaseDir BoxStarter.config)
    if($configXml.config.LocalRepo -ne $null){
        $localRepo=$configXml.config.LocalRepo
    } 
    else {
        if($Boxstarter.baseDir){
            $localRepo=(Join-Path $Boxstarter.baseDir BuildPackages)
        }
    }
    return @{
        LocalRepo=$localRepo;
        NugetSources=$configXml.config.NugetSources;
        ChocolateyRepo=$configXml.config.ChocolateyRepo;
        ChocolateyPackage=$configXml.config.ChocolateyPackage
    }
}
tools\Boxstarter.Chocolatey\Get-PackageRoot.ps1
function Get-PackageRoot{
<#
.SYNOPSIS
Returns the Root path of a Boxstarter Package given the Chocolatey $MyInvocation

.DESCRIPTION
This function is intended to be called from inside a running
ChocolateyInstall.ps1 file. It returns the root path of the package
which is one level above the Tools directory. This can be helpful
when you need to reference any files that you copied to your 
Boxstarter Repository which copies them to this location using
New-BoxstarterPackage.

.PARAMETER Invocation
This is $MyInvocation instance accessible from ChocolateyInstall.ps1

.EXAMPLE
Copy-Item "$env:programfiles\Sublime Text 2\Data\*" Package\Sublime -recurse
New_BoxstarterPackage MyPackage .\Package
#Edit install script
Notepad $($Boxstarter.LocalRepo)\MyPackage\Tools\chocolateyInstall.ps1
Invoke-BoxstarterBuild MyPackage
Invoke-ChocolateyBoxstarter MyPackage

--ChocolateyInstall.ps1--
try {
    cinst sublimetext2
    $sublimeDir = "$env:programfiles\Sublime Text 2"
    mkdir "$sublimeDir\data"
    copy-item (Join-Path Get-PackageRoot($MyInvocation) 'sublime\*') "$sublimeDir\data" -Force -Recurse
    Write-ChocolateySuccess 'MyPackage'
} catch {
  Write-ChocolateyFailure 'MyPackage' $($_.Exception.Message)
  throw
}

.NOTES
Get-PackageRoot is intended to be called from ChocolateyInstall.ps1 
and will throw if it is called from another file.

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
New_BoxstarterPackage
Invoke-ChocolateyBoxstarter
Invoke-BoxstarterBuild
#>
    param(
        [Parameter(Mandatory=$true)]
        [System.Management.Automation.InvocationInfo]$invocation
    )
    if($invocation.MyCommand.Definition -eq $null -or !($invocation.MyCommand.Definition.ToLower().EndsWith("tools\chocolateyinstall.ps1"))){
        throw "Get-PackageRoot can only be used inside of chocolateyinstall.ps1. You Tried to call it from $($invocation.MyCommand.Definition)"
    }
    return (Split-Path -parent(Split-Path -parent $invocation.MyCommand.Definition))
}
tools\Boxstarter.Chocolatey\Init-Settings.ps1
$config = Get-BoxstarterConfig
if(!$BoxStarter.LocalRepo){
   $BoxStarter.LocalRepo=$config.LocalRepo
}
if($BoxStarter.LocalRepo.StartsWith("$env:windir")) {
   $BoxStarter.LocalRepo = Join-Path $(Get-BoxstarterTempDir) "BuildPackages"
   if(!(Test-Path $BoxStarter.LocalRepo)) { mkdir $BoxStarter.LocalRepo | Out-Null }
}
$Boxstarter.NugetSources=$config.NugetSources
$Boxstarter.RebootOk=$true
tools\Boxstarter.Chocolatey\Install-BoxstarterPackage.ps1
function Install-BoxstarterPackage {
<#
.SYNOPSIS
Installs a Boxstarter package

.DESCRIPTION
This function wraps a Chocolatey Install and provides these additional features
 - Installs chocolatey if it is not already installed
 - Installs the .net 4.5 framework if it is not installed which is a chocolatey requirement
 - Disables windows update service during installation to prevent installation conflicts and minimize the need for reboots
 - Imports the Boxstarter.WinConfig module that provides functions for customizing windows
 - Detects pending reboots and restarts the machine when necessary to avoid installation failures
 - Provides Reboot Resiliency by ensuring the package installation is immediately restarted up on reboot if there is a reboot during the installation.
 - Ensures Installation runs under administrator permissions
 - Supports remote installations allowing packages to be installed on a remote machine

 The .nupkg file for the provided package name is searched in the following locations and order:
 - .\BuildPackages relative to the parent directory of the module file
 - The Chocolatey feed
 - The Boxstarter feed on MyGet
 This can be configured by editing $($Boxstarter.BaseDir)\Boxstarter.Config

 If the package name provided is a URL or resolves to a file, then 
 it is assumed that this contains the chocolatey install script and
 a .nupkg file will be created using the script.

 Boxstarter can install packages onto a remote machine. To accomplish this,
 use either the ComputerName, Session or ConnectionURI parameters. Boxstarter uses
 PowerShell remoting to establish an interactive session on the remote computer.
 Boxstarter configures all the necessary client side remoting settings necessary if 
 they are not already configured. Boxstarter will prompt the user to verify that 
 this is OK. Using the -Force switch will suppress the prompt. Boxstarter also ensures
 that CredSSP authentication is enabled so that any network calls made by a package will 
 forward the users credentials.

 PowerShell Remoting must be enabled on the target machine in order to establish a connection. 
 If that machine's WMI ports are accessible, Boxstarter can enable PowerShell remoting 
 on the remote machine on its own. Otherwise, it can be manually enabled by entering 

 Enable-PSRemoting -Force

 In an administrative PowerShell console on the remote machine.
 
 .PARAMETER ComputerName
 If provided, Boxstarter will install the specified package name on all computers.
 Boxstarter will create a Remote Session on each computer using the Credentials 
 given in the Credential parameter.

 .PARAMETER ConnectionURI
 Specifies one or more Uniform Resource Identifiers (URI) that Boxstarter will use 
 to establish a connection with the remote computers upon which the package should 
 be installed. Use this parameter if you need to use a non default PORT or SSL.

 .PARAMETER Session
 If provided, Boxstarter will install the specified package in all given Windows 
 PowerShell sessions. Note that these sessions may be closed by the time 
 Install-BoxstarterPackage finishes. If Boxstarter needs to restart the remote 
 computer, the session will be discarded and a new session will be created using 
 the ConnectionURI of the original session.

 .PARAMETER BoxstarterConnectionConfig
 If provided, Boxstarter will install the specified package name on all computers
 included in the BoxstarterConnectionConfig. This object contains a ComputerName
 and a PSCredential. Use this object if you need to pass different computers
 requiring different credentials.

 .PARAMETER PackageName
 The names of one or more Nuget Packages to be installed or URIs or 
 file paths pointing to a chocolatey script. If using package names,
 the .nupkg file for the provided package names are searched in the 
 following locations and order:
 - .\BuildPackages relative to the parent directory of the module file
 - The Chocolatey feed
 - The Boxstarter feed on MyGet

.PARAMETER DisableReboots
If set, reboots are suppressed.

.PARAMETER Credential
The credentials to use for auto logins after reboots. If installing on
a remote machine, this credential will also be used to establish the 
connection to the remote machine and also for any scheduled task that
boxstarter needs to create and run under a local context.

.PARAMETER KeepWindowOpen
Enabling this switch will prevent the command window from closing and 
prompt the user to pres the Enter key before the window closes. This 
is ideal when not invoking boxstarter from a console.

.Parameter LocalRepo
This is the path to the local boxstarter repository where boxstarter 
should look for .nupkg files to install. By default this is located 
in the BuildPackages directory just under the root Boxstarter 
directory but can be changed with Set-BoxstarterConfig.

.NOTES
If specifying only one package, Boxstarter calls chocolatey with the 
-force argument and deletes the previously installed package directory. 
This means that regardless of whether or not the package had been 
installed previously, Boxstarter will attempt to download and reinstall it.
This only holds true for the outer package. If the package contains calls 
to CINST for additional packages, those installs will not reinstall if 
previously installed.

If an array of package names are passed to Install-BoxstarterPackage, 
Boxstarter will NOT apply the above reinstall logic and will skip the 
install for any package that had been previously installed.

When establishing a remote connection, Boxstarter uses CredSSP 
authentication so that the session can access any network resources 
normally accessible to the Credential. If necessary, Boxstarter 
configures CredSSP authentication on both the local and remote 
machines as well as the necessary Group Policy and WSMan settings 
for credential delegation. When the installation completes, 
Boxstarter rolls back all settings that it changed to their original 
state.

If Boxstarter is not running in an elevated console, it will not attempt 
to enable CredSSP locally if it is not already enabled. It will also not 
try to enable PowerShell remoting if not running as administrator.

When using a Windows PowerShell session instead of ComputerName or 
ConnectionURI, Boxstarter will use the authentication mechanism of the 
existing session and will not configure CredSSP if the session provided 
is not using CredSSP. If the session is not using CredSSP, it may be 
denied access to network resources normally accessible to the Credential 
being used. If you do need to access network resources external to the 
session, you should use CredSSP when establishing the connection.

.INPUTS
ComputerName, ConnrectionURI and Session may all be specified on the 
pipeline.

.OUTPUTS
Returns a PSObject for each session, ComputerName or ConnectionURI or a 
single PSObject for local installations. The PSObject has the following 
properties:

ComputerName: The name of the computer where the package was installed

StartTime: The time that the installation began

FinishTime: The time that Boxstarter finished the installation

Completed: True or False indicating if Boxstarter was able to complete 
the installation without a terminating exception interrupting the install. 
Even if this value is True, it does not mean that all components installed 
in the package succeeded. Boxstarter will not terminate an installation if 
individual Chocolatey packages fail. Use the Errors property to discover 
errors that were raised throughout the installation.

Errors: An array of all errors encountered during the duration of the 
installation.

.EXAMPLE
Invoke-ChocolateyBoxstarter "example1","example2"

This installs the example1 and example2 .nupkg files. If pending 
reboots are detected, boxstarter will restart the machine. Boxstarter
will not perform automatic logins after restart since no Credential
was given.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage -Package https://gist.github.com/mwrock/6771863/raw/b579aa269c791a53ee1481ad01711b60090db1e2/gistfile1.txt `
   -Credential $cred

This installs the script uploaded to the github gist. The credentials
of the user mwrock are used to automatically login the user if 
boxstarter needs to reboot the machine.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage -ComputerName MyOtherComputer.mydomain.com -Package MyPackage -Credential $cred

This installs the MyPackage package on MyOtherComputer.mydomain.com.

.EXAMPLE
$cred=Get-Credential mwrock
$session=New-PSSession SomeComputer -Credential $cred
Install-BoxstarterPackage -Session $session -Package MyPackage -Credential $cred

This installs the MyPackage package on an existing session established with 
SomeComputer. A Credential is still passed to Boxstarter even though it is 
also used to establish the session because Boxstarter will need it for logons
and creating Scheduled Tasks on SomeComputer. If Boxstarter does need to 
reboot SomeComputer, it will need to create a new session after SomeComputer
has rebooted and then $session will no longer be in an Available state when
Install-BoxstarterPackage completes.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage -ConnectionURI http://RemoteComputer:59876/wsman -Package MyPackage -Credential $cred

This installs the MyPackage package on RemoteComputer which does not
listen on the default wsman port but has been configured to listen 
on port 59876.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage -ComputerName MyOtherComputer.mydomain.com -Package MyPackage -Credential $cred -Force

This installs the MyPackage package on MyOtherComputer.mydomain.com.
Because the -Force parameter is used, Boxstarter will not prompt the
user to confirm that it is OK to enable PowerShell remoting if it is 
not already enabled. It will attempt to enable it without prompts.

.EXAMPLE
$cred=Get-Credential mwrock
"computer1","computer2" | Install-BoxstarterPackage -Package MyPackage -Credential $cred -Force

This installs the MyPackage package on computer1 and computer2
Because the -Force parameter is used, Boxstarter will not prompt the
user to confirm that it is OK to enable PowerShell remoting if it is 
not already enabled. It will attempt to enable it without prompts.

Using -Force is especially advisable when installing packages on multiple 
computers because otherwise, if one computer is not accessible, the command 
will prompt the user if it is OK to try and configure the computer before 
proceeding to the other computers.

.EXAMPLE
$cred1=Get-Credential mwrock
$cred2=Get-Credential domain\mwrock
(New-Object -TypeName BoxstarterConnectionConfig -ArgumentList "computer1",$cred1), `
(New-Object -TypeName BoxstarterConnectionConfig -ArgumentList "computer2",$cred2) |
Install-BoxstarterPackage -Package MyPackage

This installs the MyPackage package on computer1 and computer2 and uses
different credentials for each computer.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage script.ps1 -Credential $cred

This installs the script located at script.ps1 
in the command line's current directory.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage \\server\share\script.ps1 -Credential $cred

This invokes boxstarter and installs the script located at the 
specified share.

.EXAMPLE
$cred=Get-Credential mwrock
Install-BoxstarterPackage win8Install -LocalRepo \\server\share\boxstarter -Credential $cred

This installs the Win8Install .nupkg. Boxstarter will look 
for the Win8Install .nupkg file in the \\serer\share\boxstarter 
directory.


.LINK
http://boxstarter.org
about_boxstarter_chocolatey
#>
    [CmdletBinding(DefaultParameterSetName="Package")]
	param(
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$True, ParameterSetName="BoxstarterConnectionConfig")]
        [BoxstarterConnectionConfig[]]$BoxstarterConnectionConfig,
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$True, ParameterSetName="ComputerName")]
        [string[]]$ComputerName,
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$True, ParameterSetName="ConnectionUri")]
        [Uri[]]$ConnectionUri,
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$True, ParameterSetName="Session")]
        [System.Management.Automation.Runspaces.PSSession[]]$Session,
        [parameter(Mandatory=$true, Position=0, ParameterSetName="Package")]
        [parameter(Mandatory=$true, Position=1, ParameterSetName="ComputerName")]
        [parameter(Mandatory=$true, Position=1, ParameterSetName="ConnectionUri")]
        [parameter(Mandatory=$true, Position=1, ParameterSetName="Session")]
        [parameter(Mandatory=$true, Position=1, ParameterSetName="BoxstarterConnectionConfig")]
        [string[]]$PackageName,
        [Management.Automation.PsCredential]$Credential,
        [switch]$Force,
        [switch]$DisableReboots,
        [parameter(ParameterSetName="Package")]
        [switch]$KeepWindowOpen,
        [string]$LocalRepo,
        [switch]$DisableRestart
    )
    $CurrentVerbosity=$global:VerbosePreference
    try {

        if($PSBoundParameters["Verbose"] -eq $true) {
            $global:VerbosePreference="Continue"
        }

        #If no PSRemoting based param's are present, we just run locally
        if($PsCmdlet.ParameterSetName -eq "Package"){
            Invoke-Locally @PSBoundParameters
            return
        }

        #me me me!
        Write-BoxstarterLogo
        
        #Convert pipeline to array
        $list=@($input)
        if($list.Count){
            Set-Variable -Name $PsCmdlet.ParameterSetName -Value $list
        }

        $sessionArgs=@{}
        if($Credential){
            $sessionArgs.Credential=$Credential
        }

        #If $sessions are being provided we assume remoting is setup on both ends
        #and don't need to test, configure and tear down
        if($Session -ne $null){
            Process-Sessions $Session $sessionArgs
            return
        }

        #We need the computer names to configure remoting
        if(!$ComputerName){
            if($BoxstarterConnectionConfig){
                $uris = $BoxstarterConnectionConfig | % { $_.ConnectionURI }
            }
            else{
                $uris = $ConnectionUri
            }
            $ComputerName = Get-ComputerNames $uris
        }

        try{
            #Enable remoting settings if necessary on client
            $ClientRemotingStatus=Enable-BoxstarterClientRemoting $ComputerName

            #If unable to enable remoting on the client, abort
            if(!$ClientRemotingStatus.Success){return}

            $CredSSPStatus=Enable-BoxstarterCredSSP $ComputerName

            if($ConnectionURI){
                $ConnectionUri | %{
                    $sessionArgs.ConnectionURI = $_
                    Write-BoxstarterMessage "Installing $packageName on $($_.ToString())"
                    Install-BoxstarterPackageOnComputer $_.Host $sessionArgs $PackageName $DisableReboots $CredSSPStatus
                }
            }
            elseif($BoxstarterConnectionConfig) {
                $BoxstarterConnectionConfig | %{
                    $sessionArgs.ConnectionURI = $_.ConnectionURI
                    if($_.Credential){
                        $sessionArgs.Credential = $_.Credential
                    }
                    if($_.PSSessionOption){
                        $sessionArgs.SessionOption = $_.PSSessionOption
                    }
                    Install-BoxstarterPackageOnComputer $_.ConnectionURI.Host $sessionArgs $PackageName $DisableReboots $CredSSPStatus $false
                }
            }
            else {
                $ComputerName | %{
                    $sessionArgs.ComputerName = $_
                    Install-BoxstarterPackageOnComputer $_ $sessionArgs $PackageName $DisableReboots $CredSSPStatus
                }
            }
        }
        finally{
            #Client settings should be as they were when we started
            Rollback-ClientRemoting $ClientRemotingStatus $CredSSPStatus
        }
    }
    finally{
        $global:VerbosePreference=$CurrentVerbosity
    }
}

function Get-ComputerNames([URI[]]$ConnectionUris) {
    $computerNames = @()

    Write-BoxstarterMessage "resolving URIs to computer names..." -Verbose
    $ConnectionUris | %{
        if($_ -eq $null) {
            Write-BoxstarterMessage "Tried to resolve Null URI" -Verbose
        }
        else {
            Write-BoxstarterMessage "$($_ -is [uri]) found $($_.Host) for $($_.ToString())" -Verbose
            $computerNames+=$_.Host
        }
    }
    return $computerNames
}

function Process-Sessions($sessions, $sessionArgs){
    $Sessions | %{
        Write-BoxstarterMessage "Processing Session..." -Verbose
        Set-SessionArgs $_ $sessionArgs
        $record = Start-Record $_.ComputerName
        try {
            if(-not (Install-BoxstarterPackageForSession $_ $PackageName $DisableReboots $sessionArgs)){
                $record.Completed=$false
            }
        }
        catch {
            $record.Completed=$false
        }
        finally{
            Finish-Record $record
        }
    }
}

function Start-Record($computerName) {
    $global:error.Clear()
    $props = @{
        StartTime = Get-Date
        Completed = $true
        ComputerName = $computerName
        Errors = @()
        FinishTime = $null
    }
    return (New-Object PSObject -Prop $props)
}

function Finish-Record($obj) {
    Write-BoxstarterMessage "Composing record for pipeline..." -Verbose
    $obj.FinishTime = Get-Date
    $global:error | %{
        if($_.CategoryInfo -ne $null -and $_.CategoryInfo.Category -eq "OperationStopped"){
            Log-BoxstarterMessage $_
        }
        else {
            $obj.Errors += $_
        }
    }
    Write-BoxstarterMessage "writing object..." -Verbose
    Write-Output $obj
    Write-BoxstarterMessage "object written..." -Verbose
}

function Install-BoxstarterPackageOnComputer ($ComputerName, $sessionArgs, $PackageName, $DisableReboots, $CredSSPStatus, $TestRemoting = $true){
    $record = Start-Record $ComputerName
    try {
        if($TestRemoting -and !(Enable-RemotingOnRemote $sessionArgs $ComputerName)){
            Write-Error "Unable to access remote computer via PowerShell Remoting or WMI. You can enable it by running: Enable-PSRemoting -Force from an Administrator PowerShell console on the remote computer."
            $record.Completed=$false
            return
        }

        if($CredSSPStatus.Success){
            $enableCredSSP = Should-EnableCredSSP $sessionArgs $computerName
        }

        write-BoxstarterMessage "Creating a new session with $computerName..." -Verbose
        $session = New-PSSession @sessionArgs -Name Boxstarter

        if(-not (Install-BoxstarterPackageForSession $session $PackageName $DisableReboots $sessionArgs $enableCredSSP)){
            $record.Completed=$false
        }
    }
    catch {
        $record.Completed=$false
        Write-Error $_
    }
    finally{
        Finish-Record $record
    }
}

function Install-BoxstarterPackageForSession($session, $PackageName, $DisableReboots, $sessionArgs, $enableCredSSP) {
    try{
        if($session.Availability -ne "Available"){
            write-Error (New-Object -TypeName ArgumentException -ArgumentList "The Session is not Available")
            return $false
        }

        for($count = 1; $count -le 5; $count++) {
            try {
                Write-BoxstarterMessage "Attempt #$count to copy Boxstarter modules to $($session.ComputerName)" -Verbose
                Setup-BoxstarterModuleAndLocalRepo $session
                break
            }
            catch {
                if($global:Error.Count -gt 0){$global:Error.RemoveAt(0)}
                if($count -eq 5) { throw $_ }
            }
        }

        if($enableCredSSP){
            $credSSPSession = Enable-RemoteCredSSP $sessionArgs
            if($session -ne $null -and $credSSPSession -ne $null){
                Write-BoxstarterMessage "CredSSP session succeeded. Replacing sessions..."
                Remove-PSSession $session -ErrorAction SilentlyContinue
                $session=$credSSPSession
            }
        }
        
        Invoke-Remotely $session $PackageName $DisableReboots $sessionArgs
        return $true
    }
    finally {
        Write-BoxstarterMessage "checking if session should be removed..." -Verbose
        if($session -ne $null -and $session.Name -eq "Boxstarter") {
            Write-BoxstarterMessage "Removing session..." -Verbose
            Remove-PSSession $Session
            Write-BoxstarterMessage "Session removed..." -Verbose
            $Session = $null
        }

        if($sessionArgs.Authentication){
            $sessionArgs.Remove("Authentication")
        }
        if($enableCredSSP){
            Disable-RemoteCredSSP $sessionArgs
        }
    }
}

function Invoke-Locally {
    param(
        [string[]]$PackageName,
        [Management.Automation.PsCredential]$Credential,
        [switch]$Force,
        [switch]$DisableReboots,
        [switch]$KeepWindowOpen,
        [switch]$DisableRestart
    )
    if($PSBoundParameters.ContainsKey("Credential")){
        if($Credential -ne $null) {
            $PSBoundParameters.Add("Password",$PSBoundParameters["Credential"].Password)
        }
        $PSBoundParameters.Remove("Credential") | out-Null
    }
    else {
        $PSBoundParameters.Add("NoPassword",$True)
    }
    if($PSBoundParameters.ContainsKey("Force")){
        $PSBoundParameters.Remove("Force") | out-Null
    }
    $PSBoundParameters.Add("BootstrapPackage", $PSBoundParameters.PackageName)
    $PSBoundParameters.Remove("PackageName") | out-Null

    $record = Start-Record 'localhost'
    try {
        Invoke-ChocolateyBoxstarter @PSBoundParameters | Out-Null
    }
    catch {
        $record.Completed=$false
        throw
    }
    finally{
        Finish-Record $record
    }
}

function Enable-RemotingOnRemote ($sessionArgs, $ComputerName){
    Write-BoxstarterMessage "Testing remoting access on $ComputerName..."
    try { 
        $remotingTest = Invoke-Command @sessionArgs { Get-WmiObject Win32_ComputerSystem } -ErrorAction Stop
    }
    catch {
        Write-BoxstarterMessage $_.ToString() -Verbose
        $sessionArgs.Keys | % {
            Write-BoxstarterMessage "session arg key: $_ has value $($sessionArgs[$_])" -Verbose
        }
        Write-BoxstarterMessage "using credential username $($sessionArgs.Credential.UserName)" -Verbose
        $global:error.RemoveAt(0)
    }
    if($remotingTest -eq $null){
        Write-BoxstarterMessage "PowerShell Remoting is not enabled or accessible on $ComputerName" -Verbose
        if(Test-Admin) {
            $wmiTest=Invoke-WmiMethod -ComputerName $ComputerName -Credential $sessionArgs.Credential Win32_Process Create -Args "cmd.exe" -ErrorAction SilentlyContinue
        }
        if($wmiTest -eq $null){
            if($global:Error.Count -gt 0){ $global:Error.RemoveAt(0) }
            return $false
        }
        if($Force -or (Confirm-Choice "PowerShell Remoting is not enabled on Remote computer. Should Boxstarter enable PowerShell remoting? This will also change the Network Location type on the remote machine to PRIVATE if it is currently PUBLIC.")){
            Write-BoxstarterMessage "Enabling PowerShell Remoting on $ComputerName"
            Enable-RemotePSRemoting $ComputerName $sessionArgs.Credential
        }
        else {
            Write-BoxstarterMessage "Not enabling local PowerShell Remoting on $ComputerName. Aborting package install"
            return $False
        }
    }
    else {
        Write-BoxstarterMessage "Remoting is accessible on $ComputerName"
    }
    return $True
}

function Setup-BoxstarterModuleAndLocalRepo($session){
    if($LocalRepo){$Boxstarter.LocalRepo=$LocalRepo}
    Write-BoxstarterMessage "Copying Boxstarter Modules and LocalRepo packages at $($Boxstarter.BaseDir) to $env:temp on $($Session.ComputerName)..."
    Invoke-Command -Session $Session { mkdir $env:temp\boxstarter\BuildPackages -Force  | out-Null }
    Send-File "$($Boxstarter.BaseDir)\Boxstarter.Chocolatey\Boxstarter.zip" "Boxstarter\boxstarter.zip" $session
    Get-ChildItem "$($Boxstarter.LocalRepo)\*.nupkg" | % { 
        Write-BoxstarterMessage "Copying $($_.Name) to $($Session.ComputerName)" -Verbose
        Send-File "$($_.FullName)" "Boxstarter\BuildPackages\$($_.Name)" $session 
    }
    Invoke-Command -Session $Session {
        Set-ExecutionPolicy Bypass -Force
        $shellApplication = new-object -com shell.application 
        $zipPackage = $shellApplication.NameSpace("$env:temp\Boxstarter\Boxstarter.zip") 
        $destinationFolder = $shellApplication.NameSpace("$env:temp\boxstarter") 
        $destinationFolder.CopyHere($zipPackage.Items(),0x10)
        [xml]$configXml = Get-Content (Join-Path $env:temp\Boxstarter BoxStarter.config)
        if($configXml.config.LocalRepo -ne $null) {
            $configXml.config.RemoveChild(($configXml.config.ChildNodes | ? { $_.Name -eq "LocalRepo"}))
            $configXml.Save((Join-Path $env:temp\Boxstarter BoxStarter.config))
        }
    }
}

function Invoke-RemoteBoxstarter($Package, $Credential, $DisableReboots, $session) {
    Write-BoxstarterMessage "Running remote install..."
    $remoteResult = Invoke-Command -session $session {
        param($SuppressLogging,$pkg,$Credential,$DisableReboots, $verbosity, $ProgressArgs)
        $global:VerbosePreference=$verbosity
        Import-Module $env:temp\Boxstarter\Boxstarter.Common\Boxstarter.Common.psd1 -DisableNameChecking
        if($Credential -eq $null){
            $currentUser = Get-CurrentUser
            $credential = (New-Object Management.Automation.PsCredential ("$($currentUser.Domain)\$($currentUser.Name)", (New-Object System.Security.SecureString)))
        }
        Create-BoxstarterTask $Credential
        Import-Module $env:temp\Boxstarter\Boxstarter.Chocolatey\Boxstarter.Chocolatey.psd1
        $Boxstarter.SuppressLogging=$SuppressLogging
        $global:Boxstarter.ProgressArgs=$ProgressArgs 
        $result=$null
        try {
            $result = Invoke-ChocolateyBoxstarter $pkg -Password $Credential.password -DisableReboots:$DisableReboots
            if($Boxstarter.IsRebooting){
                return @{Result="Rebooting"}
            }
            if($result=$true){
                return @{Result="Completed"}
            }
        }
        catch{
            throw $_
        }
    } -ArgumentList $Boxstarter.SuppressLogging, $Package, $Credential, $DisableReboots, $global:VerbosePreference, $global:Boxstarter.ProgressArgs
    Write-BoxstarterMessage "Result from Remote Boxstarter: $($remoteResult.Result)" -Verbose
    return $remoteResult
}

function Test-RebootingOrDisconnected($RemoteResult) {
    if($remoteResult -eq $null -or $remoteResult.Result -eq $null -or $remoteResult.Result -eq "Rebooting") {
        return $true
    }
    else {
        return $false
    }
}

function Wait-ForSessionToClose($session) {
    Write-BoxstarterMessage "Waiting for $($session.ComputerName) to sever remote session..."
    $timeout=0
    while($session.State -eq "Opened" -and $timeout -lt 120){
        $timeout += 2
        start-sleep -seconds 2
    }
}

function Test-ShutDownInProgress($Session) {
    $response=Invoke-Command -Session $Session {
        try {
        $systemMetrics = Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public static class SystemMetrics
{
    private const int SM_SHUTTINGDOWN = 0x2000;

    [DllImport("user32.dll")]
    public static extern int GetSystemMetrics(int smIndex);

    public static bool IsShuttingdown() 
    {
        return (GetSystemMetrics(SM_SHUTTINGDOWN) != 0);
    }

}
"@ -PassThru            
        } catch {}
        if ($systemMetrics){
            return $systemMetrics::IsShuttingdown()            
        }
    }

    if($response -eq $false) {
        Write-BoxstarterMessage "System Shutdown not in progress" -Verbose
    }
    else {
        Write-BoxstarterMessage "System Shutdown in progress" -Verbose
    }

    return $response
}

function Test-Reconnection($Session, $sessionPID) {
    $reconnected = $false

    #If there is a pending reboot then session is in the middle of a restart
    $response=Invoke-Command -Session $session { 
        Import-Module $env:temp\Boxstarter\Boxstarter.Chocolatey\Boxstarter.Chocolatey.psd1 
        return Test-PendingReboot
    } -ErrorAction SilentlyContinue
    Write-BoxstarterMessage "Reboot check returned $response" -Verbose


    if($response -ne $null -and $response -eq $false){
        #Check for a system shutdown in progress
        $response = Test-ShutDownInProgress $session

        if($response -eq $false) {
            $reconnected = $true #Session is connectible
            try{
                #In case previous session's task is still alive kill it so it does not lock anything
                Write-BoxstarterMessage "Killing $sessionPID" -Verbose
                Invoke-Command -Session $session { 
                    param($p)
                    if(Get-Process -Id $p -ErrorAction SilentlyContinue){
                        KILL $p -ErrorAction Stop -Force
                    }
                    else {
                        $global:Error.RemoveAt(0)
                    }
                } -ArgumentList $sessionPID
            } catch{
                Write-BoxstarterMessage "Failed to kill $sessionPID : $($global:Error[0])" -Verbose
                $global:Error.RemoveAt(0)
            }
        }
    }
    #if the session is pending a reboot but not in the middle of a system shutdown, 
    #try to invoke a reboot to prevent us from hanging while waiting
    elseif($response -eq $true -and !(Test-ShutDownInProgress $session)){
        Write-BoxstarterMessage "Attempting to restart $($session.ComputerName)" -Verbose
        Invoke-Command -Session $session { 
            Import-Module $env:temp\Boxstarter\Boxstarter.Chocolatey\Boxstarter.Chocolatey.psd1 
            $Boxstarter.RebootOK=$true
            if(Test-PendingReboot){restart-Computer -Force }
        } -ErrorAction SilentlyContinue
    }

    return $reconnected
}

function Invoke-Remotely($session,$Package,$DisableReboots,$sessionArgs){
    Write-BoxstarterMessage "Invoking remote install" -verbose
    while($session.Availability -eq "Available") {
        $sessionPID = Invoke-Command -Session $session { return $PID }
        Write-BoxstarterMessage "Session's process ID is $sessionPID" -verbose
        $remoteResult = Invoke-RemoteBoxstarter $Package $sessionArgs.Credential $DisableReboots $session

        if(Test-RebootingOrDisconnected $remoteResult) {
            Wait-ForSessionToClose $session

            $reconnected=$false
            Write-BoxstarterMessage "Waiting for $($session.ComputerName) to respond to remoting..."
            Do{
                if($session -ne $null){
                    Remove-PSSession $session
                    $session = $null
                }
                $response=$null
                start-sleep -seconds 2
                $session = New-PSSession @sessionArgs -Name Boxstarter -ErrorAction SilentlyContinue
                if($session -eq $null) {
                    $global:Error.RemoveAt(0)
                }
                elseif($session -ne $null -and $Session.Availability -eq "Available"){
                    if($remoteResult.Result -eq "Rebooting"){$sessionPID=-1}
                    $reconnected = Test-Reconnection $session $sessionPID
                }
            }
            Until($reconnected -eq $true)
        }
        else {
            break
        }
    }
}

function Set-SessionArgs($session, $sessionArgs) {
    $uri = try { Invoke-Command $session {return $PSSenderInfo.ConnectionString} -ErrorAction SilentlyContinue } catch{}
    if($uri){
        $sessionArgs.ConnectionURI=$uri
    }
    else{
        $sessionArgs.ComputerName=$session.ComputerName
    }    
}

function Should-EnableCredSSP($sessionArgs, $computerName) {
    Write-BoxstarterMessage "Testing remote CredSSP..." -Verbose
    if($sessionArgs.Credential){
        $uriArgs=@{}
        if($sessionArgs.ConnectionURI){
            $uri = [URI]$sessionArgs.ConnectionURI
            $uriArgs = @{Port=$uri.port;UseSSL=($uri.scheme -eq "https")}
        }
        try {
            $credsspEnabled = Test-WsMan -ComputerName $ComputerName @uriArgs -Credential $SessionArgs.Credential -Authentication CredSSP -ErrorAction SilentlyContinue
        } 
        catch {
            Write-BoxstarterMessage "Exception from testing WSMan for CredSSP access" -Verbose
            try { $xml=[xml]$_ } catch { $global:Error.RemoveAt(0) }
            if($xml -ne $null) {
                Write-BoxstarterMessage "WSMan Fault Found" -Verbose
                Write-BoxstarterMessage "$($xml.OuterXml)" -Verbose
            }
            else {
                Write-BoxstarterMessage $_ -Verbose
            }
        }
        if($credsspEnabled -eq $null){
            Write-BoxstarterMessage "Need to enable CredSSP on server" -Verbose
            if($global:Error.Count -gt 0){ $global:Error.RemoveAt(0) }
            return $True
        }
        else{
            Write-BoxstarterMessage "CredSSP test response:" -Verbose
            [System.Xml.XmlElement]$xml=$credsspEnabled
            if($xml -ne $null) {
                Write-BoxstarterMessage "WSMan XML Found..." -Verbose
                Write-BoxstarterMessage "$($xml.OuterXml)" -Verbose
            }
            $sessionArgs.Authentication="CredSSP"
        }
    }
    Write-BoxstarterMessage "Do not need to enable CredSSP on server" -Verbose
    return $false
}

function Enable-RemoteCredSSP($sessionArgs) {
    Write-BoxstarterMessage "Creating a scheduled task to enable CredSSP Authentication on $ComputerName..."
    $n=Invoke-RetriableScript {
        $splat=$args[0]
        Invoke-Command @splat { 
            param($Credential)
            Import-Module $env:temp\Boxstarter\Boxstarter.Common\Boxstarter.Common.psd1 -DisableNameChecking
            Create-BoxstarterTask $Credential
            Invoke-FromTask "Enable-WSManCredSSP -Role Server -Force | out-Null"
            Remove-BoxstarterTask
        } -ArgumentList $args[0].Credential
    } $sessionArgs
    $sessionArgs.Authentication="CredSSP"
    Write-BoxstarterMessage "Creating New session with CredSSP Authentication..." -Verbose
    try { 
        $session = Invoke-RetriableScript {
            $splat=$args[0]
            $s = New-PSSession @splat -Name Boxstarter -ErrorAction Stop
            return $s
        } $sessionArgs
    }
    catch {
        $sessionArgs.Remove("Authentication")
        $session=$null
        Write-BoxstarterMessage "Unable to create CredSSP session. Error was: $($_.ToString())" -Verbose
        $global:error.RemoveAt(0)
    }
    return $session
}

function Disable-RemoteCredSSP ($sessionArgs){
    Write-BoxstarterMessage "Disabling CredSSP Authentication on $ComputerName" -Verbose
    Invoke-Command @sessionArgs { 
        param($Credential, $verbosity)
        $Global:VerbosePreference = $verbosity
        Import-Module $env:temp\Boxstarter\Boxstarter.Common\Boxstarter.Common.psd1 -DisableNameChecking
        Create-BoxstarterTask $Credential
        $taskResult = Invoke-FromTask "Disable-WSManCredSSP -Role Server"
        Write-BoxstarterMessage "result from disabling CredSSP is: $taskResult" -Verbose
        Remove-BoxstarterTask
    } -ArgumentList $sessionArgs.Credential, $Global:VerbosePreference
    Write-BoxstarterMessage "Finished disabling CredSSP Authentication on $ComputerName" -Verbose
}

function Rollback-ClientRemoting($ClientRemotingStatus, $CredSSPStatus) {
    Write-BoxstarterMessage "Rolling back remoting settings changed by Boxstarter..."
    if($ClientRemotingStatus.PreviousTrustedHosts -ne $null){
        $currentHosts=Get-Item "wsman:\localhost\client\trustedhosts"
        if($currentHosts.Value -ne $ClientRemotingStatus.PreviousTrustedHosts) {
            Write-BoxstarterMessage "Reseting wsman Trusted Hosts to $($ClientRemotingStatus.PreviousTrustedHosts)" -Verbose
            Set-Item "wsman:\localhost\client\trustedhosts" -Value "$($ClientRemotingStatus.PreviousTrustedHosts)" -Force
        }
    }
    if($CredSSPStatus -ne $null -and $CredSSPStatus.Success){
        try {Disable-WSManCredSSP -Role Client -ErrorAction SilentlyContinue } catch{ Write-BoxstarterMessage "Unable to disable CredSSP locally" }
        if($CredSSPStatus.PreviousCSSPTrustedHosts -ne $null){
            try{
                Write-BoxstarterMessage "Reseting CredSSP Trusted Hosts to $($CredSSPStatus.PreviousCSSPTrustedHosts.Replace('wsman/',''))" -Verbose
                Enable-WSManCredSSP -DelegateComputer $CredSSPStatus.PreviousCSSPTrustedHosts.Replace("wsman/","") -Role Client -Force | Out-Null
            }
            catch{}
        }
        Write-BoxstarterMessage "Reseting GroupPolicy for Credentials Delegation" -Verbose
        if(Test-Path "$(Get-CredentialDelegationKey)\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly") {
            (Get-Item "$(Get-CredentialDelegationKey)\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly").Property | % {
                if([int]$_ -gt $CredSSPStatus["PreviousFreshNTLMCredDelegationHostCount"]) {
                    Remove-ItemProperty "$(Get-CredentialDelegationKey)\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly" -Name $_
                }
            }
        }

        if(Test-Path "$(Get-CredentialDelegationKey)\CredentialsDelegation\AllowFreshCredentials") {
            (Get-Item "$(Get-CredentialDelegationKey)\CredentialsDelegation\AllowFreshCredentials").Property | % {
                if([int]$_ -gt $CredSSPStatus["PreviousFreshCredDelegationHostCount"]) {
                    Remove-ItemProperty "$(Get-CredentialDelegationKey)\CredentialsDelegation\AllowFreshCredentials" -Name $_
                }
            }
        }
    }
}
tools\Boxstarter.Chocolatey\install-chocolatey.ps1
function Install-Chocolatey($pkgUrl) {
  $chocTempDir = Join-Path $env:TEMP "chocolatey"
  $tempDir = Join-Path $chocTempDir "chocInstall"
  if (![System.IO.Directory]::Exists($tempDir)) {[System.IO.Directory]::CreateDirectory($tempDir)}
  $file = Join-Path $tempDir "chocolatey.zip"

  # download the package
  Get-HttpToFile $pkgUrl $file

  # download 7zip
  Write-Host "Download 7Zip commandline tool"
  $7zaExe = Join-Path $tempDir '7za.exe'
  Get-HttpToFile 'https://chocolatey.org/7za.exe' "$7zaExe"

  # unzip the package
  Write-Host "Extracting $file to $tempDir..."
  Start-Process "$7zaExe" -ArgumentList "x -o`"$tempDir`" -y `"$file`"" -Wait -NoNewWindow

  # call chocolatey install
  Write-Host "Installing chocolatey on this machine"
  $toolsFolder = Join-Path $tempDir "tools"
  $chocInstallPS1 = Join-Path $toolsFolder "chocolateyInstall.ps1"

  $chocInstallVariableName = "ChocolateyInstall"
  $chocoPath = [Environment]::GetEnvironmentVariable($chocInstallVariableName, [System.EnvironmentVariableTarget]::User)
  $chocoExePath = 'C:\ProgramData\Chocolatey\bin'
  if ($chocoPath -ne $null) {
    $chocoExePath = Join-Path $chocoPath 'bin'
  }

  # The chocoExePath will only already exist if we are installing
  # old PS choco over new c# choco. If thats the case, we do not
  # want to wipe out the new shims so delete these old-style ones
  # before the choco inmstaller copies them over
  if(Test-Path $chocoExePath) {
    Remove-Item -Path "$toolsFolder\ChocolateyInstall\Redirects\*"

    # This is a shameful hack to avoid a PSv2 bug hit if installing
    # boxstarter after installing the c# choco where the bug causes
    # a PS prompt but choco wires up PS in such a way that prompts
    # are hidden and thus the install hangs
    Set-Content -Path "$toolsFolder\ChocolateyInstall\Redirects\empty.exe" -Value ""
  }

  & $chocInstallPS1

  write-host 'Ensuring chocolatey commands are on the path'
  if ($($env:Path).ToLower().Contains($($chocoExePath).ToLower()) -eq $false) {
    $env:Path = [Environment]::GetEnvironmentVariable('Path',[System.EnvironmentVariableTarget]::Machine)
  }
}
tools\Boxstarter.Chocolatey\Invoke-BoxstarterBuild.ps1
function Invoke-BoxStarterBuild {
<#
.SYNOPSIS
Packs a specific package or all packages in the Boxstarter Repository

.DESCRIPTION
Invoke-BoxStarterBuild packs either a single package or all packages
in the local repository. The packed .nupkg is placed in the root of
the LocalRepo and is then able to be consumed by 
Invoke-ChocolateyBoxstarter.

.PARAMETER Name
The name of the package to pack

.PARAMETER All
Indicates that all package directories in the repository should be packed

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
Invoke-BoxstarterBuild
New-BoxstarterPackage
#>
    [CmdletBinding()]
    param(
        [Parameter(Position=0,ParameterSetName='name')]
        [string]$name,
        [Parameter(Position=0,ParameterSetName='all')]
        [switch]$all,
        [switch]$quiet
    )
    $choco="$env:ChocolateyInstall\chocolateyinstall\chocolatey.ps1"
    if(!$boxstarter -or !$boxstarter.LocalRepo){
        throw "No Local Repository has been set in `$Boxstarter.LocalRepo."
    }
    pushd $Boxstarter.LocalRepo
    try{
        if($name){
            $searchPath = join-path $name "$name.nuspec"
            Write-BoxstarterMessage "Searching for $searchPath" -Verbose
            if(!(Test-Path $searchPath)){
                throw "Cannot find $($Boxstarter.LocalRepo)\$searchPath"
            }
            .$choco Pack (join-path $name "$name.nuspec") | out-null
            if(!$quiet){
                Write-BoxstarterMessage "Your package has been built. Using Boxstarter.bat $name or Install-BoxstarterPackage $name will run this package." -nologo
            }
        } else {
             if($all){
                Write-BoxstarterMessage "Scanning $($Boxstarter.LocalRepo) for package folders"
                Get-ChildItem . | ? { $_.PSIsContainer } | % {
                    $directoriesExist=$true
                    Write-BoxstarterMessage "Found directory $($_.name). Looking for $($_.name).nuspec"
                    if(Test-Path (join-path $_.name "$($_.name).nuspec")){
                        .$choco Pack (join-path . "$($_.Name)\$($_.Name).nuspec") | out-null
                        if(!$quiet){
                            Write-BoxstarterMessage "Your package has been built. Using Boxstarter.bat $($_.Name) or Install-BoxstarterPackage $($_.Name) will run this package." -nologo                        
                        }
                    }
                }
                if($directoriesExist -eq $null){
                    Write-BoxstarterMessage "No Directories exist under $($boxstarter.LocalRepo)"
                }
            }
        }
    }
    finally {
        popd    
    }
}
tools\Boxstarter.Chocolatey\Invoke-ChocolateyBoxstarter.ps1
function Invoke-ChocolateyBoxstarter{
<#
.SYNOPSIS
Invokes the installation of a Boxstarter package

.DESCRIPTION
This essentially wraps Chocolatey Install and provides these additional features
 - Installs chocolatey if it is not already installed
 - Installs the .net 4.5 framework if it is not installed which is a chocolatey requirement
 - Disables windows update service during installation to prevent installation conflicts and minimize the need for reboots
 - Imports the Boxstarter.WinConfig module that provides functions for customizing windows
 - Detects pending reboots and restarts the machine when necessary to avoid installation failures
 - Provides Reboot Resiliency by ensuring the package installation is immediately restarted up on reboot if there is a reboot during the installation.
 - Ensures everything runs under administrator permissions

 The .nupkg file for the provided package name is searched in the following locations and order:
 - .\BuildPackages relative to the parent directory of the module file
 - The Chocolatey feed
 - The Boxstarter feed on MyGet
 This can be configured by editing $($Boxstarter.BaseDir)\Boxstarter.Config

 If the package name provided is a URL or resolves to a file. Then 
 it is assumed that this contains the chocolatey install script and
 a .nupkg file will be created using the script.
 
 .PARAMETER BootstrapPackage
 The names of one or more Nuget Packages to be installed or URIs or 
 file paths pointing to a chocolatey script. If using package names,
 the .nupkg file for the provided package names are searched in the 
 following locations and order:
 - .\BuildPackages relative to the parent directory of the module file
 - The Chocolatey feed
 - The Boxstarter feed on MyGet

.Parameter LocalRepo
This is the path to the local boxstarter repository where boxstarter 
should look for .nupkg files to install. By default this is located 
in the BuildPackages directory just under the root Boxstarter 
directory but can be changed with Set-BoxstarterConfig.

.PARAMETER DisableReboots
If set, reboots are suppressed.

.PARAMETER Password
User's password as a Secure string to be used for reboot autologon's.
This will suppress the password prompt at the beginning of the 
Boxstarter installer.

.PARAMETER KeepWindowOpen
Enabling this switch will prevent the command window from closing and 
prompt the user to pres the Enter key before the window closes. This 
is ideal when not invoking boxstarter from a console.

.PARAMETER NoPassword
When set, Boxstarter will never prompt for logon. Use this if using
an account without password validation.

.NOTES
If specifying only one package, Boxstarter calls chocolatey with the 
-force argument and deletes the previously installed package directory. 
This means that regardless of whether or not the package had been 
installed previously, Boxstarter will attempt to download and reinstall it.
This only holds true for the outer package. If the package contains calls 
to CINST for additional packages, those installs will not reinstall if 
previously installed.

If an array of package names are passed to Invoke-ChocolateyBoxstarter, 
Boxstarter will NOT apply the above reinstall logic and will skip the 
install for any package that had been previously installed.

.EXAMPLE
Invoke-ChocolateyBoxstarter "example1","example2"

This invokes boxstarter and installs the example1 and example2 .nupkg 
files. If pending reboots are detected, boxstarter will restart the 
machine. Boxstarter will prompt the user to enter a password which will 
be used for automatic logins in the event a restart is required.

.EXAMPLE
Invoke-ChocolateyBoxstarter https://gist.github.com/mwrock/6771863/raw/b579aa269c791a53ee1481ad01711b60090db1e2/gistfile1.txt

This invokes boxstarter and installs the script uploaded to the github gist.

.EXAMPLE
Invoke-ChocolateyBoxstarter script.ps1

This invokes boxstarter and installs the script located at script.ps1 
in the command line's current directory.

.EXAMPLE
Invoke-ChocolateyBoxstarter \\server\share\script.ps1

This invokes boxstarter and installs the script located at the 
specified share.

.EXAMPLE
Invoke-ChocolateyBoxstarter win8Install -LocalRepo \\server\share\boxstarter

This installs the Win8Install .nupkg and specifies that it is OK to 
reboot the machine if a pending reboot is needed. Boxstarter will look 
for the Win8Install .nupkg file in the \\serer\share\boxstarter 
directory.

.EXAMPLE
Invoke-ChocolateyBoxstarter example -Password (ConvertTo-SecureString "mypassword" -AsPlainText -Force)

This installs the example package and uses "mypassword" for any reboot 
autologon's. The user is now not prompted for a password.

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
about_boxstarter_variable_in_chocolatey
Set-BoxstarterConfig
#>    
    [CmdletBinding()]
    param(
      [string[]]$BootstrapPackage=$null,
      [string]$LocalRepo,
      [switch]$DisableReboots,
      [System.Security.SecureString]$Password,
      [switch]$KeepWindowOpen,
      [switch]$NoPassword,
      [switch]$DisableRestart
    )
    try{
        if($DisableReboots){
            Write-BoxstarterMessage "Disabling reboots" -Verbose
            $Boxstarter.RebootOk=$false
        }
        if($Boxstarter.ScriptToCall -eq $null){
            if($bootstrapPackage -ne $null -and $bootstrapPackage.length -gt 0){
                write-BoxstarterMessage "Installing package $($bootstrapPackage -join ', ')" -Color Cyan
            }
            else{
                write-BoxstarterMessage "Installing Chocolatey" -Color Cyan
            }
            $scriptArgs=@{}
            if($bootstrapPackage){$scriptArgs.bootstrapPackage=$bootstrapPackage}
            if($LocalRepo){$scriptArgs.Localrepo=$localRepo}
            if($DisableReboots){$scriptArgs.DisableReboots = $DisableReboots}
            $script=@"
Import-Module (Join-Path "$($Boxstarter.baseDir)" BoxStarter.Chocolatey\Boxstarter.Chocolatey.psd1) -global -DisableNameChecking;
Invoke-ChocolateyBoxstarter $(if($bootstrapPackage){"-bootstrapPackage '$($bootstrapPackage -join ''',''')'"}) $(if($LocalRepo){"-LocalRepo $localRepo"})  $(if($DisableReboots){"-DisableReboots"})
"@
            return Invoke-Boxstarter ([ScriptBlock]::Create($script)) -RebootOk:$Boxstarter.RebootOk -password $password -KeepWindowOpen:$KeepWindowOpen -NoPassword:$NoPassword -DisableRestart:$DisableRestart
        }
        if(${env:ProgramFiles(x86)} -ne $null){ $programFiles86 = ${env:ProgramFiles(x86)} } else { $programFiles86 = $env:ProgramFiles }
        $Boxstarter.ProgramFiles86="$programFiles86"
        $Boxstarter.LocalRepo=Resolve-LocalRepo $localRepo
        if($bootstrapPackage -ne $null){
            Download-Package $bootstrapPackage
        }
    }
    finally {
        $Boxstarter.ScriptToCall = $null
    }
}

function Resolve-LocalRepo([string]$localRepo) {
    if($localRepo){
        $localRepo = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($localRepo)
    } else {$Localrepo = $Boxstarter.Localrepo}
    write-BoxstarterMessage "LocalRepo is at $localRepo" -Verbose
    return $localRepo
}

function Download-Package([string[]]$bootstrapPackage) {
    $BootstrapPackage = $BootstrapPackage | % {
        if($_ -like "*://*" -or (Test-Path $_ -PathType Leaf)){
            New-PackageFromScript $_
        }
        else {
            $_
        }
    }
    $Boxstarter.Package=$bootstrapPackage
    if($bootstrapPackage.Count -eq 1){
        Write-BoxstarterMessage "Deleting previous $bootstrapPackage package" -Verbose
        $chocoRoot = $env:ChocolateyInstall
        if($chocoRoot -eq $null) {
            $chocoRoot = "$env:programdata\chocolatey"
        }
        Write-BoxstarterMessage "Deleting $chocoRoot\lib\$bootstrapPackage.*" -verbose
        del "$chocoRoot\lib\$bootstrapPackage.*" -recurse -force -ErrorAction SilentlyContinue
        Write-BoxstarterMessage "Deleted $chocoRoot\lib\$bootstrapPackage.*" -verbose
        $force=$true
    }
    $source = "$($Boxstarter.LocalRepo);$((Get-BoxstarterConfig).NugetSources)"
    write-BoxstarterMessage "Installing $($bootstrapPackage.Count) packages from $source" -Verbose
    Chocolatey install $bootstrapPackage -source $source -force:$force
}
tools\Boxstarter.Chocolatey\New-BoxstarterPackage.ps1
function New-BoxstarterPackage {
<#
.SYNOPSIS
Creates a new Chocolatey package source directory intended for a Boxstarter Install

.DESCRIPTION
New-BoxstarterPackage creates a new Directory in your local 
Boxstarter repository located at $Boxstarter.LocalRepo. If no path is
provided, Boxstarter creates a minimal nuspec and 
ChocolateyInstall.ps1 file. If a path is provided, Boxstarter will 
copy the contents of the path to the new package directory. If the
path does not include a nuspec or ChocolateyInstall.ps1, Boxstarter
will create one. You can use Invoke-BoxstarterBuild to pack the 
repository directory to a Chocolatey nupkg. If your path includes 
subdirectories, you can use Get-PackageRoot inside 
ChocolateyInstall.ps1 to reference the parent directory of the copied
content.

.PARAMETER Name
The name of the package to create

.PARAMETER Description
Description of the package to be written to the nuspec

.PARAMETER Path
Optional path whose contents will be copied to the repository

.LINK
http://boxstarter.org
New-PackageFromScript
about_boxstarter_chocolatey
about_boxstarter_variable_in_chocolatey
Invoke-BoxstarterBuild
Get-PackageRoot
#>
    [CmdletBinding()]
    param(
        [string]$Name,
        [string]$description,
        [string]$path,
        [switch]$quiet
    )
    if(!$boxstarter -or !$boxstarter.LocalRepo){
        throw "No Local Repository has been set in `$Boxstarter.LocalRepo."
    }
    $nugetExe = "$env:ChocolateyInstall\ChocolateyInstall\nuget.exe"
    if(!($name -match "^\w+(?:[_.-]\w+)*$") -or ($name.length -gt 100)){
        throw "Invalid Package ID"
    }
    $pkgDir = Join-Path $Boxstarter.LocalRepo $Name
    if(test-path $pkgDir) {
        throw "A LocalRepo already exists at $($boxstarter.LocalRepo)\$name. Delete the directory before calling New-BoxstarterPackage"
    }
    MkDir $pkgDir | out-null
    Pushd $pkgDir
    if($path){
        if(!(test-path $Path)){
            popd
            throw "$path could not be found"
        }
        if(test-path "$Path\$Name.nuspec") {
            Copy-Item "$path\*" . -recurse
        }
        else { Copy-Item $path . -recurse }
    }
    $pkgFile = Join-Path $pkgDir "$name.nuspec"
    if(!(test-path $pkgFile)){
        $nugetResult = .$nugetExe spec $Name -NonInteractive 2>&1
        if($LASTEXITCODE -ne 0){
            Throw "Nuspec creation failed with exit code $LASTEXITCODE and message: $nugetResult"
        }

        Write-BoxstarterMessage "Nuget.exe result: $nugetResult" -Verbose

        Invoke-RetriableScript {
            [xml]$xml = Get-Content $args[0]
            $metadata = $xml.package.metadata
            $nodesToDelete = @()
            $nodesNamesToDelete = @("licenseUrl","projectUrl","iconUrl","requireLicenseAcceptance","releaseNotes", "copyright","dependencies")
            $metadata.ChildNodes | ? { $nodesNamesToDelete -contains $_.Name } | % { $nodesToDelete += $_ }
            $nodesToDelete | %{ $metadata.RemoveChild($_) } | out-null
            if($args[1]){$metadata.Description=$args[1]}
            $metadata.tags="Boxstarter"
            $xml.Save($args[0])
        } $pkgFile $description
    }
    if(!(test-path "tools")){
        Mkdir "tools" | out-null
    }
    $installScript=@"
try {

    Write-ChocolateySuccess '$name'
} catch {
  Write-ChocolateyFailure '$name' `$(`$_.Exception.Message)
  throw
}
"@
    if(!(test-path "tools\ChocolateyInstall.ps1")){
        new-Item "tools\ChocolateyInstall.ps1" -type file -value $installScript| out-null
    }
    Popd

    if(!$quiet){
        Write-BoxstarterMessage "A new Chocolatey package has been created at $pkgDir." -nologo
        Write-BoxstarterMessage "You may now edit the files in this package and build the final .nupkg using Invoke-BoxstarterBuild." -nologo
    }
}
tools\Boxstarter.Chocolatey\New-PackageFromScript.ps1
function New-PackageFromScript {
<#
.SYNOPSIS
Creates a Nuget package from a Chocolatey script

.DESCRIPTION
This creates a .nupkg file from a script file. It adds a dummy nuspec 
and packs the nuspec and script to a nuget package saved to 
$Boxstarter.LocalRepo. The function returns a string that is the 
Package Name of the package.

 .PARAMETER Source
 Either a file path or URI pointing to a resource containing a script.

 .PARAMETER PackageName
 The name of the package. If not provided, this will be "temp_BoxstarterPackage"

.EXAMPLE
$packageName = New-PackageFromScript myScript.ps1

Creates a Package from the myScript.ps1 file in the current directory.

.EXAMPLE
$packageName = New-PackageFromScript myScript.ps1 MyPackage

Creates a Package named "MyPackage" from the myScript.ps1 file in the current directory.

.EXAMPLE
$packageName = New-PackageFromScript c:\path\myScript.ps1

Creates a Package from the myScript.ps1 file in c:\path\myScript.ps1.

.EXAMPLE
$packageName = New-PackageFromScript \\server\share\myScript.ps1

Creates a Package from the myScript.ps1 file the share at \\server\share\myScript.ps1.

.EXAMPLE
$packageName = New-PackageFromScript https://gist.github.com/mwrock/6771863/raw/b579aa269c791a53ee1481ad01711b60090db1e2/gistfile1.txt

Creates a Package from the gist located at
https://gist.github.com/mwrock/6771863/raw/b579aa269c791a53ee1481ad01711b60090db1e2/gistfile1.txt

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
#>        
    [CmdletBinding()]
	param (
        [Parameter(Mandatory=1)]
        [string] $Source,
        [string] $PackageName="temp_BoxstarterPackage"
    )

    if(!(test-path function:\Get-WebFile)){
        . "$env:ChocolateyInstall\chocolateyinstall\helpers\functions\Get-WebFile.ps1"
    }
    if($source -like "*://*"){
        try {$text = Get-WebFile -url $Source -passthru } catch{
            throw "Unable to retrieve script from $source `r`nInner Exception is:`r`n$_"
        }
    }
    else {
        if(!(Test-Path $source)){
            throw "Path $source does not exist."
        }
        $text=Get-Content $source
    }

    if(Test-Path "$($boxstarter.LocalRepo)\$PackageName"){
        Remove-Item "$($boxstarter.LocalRepo)\$PackageName" -recurse -force
    }
    New-BoxstarterPackage $PackageName -quiet | Out-Null
    Set-Content "$($boxstarter.LocalRepo)\$PackageName\tools\ChocolateyInstall.ps1" -value $text
    Invoke-BoxstarterBuild $PackageName -quiet

    Write-BoxstarterMessage "Created a temporary package $PackageName from $source in $($boxstarter.LocalRepo)"
    return $PackageName
}
tools\Boxstarter.Chocolatey\Resolve-VMPlugin.ps1
function Resolve-VMPlugin {
    [CmdletBinding()]
    [OutputType([BoxstarterConnectionConfig])]
    param(
        $Provider
    )

    DynamicParam {
        if($provider -eq $null -or $Provider.Length -eq 0){$provider="HyperV"}
        $unNormalized=(Get-Item "$PSScriptRoot\..\Boxstarter.$provider\Boxstarter.$provider.psd1")
        Import-Module $unNormalized.FullName -global -DisableNameChecking -Force -ErrorAction SilentlyContinue | Out-Null
        $module=Get-Module "Boxstarter.$provider"
        $command = Get-Command "$module\Enable-BoxstarterVM"
        $metadata=New-Object System.Management.Automation.CommandMetaData($command)
        $paramDictionary = new-object `
                    -Type System.Management.Automation.RuntimeDefinedParameterDictionary

        $metadata.Parameters.Keys | % {
            $param=$metadata.Parameters[$_]
            $dynParam = new-object `
                    -Type System.Management.Automation.RuntimeDefinedParameter($param.Name, $param.ParameterType, $param.Attributes[1])
            $paramDictionary.Add($param.Name, $dynParam)
        }

        return $paramDictionary
    }
    Process{
        if($provider -eq $null -or $Provider.Length -eq 0){$provider="HyperV"}
        $module=Get-Module "Boxstarter.$provider"
        $command = Get-Command "$module\Enable-BoxstarterVM"
        $PSBoundParameters.Remove("Provider") | Out-Null
        &($command) @PSBoundParameters
    }
}

new-alias Enable-BoxstarterVM Resolve-VMPlugin -force
tools\Boxstarter.Chocolatey\Send-File.ps1
function Send-File {
##############################################################################
##
## Send-File
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################

<#

.SYNOPSIS

Sends a file to a remote session.

.EXAMPLE

PS >$session = New-PsSession leeholmes1c23
PS >Send-File c:\temp\test.exe c:\temp\test.exe $session

#>

param(
    ## The path on the local computer
    [Parameter(Mandatory = $true)]
    $Source,

    ## The target path on the remote computer
    [Parameter(Mandatory = $true)]
    $Destination,

    ## The session that represents the remote computer
    [Parameter(Mandatory = $true)]
    [System.Management.Automation.Runspaces.PSSession] $Session
)

Set-StrictMode -Version Latest

## Get the source file, and then get its content
$sourcePath = (Resolve-Path $source).Path
$sourceBytes = [IO.File]::ReadAllBytes($sourcePath)
$streamChunks = @()

## Now break it into chunks to stream
$streamSize = 1MB
for($position = 0; $position -lt $sourceBytes.Length;
    $position += $streamSize)
{
    $remaining = $sourceBytes.Length - $position
    $remaining = [Math]::Min($remaining, $streamSize)

    $nextChunk = New-Object byte[] $remaining
    [Array]::Copy($sourcebytes, $position, $nextChunk, 0, $remaining)
    $streamChunks += ,$nextChunk
}

$remoteScript = {
    param($destination, $length)

    ## Convert the destination path to a full file system path (to support
    ## relative paths)
    $Destination = $executionContext.SessionState.`
        Path.GetUnresolvedProviderPathFromPSPath("$env:temp\$Destination")

    ## Create a new array to hold the file content
    $destBytes = New-Object byte[] $length
    $position = 0

    ## Go through the input, and fill in the new array of file content
    foreach($chunk in $input)
    {
        [GC]::Collect()
        [Array]::Copy($chunk, 0, $destBytes, $position, $chunk.Length)
        $position += $chunk.Length
    }

    ## Write the content to the new file
    [IO.File]::WriteAllBytes($destination, $destBytes)

    [GC]::Collect()
}

## Stream the chunks into the remote script
$streamChunks | Invoke-Command -Session $session $remoteScript `
    -ArgumentList $destination,$sourceBytes.Length -ErrorAction Stop
}
tools\Boxstarter.Chocolatey\Set-BoxstarterConfig.ps1
function Set-BoxStarterConfig {
<#
.SYNOPSIS
Sets persist-able Boxstarter configuration settings.

.DESCRIPTION
Boxstarter stores configuration data in an xml file in the Boxstarter base
directory. The Set-BoxstarterConfig function is a convenience function
for changing those settings.

.Parameter LocalRepo
The path where Boxstarter will search for local packages.

.Parameter NugetSources
A semicolon delimited list of Nuget Feed URLs where Boxstarter will search for packages

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
about_boxstarter_variable_in_chocolatey
Get-BoxstarterConfig
#>    
    [CmdletBinding()]
    param([string]$LocalRepo, [string]$NugetSources)

    [xml]$configXml = Get-Content (Join-Path $Boxstarter.BaseDir BoxStarter.config)

    if($NugetSources){
        $boxstarter.NugetSources = $configXml.config.NugetSources = $NugetSources
    }
    if($LocalRepo){
        if($configXml.config.LocalRepo -eq $null) {
            $localRepoElement = $configXml.CreateElement("LocalRepo")
            $configXml.config.AppendChild($localRepoElement) | Out-Null
        }
        $boxstarter.LocalRepo = $configXml.config.LocalRepo = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($LocalRepo)
    }

    $configXml.Save((Join-Path $Boxstarter.BaseDir BoxStarter.config))
}
tools\Boxstarter.Chocolatey\Set-BoxstarterShare.ps1
function Set-BoxstarterShare {
<#
.SYNOPSIS
Shares the Boxstarter root directory - $Boxstarter.BaseDir

.DESCRIPTION
Shares the Boxstarter root directory - $Boxstarter.BaseDir - so that 
it can be accessed remotely. This allows remote machines to Invoke 
ChocolateyBoxstarter via \\server\shareName\Boxstarter.bat. Unless 
specified otherwise, the share name is Boxstarter and Everyone is 
given Read permissions.

.PARAMETER ShareName
The name to give to the share. This is the name by which other 
machines can access it. Boxstarter is the default.

.PARAMETER Accounts
A list of accounts to be given read access to the share. Everyone is 
the default.

.EXAMPLE
Set-BoxstarterShare

Shares the Boxstarter root as Boxstarter to everyone.

.EXAMPLE
Set-BoxstarterShare BuildRepo

Shares the Boxstarter Root as BuildRepo to everyone.

.EXAMPLE
Set-BoxstarterShare -Accounts "corp\mwrock","corp\gmichaels"

Shares the Boxstarter root as Boxstarter to mwrock and gmichaels in the corp domain.

.LINK
http://boxstarter.org
about_boxstarter_chocolatey
Invoke-ChocolateyBoxstarter
New-BoxstarterPackage
Invoke-BoxstarterBuild
#>
    param(
        [string]$shareName="Boxstarter",
        [string[]]$accounts=@("Everyone")
    )
    if(!(Test-Admin)) {
        $unNormalized=(Get-Item "$($Boxstarter.Basedir)\Boxstarter.Chocolatey\BoxStarter.Chocolatey.psd1")
        $command = "-ExecutionPolicy bypass -command Import-Module `"$($unNormalized.FullName)`";Set-BoxstarterShare @PSBoundParameters"
        Start-Process powershell -verb runas -argumentlist $command
        return
    }

    foreach($account in $accounts){
        $acctOption += "/GRANT:'$account,READ' "
    }
    IEX "net share $shareName='$($Boxstarter.BaseDir)' $acctOption"
    if($LastExitCode -ne 0) {
        Throw "Sharing $shareName on $($Boxstarter.BaseDir) to $acctOption was not successful. Use NET SHARE $ShareName to see if share already exists. To Delete the share use NET SHARE $ShareName /DELETE."
    }
}

tools\boxstarter.config
<config>
  <ChocolateyPackage>http://chocolatey.org/api/v2/package/chocolatey/0.9.8.33</ChocolateyPackage>
  <ChocolateyRepo>http://chocolatey.org/install.ps1</ChocolateyRepo>
  <NugetSources>http://chocolatey.org/api/v2;http://www.myget.org/F/boxstarter/api/v2</NugetSources>
</config>
tools\BoxstarterShell.ps1
$here = Split-Path -parent $MyInvocation.MyCommand.Definition
Resolve-Path $here\Boxstarter.*\*.psd1 | 
    % { Import-Module $_.ProviderPath -DisableNameChecking -Force -ErrorAction SilentlyContinue }
Import-Module $here\Boxstarter.Common\Boxstarter.Common.psd1 -Function Test-Admin

if(!(Test-Admin)) {
    Write-BoxstarterMessage "Not running with administrative rights. Attempting to elevate..."
    $command = "-ExecutionPolicy bypass -noexit -command &'$here\BoxstarterShell.ps1'"
    Start-Process powershell -verb runas -argumentlist $command
    Exit
}

$Host.UI.RawUI.WindowTitle="Boxstarter Shell"
cd $env:SystemDrive\
Write-Output @"
Welcome to the Boxstarter shell!
The Boxstarter commands have been imported from $here and are available for you to run in this shell.
You may also import them into the shell of your choice. 

Here are some commands to get you started:
Install a Package:   Install-BoxstarterPackage
Create a Package:    New-BoxstarterPackage
Build a Package:     Invoke-BoxstarterBuild
Enable a VM:         Enable-BoxstarterVM
For Command help:    Get-Help <Command Name> -Full

For Boxstarter documentation, source code, to report bugs or participate in discussions, please visit http://boxstarter.org
"@
tools\chocolateyinstall.ps1
$tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
. (Join-Path $tools Setup.ps1)
try { 
    $ModuleName = (Get-ChildItem $tools | ?{ $_.PSIsContainer }).BaseName
    Install-Boxstarter "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" $ModuleName $env:chocolateyPackageParameters
    Write-ChocolateySuccess $ModuleName
} catch {
    Write-ChocolateyFailure $ModuleName "$($_.Exception.Message)"
    throw 
}
tools\LICENSE.txt
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.
tools\setup.ps1
function Install-Boxstarter($here, $ModuleName, $installArgs = "") {
    $boxstarterPath=Join-Path $env:AppData Boxstarter
    if(!(test-Path $boxstarterPath)){
        mkdir $boxstarterPath
    }
    $packagePath=Join-Path $boxstarterPath BuildPackages
    if(!(test-Path $packagePath)){
        mkdir $packagePath
    }    
    foreach($ModulePath in (Get-ChildItem $here | ?{ $_.PSIsContainer })){
        $target=Join-Path $boxstarterPath $modulePath.BaseName
        if(test-Path $target){
            Remove-Item $target -Recurse -Force
        }
    }
    Copy-Item "$here\*" $boxstarterPath -Recurse -Force -Exclude ChocolateyInstall.ps1, Setup.*

    PersistBoxStarterPathToEnvironmentVariable "PSModulePath"
    PersistBoxStarterPathToEnvironmentVariable "Path"
    $binPath =  "$here\..\..\..\bin"
    $boxModule=Get-Module Boxstarter.Chocolatey
    if($boxModule) {
        if($boxModule.Path -like "$env:LOCALAPPDATA\Apps\*") {
            $clickonce=$true
        }
    }
    if(!$clickonce){
        Import-Module "$boxstarterPath\$ModuleName" -DisableNameChecking -Force -ErrorAction SilentlyContinue
    }
    $successMsg = @"
The $ModuleName Module has been copied to $boxstarterPath and added to your Module path. 
You will need to open a new console for the path to be visible.
Use 'Get-Module Boxstarter.* -ListAvailable' to list all Boxstarter Modules.
To list all available Boxstarter Commands, use:
PS:>Import-Module $ModuleName
PS:>Get-Command -Module Boxstarter.*

To find more info visit http://Boxstarter.org or use:
PS:>Import-Module $ModuleName
PS:>Get-Help Boxstarter
"@
    Write-Host $successMsg

    if($ModuleName -eq "Boxstarter.Chocolatey" -and !$env:appdata.StartsWith($env:windir)) {
        $desktop = $([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::DesktopDirectory))
        $startMenu=$("$env:appdata\Microsoft\Windows\Start Menu\Programs\Boxstarter")
        if(!(Test-Path $startMenu)){
            mkdir $startMenu
        }
        $target="powershell.exe"
        $targetArgs="-ExecutionPolicy bypass -NoExit -Command `"&'$boxstarterPath\BoxstarterShell.ps1'`""

		if($installArgs -inotcontains "nodesktopicon") {
			$link = Join-Path $desktop "Boxstarter Shell.lnk"
			Create-Shortcut $link $target $targetArgs $boxstarterPath
		}
        $link = Join-Path $startMenu "Boxstarter Shell.lnk"
        Create-Shortcut $link $target $targetArgs $boxstarterPath

        Set-Content -Path "$binPath\BoxstarterShell.bat" -Force -Value "$target $TargetArgs"
    }
}

function Create-Shortcut($location, $target, $targetArgs, $boxstarterPath) {
    $wshshell = New-Object -ComObject WScript.Shell
    $lnk = $wshshell.CreateShortcut($location)
    $lnk.TargetPath = $target
    $lnk.Arguments = "$targetArgs"
    $lnk.WorkingDirectory = $boxstarterPath
    $lnk.IconLocation="$boxstarterPath\BoxLogo.ico"
    $lnk.Save()

	$tempFile = "$env:temp\TempShortcut.lnk"
		
	$writer = new-object System.IO.FileStream $tempFile, ([System.IO.FileMode]::Create)
	$reader = new-object System.IO.FileStream $location, ([System.IO.FileMode]::Open)
		
	while ($reader.Position -lt $reader.Length)
	{		
		$byte = $reader.ReadByte()
		if ($reader.Position -eq 22) {
			$byte = 34
		}
		$writer.WriteByte($byte)
	}
		
	$reader.Close()
	$writer.Close()
				
	Move-Item -Path $tempFile $location -Force
}
function PersistBoxStarterPathToEnvironmentVariable($variableName){
    $value = [Environment]::GetEnvironmentVariable($variableName, 'User')
    if($value){
        $values=($value -split ';' | ?{ !($_.ToLower() -match "\\boxstarter$")}) -join ';'
        $values+=";$boxstarterPath"
    } 
    elseif($variableName -eq "PSModulePath") {
        $values=[environment]::getfolderpath("mydocuments")
        $values +="\WindowsPowerShell\Modules;$boxstarterPath"
    }
    else {
        $values ="$boxstarterPath"
    }
    if(!$value -or !($values -contains $boxstarterPath)){
        $values = $values.Replace(';;',';')
        [Environment]::SetEnvironmentVariable($variableName, $values, 'User')
        $varValue = Get-Content env:\$variableName
        $varValue += ";$boxstarterPath"
        $varValue = $varValue.Replace(';;',';')
        Set-Content env:\$variableName -value $varValue
    }
}

Log in or click on link to see number of positives.

In cases where actual malware is found, the packages are subject to removal. Software sometimes has false positives. Moderators do not necessarily validate the safety of the underlying software, only that a package retrieves software from the official distribution point and/or validate embedded software against official distribution point (where distribution rights allow redistribution).

Chocolatey Pro provides runtime protection from possible malware.

Add to Builder Version Downloads Last Updated Status
Boxstarter Chocolatey Module 3.0.2 34751 Monday, June 12, 2023 Approved
Boxstarter Chocolatey Module 3.0.1 4073 Tuesday, June 6, 2023 Approved
Boxstarter Chocolatey Module 3.0.0 91219 Thursday, July 14, 2022 Approved
Boxstarter Chocolatey Module 3.0.0-beta-20220427-21 163 Wednesday, April 27, 2022 Exempted
Boxstarter Chocolatey Module 2.13.0 153411 Thursday, October 15, 2020 Approved
Boxstarter Chocolatey Module 2.12.0 390857 Tuesday, October 30, 2018 Approved
Boxstarter Chocolatey Module 2.11.0 65090 Wednesday, May 16, 2018 Approved
Boxstarter Chocolatey Module 2.10.3 52509 Thursday, August 31, 2017 Approved
Boxstarter Chocolatey Module 2.9.26 5591 Monday, June 19, 2017 Approved
Boxstarter Chocolatey Module 2.9.24 872 Sunday, June 18, 2017 Approved
Boxstarter Chocolatey Module 2.9.14 6979 Friday, May 5, 2017 Approved
Boxstarter Chocolatey Module 2.9.5 4798 Thursday, March 30, 2017 Approved
Boxstarter Chocolatey Module 2.8.29 31392 Sunday, May 22, 2016 Approved
Boxstarter Chocolatey Module 2.8.27 950 Sunday, May 22, 2016 Approved
Boxstarter Chocolatey Module 2.8.21 1071 Thursday, April 28, 2016 Approved
Boxstarter Chocolatey Module 2.8.18 755 Tuesday, April 26, 2016 Approved
Boxstarter Chocolatey Module 2.8.12 1131 Thursday, April 21, 2016 Approved
Boxstarter Chocolatey Module 2.8.0 1206 Friday, April 15, 2016 Approved
Boxstarter Chocolatey Module 2.7.0 2018 Sunday, April 3, 2016 Approved
Boxstarter Chocolatey Module 2.6.41 3760 Sunday, February 28, 2016 Approved
Boxstarter Chocolatey Module 2.6.25 6553 Friday, December 18, 2015 Approved
Boxstarter Chocolatey Module 2.6.20 521 Thursday, December 17, 2015 Approved
Boxstarter Chocolatey Module 2.6.16 749 Tuesday, December 15, 2015 Approved
Boxstarter Chocolatey Module 2.6.2 711 Monday, December 14, 2015 Approved
Boxstarter Chocolatey Module 2.6.0 512 Sunday, December 13, 2015 Approved
Boxstarter Chocolatey Module 2.5.21 9131 Thursday, August 13, 2015 Approved
Boxstarter Chocolatey Module 2.5.19 2031 Sunday, July 26, 2015 Approved
Boxstarter Chocolatey Module 2.5.10 1790 Friday, July 10, 2015 Approved
Boxstarter Chocolatey Module 2.5.3 1396 Wednesday, July 1, 2015 Approved
Boxstarter Chocolatey Module 2.5.1 625 Wednesday, July 1, 2015 Approved
Boxstarter Chocolatey Module 2.4.209 4542 Sunday, April 26, 2015 Approved
Boxstarter Chocolatey Module 2.4.205 2667 Sunday, April 5, 2015 Approved
Boxstarter Chocolatey Module 2.4.196 1512 Friday, March 20, 2015 Approved
Boxstarter Chocolatey Module 2.4.188 1298 Monday, March 9, 2015 Approved
Boxstarter Chocolatey Module 2.4.183 912 Wednesday, March 4, 2015 Approved
Boxstarter Chocolatey Module 2.4.180 497 Tuesday, March 3, 2015 Approved
Boxstarter Chocolatey Module 2.4.179 476 Tuesday, March 3, 2015 Approved
Boxstarter Chocolatey Module 2.4.159 2793 Sunday, January 18, 2015 Approved
Boxstarter Chocolatey Module 2.4.157 686 Thursday, January 15, 2015 Approved
Boxstarter Chocolatey Module 2.4.152 844 Monday, January 12, 2015 Approved
Boxstarter Chocolatey Module 2.4.149 1410 Friday, December 26, 2014 Approved
Boxstarter Chocolatey Module 2.4.146 547 Friday, December 26, 2014 Approved
Boxstarter Chocolatey Module 2.4.128 1981 Thursday, November 27, 2014 Approved
Boxstarter Chocolatey Module 2.4.123 3873 Wednesday, September 24, 2014 Approved
Boxstarter Chocolatey Module 2.4.110 891 Wednesday, September 17, 2014 Approved
Boxstarter Chocolatey Module 2.4.93 843 Friday, September 12, 2014 Approved
Boxstarter Chocolatey Module 2.4.88 1055 Wednesday, September 3, 2014 Approved
Boxstarter Chocolatey Module 2.4.87 458 Wednesday, September 3, 2014 Approved
Boxstarter Chocolatey Module 2.4.80 2811 Monday, August 4, 2014 Approved
Boxstarter Chocolatey Module 2.4.76 520 Sunday, August 3, 2014 Approved
Boxstarter Chocolatey Module 2.4.70 695 Thursday, July 31, 2014 Approved
Boxstarter Chocolatey Module 2.4.67 727 Wednesday, July 30, 2014 Approved
Boxstarter Chocolatey Module 2.4.61 638 Monday, July 28, 2014 Approved
Boxstarter Chocolatey Module 2.4.57 496 Sunday, July 27, 2014 Approved
Boxstarter Chocolatey Module 2.4.54 669 Wednesday, July 23, 2014 Approved
Boxstarter Chocolatey Module 2.4.53 486 Wednesday, July 23, 2014 Approved
Boxstarter Chocolatey Module 2.4.51 476 Wednesday, July 23, 2014 Approved
Boxstarter Chocolatey Module 2.4.48 563 Tuesday, July 22, 2014 Approved
Boxstarter Chocolatey Module 2.4.46 630 Saturday, July 19, 2014 Approved
Boxstarter Chocolatey Module 2.4.41 740 Sunday, July 13, 2014 Approved
Boxstarter Chocolatey Module 2.4.39 464 Sunday, July 13, 2014 Approved
Boxstarter Chocolatey Module 2.4.38 492 Saturday, July 12, 2014 Approved
Boxstarter Chocolatey Module 2.4.35 448 Saturday, July 12, 2014 Approved
Boxstarter Chocolatey Module 2.4.32 466 Friday, July 11, 2014 Approved
Boxstarter Chocolatey Module 2.4.29 1311 Friday, July 4, 2014 Approved
Boxstarter Chocolatey Module 2.4.26 1126 Monday, June 23, 2014 Approved
Boxstarter Chocolatey Module 2.4.15 3065 Sunday, April 20, 2014 Approved
Boxstarter Chocolatey Module 2.4.12 484 Saturday, April 19, 2014 Approved
Boxstarter Chocolatey Module 2.4.4 849 Saturday, April 5, 2014 Approved
Boxstarter Chocolatey Module 2.4.0 487 Friday, April 4, 2014 Approved
Boxstarter Chocolatey Module 2.3.24 1949 Saturday, February 1, 2014 Approved
Boxstarter Chocolatey Module 2.3.15 606 Monday, January 27, 2014 Approved
Boxstarter Chocolatey Module 2.3.13 521 Saturday, January 25, 2014 Approved
Boxstarter Chocolatey Module 2.3.8 522 Thursday, January 23, 2014 Approved
Boxstarter Chocolatey Module 2.3.0 565 Monday, January 20, 2014 Approved
Boxstarter Chocolatey Module 2.2.78 705 Thursday, January 9, 2014 Approved
Boxstarter Chocolatey Module 2.2.59 809 Sunday, December 29, 2013 Approved
Boxstarter Chocolatey Module 2.2.23 870 Saturday, December 14, 2013 Approved
Boxstarter Chocolatey Module 2.2.16 474 Friday, December 13, 2013 Approved
Boxstarter Chocolatey Module 2.2.15 487 Friday, December 13, 2013 Approved
Boxstarter Chocolatey Module 2.2.12 481 Friday, December 13, 2013 Approved
BoxStarter Chocolatey Module 2.2.0 538 Thursday, December 12, 2013 Approved
BoxStarter Chocolatey Module 2.1.0 585 Saturday, November 30, 2013 Approved
BoxStarter Chocolatey Module 2.0.25 529 Wednesday, November 20, 2013 Approved
BoxStarter Chocolatey Module 2.0.11 535 Monday, November 11, 2013 Approved
BoxStarter Chocolatey Module 2.0.4 523 Saturday, November 9, 2013 Approved
BoxStarter Chocolatey Module 2.0.1 505 Friday, November 8, 2013 Approved
BoxStarter Chocolatey Module 1.1.40 608 Tuesday, October 1, 2013 Approved
BoxStarter Chocolatey Module 1.1.35 603 Monday, August 12, 2013 Approved
BoxStarter Chocolatey Module 1.1.30 521 Sunday, August 11, 2013 Approved
BoxStarter Chocolatey Module 1.1.22 507 Thursday, August 8, 2013 Approved
BoxStarter Chocolatey Module 1.1.18 540 Tuesday, August 6, 2013 Approved
BoxStarter Chocolatey Module 1.1.12 450 Sunday, August 4, 2013 Approved
BoxStarter Chocolatey Module 1.1.0 518 Thursday, August 1, 2013 Approved
BoxStarter Chocolatey Module 1.0.33 600 Thursday, April 18, 2013 Approved
BoxStarter Chocolatey Module 1.0.20 481 Monday, April 15, 2013 Approved
BoxStarter Chocolatey Module 1.0.13 548 Monday, March 25, 2013 Approved
BoxStarter Chocolatey Module 1.0.3 534 Wednesday, March 13, 2013 Approved

  • Fixes boxstarte install hangs on PSv2 when installing boxstarter after the new chocolatey
    • Fixes PSModulePath that has the machine environment value stripped after chocolatey package installs
    • Restart Windows Updates service before beginning installation in case updates are already running in the background
    • Dont throw exception when removing the scheduled task and it did not exist
    • Fix remote installs on win 7 and 2008R2 by creating scheduled task before importing remote chocolatey module
    • Pass -y to chocolatey if the new one is installed to avoid red output looking like an error
    • Fix installing modules via the c# based chocolatey
    • Pin to last PS chocolatey version until we finih new choco compatibility
    • Fix running gists from weblauncher more than once in win7 and 2008 R2
    • Suppress caught errors in Invoke-FromScheduledTask from bubbling up to final result
    • Work around nuget.exe limitations of handling files in system profile directory
    • Provide improved error logging of chocolatey errors.
    • Fixes issue where windows update reboots maching in the midst of a run.
    • Fixes failures from exceptions thrown from bitlocker module even when bitlocker is not in use.
    • Fixes Invoke-Reboot from a nested package and bubbles up the reboot signal
    • Update docs to reflect github as repo home and remove all codeplex links
    • Fix for all write-host calls being logged to Boxstarter log file even when there is no install session in progress
    • fixing issue where auto login is not disabled after boxstarter run
    • fixing wait for published version to retry for a minute if the new version is not yet marked published
    • Improve initial connectin performance by skipping remoting check if it has already been tested in enable-BoxstarterVM
    • provide messaging for some winconfig functions
    • fix the setting of azure storage account by looking for https endpoints
    • load storage module before azure to workaround bug with the storage module loading
    • copy the root path passed to New_BoxstarerPackage
    • add a DisableRestart parameter which will suppress the restart file and UAC enabling
    • Greatly improve progress messaging during windows updates runs
    • Fix hang scenarios when waiting for remote machine to reboot and landing in a pending reboot state shortly after reboot
    • Support for auto login and restart in winrm sessions
    • Fix issue with remote check causing an indefinite loop
    • Silencing some handled errors and keep them from leaking to the pipeline
    • Reduce WMI calls and Improve performance of testing if the current session is remote
    • When forcing the install of the outer boxstarter package, make sure to delete the last install from the right repo
    • Check scheduled task output for pending reboots after a remote windows update since 32 bit processes cant read the wsus registry keys
    • Fix Remote check when running as a servise
    • System user logs to programdata
    • when accessing a 64 bit machine from a 32bit process, the windowsupdate reg key is hidden so skip it
    • Bubble up errors from windows update
    • Provide the same scheduled task wrapping for winrm as we do for ps remoting
    • fix explorer restart when there is no explorer process
    • Correcting fallback Chocolatey install path to match release 0.9.8.24
    • Fixing typo param name in redirect call to set-WindowsExplorerOptions
    • Fix InvalidArgument from Set-TaskbarOptions when using lock or unlock params
    • Fix issues where explorer terminates and cannot restart after caling one of the winconfig functions
    • Import azure module from the pipeline to avoid errors when loading Boxstarter.azure
    • Suppress errors when reenabling windows update in case they had alrady been reenabled
    • Fix mis encoded dash in Install-Boxstarterackage
    • Fix issues when Chocolatey packages create a new module and call chocolatey functions from that module
    • When building packages, skip folders without a nuspec instead of throwing an error
    • Only restart the explore process of the current user when calling windows config functions
    • Fixing .net 4.5 install for local installs
    • Fixing TestRunner module loading for PSv2 clients
    • Add the following windows config features:
    • Enable/Disable showing charms when mouse is in the upper right corner
    • Enable/Disable switching apps when pointing in the upper left corner
    • Enable/Disable the option to launch powershell from win-x
    • Enable/Disable boot to desktop
    • Enable/Disable desktop background on the start screen
    • Enable/Disable showing the start screen on the active display
    • Enable/Disable showing the Apps View by default on the start screen
    • Enable/Disable searching everywhere in apps view. Not just apps.
    • Enable/Disable showing desktop apps first in results
    • Lock/Unlock task bar
    • Change taskbar icon size
    • Change location of taskbar docking
    • Add test and publish automation that can point to remote deployment targets
    • Provide build scripts for integration of tests and publishing in CI servers
    • Include configured nuget sources and local repo to all chocolatey install calls and not just the initial package
    • Fix enabling powershell remoting via WMI when password has ampersands
    • Avoid explorer.exe crashes when configuring explorer options
    • Fix Hyper-V heartbeat check in non US locales
    • Fix Azure module loading in 32 bit consoles
    • Fix shell shortcuts when user name has a space
    • Fix Azure VM Checkpoint listing when there are more than one VM in a service
    • Install .net 4.5 ONLY without affecting IIS settings when .net 4 is not present
    • Fix Azure VM integration when multiple subscriptions are present
    • Allow remote installs to be run by a non amin user
Discussion for the Boxstarter Chocolatey Module Package

Ground Rules:

  • This discussion is only about Boxstarter Chocolatey Module and the Boxstarter Chocolatey Module package. If you have feedback for Chocolatey, please contact the Google Group.
  • This discussion will carry over multiple versions. If you have a comment about a particular version, please note that in your comments.
  • The maintainers of this Chocolatey Package will be notified about new comments that are posted to this Disqus thread, however, it is NOT a guarantee that you will get a response. If you do not hear back from the maintainers after posting a message below, please follow up by using the link on the left side of this page or follow this link to contact maintainers. If you still hear nothing back, please follow the package triage process.
  • Tell us what you love about the package or Boxstarter Chocolatey Module, or tell us what needs improvement.
  • Share your experiences with the package, or extra configuration or gotchas that you've found.
  • If you use a url, the comment will be flagged for moderation until you've been whitelisted. Disqus moderated comments are approved on a weekly schedule if not sooner. It could take between 1-5 days for your comment to show up.
comments powered by Disqus