FreshBuild.psm1
#Region '.\Private\Find-Sources.ps1' 0 function Find-Sources{ param( [PSObject]$Item=$null ) $scoopResult = & scoop search $item.name $chocoResult = & choco search $item.name $winGetResult = & winget search $item.name } #EndRegion '.\Private\Find-Sources.ps1' 10 #Region '.\Private\Get-ByChocolatey.ps1' 0 function Get-ByChocolatey { param( [PSObject]$Item=$null ) $parameters = @("install", $item.name, "-y") if($item.parameters){ $parameters += [string[]]$item.parameters; } Write-Host ("{0}: Parameters: {1}" -f $Item.name, $parameters) if($command) { if($item.elevate){ return Start-Process -Wait -Verb RunAs -FilePath $command -ArgumentList $parameters } else { return Start-Process -Wait -NoNewWindow -FilePath $command -ArgumentList $parameters } } else { throw ("No command matching {0} was found." -f $item.command); } } #EndRegion '.\Private\Get-ByChocolatey.ps1' 22 #Region '.\Private\Get-ByCommand.ps1' 0 function Get-ByCommand { param( [PSObject]$Item=$null ) if(-not $item.command) { throw "Expected command, none provided." } $command = (Get-Command $item.command).Source; $argList = @() if($item.parameters) { $argList += $item.parameters; } if($command) { if($item.elevate){ return Start-Process -Wait -Verb RunAs -FilePath $command -ArgumentList $argList } else { return Start-Process -Wait -NoNewWindow -FilePath $command -ArgumentList $argList } } else { throw ("No command matching {0} was found." -f $item.command); } } #EndRegion '.\Private\Get-ByCommand.ps1' 20 #Region '.\Private\Get-ByInstaller.ps1' 0 function Get-ByInstaller { param( [PSObject]$Item=$null ) $name = $item.Name $parameters = $item.parameters; $path = Join-Path $downloadFolder -ChildPath $item.fileName $destination = Get-Installer $item -Destination $path if($destination -ne $path){ throw "Not downloaded: $path, received $destination"; } if(Test-Path $path) { Write-Host ("{0}: Installing from {1}." -f $name, $path) $stdOut = "./standardOut.txt" $stdError = "./standardError.txt"; Remove-Item $stdError, $stdOut -ErrorAction SilentlyContinue $argList = @() switch ($Item.command) { 'msiexec' { $argList = @("/package", $path) + $parameters; $path = (Get-Command $Item.command).Source; } default { if($parameters) { $argList += $parameters; } } } if($path){ if($Item.elevate){ $process = Start-Process -FilePath $path ` -Verb RunAs ` -ArgumentList $argList ` -RedirectStandardOutput $stdOut ` -RedirectStandardError $stdError ` -Wait ` -PassThru } else { $process = Start-Process -FilePath $path ` -NoNewWindow ` -ArgumentList $argList ` -RedirectStandardOutput $stdOut ` -RedirectStandardError $stdError ` -Wait ` -PassThru } } else { throw "`$path is not set."; } if($process.ExitCode -ne 0){ Write-Host ("{0}: ExitCode: {1}" -f $Item.name, $process.ExitCode) Get-Content $stdOut -ErrorAction SilentlyContinue | Write-Host Get-Content $stdError -ErrorAction SilentlyContinue | Write-Error } Write-Host ("{0}: Install of {1} yielded: {2}" -f $name, $path, $process.ExitCode) } } #EndRegion '.\Private\Get-ByInstaller.ps1' 69 #Region '.\Private\Get-ByScoop.ps1' 0 function Get-ByScoop { param( [PSObject]$Item=$null ) $parameters = @("-c", $command, "install", $item.name) if($item.parameters){ $parameters += [string[]]$item.parameters; } if($command) { if($item.elevate){ return Start-Process -Wait -Verb RunAs -FilePath powershell -ArgumentList $parameters } else { return Start-Process -Wait -NoNewWindow -FilePath powershell -ArgumentList $parameters } } else { throw ("No command matching {0} was found." -f $item.command); } } #EndRegion '.\Private\Get-ByScoop.ps1' 20 #Region '.\Private\Get-ByScript.ps1' 0 function Get-ByScript { param( [PSObject]$Item=$null ) $script = $item.script; Write-Host ("{0}: Installing..." -f $item.name) $argList = @("-c", $script) if($item.parameters) { $argList += $item.parameters; } if($item.elevate) { try{ Start-Process -Wait -Verb RunAs -FilePath powershell -ArgumentList $argList } catch { Write-Error $_ } } else { try{ Start-Process -Wait -NoNewWindow -FilePath powershell -ArgumentList $argList } catch { Write-Error $_ } } Write-Host ("{0}: Installation complete." -f $item.name) } #EndRegion '.\Private\Get-ByScript.ps1' 25 #Region '.\Private\Get-ByWinGet.ps1' 0 function Get-ByWinget { param( [PSObject]$Item=$null ) $parameters = @("install", $item.name) if($item.parameters){ $parameters += [string[]]$item.parameters; } if($command) { if($item.elevate){ return Start-Process -Wait -Verb RunAs -FilePath $command -ArgumentList $parameters } else { return Start-Process -Wait -NoNewWindow -FilePath $command -ArgumentList $parameters } } else { throw ("No command matching {0} was found." -f $item.command); } } #EndRegion '.\Private\Get-ByWinGet.ps1' 20 #Region '.\Private\Get-Installer.ps1' 0 function Get-Installer { param ( [PSObject]$Item=$null, [string]$Destination ) if($Item.url -and $Item.url.length -gt 0) { if(Test-Path $Destination){ return $Destination; } Write-Host ("{0}: Downloading {1} to {2}" -f $Item.name, $Item.url, $Destination); Invoke-WebRequest $Item.url -OutFile $Destination if(-not(Test-Path $Destination)){ throw ("{0}: Error downloading file." -f $Item.name) } else { Write-Host ("{0}: Downloaded to: {1}" -f $Item.name, $Destination) return $Destination } } } #EndRegion '.\Private\Get-Installer.ps1' 24 #Region '.\Private\Install-Chocolatey.ps1' 0 function Install-Chocolatey { param ( [string] $InstallFolder ) $InstallDir = 'C:\ProgramData\chocoportable' if($installFolder) { if(-not (test-path $InstallFolder)) { new-item $InstallFolder -itemType Directory } $InstallDir = $InstallFolder } # Set directory for installation - Chocolatey does not lock # down the directory if not the default if (-not $env:ChocolateyInstall -or $InstallFolder) { $env:ChocolateyInstall = "$InstallDir" "`$env:ChocolateyInstall = `"$InstallDir`"" >> $PROFILE.AllUsersAllHosts Get-Content $PROFILE.AllUsersAllHosts | Write-Host } # If your PowerShell Execution policy is restrictive, you may # not be able to get around that. Try setting your session to # Bypass. Set-ExecutionPolicy Bypass -Scope Process -Force; # All install options - offline, proxy, etc at # https://chocolatey.org/install $url = 'https://community.chocolatey.org/install.ps1'; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString($url)) } function Uninstall-Chocolatey { $VerbosePreference = 'Continue' if (-not $env:ChocolateyInstall) { $message = @( "The ChocolateyInstall environment variable was not found." "Chocolatey is not detected as installed. Nothing to do." ) -join "`n" Write-Warning $message return } if (-not (Test-Path $env:ChocolateyInstall)) { $message = @( "No Chocolatey installation detected at '$env:ChocolateyInstall'." "Nothing to do." ) -join "`n" Write-Warning $message return } <# Using the .NET registry calls is necessary here in order to preserve environment variables embedded in PATH values; Powershell's registry provider doesn't provide a method of preserving variable references, and we don't want to accidentally overwrite them with absolute path values. Where the registry allows us to see "%SystemRoot%" in a PATH entry, PowerShell's registry provider only sees "C:\Windows", for example. #> $userKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment') $userPath = $userKey.GetValue('PATH', [string]::Empty, 'DoNotExpandEnvironmentNames').ToString() $machineKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\ControlSet001\Control\Session Manager\Environment\') $machinePath = $machineKey.GetValue('PATH', [string]::Empty, 'DoNotExpandEnvironmentNames').ToString() $backupPATHs = @( "User PATH: $userPath" "Machine PATH: $machinePath" ) $backupFile = "C:\PATH_backups_ChocolateyUninstall.txt" $backupPATHs | Set-Content -Path $backupFile -Encoding UTF8 -Force $warningMessage = @" This could cause issues after reboot where nothing is found if something goes wrong. In that case, look at the backup file for the original PATH values in '$backupFile'. "@ if ($userPath -like "*$env:ChocolateyInstall*") { Write-Verbose "Chocolatey Install location found in User Path. Removing..." Write-Warning $warningMessage $newUserPATH = @( $userPath -split [System.IO.Path]::PathSeparator | Where-Object { $_ -and $_ -ne "$env:ChocolateyInstall\bin" } ) -join [System.IO.Path]::PathSeparator # NEVER use [Environment]::SetEnvironmentVariable() for PATH values; see https://github.com/dotnet/corefx/issues/36449 # This issue exists in ALL released versions of .NET and .NET Core as of 12/19/2019 $userKey.SetValue('PATH', $newUserPATH, 'ExpandString') } try { if ($machinePath -like "*$env:ChocolateyInstall*") { Write-Verbose "Chocolatey Install location found in Machine Path. Removing..." Write-Warning $warningMessage $newMachinePATH = @( $machinePath -split [System.IO.Path]::PathSeparator | Where-Object { $_ -and $_ -ne "$env:ChocolateyInstall\bin" } ) -join [System.IO.Path]::PathSeparator # NEVER use [Environment]::SetEnvironmentVariable() for PATH values; see https://github.com/dotnet/corefx/issues/36449 # This issue exists in ALL released versions of .NET and .NET Core as of 12/19/2019 $machineKey.SetValue('PATH', $newMachinePATH, 'ExpandString') } } catch { #Write-Error $_ } # Adapt for any services running in subfolders of ChocolateyInstall $agentService = Get-Service -Name chocolatey-agent -ErrorAction SilentlyContinue if ($agentService -and $agentService.Status -eq 'Running') { $agentService.Stop() } # TODO: add other services here Remove-Item -Path $env:ChocolateyInstall -Recurse -Force 'ChocolateyInstall', 'ChocolateyLastPathUpdate' | ForEach-Object { foreach ($scope in 'User', 'Machine') { [Environment]::SetEnvironmentVariable($_, [string]::Empty, $scope) } } $machineKey.Close() $userKey.Close() if ($env:ChocolateyToolsLocation -and (Test-Path $env:ChocolateyToolsLocation)) { Remove-Item -Path $env:ChocolateyToolsLocation -Recurse -Force } foreach ($scope in 'User', 'Machine') { [Environment]::SetEnvironmentVariable('ChocolateyToolsLocation', [string]::Empty, $scope) } Write-Host "Completed uninstallation of Chocolatey." } #EndRegion '.\Private\Install-Chocolatey.ps1' 146 #Region '.\Private\Install-Scoop.ps1' 0 function Install-Scoop { param ( [string] $InstallFolder ) $item = ('{ "name": "Scoop", "source": "direct", "script": "iwr -useb get.scoop.sh | iex; scoop bucket add extras" }' | ConvertFrom-Json); if($InstallFolder) { $scoopdir = $env:SCOOP = "$InstallFolder" "`$env:SCOOP = `"$InstallFolder`"" >> $PROFILE.AllUsersAllHosts "`$scoopdir = `"$InstallFolder`"" >> $PROFILE.AllUsersAllHosts } if($env:SCOOP) { Write-Host "Installing scoop to ${env:SCOOP}." } Get-ByScript $item; } function Uninstall-Scoop{ $scoop = Get-Command scoop; if($scoop) { . $scoop export | ForEach-Object -process { . $scoop uninstall $_ } . $scoop uninstall scoop } } #EndRegion '.\Private\Install-Scoop.ps1' 35 #Region '.\Private\Install-Software.ps1' 0 function Install-Software{ param( [PSObject]$Item=$null ) Write-Host $Item switch($Item.source){ "winget" { $command= $env:USERPROFILE + "/AppData/Local/Microsoft/WindowsApps/winget.exe"; if(-not(Test-Path $command)) { Install-WinGet } $result = Get-ByWinget $item if($result) { Write-Host $result; } } "scoop" { $command= $env:USERPROFILE + "/scoop/shims/scoop.ps1"; if(-not(Test-Path $command)) { Install-Scoop } $result = Get-ByScoop $item if($result) { Write-Host $result; } } "choco" { $command="C:/ProgramData/chocolatey/bin/cinst.exe"; if(-not(Test-Path $command)) { Install-Chocolatey } $result = Get-ByChocolatey $item if($result) { Write-Host $result; } } default { try{ if($item.url.length -gt 0) { Get-ByInstaller $item } elseif($item.script) { Get-ByScript $item } elseif($item.command) { Get-ByCommand $item } } catch { Write-Error $_ throw $_ } } } } #EndRegion '.\Private\Install-Software.ps1' 63 #Region '.\Private\Install-WinGet.ps1' 0 function Install-WinGet { $item = ('{ "name": "WinGet", "source": "direct", "url": "", "script": "Add-AppxPackage https://aka.ms/getwinget -InstallAllResources" }' | ConvertFrom-Json); Get-ByScript $item; '{ // For documentation on these settings, see: https://aka.ms/winget-settings // "source": { // "autoUpdateIntervalInMinutes": 5 // }, "experimentalFeatures": { "experimentalMSStore": true } }' | Out-File "$env:USERPROFILE\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\settings.json" } function Uninstall-WinGet { $winget = Get-AppxPackage Microsoft.DesktopAppInstaller; if ($winget) { $winget | Remove-AppxPackage } } #EndRegion '.\Private\Install-WinGet.ps1' 28 #Region '.\Private\Search-FreshBuild.ps1' 0 function Search-FreshBuild { [CmdletBinding()] param( [string]$jsonConfig = "$env:USERPROFILE/.freshBuild/FreshInstall.json", [string]$Exclude = $null, [string]$Include = $null, [switch]$Search = $false ) Write-Host "Seach: " if ($Include) { Write-Host ('Include: {0}' -f $Include) } if ($Exclude) { Write-Host ('Exclude: {0}' -f $Exclude) } } #EndRegion '.\Private\Search-FreshBuild.ps1' 13 #Region '.\Public\Initialize-FreshBuild.ps1' 0 function Initialize-FreshBuild { param( [Switch]$All = $false, [switch]$InstallWinGet = $false, [switch]$InstallChocolatey = $false, [switch]$InstallScoop = $false, [string]$InstallRoot = $null ) $freshbuildDir = Join-Path $Env:USERPROFILE '.freshbuild' $jsonFile = Join-Path $FreshBuildDir 'PackageManagers.json' if (!(Test-Path $freshbuildDir)) { $null = New-Item -Path $freshbuildDir -ItemType Directory -Force } if (Test-Path $jsonFile) { [string[]]$installed = Get-Content $jsonFile | ConvertFrom-Json; } else { [string[]]$installed = @(); } if ($InstallWinGet -or $All) { Install-WinGet; $installed += 'WinGet' } if ($installRoot) { if ($InstallChocolatey -or $All) { Install-Chocolatey -InstallFolder "$InstallRoot\Chocolatey"; $installed += 'Chocolatey' } if ($InstallScoop -or $All) { Install-Scoop -InstallFolder "$InstallRoot\Scoop"; $installed += 'Scoop' } } else { if ($InstallChocolatey -or $All) { Install-Chocolatey; $installed += 'Chocolatey' } if ($InstallScoop -or $All) { Install-Scoop; $installed += 'Scoop' } } $json = $installed | ConvertTo-Json; if (-not $json) { $json = '[]'; } $json | Out-File -Path $jsonFile } #EndRegion '.\Public\Initialize-FreshBuild.ps1' 48 #Region '.\Public\Start-FreshBuild.ps1' 0 function Start-FreshBuild { [CmdletBinding()] param( [string]$jsonConfig = "$env:USERPROFILE/.freshBuild/FreshInstall.json", [string]$Exclude = $null, [string]$Include = $null, [switch]$Step = $false, [switch]$UninstallWinGet=$false, [switch]$UninstallChocolatey=$false, [switch]$UninstallScoop=$false, [switch]$InstallWinGet=$false, [switch]$InstallChocolatey=$false, [switch]$InstallScoop=$false, [switch]$NoScript=$false, [switch]$UpdateJson=$false ) Push-Location try { $jsonUrl = "https://gist.github.com/sharpninja/2ad839cb141bc6b968278bd7416931ce/raw/" $defaultJsonConfig = "$env:USERPROFILE/.freshBuild/FreshInstall.json"; if($UpdateJson) { Invoke-WebRequest ` -Uri $jsonUrl ` -OutFile $defaultJsonConfig } if (-not (Test-Path $jsonConfig)) { if ($jsonConfig -eq $defaultJsonConfig) { Set-Location (Get-Module -Name "FreshBuild").Path New-Item $env:USERPROFILE/.freshBuild -ItemType Directory -ErrorAction SilentlyContinue Invoke-WebRequest ` -Uri $jsonUrl ` -OutFile $defaultJsonConfig } else { return -1; } } $items = (Get-Content $jsonConfig | ConvertFrom-Json).items $downloadFolder = "$env:USERPROFILE/.freshBuild/downloads" if($UninstallWinGet) {Uninstall-WinGet} if($UninstallChocolatey) {Uninstall-Chocolatey} if($UninstallScoop) {Uninstall-Scoop} if($InstallWinGet) {Install-WinGet} if($InstallChocolatey) {Install-Chocolatey} if($InstallScoop) {Install-Scoop} if($NoScript) {return 0;} if (-not (Test-Path $downloadFolder)) { New-Item $downloadFolder -ItemType Directory } foreach ($item in $items) { Write-Host $item.name if (-not ($item -is [string])) { if ((-not($Exclude -and ($item.name -Match $Exclude))) -and (($null -eq $Include) -or ($item.name -match $Include))) { Write-Host ("{0}: Beginning Installation." -f $item.name) [PSObject]$typed = $item; Install-Software -Item $typed Write-Host ("{0}: Finished Installation." -f $item.name) Write-Host } } if ($Step) { Read-Host "Hit enter for next step..." } } } finally { Pop-Location } } #EndRegion '.\Public\Start-FreshBuild.ps1' 83 |