Skip to content

Instantly share code, notes, and snippets.

@codingfreak
Last active November 28, 2023 22:43
Show Gist options
  • Select an option

  • Save codingfreak/a4f53ef5b5e120312bebfc99ab195022 to your computer and use it in GitHub Desktop.

Select an option

Save codingfreak/a4f53ef5b5e120312bebfc99ab195022 to your computer and use it in GitHub Desktop.
Machine init stuff
{
"title": "codingfreaks default init",
"disableWallpaper": true,
"disableSounds": true,
"removeKeyboardDelay": true,
"tryFullScreenTerminal": true,
"requireWindowsTerminal": true,
"phases": [
{
"index": 0,
"phaseName": "Init",
"disabled": false,
"reboot": true,
"steps": [
{
"title": "Setup computer",
"type": "ps",
"disabled": false,
"commands": [
{
"command": "powercfg.exe -x -monitor-timeout-ac 0;powercfg.exe -x -monitor-timeout-dc 0",
"title": "Disabling monitor energy timeout"
},
{
"command": "powercfg.exe -x -disk-timeout-ac 0;powercfg.exe -x -disk-timeout-dc 0",
"title": "Disabling disc energy timeout"
},
{
"command": "powercfg.exe -x -standby-timeout-ac 0;powercfg.exe -x -standby-timeout-dc 0",
"title": "Disabling standby energy timeout"
},
{
"command": "powercfg.exe -x -hibernate-timeout-ac 0;powercfg.exe -x -hibernate-timeout-dc 0",
"title": "Disabling hibernate energy timeout"
},
{
"command": "net stop beep | Out-Null",
"title": "Stopping beep service"
},
{
"command": "sc config beep start= disabled | Out-Null",
"title": "Disabling beep service"
}
]
},
{
"title": "OS baseline",
"type": "choco",
"disabled": false,
"packages": [
"git.install --params \"'/GitAndUnixToolsOnPath /WindowsTerminal /NoShellIntegration /NoOpenSSH /Editor:VisualStudioCode /NoAutoCrlf /DefaultBranchName:main'\"",
"7zip",
"NuGet.CommandLine",
"pping"
]
},
{
"title": "Browsers",
"type": "choco",
"disabled": false,
"packages": ["googlechrome"]
},
{
"title": "Fonts",
"type": "choco",
"disabled": false,
"packages": ["jetbrainsmononf"]
},
{
"title": "Editors",
"type": "choco",
"disabled": false,
"packages": ["vscode"]
},
{
"title": "WSL installation",
"type": "winfeat",
"disabled": false,
"features": [
{
"name": "VirtualMachinePlatform",
"title": "Virtual Machine Platform"
},
{
"name": "Microsoft-Windows-Subsystem-Linux",
"title": "Windows subsystem for Linux"
}
]
},
{
"title": "WSL setup",
"type": "ps",
"disabled": false,
"commands": [
{
"command": "wsl --set-default-version 2",
"title": "Setting WSL 2 as the default version"
},
{
"command": "wsl --install --distribution kali-linux",
"title": "Installing KALI linux in WSL"
}
]
}
]
},
{
"index": 1,
"phaseName": "Git Setup",
"reboot": false,
"disabled": false,
"steps": [
{
"title": "Git configuration",
"type": "ps",
"commands": [
{
"command": "git config --global user.name 'Alexander Schmidt'",
"title": "Setting Git user name globally"
},
{
"command": "git config --global user.email 'alexander.schmidt@devdeer.com'",
"title": "Setting Git email globally"
}
]
}
]
},
{
"index": 2,
"phaseName": "Docker",
"reboot": false,
"disabled": false,
"steps": [
{
"title": "Docker Desktop",
"type": "choco",
"disabled": false,
"packages": ["docker-desktop"]
},
{
"title": "Start Docker Desktop",
"type": "ps",
"disabled": true,
"commands": [
{
"command": "start \"[SPECIALFOLDER:ProgramFiles]\\Docker\\Docker\\Docker Desktop.exe\"",
"title": "Starting Docker Desktop"
}
]
},
{
"title": "Ramping up docker containers",
"type": "ps",
"disabled": true,
"commands": [
{
"command": "docker run --name redis -p 6379:6379 --restart always -d redis",
"title": "Starting Redis Container"
},
{
"command": "docker run --name mssql-dev -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Sql-Server-Dev' -e 'MSSQL_AGENT_ENABLED=true' -p 1433:1433 -d --restart always mcr.microsoft.com/mssql/server:2022-latest",
"title": "Starting Sql Server Container"
},
{
"command": "docker run --name azurite --restart always -p 10000:10000 -p 10001:10001 -p 10002:10002 -d mcr.microsoft.com/azure-storage/azurite",
"title": "Starting Azurite Container"
}
]
}
]
}
]
}
param (
$DefinitionFile
)
function Get-State {
$stateFile = "~/.initstate.json"
if (!(Test-Path $stateFile)) {
return 0
}
return Get-Content $stateFile
}
function Ensure-Choco {
$choco = Get-Command choco -ErrorAction SilentlyContinue | Measure-Object
if ($choco.Count -gt 0) {
return
}
# choco is not installed
Write-StatusStart -Message "Installing choco"
Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) | Out-Null
$added = New-EnvironmentPath -Path "C:\ProgramData\chocolatey\bin"
if ($added) {
Write-Host "Choco path was added to PATH."
}
Write-StatusResult -Message "Done" -Success
}
function Ensure-Winget {
# This actually creates a lot of trouble. See https://github.com/microsoft/winget-cli/issues/2666
return
$winget = Get-Command winget -ErrorAction SilentlyContinue | Measure-Object
if ($winget.Count -gt 0) {
return
}
$progressPreference = 'silentlyContinue'
Write-StatusStart -Message "Installing winget"
Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle | Out-Null
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx | Out-Null
Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.7.3/Microsoft.UI.Xaml.2.7.x64.appx -OutFile Microsoft.UI.Xaml.2.7.x64.appx | Out-Null
Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx | Out-Null
Add-AppxPackage Microsoft.UI.Xaml.2.7.x64.appx | Out-Null
Add-AppxPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle | Out-Null
Write-StatusResult -Message "Done" -Success
}
function Start-Reboot {
param (
$ScriptPathAfterReboot,
$TaskNameSuffix,
$WaitSeconds = 10
)
$user = whoami
$trigger = New-ScheduledTaskTrigger -AtLogon -User $user
$terminalPath = "%LocalAppData%\Microsoft\WindowsApps\wt.exe"
$action = New-ScheduledTaskAction -WorkingDirectory $PSScriptRoot -Execute $terminalPath -Argument $ScriptPathAfterReboot
Register-ScheduledTask -Action $action -TaskName "Init Script Continuation $TaskNameSuffix" -Trigger $trigger -RunLevel Highest | Out-Null
Write-Host "Your computer will restart in $WaitSeconds seconds and continue the setup operation after you logged in again. NOTE: It may take a while!" -ForegroundColor Magenta
Start-Sleep $WaitSeconds
Restart-Computer -Force | Out-Null
}
function Set-State {
param (
$State
)
$stateFile = "~/.initstate.json"
Set-Content $stateFile $State
}
function Write-StatusResult {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)] [string] $Message,
[Parameter(Mandatory = $false)] [switch] $Success,
[Parameter(Mandatory = $false)] [switch] $Failure
)
Process {
$color = "White"
if ($Success) {
$color = "Green"
}
if ($Failure) {
$color = "Red"
}
Write-Host "$Message" -ForegroundColor $color
}
}
function Write-StatusStart {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)] [string] $Message
)
Process {
Write-Host "$Message..." -NoNewline
}
}
function New-EnvironmentPath {
param (
$Path
)
$current = $env:PATH
if ($current.Contains($Path)) {
return $false
}
$current += ";$Path"
$env:PATH = $current
return $true
}
function Get-IsSessionElevated {
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Get-RunsInTerminal {
$currentParentId = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = $PID").ParentProcessId
return (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = $currentParentId").Name -eq "WindowsTerminal.exe"
}
function Disable-Wallpaper {
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name WallPaper -Value '' -ErrorAction SilentlyContinue | Out-Null
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers" -Name BackgroundType -Type DWORD -Value 1 | Out-Null
Set-ItemProperty -Path "HKCU:\Control Panel\Colors" -Name Background -Value "0 0 0" | Out-Null
}
function Get-Summary {
param (
$Definition
)
# CREATE DEFINITON SUMMARY
$summary = @{
Title = $Definition.title
ChocoPackages = 0
WingetPackages = 0
WindowsFeatures = 0
PowerShellCommands = 0
Phases = 0
Steps = 0
DisabledPhases = 0
DisabledSteps = 0
Reboots = 0
}
foreach ($phase in $Definition.phases) {
$summary.Phases++
if ($phase.disabled -eq $true) {
$summary.DisabledPhases++
}
else {
if ($phase.reboot -eq $true) {
$summary.Reboots++
}
}
foreach ($step in $phase.steps) {
$summary.Steps++
if ($phase.disabled -eq $true -or $step.disabled -eq $true) {
$summary.DisabledSteps++
}
else {
if ($step.type -eq 'choco') {
foreach ($package in $step.packages) {
$summary.ChocoPackages++
}
}
elseif ($step.type -eq 'winget') {
foreach ($package in $step.packages) {
$summary.WingetPackages++
}
}
elseif ($step.type -eq 'winfeat') {
foreach ($feature in $step.features) {
$summary.WindowsFeatures++
}
}
elseif ($step.type -eq 'ps') {
foreach ($cmd in $step.commands) {
$summary.PowerShellCommands++
}
}
}
}
}
if ($summary.WingetPackages -gt 0) {
throw "Sadly we are not ready for winget support because it causes potential issues when used from automation. Consider switching to chocolatey.org!"
}
return $summary
}
function Write-Summary {
param (
$Summary
)
Write-Host "`nSUMMARY"
Write-Host "===============================================`n"
Write-Host "Title : $($Summary.title)`n"
Write-Host "Phases : $($Summary.Phases) ($($Summary.DisabledPhases) disabled)"
Write-Host "Steps : $($Summary.Steps) ($($Summary.DisabledSteps) disabled)"
Write-Host "Planned reboots : $($Summary.Reboots)"
Write-Host "Chocolatey packages : $($Summary.ChocoPackages)"
#Write-Host "Winget packages : $($Summary.WingetPackages)"
Write-Host "Windows features : $($Summary.WindowsFeatures)"
Write-Host "Posh commands : $($Summary.PowerShellCommands)`n"
}
function Switch-FullScreen {
$wshell = New-Object -ComObject wscript.shell;
$wshell.SendKeys("{f11}")
}
# ----------------------------------------------
# Main script
# ----------------------------------------------
$ErrorActionPreference = 'Stop'
Clear-Host
# READING CONFIG FILE
$definition = Get-Content $DefinitionFile -Raw | ConvertFrom-Json
# ENSURE WINDOWS TERMINAL
if ($definition.requireWindowsTerminal -eq $true) {
$isTerminal = Get-RunsInTerminal
if ($isTerminal -eq $false) {
throw "Run this tool in a Windows Terminal and be sure to set Windows Terminal as your default terminal in Windows!"
}
}
# ENSURE ADMINISTRATIVE SESSION
$elevated = Get-IsSessionElevated
if ($elevated -eq $false) {
throw "Run in an elevated shell!"
}
# MAIN RUN
Write-Host "You are running in elevated session." -ForegroundColor Green
$summary = Get-Summary -Definition $definition
Write-Summary -Summary $summary
# MAKE TERMINAL FULL SCREEN
if ($definition.tryFullScreenTerminal -eq $true) {
Switch-FullScreen
}
# STATE HANDLING
$state = Get-State
# DEPS
if ($state -eq 0) {
Write-Host "`n`nThis script will ensure that chocolatey and winget are present if they are needed for the steps. Be aware that this script will execute planned reboots whenever needed/defined.`n" -ForegroundColor Magenta
Write-Host "`n`nAre you sure that you want to apply this definition to your computer now (type 'yes')?: " -NoNewline
$answer = Read-Host
if ($answer -ne "yes") {
Switch-FullScreen
return
}
# only run this on the first run
if ($summary.WingetPackages -gt 0) {
Ensure-Winget
}
if ($summary.ChocoPackages -gt 0) {
Ensure-Choco
}
Clear-Host
Write-Summary -Summary $summary
if ($definition.disableSounds -eq $true) {
Write-StatusStart -Message "Disabling Windows sounds"
New-ItemProperty -path "HKCU:\AppEvents\Schemes" -Name "(Default)" -value ".None" -Force -ErrorAction SilentlyContinue | Out-Null
Get-ChildItem -Path "HKCU:\AppEvents\Schemes\Apps" | `
Get-ChildItem | `
Get-ChildItem | `
Where-Object { $_.PSChildName -eq ".Current" } | `
Set-ItemProperty -Name "(Default)" -Value "" -Force -ErrorAction SilentlyContinue | Out-Null
if ($?) {
Write-StatusResult -Message "Done" -Success
}
else {
Write-StatusResult -Message "Error" -Failure
}
}
if ($definition.removeKeyboardDelay -eq $true) {
Write-StatusStart -Message "Disabling keyboard delay"
New-ItemProperty -path "HKCU:\Control Panel\Keyboard" -Name "KeyboardDelay" -value "0" -Force -ErrorAction SilentlyContinue | Out-Null
if ($?) {
Write-StatusResult -Message "Done" -Success
}
else {
Write-StatusResult -Message "Error" -Failure
}
}
if ($definition.disableWallpaper -eq $true) {
Write-StatusStart -Message "Disabling keyboard delay (after next login)"
Disable-Wallpaper
if ($?) {
Write-StatusResult -Message "Done" -Success
}
else {
Write-StatusResult -Message "Error" -Failure
}
}
}
else {
#remove the previously created task
Switch-FullScreen
Write-Summary -Summary $summary
$taskName = "Init Script Continuation $state"
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
}
$totalPhases = $definition.phases.Length
$currentPhase = 0
foreach ($phase in $definition.phases) {
$currentPhase++
if ($phase.index -lt $state) {
continue
}
if ($phase.disabled -eq $true) {
Write-Host "Phase $currentPhase of $totalPhases [$($phase.phaseName)] is disabled." -ForegroundColor DarkGray
continue;
}
Write-Host "Running phase $currentPhase of $totalPhases [$($phase.phaseName)]."
$totalSteps = $phase.steps.Length
$currentStep = 0
foreach ($step in $phase.steps) {
$currentStep++
if ($step.disabled -eq $true) {
Write-Host " Step $currentStep of $totalSteps [$($step.title) is disabled." -ForegroundColor DarkGray
continue;
}
Write-Host -Message " Running step $currentStep of $totalSteps [$($step.title)]..."
if ($step.type -eq 'choco') {
$total = $step.packages.Length
$current = 0
foreach ($package in $step.packages) {
$current++
$command = $package.Replace('\"', '`"')
$isMatch = $command -match "\[SPECIALFOLDER:(.*)\]"
if ($isMatch) {
$folder = [environment]::getfolderpath($Matches[1])
$command = $command.Replace($Matches[0], $folder)
}
$command += " | Out-Null"
Write-StatusStart -Message " Installing choco package $current of $total [$package]"
Invoke-Expression "choco install $package -y | Out-Null" | Out-Null
if ($?) {
Write-StatusResult -Message "Done" -Success
}
else {
Write-StatusResult -Message "Error" -Failure
}
}
}
# elseif ($step.type -eq 'winget') {
# $total = $step.packages.Length
# $current = 0
# foreach ($package in $step.packages) {
# Write-StatusStart -Message " Installing winget package $current of $total [$package]"
# Invoke-Expression "winget install $package -y | Out-Null" | Out-Null
# if ($?) {
# Write-StatusResult -Message "Done" -Success
# }
# else {
# Write-StatusResult -Message "Error" -Failure
# }
# }
# }
elseif ($step.type -eq 'winfeat') {
$total = $step.features.Length
$current = 0
foreach ($feature in $step.features) {
Write-StatusStart -Message " Installing winget package $current of $total [$($feature.title)]"
Enable-WindowsOptionalFeature -Online -FeatureName $feature.name -NoRestart -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null
if ($?) {
Write-StatusResult -Message "Done" -Success
}
else {
Write-StatusResult -Message "Error" -Failure
}
}
}
elseif ($step.type -eq 'ps') {
$total = $step.commands.Length
$current = 0
foreach ($cmd in $step.commands) {
$current++
$command = $cmd.command.Replace('\"', '`"')
Write-StatusStart -Message " Running PowerShell task $current of $total [$($cmd.title)]"
try {
Invoke-Expression $command | Out-Null
Write-StatusResult -Message "Done" -Success
}
catch {
Write-StatusResult -Message "Error" -Failure
Write-Host $command
}
}
}
}
Write-Host "Phase [$($phase.phaseName)] finished."
if ($phase.reboot -eq $true) {
# we have to reboot now
$newIndex = $phase.index + 1
Set-State -State $newIndex
$cmd = '--title "YADSI" pwsh.exe -NoExit -Command "' + $PSCommandPath + ' -DefinitionFile ' + $DefinitionFile + '"'
Start-Reboot -ScriptPathAfterReboot $cmd -TaskNameSuffix $newIndex
return
}
}
# CLEANUP
Write-Host "Cleaning up artifacts"
Remove-Item $DefinitionFile -Force
Remove-Item $PSCommandPath -Force
if (Test-Path "~/.initstate.json") {
Remove-Item "~/.initstate.json"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment