From 94cab560d29444159e0648bbc0f421bffe28b2e5 Mon Sep 17 00:00:00 2001 From: srdusr Date: Wed, 1 Oct 2025 17:04:38 +0200 Subject: Testing updated dir structures --- windows/AppData/windows-terminal/settings.json | 590 ------------------ windows/D-Drive/.gitkeep | 0 .../PowerShell/Microsoft.PowerShell_profile.ps1 | 284 --------- windows/Documents/PowerShell/bloatware.ps1 | 332 ---------- windows/Documents/PowerShell/bootstrap.ps1 | 669 --------------------- windows/Documents/PowerShell/initialize.ps1 | 227 ------- windows/ProgramData/.gitkeep | 0 windows/System32/.gitkeep | 0 .../Users/AppData/windows-terminal/settings.json | 590 ++++++++++++++++++ .../PowerShell/Microsoft.PowerShell_profile.ps1 | 284 +++++++++ windows/Users/Documents/PowerShell/bloatware.ps1 | 340 +++++++++++ windows/Users/Documents/PowerShell/bootstrap.ps1 | 645 ++++++++++++++++++++ windows/Users/Documents/PowerShell/initialize.ps1 | 227 +++++++ windows/Users/install.bat | 11 + windows/install.bat | 11 - 15 files changed, 2097 insertions(+), 2113 deletions(-) delete mode 100644 windows/AppData/windows-terminal/settings.json create mode 100644 windows/D-Drive/.gitkeep delete mode 100644 windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 delete mode 100644 windows/Documents/PowerShell/bloatware.ps1 delete mode 100644 windows/Documents/PowerShell/bootstrap.ps1 delete mode 100644 windows/Documents/PowerShell/initialize.ps1 create mode 100644 windows/ProgramData/.gitkeep create mode 100644 windows/System32/.gitkeep create mode 100644 windows/Users/AppData/windows-terminal/settings.json create mode 100644 windows/Users/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 create mode 100644 windows/Users/Documents/PowerShell/bloatware.ps1 create mode 100644 windows/Users/Documents/PowerShell/bootstrap.ps1 create mode 100644 windows/Users/Documents/PowerShell/initialize.ps1 create mode 100644 windows/Users/install.bat delete mode 100644 windows/install.bat (limited to 'windows') diff --git a/windows/AppData/windows-terminal/settings.json b/windows/AppData/windows-terminal/settings.json deleted file mode 100644 index 71bf5bd..0000000 --- a/windows/AppData/windows-terminal/settings.json +++ /dev/null @@ -1,590 +0,0 @@ -{ - "$help": "https://aka.ms/terminal-documentation", - "$schema": "https://aka.ms/terminal-profiles-schema", - "actions": - [ - { "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" }, - { "command": "unbound", "keys": "ctrl+v" }, - { "command": "unbound", "keys": "ctrl+c" }, - { "command": { "action": "copy", "singleLine": false } }, - { "command": { "action": "scrollUp" }, "keys": "ctrl+shift+up" }, - { "command": "find", "keys": "ctrl+shift+f" }, - { "command": "paste" }, - - { "command": { "action": "splitPane", "split": "vertical", "splitMode": "duplicate" }, "keys": "alt+shift+plus" }, - { "command": { "action": "splitPane", "split": "horizontal", "splitMode": "duplicate" }, "keys": "alt+shift+-" }, - - { "command": { "action": "nextTab", "tabSwitcherMode": "mru" }, "keys": "ctrl+tab" }, - { "command": "openTabRenamer", "keys": "ctrl+shift+r" }, - - { "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" }, - { "command": { "action": "scrollDown" }, "keys": "ctrl+shift+down" }, - - { "command": "scrollUpPage", "keys": "ctrl+shift+pgup" }, - - { "command": { "action": "moveFocus", "direction": "left" }, "keys": "alt+h" }, - { "command": { "action": "moveFocus", "direction": "down" }, "keys": "alt+j" }, - { "command": { "action": "moveFocus", "direction": "up" }, "keys": "alt+k" }, - { "command": { "action": "moveFocus", "direction": "right" }, "keys": "alt+l" }, - - { "command": { "action": "resizePane", "direction": "left" }, "keys": "alt+shift+y" }, - { "command": { "action": "resizePane", "direction": "down" }, "keys": "alt+shift+u" }, - { "command": { "action": "resizePane", "direction": "up" }, "keys": "alt+shift+i" }, - { "command": { "action": "resizePane", "direction": "right" }, "keys": "alt+shift+o" }, - - { "command": { "action": "swapPane", "direction": "left" }, "keys": "alt+shift+h" }, - { "command": { "action": "swapPane", "direction": "down" }, "keys": "alt+shift+j" }, - { "command": { "action": "swapPane", "direction": "up" }, "keys": "alt+shift+k" }, - { "command": { "action": "swapPane", "direction": "right" }, "keys": "alt+shift+l" }, - - { "command": "togglePaneZoom", "keys": "alt+f" } - ], - "copyFormatting": "none", - "copyOnSelect": false, - "defaultProfile": "{f19ccc1d-fe9a-4e79-ad18-49276786d144}", - "launchMode": "default", - "profiles": - { - "defaults": - { - "backgroundImage": null, - "colorScheme": "Gruvbox Dark", - "font": - { - "face": "CaskaydiaCove NF" - }, - "historySize": 9001, - "opacity": 100, - "padding": "0", - "snapOnInput": false, - "useAcrylic": false, - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - "list": - [ - { - "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\download3.jpg", - "backgroundImageOpacity": 0.089999999999999997, - "colorScheme": "Tokyo Night", - "commandline": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", - "experimental.retroTerminalEffect": false, - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{f19ccc1d-fe9a-4e79-ad18-49276786d144}", - "historySize": 99999, - "icon": "ms-appx:///ProfileIcons/pwsh.png", - "name": "PowerShell 7 - BG", - "opacity": 100, - "padding": "0", - "scrollbarState": "visible", - "startingDirectory": "%USERPROFILE%", - "suppressApplicationTitle": false, - "useAcrylic": false, - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\photo-1533484306792-cf313c2b8ab0 (2).jpg", - "backgroundImageOpacity": 0.19, - "bellStyle": "taskbar", - "colorScheme": "Tokyo Night", - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}", - "hidden": false, - "historySize": 99999, - "name": "Ubuntu-20.04", - "source": "Windows.Terminal.Wsl", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "guid": "{f9ceaf27-504c-58d7-927c-d1d6a7ac7d3c}", - "hidden": false, - "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\photo-1533484306792-cf313c2b8ab0 (2).jpg", - "backgroundImageOpacity": 0.19, - "name": "Ubuntu 22.04.1 LTS", - "source": "CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc", - "colorScheme": "Tokyo Night", - "font": - { - "face": "CaskaydiaCove NF" - }, - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}", - "hidden": false, - "historySize": 99999, - "name": "PowerShell 7 - NO BG", - "padding": "0", - "source": "Windows.Terminal.PowershellCore", - "suppressApplicationTitle": false, - "useAcrylic": false, - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", - "hidden": false, - "historySize": 99999, - "name": "Command Prompt", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", - "hidden": false, - "historySize": 99999, - "name": "PowerShell 5", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{46ca431a-3a87-5fb3-83cd-11ececc031d2}", - "hidden": false, - "name": "Kali Linux", - "source": "Windows.Terminal.Wsl", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", - "hidden": false, - "historySize": 99999, - "name": "Azure Cloud Shell", - "source": "Windows.Terminal.Azure", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "backgroundImage": null, - "backgroundImageOpacity": 0.29999999999999999, - "commandline": "C:\\GBox\\Applications\\Tools\\Applications\\Neovim\\nvim-win64\\0.6.0\\bin\\nvim.exe", - "font": - { - "face": "CaskaydiaCove NF" - }, - "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6102}", - "hidden": false, - "historySize": 99999, - "name": "Neovim", - "padding": "0", - "useAcrylic": false, - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "guid": "{d701ea23-d39a-51a9-9966-855f1c8051f1}", - "hidden": false, - "name": "Developer Command Prompt for VS 2022 [Preview]", - "source": "Windows.Terminal.VisualStudio", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "guid": "{960e8c7a-d53d-5f77-ad6f-daf9dfeb597d}", - "hidden": false, - "name": "Developer PowerShell for VS 2022 [Preview]", - "source": "Windows.Terminal.VisualStudio", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "guid": "{fddd4872-371a-5869-85aa-657716af07fa}", - "hidden": true, - "name": "Developer Command Prompt for VS 2022", - "source": "Windows.Terminal.VisualStudio", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - }, - { - "guid": "{e1c4148c-0ee2-5cd8-802c-8a170e188519}", - "hidden": true, - "name": "Developer PowerShell for VS 2022", - "source": "Windows.Terminal.VisualStudio", - "closeOnExit":"graceful", - "intenseTextStyle": "all" - } - ] - }, - "schemes": - [ - { - "background": "#0C0C0C", - "black": "#0C0C0C", - "blue": "#0037DA", - "brightBlack": "#767676", - "brightBlue": "#3B78FF", - "brightCyan": "#61D6D6", - "brightGreen": "#16C60C", - "brightPurple": "#B4009E", - "brightRed": "#E74856", - "brightWhite": "#F2F2F2", - "brightYellow": "#F9F1A5", - "cursorColor": "#FFFFFF", - "cyan": "#3A96DD", - "foreground": "#CCCCCC", - "green": "#13A10E", - "name": "Campbell", - "purple": "#881798", - "red": "#C50F1F", - "selectionBackground": "#FFFFFF", - "white": "#CCCCCC", - "yellow": "#C19C00" - }, - { - "background": "#012456", - "black": "#0C0C0C", - "blue": "#0037DA", - "brightBlack": "#767676", - "brightBlue": "#3B78FF", - "brightCyan": "#61D6D6", - "brightGreen": "#16C60C", - "brightPurple": "#B4009E", - "brightRed": "#E74856", - "brightWhite": "#F2F2F2", - "brightYellow": "#F9F1A5", - "cursorColor": "#FFFFFF", - "cyan": "#3A96DD", - "foreground": "#CCCCCC", - "green": "#13A10E", - "name": "Campbell Powershell", - "purple": "#881798", - "red": "#C50F1F", - "selectionBackground": "#FFFFFF", - "white": "#CCCCCC", - "yellow": "#C19C00" - }, - { - "background": "#282828", - "black": "#282828", - "blue": "#458588", - "brightBlack": "#928374", - "brightBlue": "#83A598", - "brightCyan": "#8EC07C", - "brightGreen": "#B8BB26", - "brightPurple": "#D3869B", - "brightRed": "#FB4934", - "brightWhite": "#EBDBB2", - "brightYellow": "#FABD2F", - "cursorColor": "#FFFFFF", - "cyan": "#689D6A", - "foreground": "#EBDBB2", - "green": "#98971A", - "name": "Gruvbox Dark", - "purple": "#B16286", - "red": "#CC241D", - "selectionBackground": "#FFFFFF", - "white": "#A89984", - "yellow": "#D79921" - }, - { - "background": "#282C34", - "black": "#282C34", - "blue": "#61AFEF", - "brightBlack": "#5A6374", - "brightBlue": "#61AFEF", - "brightCyan": "#56B6C2", - "brightGreen": "#98C379", - "brightPurple": "#C678DD", - "brightRed": "#E06C75", - "brightWhite": "#DCDFE4", - "brightYellow": "#E5C07B", - "cursorColor": "#FFFFFF", - "cyan": "#56B6C2", - "foreground": "#DCDFE4", - "green": "#98C379", - "name": "One Half Dark", - "purple": "#C678DD", - "red": "#E06C75", - "selectionBackground": "#FFFFFF", - "white": "#DCDFE4", - "yellow": "#E5C07B" - }, - { - "background": "#282C34", - "black": "#282C34", - "blue": "#61AFEF", - "brightBlack": "#282C34", - "brightBlue": "#61AFEF", - "brightCyan": "#56B6C2", - "brightGreen": "#98C379", - "brightPurple": "#C678DD", - "brightRed": "#E06C75", - "brightWhite": "#DCDFE4", - "brightYellow": "#E5C07B", - "cursorColor": "#FFFFFF", - "cyan": "#56B6C2", - "foreground": "#DCDFE4", - "green": "#98C379", - "name": "One Half Dark2", - "purple": "#C678DD", - "red": "#E06C75", - "selectionBackground": "#FFFFFF", - "white": "#DCDFE4", - "yellow": "#E5C07B" - }, - { - "background": "#FAFAFA", - "black": "#383A42", - "blue": "#0184BC", - "brightBlack": "#4F525D", - "brightBlue": "#61AFEF", - "brightCyan": "#56B5C1", - "brightGreen": "#98C379", - "brightPurple": "#C577DD", - "brightRed": "#DF6C75", - "brightWhite": "#FFFFFF", - "brightYellow": "#E4C07A", - "cursorColor": "#4F525D", - "cyan": "#0997B3", - "foreground": "#383A42", - "green": "#50A14F", - "name": "One Half Light", - "purple": "#A626A4", - "red": "#E45649", - "selectionBackground": "#FFFFFF", - "white": "#FAFAFA", - "yellow": "#C18301" - }, - { - "background": "#FAFAFA", - "black": "#383A42", - "blue": "#0184BC", - "brightBlack": "#383A42", - "brightBlue": "#0184BC", - "brightCyan": "#0997B3", - "brightGreen": "#50A14F", - "brightPurple": "#A626A4", - "brightRed": "#E45649", - "brightWhite": "#FAFAFA", - "brightYellow": "#C18401", - "cursorColor": "#FFFFFF", - "cyan": "#0997B3", - "foreground": "#383A42", - "green": "#50A14F", - "name": "One Half Light2", - "purple": "#A626A4", - "red": "#E45649", - "selectionBackground": "#FFFFFF", - "white": "#FAFAFA", - "yellow": "#C18401" - }, - { - "background": "#002B36", - "black": "#002B36", - "blue": "#268BD2", - "brightBlack": "#073642", - "brightBlue": "#839496", - "brightCyan": "#93A1A1", - "brightGreen": "#586E75", - "brightPurple": "#6C71C4", - "brightRed": "#CB4B16", - "brightWhite": "#FDF6E3", - "brightYellow": "#657B83", - "cursorColor": "#FFFFFF", - "cyan": "#2AA198", - "foreground": "#839496", - "green": "#859900", - "name": "Solarized Dark", - "purple": "#D33682", - "red": "#DC322F", - "selectionBackground": "#FFFFFF", - "white": "#EEE8D5", - "yellow": "#B58900" - }, - { - "background": "#001E27", - "black": "#002831", - "blue": "#2176C7", - "brightBlack": "#475B62", - "brightBlue": "#708284", - "brightCyan": "#819090", - "brightGreen": "#475B62", - "brightPurple": "#5956BA", - "brightRed": "#BD3613", - "brightWhite": "#FCF4DC", - "brightYellow": "#536870", - "cursorColor": "#FFFFFF", - "cyan": "#259286", - "foreground": "#708284", - "green": "#738A05", - "name": "Solarized Dark - Patched", - "purple": "#C61C6F", - "red": "#D11C24", - "selectionBackground": "#FFFFFF", - "white": "#EAE3CB", - "yellow": "#A57706" - }, - { - "background": "#FDF6E3", - "black": "#002B36", - "blue": "#268BD2", - "brightBlack": "#073642", - "brightBlue": "#839496", - "brightCyan": "#93A1A1", - "brightGreen": "#586E75", - "brightPurple": "#6C71C4", - "brightRed": "#CB4B16", - "brightWhite": "#FDF6E3", - "brightYellow": "#657B83", - "cursorColor": "#002B36", - "cyan": "#2AA198", - "foreground": "#657B83", - "green": "#859900", - "name": "Solarized Light", - "purple": "#D33682", - "red": "#DC322F", - "selectionBackground": "#FFFFFF", - "white": "#EEE8D5", - "yellow": "#B58900" - }, - { - "background": "#000000", - "black": "#000000", - "blue": "#3465A4", - "brightBlack": "#555753", - "brightBlue": "#729FCF", - "brightCyan": "#34E2E2", - "brightGreen": "#8AE234", - "brightPurple": "#AD7FA8", - "brightRed": "#EF2929", - "brightWhite": "#EEEEEC", - "brightYellow": "#FCE94F", - "cursorColor": "#FFFFFF", - "cyan": "#06989A", - "foreground": "#D3D7CF", - "green": "#4E9A06", - "name": "Tango Dark", - "purple": "#75507B", - "red": "#CC0000", - "selectionBackground": "#FFFFFF", - "white": "#D3D7CF", - "yellow": "#C4A000" - }, - { - "background": "#FFFFFF", - "black": "#000000", - "blue": "#3465A4", - "brightBlack": "#555753", - "brightBlue": "#729FCF", - "brightCyan": "#34E2E2", - "brightGreen": "#8AE234", - "brightPurple": "#AD7FA8", - "brightRed": "#EF2929", - "brightWhite": "#EEEEEC", - "brightYellow": "#FCE94F", - "cursorColor": "#000000", - "cyan": "#06989A", - "foreground": "#555753", - "green": "#4E9A06", - "name": "Tango Light", - "purple": "#75507B", - "red": "#CC0000", - "selectionBackground": "#FFFFFF", - "white": "#D3D7CF", - "yellow": "#C4A000" - }, - { - "background": "#1A1B2C", - "black": "#414868", - "blue": "#7AA2F7", - "brightBlack": "#414868", - "brightBlue": "#7AA2F7", - "brightCyan": "#7DCFFF", - "brightGreen": "#73DACA", - "brightPurple": "#BB9AF7", - "brightRed": "#F7768E", - "brightWhite": "#C0CAF5", - "brightYellow": "#E0AF68", - "cursorColor": "#C0CAF5", - "cyan": "#7DCFFF", - "foreground": "#A9B1DC", - "green": "#73DACA", - "name": "Tokyo Night", - "purple": "#BB9AF7", - "red": "#F7768E", - "selectionBackground": "#28344A", - "white": "#C0CAF5", - "yellow": "#E0AF68" - }, - { - "background": "#24283B", - "black": "#414868", - "blue": "#7AA2F7", - "brightBlack": "#414868", - "brightBlue": "#7AA2F7", - "brightCyan": "#7DCFFF", - "brightGreen": "#73DACA", - "brightPurple": "#BB9AF7", - "brightRed": "#F7768E", - "brightWhite": "#C0CAF5", - "brightYellow": "#E0AF68", - "cursorColor": "#C0CAF5", - "cyan": "#7DCFFF", - "foreground": "#A9B1DC", - "green": "#73DACA", - "name": "Tokyo Night Storm", - "purple": "#BB9AF7", - "red": "#F7768E", - "selectionBackground": "#28344A", - "white": "#C0CAF5", - "yellow": "#E0AF68" - }, - { - "background": "#000000", - "black": "#000000", - "blue": "#000080", - "brightBlack": "#808080", - "brightBlue": "#0000FF", - "brightCyan": "#00FFFF", - "brightGreen": "#00FF00", - "brightPurple": "#FF00FF", - "brightRed": "#FF0000", - "brightWhite": "#FFFFFF", - "brightYellow": "#FFFF00", - "cursorColor": "#FFFFFF", - "cyan": "#008080", - "foreground": "#C0C0C0", - "green": "#008000", - "name": "Vintage", - "purple": "#800080", - "red": "#800000", - "selectionBackground": "#FFFFFF", - "white": "#C0C0C0", - "yellow": "#808000" - } - ], - "showTabsInTitlebar": true, - "showTerminalTitleInTitlebar": true, - "tabWidthMode": "titleLength", - "trimBlockSelection": true, - "useAcrylicInTabRow": false -} diff --git a/windows/D-Drive/.gitkeep b/windows/D-Drive/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 b/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 deleted file mode 100644 index 40b5879..0000000 --- a/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 +++ /dev/null @@ -1,284 +0,0 @@ -# Dotfiles Management System -if (Test-Path "$HOME\.cfg" -and Test-Path "$HOME\.cfg\refs") { - - # Core git wrapper with repository as work-tree - function _config { - param( - [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] - [String[]]$Args - ) - git --git-dir="$HOME\.cfg" --work-tree="$HOME\.cfg" @Args - } - - # Detect OS (cross-platform, PowerShell-native) - $osPlatform = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform - if ($osPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)) { - $global:CFG_OS = "windows" - } elseif ($osPlatform([System.Runtime.InteropServices.OSPlatform]::Linux)) { - $global:CFG_OS = "linux" - } elseif ($osPlatform([System.Runtime.InteropServices.OSPlatform]::OSX)) { - $global:CFG_OS = "macos" - } else { - $global:CFG_OS = "other" - } - - # Map system path to repository path - function _repo_path { - param([string]$FilePath) - - # If it's an absolute path that's not in HOME, handle it specially - if (($FilePath.StartsWith("\\") -or $FilePath.Contains(":")) -and -not $FilePath.StartsWith($HOME)) { - return "$CFG_OS/" + ($FilePath -replace '^[A-Z]:\\', '' -replace '\\', '/') - } - - # Check for paths that should go to the repository root - if ($FilePath -match '^(common|linux|macos|windows|profile)/.*|^README\.md$') { - return $FilePath -replace '\\', '/' - } - - # Remove HOME prefix if present - if ($FilePath.StartsWith($HOME)) { - $FilePath = $FilePath.Substring($HOME.Length + 1) - } - - # Default: put under OS-specific home - return "$CFG_OS/home/" + ($FilePath -replace '\\', '/') - } - - # Map repository path back to system path - function _sys_path { - param([string]$RepoPath) - - $osPathPattern = "$CFG_OS/" - - # Handle OS-specific files that are not in the home subdirectory - if ($RepoPath.StartsWith($osPathPattern) -and $RepoPath -notmatch '/home/') { - return ($RepoPath.Substring($osPathPattern.Length) -replace '/', '\\') - } - - switch -Wildcard ($RepoPath) { - "common/config/*" { - $file = $RepoPath.Substring("common/config/".Length) - switch ($CFG_OS) { - "linux" { return Join-Path ($env:XDG_CONFIG_HOME ?? "$HOME\.config") $file } - "macos" { return Join-Path "$HOME\Library\Application Support" $file } - "windows" { return Join-Path $env:LOCALAPPDATA $file } - default { return Join-Path "$HOME\.config" $file } - } - } - "common/assets/*" { return Join-Path "$HOME\.cfg" $RepoPath } - "common/*" { return Join-Path $HOME ($RepoPath.Substring("common/".Length)) } - "*/home/*" { return Join-Path $HOME ($RepoPath.Substring($RepoPath.IndexOf("home/") + 5)) } - "profile/*" { return Join-Path "$HOME\.cfg" $RepoPath } - "README.md" { return Join-Path "$HOME\.cfg" $RepoPath } - default { return Join-Path "$HOME\.cfg" $RepoPath } - } - } - - # Prompts for administrator permissions if needed and runs the command - function _admin_prompt { - param( - [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] - [String[]]$Command - ) - if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { - Write-Host "Warning: This action requires administrator privileges." -ForegroundColor Yellow - Start-Process powershell.exe -ArgumentList "-NoProfile", "-Command", "Set-Location '$PWD'; & $Command" -Verb RunAs - } else { - & $Command - } - } - - # Main config command - function config { - param( - [string]$Command, - [string]$TargetDir = "", - [Parameter(ValueFromRemainingArguments=$true)] - [string[]]$Args - ) - - # Parse --target flag for add command - if ($Command -eq "add" -and $Args.Count -gt 0) { - $i = 0 - while ($i -lt $Args.Count) { - if ($Args[$i] -eq "--target" -or $Args[$i] -eq "-t") { - if ($i + 1 -lt $Args.Count) { - $TargetDir = $Args[$i + 1] - $Args = $Args[0..($i-1)] + $Args[($i+2)..($Args.Count-1)] - break - } else { - Write-Host "Error: --target requires a directory argument" -ForegroundColor Red - return - } - } - $i++ - } - } - - switch ($Command) { - "add" { - foreach ($file in $Args) { - if (-not $TargetDir) { - $repoPath = _repo_path $file - } else { - $fileName = if ($file.Contains("\\") -or $file.Contains(":")) { Split-Path $file -Leaf } else { $file } - $repoPath = "$TargetDir/$fileName" -replace '\\', '/' - } - - $fullRepoPath = Join-Path "$HOME\.cfg" $repoPath - $dir = Split-Path $fullRepoPath - if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } - Copy-Item -Path $file -Destination $fullRepoPath -Recurse -Force - _config add $repoPath - Write-Host "Added: $file -> $repoPath" -ForegroundColor Green - } - } - "rm" { - $rmOpts = @() - $fileList = @() - - foreach ($arg in $Args) { - if ($arg.StartsWith("-")) { - $rmOpts += $arg - } else { - $fileList += $arg - } - } - - foreach ($file in $fileList) { - $repoPath = _repo_path $file - if ($rmOpts -contains "-r") { - _config rm --cached -r $repoPath - } else { - _config rm --cached $repoPath - } - Remove-Item -Path $file -Recurse:($rmOpts -contains "-r") -Force - Write-Host "Removed: $file" -ForegroundColor Yellow - } - } - "sync" { - $direction = if ($Args.Count -gt 0) { $Args[0] } else { "to-repo" } - _config ls-files | ForEach-Object { - $repoFile = $_ - $sysFile = _sys_path $repoFile - $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile - - if ($direction -eq "to-repo") { - if ((Test-Path $sysFile) -and (Test-Path $fullRepoPath)) { - $diff = Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) - if ($diff) { - Copy-Item $sysFile $fullRepoPath -Force - Write-Host "Synced to repo: $sysFile" -ForegroundColor Cyan - } - } - } elseif ($direction -eq "from-repo") { - if ((Test-Path $fullRepoPath)) { - $diff = if (Test-Path $sysFile) { Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) } else { $true } - if ($diff) { - $destDir = Split-Path $sysFile - if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { - _admin_prompt "Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" - } else { - if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } - Copy-Item $fullRepoPath $sysFile -Recurse -Force - } - Write-Host "Synced from repo: $sysFile" -ForegroundColor Cyan - } - } - } - } - } - "status" { - $autoSynced = @() - _config ls-files | ForEach-Object { - $repoFile = $_ - $sysFile = _sys_path $repoFile - $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile - if ((Test-Path $sysFile) -and (Test-Path $fullRepoPath)) { - $diff = Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) - if ($diff) { - Copy-Item $sysFile $fullRepoPath -Force - $autoSynced += $repoFile - } - } - } - if ($autoSynced.Count -gt 0) { - Write-Host "=== Auto-synced Files ===" -ForegroundColor Magenta - foreach ($repoFile in $autoSynced) { - Write-Host "synced: $(_sys_path $repoFile) -> $repoFile" -ForegroundColor Cyan - } - Write-Host - } - _config status - Write-Host - } - "deploy" { - _config ls-files | ForEach-Object { - $repoFile = $_ - $sysFile = _sys_path $repoFile - $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile - - if ((Test-Path $fullRepoPath) -and $sysFile) { - $destDir = Split-Path $sysFile - if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { - _admin_prompt "New-Item -ItemType Directory -Path '$destDir' -Force; Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" - } else { - if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } - Copy-Item $fullRepoPath $sysFile -Recurse -Force - } - Write-Host "Deployed: $repoFile -> $sysFile" -ForegroundColor Green - } - } - } - "checkout" { - Write-Host "Checking out dotfiles from .cfg..." -ForegroundColor Blue - _config ls-files | ForEach-Object { - $repoFile = $_ - $sysFile = _sys_path $repoFile - $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile - - if ((Test-Path $fullRepoPath) -and $sysFile) { - $destDir = Split-Path $sysFile - if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { - _admin_prompt "New-Item -ItemType Directory -Path '$destDir' -Force; Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" - } else { - if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } - Copy-Item $fullRepoPath $sysFile -Recurse -Force - } - Write-Host "Checked out: $repoFile -> $sysFile" -ForegroundColor Green - } - } - } - "backup" { - $timestamp = Get-Date -Format "yyyyMMddHHmmss" - $backupDir = Join-Path $HOME ".dotfiles_backup\$timestamp" - Write-Host "Backing up existing dotfiles to $backupDir..." -ForegroundColor Blue - - _config ls-files | ForEach-Object { - $repoFile = $_ - $sysFile = _sys_path $repoFile - if (Test-Path $sysFile) { - $destDirFull = Join-Path $backupDir (Split-Path $repoFile) - if (-not (Test-Path $destDirFull)) { New-Item -ItemType Directory -Path $destDirFull -Force | Out-Null } - Copy-Item $sysFile (Join-Path $backupDir $repoFile) -Recurse -Force - } - } - Write-Host "Backup complete. To restore, copy files from $backupDir to their original locations." -ForegroundColor Green - } - default { - _config $Command @Args - } - } - } -} - -# Shows navigable menu of all options when hitting Tab -Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete - -# Autocompletion for arrow keys -Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward -Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward - -New-Alias vi nvim.exe - diff --git a/windows/Documents/PowerShell/bloatware.ps1 b/windows/Documents/PowerShell/bloatware.ps1 deleted file mode 100644 index 2ee078a..0000000 --- a/windows/Documents/PowerShell/bloatware.ps1 +++ /dev/null @@ -1,332 +0,0 @@ -# bloatware.ps1 - -# Check if the powershell-yaml module is installed, if not, install it -if (-not (Get-Module powershell-yaml -ListAvailable)) { - $policy = Get-PSRepository -Name 'PSGallery' | Select-Object -ExpandProperty InstallationPolicy - Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted - Install-Module powershell-yaml - Set-PSRepository -Name 'PSGallery' -InstallationPolicy $policy -} - -Import-Module powershell-yaml - -# Define the path to the YAML file -$yamlFilePath = "$HOME\packages.yml" - -# Parse the YAML file -$packages = ConvertFrom-Yaml -Path $yamlFilePath -$bloatware = $packages.bloatware -$defaultApps = $packages.defaultApps - -# Check if Registry key exists -function Check-RegistryKeyExists { - param( - [Parameter(Mandatory = $true)] - [string]$KeyPath - ) - - if (Test-Path $KeyPath) { - Write-Host "Registry key exists: $KeyPath" - return $true - } else { - Write-Host "Registry key does not exist: $KeyPath" - return $false - } -} - -# Helper functions ------------------------ -function force-mkdir($path) { - if (!(Test-Path $path)) { - Write-Host "-- Creating full path to: " $path -ForegroundColor White -BackgroundColor DarkGreen - New-Item -ItemType Directory -Force -Path $path - } -} - -function Takeown-Registry($key) { - # TODO does not work for all root keys yet - switch ($key.split('\')[0]) { - "HKEY_CLASSES_ROOT" { - $reg = [Microsoft.Win32.Registry]::ClassesRoot - $key = $key.substring(18) - } - "HKEY_CURRENT_USER" { - $reg = [Microsoft.Win32.Registry]::CurrentUser - $key = $key.substring(18) - } - "HKEY_LOCAL_MACHINE" { - $reg = [Microsoft.Win32.Registry]::LocalMachine - $key = $key.substring(19) - } - } - - # get administrator group - $admins = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") - $admins = $admins.Translate([System.Security.Principal.NTAccount]) - - # set owner - $key = $reg.OpenSubKey($key, "ReadWriteSubTree", "TakeOwnership") - $acl = $key.GetAccessControl() - $acl.SetOwner($admins) - $key.SetAccessControl($acl) - - # set FullControl - $acl = $key.GetAccessControl() - $rule = New-Object System.Security.AccessControl.RegistryAccessRule($admins, "FullControl", "Allow") - $acl.SetAccessRule($rule) - $key.SetAccessControl($acl) -} - -# Function to take ownership of registry keys -function Takeown-Registry($keyPath) { - $regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership) - $acl = $regKey.GetAccessControl() - $acl.SetOwner([System.Security.Principal.NTAccount]"Administrators") - $regKey.SetAccessControl($acl) - $regKey.Close() -} - -# Remove Features -function Takeown-File($path) { - takeown.exe /A /F $path - $acl = Get-Acl $path - - # get administrator group - $admins = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") - $admins = $admins.Translate([System.Security.Principal.NTAccount]) - - # add NT Authority\SYSTEM - $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($admins, "FullControl", "None", "None", "Allow") - $acl.AddAccessRule($rule) - - Set-Acl -Path $path -AclObject $acl -} - -function Takeown-Folder($path) { - Takeown-File $path - foreach ($item in Get-ChildItem $path) { - if (Test-Path $item -PathType Container) { - Takeown-Folder $item.FullName - } - else { - Takeown-File $item.FullName - } - } -} - -function Elevate-Privileges { - param($Privilege) - $Definition = @" - using System; - using System.Runtime.InteropServices; - - public class AdjPriv { - [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr rele); - - [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); - - [DllImport("advapi32.dll", SetLastError = true)] - internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct TokPriv1Luid { - public int Count; - public long Luid; - public int Attr; - } - - internal const int SE_PRIVILEGE_ENABLED = 0x00000002; - internal const int TOKEN_QUERY = 0x00000008; - internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; - - public static bool EnablePrivilege(long processHandle, string privilege) { - bool retVal; - TokPriv1Luid tp; - IntPtr hproc = new IntPtr(processHandle); - IntPtr htok = IntPtr.Zero; - retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); - tp.Count = 1; - tp.Luid = 0; - tp.Attr = SE_PRIVILEGE_ENABLED; - retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid); - retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); - return retVal; - } - } -"@ - $ProcessHandle = (Get-Process -id $pid).Handle - $type = Add-Type $definition -PassThru - $type[0]::EnablePrivilege($processHandle, $Privilege) -} - -# Remove Features ------------------------ -foreach ($bloat in $bloatware) { - Write-Output "Removing packages containing $bloat" - $pkgs = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages" | Where-Object Name -Like "*$bloat*" - - foreach ($pkg in $pkgs) { - $pkgname = $pkg.Name.Split('\')[-1] - Takeown-Registry $pkg.Name - Takeown-Registry ($pkg.Name + "\Owners") - Set-ItemProperty -Path ("HKLM:" + $pkg.Name.Substring(18)) -Name Visibility -Value 1 - New-ItemProperty -Path ("HKLM:" + $pkg.Name.Substring(18)) -Name DefVis -PropertyType DWord -Value 2 - Remove-Item -Path ("HKLM:" + $pkg.Name.Substring(18) + "\Owners") - dism.exe /Online /Remove-Package /PackageName:$pkgname /NoRestart - } -} - -# Remove default apps and bloat -Write-Output "Uninstalling default apps" -foreach ($app in $defaultApps) { - Write-Output "Trying to remove $app" - Get-AppxPackage -Name $app -AllUsers | Remove-AppxPackage -AllUsers - Get-AppXProvisionedPackage -Online | Where-Object DisplayName -EQ $app | Remove-AppxProvisionedPackage -Online -} - -# Disable Microsoft Edge sidebar -$RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' -$Name = 'HubsSidebarEnabled' -$Value = '00000000' -# Create the key if it does not exist -If (-NOT (Test-Path $RegistryPath)) { - New-Item -Path $RegistryPath -Force | Out-Null -} -New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force - -# Disable Microsoft Edge first-run Welcome screen -$RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' -$Name = 'HideFirstRunExperience' -$Value = '00000001' -# Create the key if it does not exist -If (-NOT (Test-Path $RegistryPath)) { - New-Item -Path $RegistryPath -Force | Out-Null -} -New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force - -# Remove Microsoft Edge ------------------------ -$ErrorActionPreference = "Stop" -$regView = [Microsoft.Win32.RegistryView]::Registry32 -$microsoft = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $regView). -OpenSubKey('SOFTWARE\Microsoft', $true) -$edgeUWP = "$env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe" -$uninstallRegKey = $microsoft.OpenSubKey('Windows\CurrentVersion\Uninstall\Microsoft Edge') -$uninstallString = $uninstallRegKey.GetValue('UninstallString') + ' --force-uninstall' -Write-Host "Removed Microsoft Edge" - -$edgeClient = $microsoft.OpenSubKey('EdgeUpdate\ClientState\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}', $true) -if ($null -ne $edgeClient.GetValue('experiment_control_labels')) { - $edgeClient.DeleteValue('experiment_control_labels') -} -$microsoft.CreateSubKey('EdgeUpdateDev').SetValue('AllowUninstall', '') -[void](New-Item $edgeUWP -ItemType Directory -ErrorVariable fail -ErrorAction SilentlyContinue) -[void](New-Item "$edgeUWP\MicrosoftEdge.exe" -ErrorAction Continue) -Start-Process cmd.exe "/c $uninstallString" -WindowStyle Hidden -Wait -[void](Remove-Item "$edgeUWP\MicrosoftEdge.exe" -ErrorAction Continue) - -if (-not $fail) { - [void](Remove-Item "$edgeUWP") -} - -Write-Output "Edge should now be uninstalled!" - -# Kill OneDrive with fire ------------------------ -Write-Output "Kill OneDrive process" -taskkill.exe /F /IM "OneDrive.exe" -taskkill.exe /F /IM "explorer.exe" -Write-Output "Remove OneDrive" -if (Test-Path "$env:systemroot\System32\OneDriveSetup.exe") { - & "$env:systemroot\System32\OneDriveSetup.exe" /uninstall -} -if (Test-Path "$env:systemroot\SysWOW64\OneDriveSetup.exe") { - & "$env:systemroot\SysWOW64\OneDriveSetup.exe" /uninstall -} - -Write-Output "Removing OneDrive leftovers" -Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:localappdata\Microsoft\OneDrive" -Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:programdata\Microsoft OneDrive" -Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:systemdrive\OneDriveTemp" -# check if directory is empty before removing: -If ((Get-ChildItem "$env:userprofile\OneDrive" -Recurse | Measure-Object).Count -eq 0) { - Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:userprofile\OneDrive" -} - -Write-Output "Disable OneDrive via Group Policies" -force-mkdir "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\OneDrive" -Set-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\OneDrive" "DisableFileSyncNGSC" 1 - -Write-Output "Remove Onedrive from explorer sidebar" -New-PSDrive -PSProvider "Registry" -Root "HKEY_CLASSES_ROOT" -Name "HKCR" -force-mkdir "HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" -Set-ItemProperty "HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" "System.IsPinnedToNameSpaceTree" 0 -force-mkdir "HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" -Set-ItemProperty "HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" "System.IsPinnedToNameSpaceTree" 0 -Remove-PSDrive "HKCR" - -# Thank you Matthew Israelsson -Write-Output "Removing run hook for new users" -reg load "hku\Default" "C:\Users\Default\NTUSER.DAT" -reg delete "HKEY_USERS\Default\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "OneDriveSetup" /f -reg unload "hku\Default" - -Write-Output "Removing startmenu entry" -Remove-Item -Force -ErrorAction SilentlyContinue "$env:userprofile\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk" - -Write-Output "Removing scheduled task" -$scheduledTasks = Get-ScheduledTask -TaskPath '\' -TaskName 'OneDrive*' -ErrorAction SilentlyContinue -if ($scheduledTasks) { - try { - $scheduledTasks | Unregister-ScheduledTask -Confirm:$false - Write-Output "OneDrive scheduled tasks removed." - } catch { - Write-Warning "Failed to unregister scheduled tasks: $_" - } -} else { - Write-Output "No OneDrive scheduled tasks found." -} - -Write-Output "Restarting explorer" -Start-Process "explorer.exe" - -Write-Output "Waiting for explorer to complete loading" -Start-Sleep 10 - -Write-Output "Removing additional OneDrive leftovers" -foreach ($item in (Get-ChildItem "$env:WinDir\WinSxS\*onedrive*")) { - Takeown-Folder $item.FullName - try { - Remove-Item -Recurse -Force -ErrorAction Continue -ErrorVariable RemoveError $item.FullName - if ($RemoveError) { - Write-Warning "Failed to remove $($item.FullName): $($RemoveError.Exception.Message)" - } else { - Write-Output "Successfully removed: $($item.FullName)" - } - } catch { - Write-Warning "Failed to remove $($item.FullName): $_" - } -} - -# Remove OneDrive directory if it exists -Write-Host "Removing OneDrive directory" - -# Change directory to user's home directory -Set-Location $HOME - -# Check if OneDrive directory exists -$OneDrivePath = Join-Path $HOME "OneDrive" -if (Test-Path -Path $OneDrivePath -PathType Container) { - # Remove OneDrive directory recursively and forcefully - Remove-Item -Path $OneDrivePath -Recurse -Force -ErrorAction Continue - if ($?) { - Write-Output "OneDrive directory removed successfully." - } else { - Write-Warning "Failed to remove OneDrive directory." - } -} else { - Write-Output "OneDrive directory not found." -} - -# Prevents "Suggested Applications" returning -if (Check-RegistryKeyExists -KeyPath "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content") { - Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content" "DisableWindowsConsumerFeatures" 1 -} diff --git a/windows/Documents/PowerShell/bootstrap.ps1 b/windows/Documents/PowerShell/bootstrap.ps1 deleted file mode 100644 index d2f4369..0000000 --- a/windows/Documents/PowerShell/bootstrap.ps1 +++ /dev/null @@ -1,669 +0,0 @@ -#!/usr/bin/env pwsh - -# Created By: srdusr -# Created On: Windows PowerShell Bootstrap Script -# Project: Dotfiles installation script for Windows - -# Dependencies: git, powershell - -param( - [string]$Profile = "essentials", - [switch]$Force = $false, - [switch]$Ask = $false, - [switch]$Help = $false -) - -# Color definitions for pretty UI -$Script:Colors = @{ - Reset = "`e[0m" - Red = "`e[0;31m" - Green = "`e[0;32m" - Yellow = "`e[0;33m" - Blue = "`e[0;34m" - Cyan = "`e[0;36m" - White = "`e[0;37m" - Bold = "`e[1m" -} - -# Prompt helper: Yes/No with default; in non-Ask mode, returns default immediately -function Prompt-YesNo { - param( - [Parameter(Mandatory=$true)][string]$Question, - [ValidateSet('Y','N')][string]$Default = 'Y' - ) - if (-not $Script:AskPreference) { - return $Default -eq 'Y' - } - $suffix = if ($Default -eq 'Y') { '[Y/n]' } else { '[y/N]' } - while ($true) { - Write-Host -NoNewline "$Question $suffix: " -ForegroundColor Yellow - $resp = Read-Host - if ([string]::IsNullOrWhiteSpace($resp)) { $resp = $Default } - switch ($resp.ToUpper()) { - 'Y' { return $true } - 'YES' { return $true } - 'N' { return $false } - 'NO' { return $false } - default { Write-Warning "Please answer Y/yes or N/no" } - } - } -} - -# Configuration -$Script:Config = @{ - DotfilesUrl = 'https://github.com/srdusr/dotfiles.git' - DotfilesDir = "$HOME\.cfg" - LogFile = "$HOME\AppData\Local\dotfiles_install.log" - StateFile = "$HOME\AppData\Local\dotfiles_install_state" - BackupDir = "$HOME\.dotfiles-backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')" - PackagesFile = "packages.yml" - OS = "windows" -} - -# Logging functions -function Write-Log { - param([string]$Message, [string]$Level = "INFO") - $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" - $logEntry = "[$timestamp] [$Level] $Message" - Add-Content -Path $Script:Config.LogFile -Value $logEntry -Force -} - -function Write-ColorOutput { - param([string]$Message, [string]$Color = "White") - Write-Host $Message -ForegroundColor $Color - Write-Log $Message -} - -function Write-Success { param([string]$Message) Write-ColorOutput "✓ $Message" "Green" } -function Write-Info { param([string]$Message) Write-ColorOutput "ℹ $Message" "Cyan" } -function Write-Warning { param([string]$Message) Write-ColorOutput "⚠ $Message" "Yellow" } -function Write-Error { param([string]$Message) Write-ColorOutput "✗ $Message" "Red" } - -function Write-Header { - param([string]$Title) - Write-Host "" - Write-Host "=" * 60 -ForegroundColor Blue - Write-Host " $Title" -ForegroundColor Bold - Write-Host "=" * 60 -ForegroundColor Blue - Write-Host "" -} - -# Utility functions -function Test-CommandExists { - param([string]$Command) - return [bool](Get-Command $Command -ErrorAction SilentlyContinue) -} - -function Test-IsAdmin { - $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() - $principal = New-Object Security.Principal.WindowsPrincipal($currentUser) - return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -} - -function Invoke-AdminCommand { - param([string]$Command) - if (-not (Test-IsAdmin)) { - Write-Warning "Elevating privileges for: $Command" - Start-Process powershell.exe -ArgumentList "-NoProfile", "-Command", $Command -Verb RunAs -Wait - } else { - Invoke-Expression $Command - } -} - -# Package management functions -function Get-PackageManager { - if (Test-CommandExists "choco") { return "chocolatey" } - if (Test-CommandExists "winget") { return "winget" } - if (Test-CommandExists "scoop") { return "scoop" } - return $null -} - -# Return $true if a package appears to be installed for the given manager -function Test-PackageInstalled { - param( - [Parameter(Mandatory=$true)][string]$Manager, - [Parameter(Mandatory=$true)][string]$Name - ) - switch ($Manager) { - "chocolatey" { - $out = choco list --local-only --exact $Name 2>$null - return ($out | Select-String -Pattern "^\s*$([regex]::Escape($Name))\s").Length -gt 0 - } - "winget" { - # Winget list may return multiple rows; use --exact name match when possible - $out = winget list --name $Name 2>$null - return ($out | Select-String -SimpleMatch $Name).Length -gt 0 - } - "scoop" { - # scoop list returns 0 when installed - scoop list $Name *> $null - return $LASTEXITCODE -eq 0 - } - default { return $false } - } -} - -function Install-PackageManager { - Write-Header "Installing Package Manager" - - if (-not (Test-CommandExists "choco")) { - Write-Info "Installing Chocolatey..." - Set-ExecutionPolicy Bypass -Scope Process -Force - [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 - Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - - if (Test-CommandExists "choco") { - Write-Success "Chocolatey installed successfully" - } else { - Write-Error "Failed to install Chocolatey" - return $false - } - } else { - Write-Info "Chocolatey already installed" - } - return $true -} - -function Install-Packages { - param([string]$PackagesFile, [string]$Profile) - - if (-not (Test-Path $PackagesFile)) { - Write-Warning "Packages file not found: $PackagesFile" - return - } - - Write-Header "Installing Packages" - - # Install powershell-yaml if not available - if (-not (Get-Module powershell-yaml -ListAvailable)) { - Write-Info "Installing powershell-yaml module..." - $policy = Get-PSRepository -Name 'PSGallery' | Select-Object -ExpandProperty InstallationPolicy - Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted - Install-Module powershell-yaml -Force - Set-PSRepository -Name 'PSGallery' -InstallationPolicy $policy - } - - Import-Module powershell-yaml - - # Helper: run custom_installs..windows if condition passes - function Invoke-CustomInstallsWindows { - param([Parameter(Mandatory=$true)]$Yaml) - if (-not $Yaml.custom_installs) { return } - foreach ($name in $Yaml.custom_installs.PSObject.Properties.Name) { - $entry = $Yaml.custom_installs.$name - if (-not $entry) { continue } - $winCmd = $entry.windows - if (-not $winCmd) { continue } - $shouldRun = $true - if ($entry.condition) { - $cond = [string]$entry.condition - if ($cond -match "!\s*command\s+-v\s+([A-Za-z0-9._-]+)") { - $shouldRun = -not (Test-CommandExists $Matches[1]) - } elseif ($cond -match "command\s+-v\s+([A-Za-z0-9._-]+)") { - $shouldRun = (Test-CommandExists $Matches[1]) - } - } - if (-not $shouldRun) { Write-Info "Skipping custom install: $name"; continue } - Write-Info "Running custom install: $name" - try { Invoke-Expression $winCmd; Write-Success "Custom install completed: $name" } - catch { Write-Warning "Custom install failed for '$name': $_" } - } - } - - try { - $packages = Get-Content $PackagesFile | ConvertFrom-Yaml - $packageManager = Get-PackageManager - - if (-not $packageManager) { - Write-Error "No package manager available" - return - } - - # Get packages for current profile and OS - $profilePackages = @() - if ($packages.profiles.$Profile.windows) { - $profilePackages += $packages.profiles.$Profile.windows - } - if ($packages.profiles.$Profile.common) { - $profilePackages += $packages.profiles.$Profile.common - } - - foreach ($package in $profilePackages) { - $packageName = if ($packages.packages.$package.windows) { - $packages.packages.$package.windows - } else { - $package - } - - if (Test-PackageInstalled -Manager $packageManager -Name $packageName) { - Write-Info "Already installed: $packageName" - continue - } - - Write-Info "Installing package: $packageName" - - switch ($packageManager) { - "chocolatey" { - if (-not (choco list --local-only | Select-String -Pattern "^$packageName\s")) { - choco install $packageName -y - if ($LASTEXITCODE -eq 0) { - Write-Success "Installed: $packageName" - } else { - Write-Error "Failed to install: $packageName" - } - } else { - Write-Info "Already installed: $packageName" - } - } - "winget" { - winget install $packageName --accept-package-agreements --accept-source-agreements - } - "scoop" { - scoop install $packageName - } - } - } - - # Also install top-level Windows packages list if present - if ($packages.windows) { - foreach ($pkg in $packages.windows) { - if ([string]::IsNullOrWhiteSpace($pkg)) { continue } - if (Test-PackageInstalled -Manager $packageManager -Name $pkg) { Write-Info "Already installed: $pkg"; continue } - Write-Info "Installing package: $pkg" - switch ($packageManager) { - "chocolatey" { - if (-not (choco list --local-only | Select-String -Pattern "^$([regex]::Escape($pkg))\s")) { choco install $pkg -y } - } - "winget" { winget install --id $pkg --silent --accept-package-agreements --accept-source-agreements } - "scoop" { scoop install $pkg } - } - } - } - - # Execute Windows custom installs from packages.yml - Invoke-CustomInstallsWindows -Yaml $packages - } catch { - Write-Error "Error processing packages: $_" - } -} - -# Dotfiles management functions -function Install-Dotfiles { - Write-Header "Installing Dotfiles" - - if (Test-Path $Script:Config.DotfilesDir) { - Write-Info "Updating existing dotfiles repository..." - & git --git-dir="$($Script:Config.DotfilesDir)" --work-tree="$($Script:Config.DotfilesDir)" pull origin main - } else { - Write-Info "Cloning dotfiles repository..." - git clone --bare $Script:Config.DotfilesUrl $Script:Config.DotfilesDir - - if (-not (Test-Path $Script:Config.DotfilesDir)) { - Write-Error "Failed to clone dotfiles repository" - return $false - } - } - - # Set up config alias for this session - function script:config { - git --git-dir="$($Script:Config.DotfilesDir)" --work-tree="$($Script:Config.DotfilesDir)" @args - } - - # Configure repository - config config --local status.showUntrackedFiles no - - # Checkout files to restore directory structure - Write-Info "Checking out dotfiles..." - try { - config checkout 2>$null - if ($LASTEXITCODE -ne 0) { - Write-Info "Forcing checkout to overwrite existing files..." - config checkout -f - } - Write-Success "Dotfiles checked out successfully" - } catch { - Write-Error "Failed to checkout dotfiles: $_" - return $false - } - - return $true -} - -function Deploy-Dotfiles { - Write-Header "Deploying Dotfiles" - - if (-not (Test-Path $Script:Config.DotfilesDir)) { - Write-Error "Dotfiles directory not found. Run Install-Dotfiles first." - return $false - } - - # Source the config command from profile if available - $profilePath = "$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" - if (Test-Path $profilePath) { - Write-Info "Loading config command from profile..." - . $profilePath - } - - # Deploy using config command if available, otherwise manual deployment - if (Get-Command config -ErrorAction SilentlyContinue) { - Write-Info "Deploying dotfiles using config command..." - config deploy - } else { - Write-Warning "Config command not available, using manual deployment..." - # Manual deployment fallback would go here - } - - Write-Success "Dotfiles deployment completed" - return $true -} - -# Locate profile-specific packages.yml similar to Linux installer -function Get-ProfilePackagesFile { - param([string]$Profile) - $candidates = @( - Join-Path $HOME ".cfg/profile/$Profile/packages.yml", - Join-Path $HOME "profile/$Profile/packages.yml", - Join-Path $HOME "dot_setup/profile/$Profile/packages.yml", - Join-Path $Script:Config.DotfilesDir "common/$($Script:Config.PackagesFile)" - ) - foreach ($pf in $candidates) { - if (Test-Path $pf) { return $pf } - } - return $null -} - -# System configuration functions -function Set-WindowsConfiguration { - param( - [string]$PackagesFile - ) - - Write-Header "Configuring Windows Settings" - - if (-not $PackagesFile -or -not (Test-Path $PackagesFile)) { - Write-Warning "Packages file not found, skipping Windows configuration" - return - } - - try { - # Load YAML content - $yamlContent = Get-Content $PackagesFile -Raw | ConvertFrom-Yaml - $registrySettings = $yamlContent.system_tweaks.windows.registry - - if (-not $registrySettings) { - Write-Warning "No Windows registry settings found in packages.yml" - return - } - - Write-Info "Applying registry settings from packages.yml..." - - foreach ($setting in $registrySettings) { - try { - $path = $setting.path - $name = $setting.name - $value = $setting.value - $type = $setting.type - $description = $setting.description - - Write-Info "Setting: $description" - - # Ensure the registry path exists - $pathParts = $path -split '\\' - $currentPath = $pathParts[0] - for ($i = 1; $i -lt $pathParts.Length; $i++) { - $currentPath = "$currentPath\$($pathParts[$i])" - if (-not (Test-Path $currentPath)) { - New-Item -Path $currentPath -Force | Out-Null - } - } - - # Set the registry value - Set-ItemProperty -Path $path -Name $name -Value $value -Type $type -Force - Write-Success "Applied: $description" - - } catch { - Write-Warning "Failed to apply setting '$($setting.description)': $_" - } - } - - Write-Success "Windows configuration applied" - - # Restart explorer to apply changes - Write-Info "Restarting Windows Explorer..." - Stop-Process -Name explorer -Force - Start-Process explorer.exe - - } catch { - Write-Warning "Failed to process Windows configuration: $_" - } -} - -function Enable-WindowsFeatures { - param( - [string]$PackagesFile - ) - - Write-Header "Enabling Windows Features" - - if (-not $PackagesFile -or -not (Test-Path $PackagesFile)) { - Write-Warning "Packages file not found, skipping Windows features" - return - } - - try { - # Load YAML content - $yamlContent = Get-Content $PackagesFile -Raw | ConvertFrom-Yaml - $features = $yamlContent.system_tweaks.windows.features - - if (-not $features) { - Write-Warning "No Windows features found in packages.yml" - return - } - - foreach ($feature in $features) { - $featureName = $feature.name - $description = $feature.description - $requiresAdmin = $feature.requires_admin - - if ($requiresAdmin -and -not (Test-IsAdmin)) { - Write-Warning "Skipping '$description' - requires administrator privileges" - continue - } - - try { - Write-Info "Enabling: $description" - dism.exe /online /enable-feature /featurename:$featureName /all /norestart - Write-Success "Enabled: $description" - } catch { - Write-Warning "Failed to enable '$description': $_" - } - } - - Write-Success "Windows features processing complete (restart may be required)" - - } catch { - Write-Warning "Failed to process Windows features: $_" - } -} - -function Install-PowerShellProfile { - Write-Header "Setting up PowerShell Profile" - - $documentsPath = [System.Environment]::GetFolderPath('MyDocuments') - $powerShellProfileDir = "$documentsPath\PowerShell" - $profilePath = "$powerShellProfileDir\Microsoft.PowerShell_profile.ps1" - - Write-Info "PowerShell profile directory: $powerShellProfileDir" - - if (-not (Test-Path $powerShellProfileDir)) { - New-Item -ItemType Directory -Path $powerShellProfileDir -Force | Out-Null - Write-Success "Created PowerShell profile directory" - } - - # Copy profile from dotfiles if it exists - $dotfilesProfile = "$($Script:Config.DotfilesDir)\windows\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" - if (Test-Path $dotfilesProfile) { - Copy-Item $dotfilesProfile $profilePath -Force - Write-Success "PowerShell profile installed from dotfiles" - } else { - Write-Warning "PowerShell profile not found in dotfiles" - } -} - -# Main execution function -function Start-Bootstrap { - param([string]$Profile, [switch]$Force, [switch]$Ask) - - Write-Header "Windows Dotfiles Bootstrap" - Write-Info "Profile: $Profile" - Write-Info "Force mode: $Force" - Write-Info "Interactive mode: $Ask" - - # Initialize logging - $logDir = Split-Path $Script:Config.LogFile - if (-not (Test-Path $logDir)) { - New-Item -ItemType Directory -Path $logDir -Force | Out-Null - } - - Write-Log "Bootstrap started with profile: $Profile" - - # Set Ask preference for all prompts - $Script:AskPreference = [bool]$Ask - - # Check dependencies - Write-Header "Checking Dependencies" - $requiredCommands = @("git", "powershell") - $missingCommands = @() - - foreach ($cmd in $requiredCommands) { - if (-not (Test-CommandExists $cmd)) { - $missingCommands += $cmd - Write-Error "Required command not found: $cmd" - } else { - Write-Success "Found: $cmd" - } - } - - if ($missingCommands.Count -gt 0) { - Write-Error "Missing required dependencies. Please install: $($missingCommands -join ', ')" - return $false - } - - # Install package manager (skippable) - if (Prompt-YesNo -Question "Install/check package manager?" -Default 'Y') { - if (-not (Install-PackageManager)) { - Write-Error "Failed to install package manager" - return $false - } - } else { - Write-Warning "Skipped package manager step by user choice" - } - - # Install dotfiles - if (Prompt-YesNo -Question "Install or update dotfiles?" -Default 'Y') { - if (-not (Install-Dotfiles)) { - Write-Error "Failed to install dotfiles" - return $false - } - } else { - Write-Warning "Skipped dotfiles installation by user choice" - } - - # Get packages file (profile-aware) - $packagesFile = Get-ProfilePackagesFile -Profile $Profile - if (-not $packagesFile) { - Write-Error "Failed to get packages file for profile '$Profile'" - return $false - } - - # Install packages - if (Prompt-YesNo -Question "Install profile packages?" -Default 'Y') { - Install-Packages -PackagesFile $packagesFile -Profile $Profile - } else { - Write-Warning "Skipped package installation by user choice" - } - - # Set up PowerShell profile - if (Prompt-YesNo -Question "Install PowerShell profile?" -Default 'Y') { - Install-PowerShellProfile - } else { - Write-Warning "Skipped PowerShell profile setup by user choice" - } - - # Deploy dotfiles - if (Prompt-YesNo -Question "Deploy dotfiles to system locations?" -Default 'Y') { - if (-not (Deploy-Dotfiles)) { - Write-Error "Failed to deploy dotfiles" - return $false - } - } else { - Write-Warning "Skipped dotfiles deployment by user choice" - } - - # Configure Windows - if (Prompt-YesNo -Question "Apply Windows configuration from packages.yml?" -Default 'N') { - Set-WindowsConfiguration -PackagesFile $packagesPath - } else { - Write-Warning "Skipped Windows configuration by user choice" - } - - # Enable Windows features (if admin) - if (Prompt-YesNo -Question "Enable Windows optional features?" -Default 'N') { - Enable-WindowsFeatures -PackagesFile $packagesPath - } else { - Write-Warning "Skipped enabling Windows features by user choice" - } - - Write-Header "Bootstrap Complete" - Write-Success "Windows dotfiles bootstrap completed successfully!" - Write-Info "Please restart your computer to apply all changes." - Write-Log "Bootstrap completed successfully" - - return $true -} - -# Help function -function Show-Help { - Write-Host @" -Windows Dotfiles Bootstrap Script - -USAGE: - .\bootstrap.ps1 [-Profile ] [-Force] [-Ask] [-Help] - -PARAMETERS: - -Profile Installation profile (default: essentials) - Available: essentials, minimal, dev, server, full, or a custom profile. - Custom profile files are resolved from: - - %USERPROFILE%\.cfg\profile\\packages.yml - - %USERPROFILE%\profile\\packages.yml - - %USERPROFILE%\dot_setup\profile\\packages.yml - -Force Force installation without prompts - -Ask Interactive mode with step-by-step prompts - -Help Show this help message - -EXAMPLES: - .\bootstrap.ps1 # Install with essentials profile - .\bootstrap.ps1 -Profile dev # Install development profile - .\bootstrap.ps1 -Profile full -Force # Force install full profile - .\bootstrap.ps1 -Ask # Interactive installation - -"@ -ForegroundColor Cyan -} - -# Script entry point -if ($Help) { - Show-Help - exit 0 -} - -# Run bootstrap -try { - $result = Start-Bootstrap -Profile $Profile -Force:$Force -Ask:$Ask - if (-not $result) { - exit 1 - } -} catch { - Write-Error "Bootstrap failed: $_" - Write-Log "Bootstrap failed: $_" "ERROR" - exit 1 -} diff --git a/windows/Documents/PowerShell/initialize.ps1 b/windows/Documents/PowerShell/initialize.ps1 deleted file mode 100644 index 72f0ea4..0000000 --- a/windows/Documents/PowerShell/initialize.ps1 +++ /dev/null @@ -1,227 +0,0 @@ -<# - .SYNOPSIS - Bootstrap Windows command prompts (cmd, PS, PSCore) with my dotfiles and apps. - - .DESCRIPTION - To bootstrap directly from GitHub, run these 2 cmdlets in a PowerShell prompt: - > Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force - > irm 'https://raw.githubusercontent.com/srdusr/dotfiles/main/windows/Documents/PowerShell/bootstrap.ps1' | iex -#> -[CmdletBinding()] -param ( - [ValidateSet('clone', 'setup', 'apps', 'env', IgnoreCase = $true)] - [Parameter(Position = 0)] [string] - $verb = 'clone', - [Parameter()] [string] - $userName = $null, - [Parameter()] [string] - $email = $null, - [Parameter()] [switch] - $runAsAdmin = $false -) - -$ErrorActionPreference = 'Stop' - -$originGitHub = 'https://github.com/srdusr/dotfiles.git' -$dotPath = (Join-Path $env:USERPROFILE '.cfg') - -# Ensure Tls12 -[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 - -function ensureLocalGit { - if (Get-Command 'git' -ErrorAction SilentlyContinue) { - return - } - - $localGitFolder = (Join-Path $env:USERPROFILE (Join-Path "Downloads" "localGit")) - Write-Host "Installing ad-hoc git into $localGitFolder..." - - $gitUrl = Invoke-RestMethod 'https://api.github.com/repos/git-for-windows/git/releases/latest' | - Select-Object -ExpandProperty 'assets' | - Where-Object { $_.name -Match 'MinGit' -and $_.name -Match '64-bit' -and $_.name -notmatch 'busybox' } | - Select-Object -ExpandProperty 'browser_download_url' - $localGitZip = (Join-Path $localGitFolder "MinGit.zip") - New-Item -ItemType Directory -Path $localGitFolder -Force | Out-Null - (New-Object Net.WebClient).DownloadFile($gitUrl, $localGitZip) - Expand-Archive -Path $localGitZip -DestinationPath $localGitFolder -Force - - $gitPath = (Join-Path $localGitFolder 'cmd') - $env:Path += ";$gitPath" -} - -function cloneDotfiles { - Write-Host "Cloning $originGitHub -> $dotPath" - Write-Host -NoNewline "OK to proceed with setup? [Y/n] " - $answer = (Read-Host).ToUpper() - if ($answer -ne 'Y' -and $answer -ne '') { - Write-Warning "Aborting." - return 4 - } - - ensureLocalGit - - if (-not $userName -or $userName -eq '') { - $userName = (& git config --global --get user.name) - } - if (-not $userName -or $userName -eq '') { - $userName = "$env:USERNAME@$env:COMPUTERNAME" - } - - if (-not $email -or $email -eq '') { - $email = (& git config --global --get user.email) - } - if (-not $email -or $email -eq '') { - $email = Read-Host "Enter your email address for git commits" - if ($email -eq '') { - Write-Warning "Need email address, aborting." - return 3 - } - } - - & git.exe config --global user.name $userName - & git.exe config --global user.email $email - - - function global:config { - git --git-dir="$dotPath" --work-tree="$env:USERPROFILE" $args - } - - Add-Content -Path "$env:USERPROFILE\.gitignore" -Value ".cfg" - - if (Test-Path -Path $dotfiles_dir) { - config pull | Out-Null - $update = $true - } else { - git clone --bare $originGitHub $dotPath | Out-Null - $update = $false - } - - $std_err_output = config checkout 1>&1 - - if ($std_err_output -match "following untracked working tree files would be overwritten") { - if (-not $update) { - config checkout | Out-Null - } - } - config config --local status.showUntrackedFiles no - - if ($update -or (Read-Host "Do you want to overwrite existing files and continue with the dotfiles setup? [Y/n]" -eq "Y")) { - config fetch origin main:main | Out-Null - config reset --hard main | Out-Null - config checkout -f - if ($?) { - Write-Host "Successfully imported $dotPath." - } else { - handle_error "Mission failed." - } - } else { - handle_error "Aborted by user. Exiting..." - } - - return 0 -} - -function setup { - ensureLocalGit -} - -function installApps { - ensureLocalGit -} - -function writeGitConfig { - param ( - [Parameter(Mandatory = $true)] [string] $configIniFile - ) - - if ((Test-Path (Join-Path $env:USERPROFILE '.gitconfig')) -and -not (Test-Path (Join-Path $env:USERPROFILE '.gitconfig.bak'))) { - $userName = (& git config --global --get user.name) - $email = (& git config --global --get user.email) - - Move-Item -Path (Join-Path $env:USERPROFILE '.gitconfig') -Destination (Join-Path $env:USERPROFILE '.gitconfig.bak') - - if ($userName -and $userName -ne '') { - & git.exe config --global user.name $userName - } - if ($email -and $email -ne '') { - & git.exe config --global user.email $email - } - } - - Get-Content $configIniFile | ForEach-Object { - if ($_.TrimStart().StartsWith('#')) { return } - $key, $value = $_.Split('=', 2) - Write-Verbose "git config --global $key $value" - & git.exe config --global $key "$value" - } -} - -function setupShellEnvs { - Write-Host "Setting cmd console properties:" - $consolePath = 'HKCU\Console' - & reg add $consolePath /v QuickEdit /d 0x1 /t REG_DWORD /f | Out-Null - & reg add $consolePath /v WindowSize /d 0x00320078 /t REG_DWORD /f | Out-Null - & reg add $consolePath /v ScreenBufferSize /d 0x23280078 /t REG_DWORD /f | Out-Null - & reg add $consolePath /v FontFamily /d 0x36 /t REG_DWORD /f | Out-Null - & reg add $consolePath /v HistoryBufferSize /d 0x64 /t REG_DWORD /f | Out-Null - & reg add $consolePath /v FaceName /d "Hack Nerd Font Mono" /t REG_SZ /f | Out-Null - & reg add $consolePath /v FontSize /d 0x00100000 /t REG_DWORD /f | Out-Null - - $win32rc = (Join-Path $PSScriptRoot (Join-Path 'win' 'win32-rc.cmd')) - Write-Host "Setting up cmd autorun: $win32rc" - & reg add "HKCU\Software\Microsoft\Command Processor" /v AutoRun /t REG_SZ /d $win32rc /f | Out-Null - - Write-Host "Configuring user home dir..." - $configDir = (Join-Path $env:USERPROFILE '.config') - New-Item -ItemType Directory -Path $configDir -ErrorAction SilentlyContinue | Out-Null - - $sshDir = (Join-Path $env:USERPROFILE '.ssh') - Remove-Item (Join-Path $sshDir 'config') -ErrorAction SilentlyContinue -Force | Out-Null - $openSsh = ((Join-Path $env:windir 'System32\OpenSSH\ssh.exe').Replace("\", "/")) - & git config --global core.sshCommand $openSsh -} - -function main { - param ( - [Parameter(Mandatory = $true)] [string] $verbAction - ) - - Write-Verbose "PS: $($PSVersionTable.PSVersion)-$($PSVersionTable.PSEdition)" - switch ($verbAction) { - 'clone' { - Write-Host - if (Test-Path (Join-Path $dotPath '.git')) { - Write-Host "Local git repo already exists, skipping." - main setup - return - } - - $rc = cloneDotfiles - if ($rc -ne 0) { - Write-Error "Cloning dotfiles failed, aborting." - return - } - - $script = (Join-Path $dotPath 'Documents\PowerShell\bootstrap.ps1') - Write-Host "Continue $script in child process" - Start-Process -PassThru -NoNewWindow -FilePath "powershell.exe" -ArgumentList "-NoProfile -File $script setup" | Wait-Process - } - - 'setup' { - Write-Host "Setting up..." - setup - installApps - setupShellEnvs - Write-Host "Done (setup)." - exit - } - - 'apps' { installApps } - - 'env' { setupShellEnvs } - } - - Write-Host "Done." -} - -main $verb diff --git a/windows/ProgramData/.gitkeep b/windows/ProgramData/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/windows/System32/.gitkeep b/windows/System32/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/windows/Users/AppData/windows-terminal/settings.json b/windows/Users/AppData/windows-terminal/settings.json new file mode 100644 index 0000000..71bf5bd --- /dev/null +++ b/windows/Users/AppData/windows-terminal/settings.json @@ -0,0 +1,590 @@ +{ + "$help": "https://aka.ms/terminal-documentation", + "$schema": "https://aka.ms/terminal-profiles-schema", + "actions": + [ + { "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" }, + { "command": "unbound", "keys": "ctrl+v" }, + { "command": "unbound", "keys": "ctrl+c" }, + { "command": { "action": "copy", "singleLine": false } }, + { "command": { "action": "scrollUp" }, "keys": "ctrl+shift+up" }, + { "command": "find", "keys": "ctrl+shift+f" }, + { "command": "paste" }, + + { "command": { "action": "splitPane", "split": "vertical", "splitMode": "duplicate" }, "keys": "alt+shift+plus" }, + { "command": { "action": "splitPane", "split": "horizontal", "splitMode": "duplicate" }, "keys": "alt+shift+-" }, + + { "command": { "action": "nextTab", "tabSwitcherMode": "mru" }, "keys": "ctrl+tab" }, + { "command": "openTabRenamer", "keys": "ctrl+shift+r" }, + + { "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" }, + { "command": { "action": "scrollDown" }, "keys": "ctrl+shift+down" }, + + { "command": "scrollUpPage", "keys": "ctrl+shift+pgup" }, + + { "command": { "action": "moveFocus", "direction": "left" }, "keys": "alt+h" }, + { "command": { "action": "moveFocus", "direction": "down" }, "keys": "alt+j" }, + { "command": { "action": "moveFocus", "direction": "up" }, "keys": "alt+k" }, + { "command": { "action": "moveFocus", "direction": "right" }, "keys": "alt+l" }, + + { "command": { "action": "resizePane", "direction": "left" }, "keys": "alt+shift+y" }, + { "command": { "action": "resizePane", "direction": "down" }, "keys": "alt+shift+u" }, + { "command": { "action": "resizePane", "direction": "up" }, "keys": "alt+shift+i" }, + { "command": { "action": "resizePane", "direction": "right" }, "keys": "alt+shift+o" }, + + { "command": { "action": "swapPane", "direction": "left" }, "keys": "alt+shift+h" }, + { "command": { "action": "swapPane", "direction": "down" }, "keys": "alt+shift+j" }, + { "command": { "action": "swapPane", "direction": "up" }, "keys": "alt+shift+k" }, + { "command": { "action": "swapPane", "direction": "right" }, "keys": "alt+shift+l" }, + + { "command": "togglePaneZoom", "keys": "alt+f" } + ], + "copyFormatting": "none", + "copyOnSelect": false, + "defaultProfile": "{f19ccc1d-fe9a-4e79-ad18-49276786d144}", + "launchMode": "default", + "profiles": + { + "defaults": + { + "backgroundImage": null, + "colorScheme": "Gruvbox Dark", + "font": + { + "face": "CaskaydiaCove NF" + }, + "historySize": 9001, + "opacity": 100, + "padding": "0", + "snapOnInput": false, + "useAcrylic": false, + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + "list": + [ + { + "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\download3.jpg", + "backgroundImageOpacity": 0.089999999999999997, + "colorScheme": "Tokyo Night", + "commandline": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", + "experimental.retroTerminalEffect": false, + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{f19ccc1d-fe9a-4e79-ad18-49276786d144}", + "historySize": 99999, + "icon": "ms-appx:///ProfileIcons/pwsh.png", + "name": "PowerShell 7 - BG", + "opacity": 100, + "padding": "0", + "scrollbarState": "visible", + "startingDirectory": "%USERPROFILE%", + "suppressApplicationTitle": false, + "useAcrylic": false, + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\photo-1533484306792-cf313c2b8ab0 (2).jpg", + "backgroundImageOpacity": 0.19, + "bellStyle": "taskbar", + "colorScheme": "Tokyo Night", + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}", + "hidden": false, + "historySize": 99999, + "name": "Ubuntu-20.04", + "source": "Windows.Terminal.Wsl", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "guid": "{f9ceaf27-504c-58d7-927c-d1d6a7ac7d3c}", + "hidden": false, + "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\photo-1533484306792-cf313c2b8ab0 (2).jpg", + "backgroundImageOpacity": 0.19, + "name": "Ubuntu 22.04.1 LTS", + "source": "CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc", + "colorScheme": "Tokyo Night", + "font": + { + "face": "CaskaydiaCove NF" + }, + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}", + "hidden": false, + "historySize": 99999, + "name": "PowerShell 7 - NO BG", + "padding": "0", + "source": "Windows.Terminal.PowershellCore", + "suppressApplicationTitle": false, + "useAcrylic": false, + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", + "hidden": false, + "historySize": 99999, + "name": "Command Prompt", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", + "hidden": false, + "historySize": 99999, + "name": "PowerShell 5", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{46ca431a-3a87-5fb3-83cd-11ececc031d2}", + "hidden": false, + "name": "Kali Linux", + "source": "Windows.Terminal.Wsl", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", + "hidden": false, + "historySize": 99999, + "name": "Azure Cloud Shell", + "source": "Windows.Terminal.Azure", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "backgroundImage": null, + "backgroundImageOpacity": 0.29999999999999999, + "commandline": "C:\\GBox\\Applications\\Tools\\Applications\\Neovim\\nvim-win64\\0.6.0\\bin\\nvim.exe", + "font": + { + "face": "CaskaydiaCove NF" + }, + "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6102}", + "hidden": false, + "historySize": 99999, + "name": "Neovim", + "padding": "0", + "useAcrylic": false, + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "guid": "{d701ea23-d39a-51a9-9966-855f1c8051f1}", + "hidden": false, + "name": "Developer Command Prompt for VS 2022 [Preview]", + "source": "Windows.Terminal.VisualStudio", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "guid": "{960e8c7a-d53d-5f77-ad6f-daf9dfeb597d}", + "hidden": false, + "name": "Developer PowerShell for VS 2022 [Preview]", + "source": "Windows.Terminal.VisualStudio", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "guid": "{fddd4872-371a-5869-85aa-657716af07fa}", + "hidden": true, + "name": "Developer Command Prompt for VS 2022", + "source": "Windows.Terminal.VisualStudio", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + }, + { + "guid": "{e1c4148c-0ee2-5cd8-802c-8a170e188519}", + "hidden": true, + "name": "Developer PowerShell for VS 2022", + "source": "Windows.Terminal.VisualStudio", + "closeOnExit":"graceful", + "intenseTextStyle": "all" + } + ] + }, + "schemes": + [ + { + "background": "#0C0C0C", + "black": "#0C0C0C", + "blue": "#0037DA", + "brightBlack": "#767676", + "brightBlue": "#3B78FF", + "brightCyan": "#61D6D6", + "brightGreen": "#16C60C", + "brightPurple": "#B4009E", + "brightRed": "#E74856", + "brightWhite": "#F2F2F2", + "brightYellow": "#F9F1A5", + "cursorColor": "#FFFFFF", + "cyan": "#3A96DD", + "foreground": "#CCCCCC", + "green": "#13A10E", + "name": "Campbell", + "purple": "#881798", + "red": "#C50F1F", + "selectionBackground": "#FFFFFF", + "white": "#CCCCCC", + "yellow": "#C19C00" + }, + { + "background": "#012456", + "black": "#0C0C0C", + "blue": "#0037DA", + "brightBlack": "#767676", + "brightBlue": "#3B78FF", + "brightCyan": "#61D6D6", + "brightGreen": "#16C60C", + "brightPurple": "#B4009E", + "brightRed": "#E74856", + "brightWhite": "#F2F2F2", + "brightYellow": "#F9F1A5", + "cursorColor": "#FFFFFF", + "cyan": "#3A96DD", + "foreground": "#CCCCCC", + "green": "#13A10E", + "name": "Campbell Powershell", + "purple": "#881798", + "red": "#C50F1F", + "selectionBackground": "#FFFFFF", + "white": "#CCCCCC", + "yellow": "#C19C00" + }, + { + "background": "#282828", + "black": "#282828", + "blue": "#458588", + "brightBlack": "#928374", + "brightBlue": "#83A598", + "brightCyan": "#8EC07C", + "brightGreen": "#B8BB26", + "brightPurple": "#D3869B", + "brightRed": "#FB4934", + "brightWhite": "#EBDBB2", + "brightYellow": "#FABD2F", + "cursorColor": "#FFFFFF", + "cyan": "#689D6A", + "foreground": "#EBDBB2", + "green": "#98971A", + "name": "Gruvbox Dark", + "purple": "#B16286", + "red": "#CC241D", + "selectionBackground": "#FFFFFF", + "white": "#A89984", + "yellow": "#D79921" + }, + { + "background": "#282C34", + "black": "#282C34", + "blue": "#61AFEF", + "brightBlack": "#5A6374", + "brightBlue": "#61AFEF", + "brightCyan": "#56B6C2", + "brightGreen": "#98C379", + "brightPurple": "#C678DD", + "brightRed": "#E06C75", + "brightWhite": "#DCDFE4", + "brightYellow": "#E5C07B", + "cursorColor": "#FFFFFF", + "cyan": "#56B6C2", + "foreground": "#DCDFE4", + "green": "#98C379", + "name": "One Half Dark", + "purple": "#C678DD", + "red": "#E06C75", + "selectionBackground": "#FFFFFF", + "white": "#DCDFE4", + "yellow": "#E5C07B" + }, + { + "background": "#282C34", + "black": "#282C34", + "blue": "#61AFEF", + "brightBlack": "#282C34", + "brightBlue": "#61AFEF", + "brightCyan": "#56B6C2", + "brightGreen": "#98C379", + "brightPurple": "#C678DD", + "brightRed": "#E06C75", + "brightWhite": "#DCDFE4", + "brightYellow": "#E5C07B", + "cursorColor": "#FFFFFF", + "cyan": "#56B6C2", + "foreground": "#DCDFE4", + "green": "#98C379", + "name": "One Half Dark2", + "purple": "#C678DD", + "red": "#E06C75", + "selectionBackground": "#FFFFFF", + "white": "#DCDFE4", + "yellow": "#E5C07B" + }, + { + "background": "#FAFAFA", + "black": "#383A42", + "blue": "#0184BC", + "brightBlack": "#4F525D", + "brightBlue": "#61AFEF", + "brightCyan": "#56B5C1", + "brightGreen": "#98C379", + "brightPurple": "#C577DD", + "brightRed": "#DF6C75", + "brightWhite": "#FFFFFF", + "brightYellow": "#E4C07A", + "cursorColor": "#4F525D", + "cyan": "#0997B3", + "foreground": "#383A42", + "green": "#50A14F", + "name": "One Half Light", + "purple": "#A626A4", + "red": "#E45649", + "selectionBackground": "#FFFFFF", + "white": "#FAFAFA", + "yellow": "#C18301" + }, + { + "background": "#FAFAFA", + "black": "#383A42", + "blue": "#0184BC", + "brightBlack": "#383A42", + "brightBlue": "#0184BC", + "brightCyan": "#0997B3", + "brightGreen": "#50A14F", + "brightPurple": "#A626A4", + "brightRed": "#E45649", + "brightWhite": "#FAFAFA", + "brightYellow": "#C18401", + "cursorColor": "#FFFFFF", + "cyan": "#0997B3", + "foreground": "#383A42", + "green": "#50A14F", + "name": "One Half Light2", + "purple": "#A626A4", + "red": "#E45649", + "selectionBackground": "#FFFFFF", + "white": "#FAFAFA", + "yellow": "#C18401" + }, + { + "background": "#002B36", + "black": "#002B36", + "blue": "#268BD2", + "brightBlack": "#073642", + "brightBlue": "#839496", + "brightCyan": "#93A1A1", + "brightGreen": "#586E75", + "brightPurple": "#6C71C4", + "brightRed": "#CB4B16", + "brightWhite": "#FDF6E3", + "brightYellow": "#657B83", + "cursorColor": "#FFFFFF", + "cyan": "#2AA198", + "foreground": "#839496", + "green": "#859900", + "name": "Solarized Dark", + "purple": "#D33682", + "red": "#DC322F", + "selectionBackground": "#FFFFFF", + "white": "#EEE8D5", + "yellow": "#B58900" + }, + { + "background": "#001E27", + "black": "#002831", + "blue": "#2176C7", + "brightBlack": "#475B62", + "brightBlue": "#708284", + "brightCyan": "#819090", + "brightGreen": "#475B62", + "brightPurple": "#5956BA", + "brightRed": "#BD3613", + "brightWhite": "#FCF4DC", + "brightYellow": "#536870", + "cursorColor": "#FFFFFF", + "cyan": "#259286", + "foreground": "#708284", + "green": "#738A05", + "name": "Solarized Dark - Patched", + "purple": "#C61C6F", + "red": "#D11C24", + "selectionBackground": "#FFFFFF", + "white": "#EAE3CB", + "yellow": "#A57706" + }, + { + "background": "#FDF6E3", + "black": "#002B36", + "blue": "#268BD2", + "brightBlack": "#073642", + "brightBlue": "#839496", + "brightCyan": "#93A1A1", + "brightGreen": "#586E75", + "brightPurple": "#6C71C4", + "brightRed": "#CB4B16", + "brightWhite": "#FDF6E3", + "brightYellow": "#657B83", + "cursorColor": "#002B36", + "cyan": "#2AA198", + "foreground": "#657B83", + "green": "#859900", + "name": "Solarized Light", + "purple": "#D33682", + "red": "#DC322F", + "selectionBackground": "#FFFFFF", + "white": "#EEE8D5", + "yellow": "#B58900" + }, + { + "background": "#000000", + "black": "#000000", + "blue": "#3465A4", + "brightBlack": "#555753", + "brightBlue": "#729FCF", + "brightCyan": "#34E2E2", + "brightGreen": "#8AE234", + "brightPurple": "#AD7FA8", + "brightRed": "#EF2929", + "brightWhite": "#EEEEEC", + "brightYellow": "#FCE94F", + "cursorColor": "#FFFFFF", + "cyan": "#06989A", + "foreground": "#D3D7CF", + "green": "#4E9A06", + "name": "Tango Dark", + "purple": "#75507B", + "red": "#CC0000", + "selectionBackground": "#FFFFFF", + "white": "#D3D7CF", + "yellow": "#C4A000" + }, + { + "background": "#FFFFFF", + "black": "#000000", + "blue": "#3465A4", + "brightBlack": "#555753", + "brightBlue": "#729FCF", + "brightCyan": "#34E2E2", + "brightGreen": "#8AE234", + "brightPurple": "#AD7FA8", + "brightRed": "#EF2929", + "brightWhite": "#EEEEEC", + "brightYellow": "#FCE94F", + "cursorColor": "#000000", + "cyan": "#06989A", + "foreground": "#555753", + "green": "#4E9A06", + "name": "Tango Light", + "purple": "#75507B", + "red": "#CC0000", + "selectionBackground": "#FFFFFF", + "white": "#D3D7CF", + "yellow": "#C4A000" + }, + { + "background": "#1A1B2C", + "black": "#414868", + "blue": "#7AA2F7", + "brightBlack": "#414868", + "brightBlue": "#7AA2F7", + "brightCyan": "#7DCFFF", + "brightGreen": "#73DACA", + "brightPurple": "#BB9AF7", + "brightRed": "#F7768E", + "brightWhite": "#C0CAF5", + "brightYellow": "#E0AF68", + "cursorColor": "#C0CAF5", + "cyan": "#7DCFFF", + "foreground": "#A9B1DC", + "green": "#73DACA", + "name": "Tokyo Night", + "purple": "#BB9AF7", + "red": "#F7768E", + "selectionBackground": "#28344A", + "white": "#C0CAF5", + "yellow": "#E0AF68" + }, + { + "background": "#24283B", + "black": "#414868", + "blue": "#7AA2F7", + "brightBlack": "#414868", + "brightBlue": "#7AA2F7", + "brightCyan": "#7DCFFF", + "brightGreen": "#73DACA", + "brightPurple": "#BB9AF7", + "brightRed": "#F7768E", + "brightWhite": "#C0CAF5", + "brightYellow": "#E0AF68", + "cursorColor": "#C0CAF5", + "cyan": "#7DCFFF", + "foreground": "#A9B1DC", + "green": "#73DACA", + "name": "Tokyo Night Storm", + "purple": "#BB9AF7", + "red": "#F7768E", + "selectionBackground": "#28344A", + "white": "#C0CAF5", + "yellow": "#E0AF68" + }, + { + "background": "#000000", + "black": "#000000", + "blue": "#000080", + "brightBlack": "#808080", + "brightBlue": "#0000FF", + "brightCyan": "#00FFFF", + "brightGreen": "#00FF00", + "brightPurple": "#FF00FF", + "brightRed": "#FF0000", + "brightWhite": "#FFFFFF", + "brightYellow": "#FFFF00", + "cursorColor": "#FFFFFF", + "cyan": "#008080", + "foreground": "#C0C0C0", + "green": "#008000", + "name": "Vintage", + "purple": "#800080", + "red": "#800000", + "selectionBackground": "#FFFFFF", + "white": "#C0C0C0", + "yellow": "#808000" + } + ], + "showTabsInTitlebar": true, + "showTerminalTitleInTitlebar": true, + "tabWidthMode": "titleLength", + "trimBlockSelection": true, + "useAcrylicInTabRow": false +} diff --git a/windows/Users/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 b/windows/Users/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 new file mode 100644 index 0000000..40b5879 --- /dev/null +++ b/windows/Users/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 @@ -0,0 +1,284 @@ +# Dotfiles Management System +if (Test-Path "$HOME\.cfg" -and Test-Path "$HOME\.cfg\refs") { + + # Core git wrapper with repository as work-tree + function _config { + param( + [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] + [String[]]$Args + ) + git --git-dir="$HOME\.cfg" --work-tree="$HOME\.cfg" @Args + } + + # Detect OS (cross-platform, PowerShell-native) + $osPlatform = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform + if ($osPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)) { + $global:CFG_OS = "windows" + } elseif ($osPlatform([System.Runtime.InteropServices.OSPlatform]::Linux)) { + $global:CFG_OS = "linux" + } elseif ($osPlatform([System.Runtime.InteropServices.OSPlatform]::OSX)) { + $global:CFG_OS = "macos" + } else { + $global:CFG_OS = "other" + } + + # Map system path to repository path + function _repo_path { + param([string]$FilePath) + + # If it's an absolute path that's not in HOME, handle it specially + if (($FilePath.StartsWith("\\") -or $FilePath.Contains(":")) -and -not $FilePath.StartsWith($HOME)) { + return "$CFG_OS/" + ($FilePath -replace '^[A-Z]:\\', '' -replace '\\', '/') + } + + # Check for paths that should go to the repository root + if ($FilePath -match '^(common|linux|macos|windows|profile)/.*|^README\.md$') { + return $FilePath -replace '\\', '/' + } + + # Remove HOME prefix if present + if ($FilePath.StartsWith($HOME)) { + $FilePath = $FilePath.Substring($HOME.Length + 1) + } + + # Default: put under OS-specific home + return "$CFG_OS/home/" + ($FilePath -replace '\\', '/') + } + + # Map repository path back to system path + function _sys_path { + param([string]$RepoPath) + + $osPathPattern = "$CFG_OS/" + + # Handle OS-specific files that are not in the home subdirectory + if ($RepoPath.StartsWith($osPathPattern) -and $RepoPath -notmatch '/home/') { + return ($RepoPath.Substring($osPathPattern.Length) -replace '/', '\\') + } + + switch -Wildcard ($RepoPath) { + "common/config/*" { + $file = $RepoPath.Substring("common/config/".Length) + switch ($CFG_OS) { + "linux" { return Join-Path ($env:XDG_CONFIG_HOME ?? "$HOME\.config") $file } + "macos" { return Join-Path "$HOME\Library\Application Support" $file } + "windows" { return Join-Path $env:LOCALAPPDATA $file } + default { return Join-Path "$HOME\.config" $file } + } + } + "common/assets/*" { return Join-Path "$HOME\.cfg" $RepoPath } + "common/*" { return Join-Path $HOME ($RepoPath.Substring("common/".Length)) } + "*/home/*" { return Join-Path $HOME ($RepoPath.Substring($RepoPath.IndexOf("home/") + 5)) } + "profile/*" { return Join-Path "$HOME\.cfg" $RepoPath } + "README.md" { return Join-Path "$HOME\.cfg" $RepoPath } + default { return Join-Path "$HOME\.cfg" $RepoPath } + } + } + + # Prompts for administrator permissions if needed and runs the command + function _admin_prompt { + param( + [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] + [String[]]$Command + ) + if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { + Write-Host "Warning: This action requires administrator privileges." -ForegroundColor Yellow + Start-Process powershell.exe -ArgumentList "-NoProfile", "-Command", "Set-Location '$PWD'; & $Command" -Verb RunAs + } else { + & $Command + } + } + + # Main config command + function config { + param( + [string]$Command, + [string]$TargetDir = "", + [Parameter(ValueFromRemainingArguments=$true)] + [string[]]$Args + ) + + # Parse --target flag for add command + if ($Command -eq "add" -and $Args.Count -gt 0) { + $i = 0 + while ($i -lt $Args.Count) { + if ($Args[$i] -eq "--target" -or $Args[$i] -eq "-t") { + if ($i + 1 -lt $Args.Count) { + $TargetDir = $Args[$i + 1] + $Args = $Args[0..($i-1)] + $Args[($i+2)..($Args.Count-1)] + break + } else { + Write-Host "Error: --target requires a directory argument" -ForegroundColor Red + return + } + } + $i++ + } + } + + switch ($Command) { + "add" { + foreach ($file in $Args) { + if (-not $TargetDir) { + $repoPath = _repo_path $file + } else { + $fileName = if ($file.Contains("\\") -or $file.Contains(":")) { Split-Path $file -Leaf } else { $file } + $repoPath = "$TargetDir/$fileName" -replace '\\', '/' + } + + $fullRepoPath = Join-Path "$HOME\.cfg" $repoPath + $dir = Split-Path $fullRepoPath + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + Copy-Item -Path $file -Destination $fullRepoPath -Recurse -Force + _config add $repoPath + Write-Host "Added: $file -> $repoPath" -ForegroundColor Green + } + } + "rm" { + $rmOpts = @() + $fileList = @() + + foreach ($arg in $Args) { + if ($arg.StartsWith("-")) { + $rmOpts += $arg + } else { + $fileList += $arg + } + } + + foreach ($file in $fileList) { + $repoPath = _repo_path $file + if ($rmOpts -contains "-r") { + _config rm --cached -r $repoPath + } else { + _config rm --cached $repoPath + } + Remove-Item -Path $file -Recurse:($rmOpts -contains "-r") -Force + Write-Host "Removed: $file" -ForegroundColor Yellow + } + } + "sync" { + $direction = if ($Args.Count -gt 0) { $Args[0] } else { "to-repo" } + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + + if ($direction -eq "to-repo") { + if ((Test-Path $sysFile) -and (Test-Path $fullRepoPath)) { + $diff = Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) + if ($diff) { + Copy-Item $sysFile $fullRepoPath -Force + Write-Host "Synced to repo: $sysFile" -ForegroundColor Cyan + } + } + } elseif ($direction -eq "from-repo") { + if ((Test-Path $fullRepoPath)) { + $diff = if (Test-Path $sysFile) { Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) } else { $true } + if ($diff) { + $destDir = Split-Path $sysFile + if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { + _admin_prompt "Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" + } else { + if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } + Copy-Item $fullRepoPath $sysFile -Recurse -Force + } + Write-Host "Synced from repo: $sysFile" -ForegroundColor Cyan + } + } + } + } + } + "status" { + $autoSynced = @() + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + if ((Test-Path $sysFile) -and (Test-Path $fullRepoPath)) { + $diff = Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) + if ($diff) { + Copy-Item $sysFile $fullRepoPath -Force + $autoSynced += $repoFile + } + } + } + if ($autoSynced.Count -gt 0) { + Write-Host "=== Auto-synced Files ===" -ForegroundColor Magenta + foreach ($repoFile in $autoSynced) { + Write-Host "synced: $(_sys_path $repoFile) -> $repoFile" -ForegroundColor Cyan + } + Write-Host + } + _config status + Write-Host + } + "deploy" { + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + + if ((Test-Path $fullRepoPath) -and $sysFile) { + $destDir = Split-Path $sysFile + if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { + _admin_prompt "New-Item -ItemType Directory -Path '$destDir' -Force; Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" + } else { + if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } + Copy-Item $fullRepoPath $sysFile -Recurse -Force + } + Write-Host "Deployed: $repoFile -> $sysFile" -ForegroundColor Green + } + } + } + "checkout" { + Write-Host "Checking out dotfiles from .cfg..." -ForegroundColor Blue + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + + if ((Test-Path $fullRepoPath) -and $sysFile) { + $destDir = Split-Path $sysFile + if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { + _admin_prompt "New-Item -ItemType Directory -Path '$destDir' -Force; Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" + } else { + if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } + Copy-Item $fullRepoPath $sysFile -Recurse -Force + } + Write-Host "Checked out: $repoFile -> $sysFile" -ForegroundColor Green + } + } + } + "backup" { + $timestamp = Get-Date -Format "yyyyMMddHHmmss" + $backupDir = Join-Path $HOME ".dotfiles_backup\$timestamp" + Write-Host "Backing up existing dotfiles to $backupDir..." -ForegroundColor Blue + + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + if (Test-Path $sysFile) { + $destDirFull = Join-Path $backupDir (Split-Path $repoFile) + if (-not (Test-Path $destDirFull)) { New-Item -ItemType Directory -Path $destDirFull -Force | Out-Null } + Copy-Item $sysFile (Join-Path $backupDir $repoFile) -Recurse -Force + } + } + Write-Host "Backup complete. To restore, copy files from $backupDir to their original locations." -ForegroundColor Green + } + default { + _config $Command @Args + } + } + } +} + +# Shows navigable menu of all options when hitting Tab +Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete + +# Autocompletion for arrow keys +Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward +Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward + +New-Alias vi nvim.exe + diff --git a/windows/Users/Documents/PowerShell/bloatware.ps1 b/windows/Users/Documents/PowerShell/bloatware.ps1 new file mode 100644 index 0000000..ffee6d5 --- /dev/null +++ b/windows/Users/Documents/PowerShell/bloatware.ps1 @@ -0,0 +1,340 @@ +# bloatware.ps1 + +# Check if the powershell-yaml module is installed, if not, install it +if (-not (Get-Module powershell-yaml -ListAvailable)) { + $policy = Get-PSRepository -Name 'PSGallery' | Select-Object -ExpandProperty InstallationPolicy + Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted + Install-Module powershell-yaml + Set-PSRepository -Name 'PSGallery' -InstallationPolicy $policy +} + +Import-Module powershell-yaml + +# Locate packages.yml from common locations +$candidates = @( + Join-Path $HOME ".cfg/common/packages.yml", + Join-Path $HOME "packages.yml", + Join-Path $HOME "common/packages.yml", + Join-Path $HOME "dot_setup/packages.yml" +) +$yamlFilePath = $null +foreach ($pf in $candidates) { if (Test-Path $pf) { $yamlFilePath = $pf; break } } +if (-not $yamlFilePath) { throw "packages.yml not found in expected locations: $($candidates -join ', ')" } + +# Parse the YAML file +$packages = ConvertFrom-Yaml -Path $yamlFilePath +$bloatware = $packages.bloatware +$defaultApps = $packages.defaultApps + +# Check if Registry key exists +function Check-RegistryKeyExists { + param( + [Parameter(Mandatory = $true)] + [string]$KeyPath + ) + + if (Test-Path $KeyPath) { + Write-Host "Registry key exists: $KeyPath" + return $true + } else { + Write-Host "Registry key does not exist: $KeyPath" + return $false + } +} + +# Helper functions ------------------------ +function force-mkdir($path) { + if (!(Test-Path $path)) { + Write-Host "-- Creating full path to: " $path -ForegroundColor White -BackgroundColor DarkGreen + New-Item -ItemType Directory -Force -Path $path + } +} + +function Takeown-Registry($key) { + # TODO does not work for all root keys yet + switch ($key.split('\')[0]) { + "HKEY_CLASSES_ROOT" { + $reg = [Microsoft.Win32.Registry]::ClassesRoot + $key = $key.substring(18) + } + "HKEY_CURRENT_USER" { + $reg = [Microsoft.Win32.Registry]::CurrentUser + $key = $key.substring(18) + } + "HKEY_LOCAL_MACHINE" { + $reg = [Microsoft.Win32.Registry]::LocalMachine + $key = $key.substring(19) + } + } + + # get administrator group + $admins = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") + $admins = $admins.Translate([System.Security.Principal.NTAccount]) + + # set owner + $key = $reg.OpenSubKey($key, "ReadWriteSubTree", "TakeOwnership") + $acl = $key.GetAccessControl() + $acl.SetOwner($admins) + $key.SetAccessControl($acl) + + # set FullControl + $acl = $key.GetAccessControl() + $rule = New-Object System.Security.AccessControl.RegistryAccessRule($admins, "FullControl", "Allow") + $acl.SetAccessRule($rule) + $key.SetAccessControl($acl) +} + +# Function to take ownership of registry keys +function Takeown-Registry($keyPath) { + $regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership) + $acl = $regKey.GetAccessControl() + $acl.SetOwner([System.Security.Principal.NTAccount]"Administrators") + $regKey.SetAccessControl($acl) + $regKey.Close() +} + +# Remove Features +function Takeown-File($path) { + takeown.exe /A /F $path + $acl = Get-Acl $path + + # get administrator group + $admins = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") + $admins = $admins.Translate([System.Security.Principal.NTAccount]) + + # add NT Authority\SYSTEM + $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($admins, "FullControl", "None", "None", "Allow") + $acl.AddAccessRule($rule) + + Set-Acl -Path $path -AclObject $acl +} + +function Takeown-Folder($path) { + Takeown-File $path + foreach ($item in Get-ChildItem $path) { + if (Test-Path $item -PathType Container) { + Takeown-Folder $item.FullName + } + else { + Takeown-File $item.FullName + } + } +} + +function Elevate-Privileges { + param($Privilege) + $Definition = @" + using System; + using System.Runtime.InteropServices; + + public class AdjPriv { + [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr rele); + + [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); + + [DllImport("advapi32.dll", SetLastError = true)] + internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct TokPriv1Luid { + public int Count; + public long Luid; + public int Attr; + } + + internal const int SE_PRIVILEGE_ENABLED = 0x00000002; + internal const int TOKEN_QUERY = 0x00000008; + internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; + + public static bool EnablePrivilege(long processHandle, string privilege) { + bool retVal; + TokPriv1Luid tp; + IntPtr hproc = new IntPtr(processHandle); + IntPtr htok = IntPtr.Zero; + retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); + tp.Count = 1; + tp.Luid = 0; + tp.Attr = SE_PRIVILEGE_ENABLED; + retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid); + retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); + return retVal; + } + } +"@ + $ProcessHandle = (Get-Process -id $pid).Handle + $type = Add-Type $definition -PassThru + $type[0]::EnablePrivilege($processHandle, $Privilege) +} + +# Remove Features ------------------------ +foreach ($bloat in $bloatware) { + Write-Output "Removing packages containing $bloat" + $pkgs = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages" | Where-Object Name -Like "*$bloat*" + + foreach ($pkg in $pkgs) { + $pkgname = $pkg.Name.Split('\')[-1] + Takeown-Registry $pkg.Name + Takeown-Registry ($pkg.Name + "\Owners") + Set-ItemProperty -Path ("HKLM:" + $pkg.Name.Substring(18)) -Name Visibility -Value 1 + New-ItemProperty -Path ("HKLM:" + $pkg.Name.Substring(18)) -Name DefVis -PropertyType DWord -Value 2 + Remove-Item -Path ("HKLM:" + $pkg.Name.Substring(18) + "\Owners") + dism.exe /Online /Remove-Package /PackageName:$pkgname /NoRestart + } +} + +# Remove default apps and bloat +Write-Output "Uninstalling default apps" +foreach ($app in $defaultApps) { + Write-Output "Trying to remove $app" + Get-AppxPackage -Name $app -AllUsers | Remove-AppxPackage -AllUsers + Get-AppXProvisionedPackage -Online | Where-Object DisplayName -EQ $app | Remove-AppxProvisionedPackage -Online +} + +# Disable Microsoft Edge sidebar +$RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' +$Name = 'HubsSidebarEnabled' +$Value = '00000000' +# Create the key if it does not exist +If (-NOT (Test-Path $RegistryPath)) { + New-Item -Path $RegistryPath -Force | Out-Null +} +New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force + +# Disable Microsoft Edge first-run Welcome screen +$RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' +$Name = 'HideFirstRunExperience' +$Value = '00000001' +# Create the key if it does not exist +If (-NOT (Test-Path $RegistryPath)) { + New-Item -Path $RegistryPath -Force | Out-Null +} +New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force + +# Remove Microsoft Edge ------------------------ +$ErrorActionPreference = "Stop" +$regView = [Microsoft.Win32.RegistryView]::Registry32 +$microsoft = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $regView). +OpenSubKey('SOFTWARE\Microsoft', $true) +$edgeUWP = "$env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe" +$uninstallRegKey = $microsoft.OpenSubKey('Windows\CurrentVersion\Uninstall\Microsoft Edge') +$uninstallString = $uninstallRegKey.GetValue('UninstallString') + ' --force-uninstall' +Write-Host "Removed Microsoft Edge" + +$edgeClient = $microsoft.OpenSubKey('EdgeUpdate\ClientState\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}', $true) +if ($null -ne $edgeClient.GetValue('experiment_control_labels')) { + $edgeClient.DeleteValue('experiment_control_labels') +} +$microsoft.CreateSubKey('EdgeUpdateDev').SetValue('AllowUninstall', '') +[void](New-Item $edgeUWP -ItemType Directory -ErrorVariable fail -ErrorAction SilentlyContinue) +[void](New-Item "$edgeUWP\MicrosoftEdge.exe" -ErrorAction Continue) +Start-Process cmd.exe "/c $uninstallString" -WindowStyle Hidden -Wait +[void](Remove-Item "$edgeUWP\MicrosoftEdge.exe" -ErrorAction Continue) + +if (-not $fail) { + [void](Remove-Item "$edgeUWP") +} + +Write-Output "Edge should now be uninstalled!" + +# Kill OneDrive with fire ------------------------ +Write-Output "Kill OneDrive process" +taskkill.exe /F /IM "OneDrive.exe" +taskkill.exe /F /IM "explorer.exe" +Write-Output "Remove OneDrive" +if (Test-Path "$env:systemroot\System32\OneDriveSetup.exe") { + & "$env:systemroot\System32\OneDriveSetup.exe" /uninstall +} +if (Test-Path "$env:systemroot\SysWOW64\OneDriveSetup.exe") { + & "$env:systemroot\SysWOW64\OneDriveSetup.exe" /uninstall +} + +Write-Output "Removing OneDrive leftovers" +Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:localappdata\Microsoft\OneDrive" +Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:programdata\Microsoft OneDrive" +Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:systemdrive\OneDriveTemp" +# check if directory is empty before removing: +If ((Get-ChildItem "$env:userprofile\OneDrive" -Recurse | Measure-Object).Count -eq 0) { + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:userprofile\OneDrive" +} + +Write-Output "Disable OneDrive via Group Policies" +force-mkdir "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\OneDrive" +Set-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\OneDrive" "DisableFileSyncNGSC" 1 + +Write-Output "Remove Onedrive from explorer sidebar" +New-PSDrive -PSProvider "Registry" -Root "HKEY_CLASSES_ROOT" -Name "HKCR" +force-mkdir "HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" +Set-ItemProperty "HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" "System.IsPinnedToNameSpaceTree" 0 +force-mkdir "HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" +Set-ItemProperty "HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" "System.IsPinnedToNameSpaceTree" 0 +Remove-PSDrive "HKCR" + +# Thank you Matthew Israelsson +Write-Output "Removing run hook for new users" +reg load "hku\Default" "C:\Users\Default\NTUSER.DAT" +reg delete "HKEY_USERS\Default\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "OneDriveSetup" /f +reg unload "hku\Default" + +Write-Output "Removing startmenu entry" +Remove-Item -Force -ErrorAction SilentlyContinue "$env:userprofile\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk" + +Write-Output "Removing scheduled task" +$scheduledTasks = Get-ScheduledTask -TaskPath '\' -TaskName 'OneDrive*' -ErrorAction SilentlyContinue +if ($scheduledTasks) { + try { + $scheduledTasks | Unregister-ScheduledTask -Confirm:$false + Write-Output "OneDrive scheduled tasks removed." + } catch { + Write-Warning "Failed to unregister scheduled tasks: $_" + } +} else { + Write-Output "No OneDrive scheduled tasks found." +} + +Write-Output "Restarting explorer" +Start-Process "explorer.exe" + +Write-Output "Waiting for explorer to complete loading" +Start-Sleep 10 + +Write-Output "Removing additional OneDrive leftovers" +foreach ($item in (Get-ChildItem "$env:WinDir\WinSxS\*onedrive*")) { + Takeown-Folder $item.FullName + try { + Remove-Item -Recurse -Force -ErrorAction Continue -ErrorVariable RemoveError $item.FullName + if ($RemoveError) { + Write-Warning "Failed to remove $($item.FullName): $($RemoveError.Exception.Message)" + } else { + Write-Output "Successfully removed: $($item.FullName)" + } + } catch { + Write-Warning "Failed to remove $($item.FullName): $_" + } +} + +# Remove OneDrive directory if it exists +Write-Host "Removing OneDrive directory" + +# Change directory to user's home directory +Set-Location $HOME + +# Check if OneDrive directory exists +$OneDrivePath = Join-Path $HOME "OneDrive" +if (Test-Path -Path $OneDrivePath -PathType Container) { + # Remove OneDrive directory recursively and forcefully + Remove-Item -Path $OneDrivePath -Recurse -Force -ErrorAction Continue + if ($?) { + Write-Output "OneDrive directory removed successfully." + } else { + Write-Warning "Failed to remove OneDrive directory." + } +} else { + Write-Output "OneDrive directory not found." +} + +# Prevents "Suggested Applications" returning +if (Check-RegistryKeyExists -KeyPath "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content") { + Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content" "DisableWindowsConsumerFeatures" 1 +} diff --git a/windows/Users/Documents/PowerShell/bootstrap.ps1 b/windows/Users/Documents/PowerShell/bootstrap.ps1 new file mode 100644 index 0000000..aa3bd5b --- /dev/null +++ b/windows/Users/Documents/PowerShell/bootstrap.ps1 @@ -0,0 +1,645 @@ +#!/usr/bin/env pwsh + +# Created By: srdusr +# Created On: Windows PowerShell Bootstrap Script +# Project: Dotfiles installation script for Windows + +# Dependencies: git, powershell + +param( + [string]$Profile = "essentials", + [switch]$Force = $false, + [switch]$Ask = $false, + [switch]$Help = $false +) + +# Color definitions for pretty UI +$Script:Colors = @{ + Reset = "`e[0m" + Red = "`e[0;31m" + Green = "`e[0;32m" + Yellow = "`e[0;33m" + Blue = "`e[0;34m" + Cyan = "`e[0;36m" + White = "`e[0;37m" + Bold = "`e[1m" +} + +# Prompt helper: Yes/No with default; in non-Ask mode, returns default immediately +function Prompt-YesNo { + param( + [Parameter(Mandatory=$true)][string]$Question, + [ValidateSet('Y','N')][string]$Default = 'Y' + ) + if (-not $Script:AskPreference) { + return $Default -eq 'Y' + } + $suffix = if ($Default -eq 'Y') { '[Y/n]' } else { '[y/N]' } + while ($true) { + Write-Host -NoNewline "$Question $suffix: " -ForegroundColor Yellow + $resp = Read-Host + if ([string]::IsNullOrWhiteSpace($resp)) { $resp = $Default } + switch ($resp.ToUpper()) { + 'Y' { return $true } + 'YES' { return $true } + 'N' { return $false } + 'NO' { return $false } + default { Write-Warning "Please answer Y/yes or N/no" } + } + } +} + +# Configuration +$Script:Config = @{ + DotfilesUrl = 'https://github.com/srdusr/dotfiles.git' + DotfilesDir = "$HOME\.cfg" + LogFile = "$HOME\AppData\Local\dotfiles_install.log" + StateFile = "$HOME\AppData\Local\dotfiles_install_state" + BackupDir = "$HOME\.dotfiles-backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')" + PackagesFile = "packages.yml" + OS = "windows" +} + +# Logging functions +function Write-Log { + param([string]$Message, [string]$Level = "INFO") + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logEntry = "[$timestamp] [$Level] $Message" + Add-Content -Path $Script:Config.LogFile -Value $logEntry -Force +} + +function Write-ColorOutput { + param([string]$Message, [string]$Color = "White") + Write-Host $Message -ForegroundColor $Color + Write-Log $Message +} + +function Write-Success { param([string]$Message) Write-ColorOutput "✓ $Message" "Green" } +function Write-Info { param([string]$Message) Write-ColorOutput "ℹ $Message" "Cyan" } +function Write-Warning { param([string]$Message) Write-ColorOutput "⚠ $Message" "Yellow" } +function Write-Error { param([string]$Message) Write-ColorOutput "✗ $Message" "Red" } + +function Write-Header { + param([string]$Title) + Write-Host "" + Write-Host "=" * 60 -ForegroundColor Blue + Write-Host " $Title" -ForegroundColor Bold + Write-Host "=" * 60 -ForegroundColor Blue + Write-Host "" +} + +# Utility functions +function Test-CommandExists { + param([string]$Command) + return [bool](Get-Command $Command -ErrorAction SilentlyContinue) +} + +function Test-IsAdmin { + $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal($currentUser) + return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +function Invoke-AdminCommand { + param([string]$Command) + if (-not (Test-IsAdmin)) { + Write-Warning "Elevating privileges for: $Command" + Start-Process powershell.exe -ArgumentList "-NoProfile", "-Command", $Command -Verb RunAs -Wait + } else { + Invoke-Expression $Command + } +} + +# Package management functions +function Get-PackageManager { + if (Test-CommandExists "choco") { return "chocolatey" } + if (Test-CommandExists "winget") { return "winget" } + if (Test-CommandExists "scoop") { return "scoop" } + return $null +} + +# Return $true if a package appears to be installed for the given manager +function Test-PackageInstalled { + param( + [Parameter(Mandatory=$true)][string]$Manager, + [Parameter(Mandatory=$true)][string]$Name + ) + switch ($Manager) { + "chocolatey" { + $out = choco list --local-only --exact $Name 2>$null + return ($out | Select-String -Pattern "^\s*$([regex]::Escape($Name))\s").Length -gt 0 + } + "winget" { + # Winget list may return multiple rows; use --exact name match when possible + $out = winget list --name $Name 2>$null + return ($out | Select-String -SimpleMatch $Name).Length -gt 0 + } + "scoop" { + # scoop list returns 0 when installed + scoop list $Name *> $null + return $LASTEXITCODE -eq 0 + } + default { return $false } + } +} + +function Install-PackageManager { + Write-Header "Installing Package Manager" + + if (-not (Test-CommandExists "choco")) { + Write-Info "Installing Chocolatey..." + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + + if (Test-CommandExists "choco") { + Write-Success "Chocolatey installed successfully" + } else { + Write-Error "Failed to install Chocolatey" + return $false + } + } else { + Write-Info "Chocolatey already installed" + } + return $true +} + +function Install-Packages { + param([string]$PackagesFile, [string]$Profile) + + if (-not (Test-Path $PackagesFile)) { + Write-Warning "Packages file not found: $PackagesFile" + return + } + + Write-Header "Installing Packages" + + # Install powershell-yaml if not available + if (-not (Get-Module powershell-yaml -ListAvailable)) { + Write-Info "Installing powershell-yaml module..." + $policy = Get-PSRepository -Name 'PSGallery' | Select-Object -ExpandProperty InstallationPolicy + Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted + Install-Module powershell-yaml -Force + Set-PSRepository -Name 'PSGallery' -InstallationPolicy $policy + } + + Import-Module powershell-yaml + + # Helper: run custom_installs..windows if condition passes + function Invoke-CustomInstallsWindows { + param([Parameter(Mandatory=$true)]$Yaml) + if (-not $Yaml.custom_installs) { return } + foreach ($name in $Yaml.custom_installs.PSObject.Properties.Name) { + $entry = $Yaml.custom_installs.$name + if (-not $entry) { continue } + $winCmd = $entry.windows + if (-not $winCmd) { continue } + $shouldRun = $true + if ($entry.condition) { + $cond = [string]$entry.condition + if ($cond -match "!\s*command\s+-v\s+([A-Za-z0-9._-]+)") { + $shouldRun = -not (Test-CommandExists $Matches[1]) + } elseif ($cond -match "command\s+-v\s+([A-Za-z0-9._-]+)") { + $shouldRun = (Test-CommandExists $Matches[1]) + } + } + if (-not $shouldRun) { Write-Info "Skipping custom install: $name"; continue } + Write-Info "Running custom install: $name" + try { Invoke-Expression $winCmd; Write-Success "Custom install completed: $name" } + catch { Write-Warning "Custom install failed for '$name': $_" } + } + } + + try { + $packages = Get-Content $PackagesFile | ConvertFrom-Yaml + $packageManager = Get-PackageManager + + if (-not $packageManager) { + Write-Error "No package manager available" + return + } + + # Install profile-specific Windows packages (profiles..windows) + if ($packages.profiles.$Profile.windows) { + foreach ($pkg in $packages.profiles.$Profile.windows) { + if ([string]::IsNullOrWhiteSpace($pkg)) { continue } + if (Test-PackageInstalled -Manager $packageManager -Name $pkg) { Write-Info "Already installed: $pkg"; continue } + Write-Info "Installing package: $pkg" + switch ($packageManager) { + "chocolatey" { if (-not (choco list --local-only | Select-String -Pattern "^$([regex]::Escape($pkg))\s")) { choco install $pkg -y } } + "winget" { winget install --id $pkg --silent --accept-package-agreements --accept-source-agreements } + "scoop" { scoop install $pkg } + } + } + } + + # Install top-level Windows packages list if present + if ($packages.windows) { + foreach ($pkg in $packages.windows) { + if ([string]::IsNullOrWhiteSpace($pkg)) { continue } + if (Test-PackageInstalled -Manager $packageManager -Name $pkg) { Write-Info "Already installed: $pkg"; continue } + Write-Info "Installing package: $pkg" + switch ($packageManager) { + "chocolatey" { + if (-not (choco list --local-only | Select-String -Pattern "^$([regex]::Escape($pkg))\s")) { choco install $pkg -y } + } + "winget" { winget install --id $pkg --silent --accept-package-agreements --accept-source-agreements } + "scoop" { scoop install $pkg } + } + } + } + + # Execute Windows custom installs from packages.yml + Invoke-CustomInstallsWindows -Yaml $packages + } catch { + Write-Error "Error processing packages: $_" + } +} + +# Dotfiles management functions +function Install-Dotfiles { + Write-Header "Installing Dotfiles" + + if (Test-Path $Script:Config.DotfilesDir) { + Write-Info "Updating existing dotfiles repository..." + & git --git-dir="$($Script:Config.DotfilesDir)" --work-tree="$($Script:Config.DotfilesDir)" pull origin main + } else { + Write-Info "Cloning dotfiles repository..." + git clone --bare $Script:Config.DotfilesUrl $Script:Config.DotfilesDir + + if (-not (Test-Path $Script:Config.DotfilesDir)) { + Write-Error "Failed to clone dotfiles repository" + return $false + } + } + + # Set up config alias for this session + function script:config { + git --git-dir="$($Script:Config.DotfilesDir)" --work-tree="$($Script:Config.DotfilesDir)" @args + } + + # Configure repository + config config --local status.showUntrackedFiles no + + # Checkout files to restore directory structure + Write-Info "Checking out dotfiles..." + try { + config checkout 2>$null + if ($LASTEXITCODE -ne 0) { + Write-Info "Forcing checkout to overwrite existing files..." + config checkout -f + } + Write-Success "Dotfiles checked out successfully" + } catch { + Write-Error "Failed to checkout dotfiles: $_" + return $false + } + + return $true +} + +function Deploy-Dotfiles { + Write-Header "Deploying Dotfiles" + + if (-not (Test-Path $Script:Config.DotfilesDir)) { + Write-Error "Dotfiles directory not found. Run Install-Dotfiles first." + return $false + } + + # Source the config command from profile if available + $profilePath = "$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" + if (Test-Path $profilePath) { + Write-Info "Loading config command from profile..." + . $profilePath + } + + # Deploy using config command if available, otherwise manual deployment + if (Get-Command config -ErrorAction SilentlyContinue) { + Write-Info "Deploying dotfiles using config command..." + config deploy + } else { + Write-Warning "Config command not available, using manual deployment..." + # Manual deployment fallback would go here + } + + Write-Success "Dotfiles deployment completed" + return $true +} + +# Locate profile-specific packages.yml similar to Linux installer +function Get-ProfilePackagesFile { + param([string]$Profile) + $candidates = @( + # Profile-specific overrides + Join-Path $HOME ".cfg/profile/$Profile/packages.yml", + Join-Path $HOME "profile/$Profile/packages.yml", + Join-Path $HOME "dot_setup/profile/$Profile/packages.yml", + # Common locations for the primary packages.yml + Join-Path $HOME ".cfg/common/$($Script:Config.PackagesFile)", + Join-Path $HOME "$($Script:Config.PackagesFile)", + Join-Path $HOME "common/$($Script:Config.PackagesFile)", + Join-Path $HOME "dot_setup/packages.yml", + Join-Path $Script:Config.DotfilesDir "common/$($Script:Config.PackagesFile)", + Join-Path $Script:Config.DotfilesDir "packages.yml" + ) + foreach ($pf in $candidates) { + if (Test-Path $pf) { return $pf } + } + return $null +} + +# System configuration functions +function Set-WindowsConfiguration { + param( + [string]$PackagesFile + ) + + Write-Header "Configuring Windows Settings" + + if (-not $PackagesFile -or -not (Test-Path $PackagesFile)) { + Write-Warning "Packages file not found, skipping Windows configuration" + return + } + + try { + # Load YAML content + $yamlContent = Get-Content $PackagesFile -Raw | ConvertFrom-Yaml + $registrySettings = $yamlContent.system_tweaks.windows.registry + + if (-not $registrySettings) { + Write-Warning "No Windows registry settings found in packages.yml" + return + } + + Write-Info "Applying registry settings from packages.yml..." + + foreach ($setting in $registrySettings) { + try { + $path = $setting.path + $name = $setting.name + $value = $setting.value + $type = $setting.type + $description = $setting.description + + Write-Info "Setting: $description" + + # Ensure the registry path exists + $pathParts = $path -split '\\' + $currentPath = $pathParts[0] + for ($i = 1; $i -lt $pathParts.Length; $i++) { + $currentPath = "$currentPath\$($pathParts[$i])" + if (-not (Test-Path $currentPath)) { + New-Item -Path $currentPath -Force | Out-Null + } + } + + # Set the registry value + Set-ItemProperty -Path $path -Name $name -Value $value -Type $type -Force + Write-Success "Applied: $description" + + } catch { + Write-Warning "Failed to apply setting '$($setting.description)': $_" + } + } + + Write-Success "Windows configuration applied" + + # Restart explorer to apply changes + Write-Info "Restarting Windows Explorer..." + Stop-Process -Name explorer -Force + Start-Process explorer.exe + + } catch { + Write-Warning "Failed to process Windows configuration: $_" + } +} + +function Enable-WindowsFeatures { + param( + [string]$PackagesFile + ) + + Write-Header "Enabling Windows Features" + + if (-not $PackagesFile -or -not (Test-Path $PackagesFile)) { + Write-Warning "Packages file not found, skipping Windows features" + return + } + + try { + # Load YAML content + $yamlContent = Get-Content $PackagesFile -Raw | ConvertFrom-Yaml + $features = $yamlContent.system_tweaks.windows.features + + if (-not $features) { + Write-Warning "No Windows features found in packages.yml" + return + } + + foreach ($feature in $features) { + $featureName = $feature.name + $description = $feature.description + $requiresAdmin = $feature.requires_admin + + if ($requiresAdmin -and -not (Test-IsAdmin)) { + Write-Warning "Skipping '$description' - requires administrator privileges" + continue + } + + try { + Write-Info "Enabling: $description" + dism.exe /online /enable-feature /featurename:$featureName /all /norestart + Write-Success "Enabled: $description" + } catch { + Write-Warning "Failed to enable '$description': $_" + } + } + + Write-Success "Windows features processing complete (restart may be required)" + + } catch { + Write-Warning "Failed to process Windows features: $_" + } +} + +function Install-PowerShellProfile { + Write-Header "Setting up PowerShell Profile" + + $documentsPath = [System.Environment]::GetFolderPath('MyDocuments') + $powerShellProfileDir = "$documentsPath\PowerShell" + $profilePath = "$powerShellProfileDir\Microsoft.PowerShell_profile.ps1" + + Write-Info "PowerShell profile directory: $powerShellProfileDir" + + if (-not (Test-Path $powerShellProfileDir)) { + New-Item -ItemType Directory -Path $powerShellProfileDir -Force | Out-Null + Write-Success "Created PowerShell profile directory" + } + + # Copy profile from dotfiles if it exists + $dotfilesProfile = "$($Script:Config.DotfilesDir)\windows\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" + if (Test-Path $dotfilesProfile) { + Copy-Item $dotfilesProfile $profilePath -Force + Write-Success "PowerShell profile installed from dotfiles" + } else { + Write-Warning "PowerShell profile not found in dotfiles" + } +} + +# Main execution function +function Start-Bootstrap { + param([string]$Profile, [switch]$Force, [switch]$Ask) + + Write-Header "Windows Dotfiles Bootstrap" + Write-Info "Profile: $Profile" + Write-Info "Force mode: $Force" + Write-Info "Interactive mode: $Ask" + + # Initialize logging + $logDir = Split-Path $Script:Config.LogFile + if (-not (Test-Path $logDir)) { + New-Item -ItemType Directory -Path $logDir -Force | Out-Null + } + + Write-Log "Bootstrap started with profile: $Profile" + + # Set Ask preference for all prompts + $Script:AskPreference = [bool]$Ask + + # Check dependencies + Write-Header "Checking Dependencies" + $requiredCommands = @("git", "powershell") + $missingCommands = @() + + foreach ($cmd in $requiredCommands) { + if (-not (Test-CommandExists $cmd)) { + $missingCommands += $cmd + Write-Error "Required command not found: $cmd" + } else { + Write-Success "Found: $cmd" + } + } + + if ($missingCommands.Count -gt 0) { + Write-Error "Missing required dependencies. Please install: $($missingCommands -join ', ')" + return $false + } + + # Install package manager (skippable) + if (Prompt-YesNo -Question "Install/check package manager?" -Default 'Y') { + if (-not (Install-PackageManager)) { + Write-Error "Failed to install package manager" + return $false + } + } else { + Write-Warning "Skipped package manager step by user choice" + } + + # Install dotfiles + if (Prompt-YesNo -Question "Install or update dotfiles?" -Default 'Y') { + if (-not (Install-Dotfiles)) { + Write-Error "Failed to install dotfiles" + return $false + } + } else { + Write-Warning "Skipped dotfiles installation by user choice" + } + + # Get packages file (profile-aware) + $packagesFile = Get-ProfilePackagesFile -Profile $Profile + if (-not $packagesFile) { + Write-Error "Failed to get packages file for profile '$Profile'" + return $false + } + + # Install packages + if (Prompt-YesNo -Question "Install profile packages?" -Default 'Y') { + Install-Packages -PackagesFile $packagesFile -Profile $Profile + } else { + Write-Warning "Skipped package installation by user choice" + } + + # Set up PowerShell profile + if (Prompt-YesNo -Question "Install PowerShell profile?" -Default 'Y') { + Install-PowerShellProfile + } else { + Write-Warning "Skipped PowerShell profile setup by user choice" + } + + # Deploy dotfiles + if (Prompt-YesNo -Question "Deploy dotfiles to system locations?" -Default 'Y') { + if (-not (Deploy-Dotfiles)) { + Write-Error "Failed to deploy dotfiles" + return $false + } + } else { + Write-Warning "Skipped dotfiles deployment by user choice" + } + + # Configure Windows + if (Prompt-YesNo -Question "Apply Windows configuration from packages.yml?" -Default 'N') { + Set-WindowsConfiguration -PackagesFile $packagesFile + } else { + Write-Warning "Skipped Windows configuration by user choice" + } + + # Enable Windows features (if admin) + if (Prompt-YesNo -Question "Enable Windows optional features?" -Default 'N') { + Enable-WindowsFeatures -PackagesFile $packagesFile + } else { + Write-Warning "Skipped enabling Windows features by user choice" + } + + Write-Header "Bootstrap Complete" + Write-Success "Windows dotfiles bootstrap completed successfully!" + Write-Info "Please restart your computer to apply all changes." + Write-Log "Bootstrap completed successfully" + + return $true +} + +# Help function +function Show-Help { + Write-Host @" +Windows Dotfiles Bootstrap Script + +USAGE: + .\bootstrap.ps1 [-Profile ] [-Force] [-Ask] [-Help] + +PARAMETERS: + -Profile Installation profile (default: essentials) + Available: essentials, minimal, dev, server, full, or a custom profile. + Custom profile files are resolved from: + - %USERPROFILE%\.cfg\profile\\packages.yml + - %USERPROFILE%\profile\\packages.yml + - %USERPROFILE%\dot_setup\profile\\packages.yml + -Force Force installation without prompts + -Ask Interactive mode with step-by-step prompts + -Help Show this help message + +EXAMPLES: + .\bootstrap.ps1 # Install with essentials profile + .\bootstrap.ps1 -Profile dev # Install development profile + .\bootstrap.ps1 -Profile full -Force # Force install full profile + .\bootstrap.ps1 -Ask # Interactive installation + +"@ -ForegroundColor Cyan +} + +# Script entry point +if ($Help) { + Show-Help + exit 0 +} + +# Run bootstrap +try { + $result = Start-Bootstrap -Profile $Profile -Force:$Force -Ask:$Ask + if (-not $result) { + exit 1 + } +} catch { + Write-Error "Bootstrap failed: $_" + Write-Log "Bootstrap failed: $_" "ERROR" + exit 1 +} diff --git a/windows/Users/Documents/PowerShell/initialize.ps1 b/windows/Users/Documents/PowerShell/initialize.ps1 new file mode 100644 index 0000000..72f0ea4 --- /dev/null +++ b/windows/Users/Documents/PowerShell/initialize.ps1 @@ -0,0 +1,227 @@ +<# + .SYNOPSIS + Bootstrap Windows command prompts (cmd, PS, PSCore) with my dotfiles and apps. + + .DESCRIPTION + To bootstrap directly from GitHub, run these 2 cmdlets in a PowerShell prompt: + > Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force + > irm 'https://raw.githubusercontent.com/srdusr/dotfiles/main/windows/Documents/PowerShell/bootstrap.ps1' | iex +#> +[CmdletBinding()] +param ( + [ValidateSet('clone', 'setup', 'apps', 'env', IgnoreCase = $true)] + [Parameter(Position = 0)] [string] + $verb = 'clone', + [Parameter()] [string] + $userName = $null, + [Parameter()] [string] + $email = $null, + [Parameter()] [switch] + $runAsAdmin = $false +) + +$ErrorActionPreference = 'Stop' + +$originGitHub = 'https://github.com/srdusr/dotfiles.git' +$dotPath = (Join-Path $env:USERPROFILE '.cfg') + +# Ensure Tls12 +[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 + +function ensureLocalGit { + if (Get-Command 'git' -ErrorAction SilentlyContinue) { + return + } + + $localGitFolder = (Join-Path $env:USERPROFILE (Join-Path "Downloads" "localGit")) + Write-Host "Installing ad-hoc git into $localGitFolder..." + + $gitUrl = Invoke-RestMethod 'https://api.github.com/repos/git-for-windows/git/releases/latest' | + Select-Object -ExpandProperty 'assets' | + Where-Object { $_.name -Match 'MinGit' -and $_.name -Match '64-bit' -and $_.name -notmatch 'busybox' } | + Select-Object -ExpandProperty 'browser_download_url' + $localGitZip = (Join-Path $localGitFolder "MinGit.zip") + New-Item -ItemType Directory -Path $localGitFolder -Force | Out-Null + (New-Object Net.WebClient).DownloadFile($gitUrl, $localGitZip) + Expand-Archive -Path $localGitZip -DestinationPath $localGitFolder -Force + + $gitPath = (Join-Path $localGitFolder 'cmd') + $env:Path += ";$gitPath" +} + +function cloneDotfiles { + Write-Host "Cloning $originGitHub -> $dotPath" + Write-Host -NoNewline "OK to proceed with setup? [Y/n] " + $answer = (Read-Host).ToUpper() + if ($answer -ne 'Y' -and $answer -ne '') { + Write-Warning "Aborting." + return 4 + } + + ensureLocalGit + + if (-not $userName -or $userName -eq '') { + $userName = (& git config --global --get user.name) + } + if (-not $userName -or $userName -eq '') { + $userName = "$env:USERNAME@$env:COMPUTERNAME" + } + + if (-not $email -or $email -eq '') { + $email = (& git config --global --get user.email) + } + if (-not $email -or $email -eq '') { + $email = Read-Host "Enter your email address for git commits" + if ($email -eq '') { + Write-Warning "Need email address, aborting." + return 3 + } + } + + & git.exe config --global user.name $userName + & git.exe config --global user.email $email + + + function global:config { + git --git-dir="$dotPath" --work-tree="$env:USERPROFILE" $args + } + + Add-Content -Path "$env:USERPROFILE\.gitignore" -Value ".cfg" + + if (Test-Path -Path $dotfiles_dir) { + config pull | Out-Null + $update = $true + } else { + git clone --bare $originGitHub $dotPath | Out-Null + $update = $false + } + + $std_err_output = config checkout 1>&1 + + if ($std_err_output -match "following untracked working tree files would be overwritten") { + if (-not $update) { + config checkout | Out-Null + } + } + config config --local status.showUntrackedFiles no + + if ($update -or (Read-Host "Do you want to overwrite existing files and continue with the dotfiles setup? [Y/n]" -eq "Y")) { + config fetch origin main:main | Out-Null + config reset --hard main | Out-Null + config checkout -f + if ($?) { + Write-Host "Successfully imported $dotPath." + } else { + handle_error "Mission failed." + } + } else { + handle_error "Aborted by user. Exiting..." + } + + return 0 +} + +function setup { + ensureLocalGit +} + +function installApps { + ensureLocalGit +} + +function writeGitConfig { + param ( + [Parameter(Mandatory = $true)] [string] $configIniFile + ) + + if ((Test-Path (Join-Path $env:USERPROFILE '.gitconfig')) -and -not (Test-Path (Join-Path $env:USERPROFILE '.gitconfig.bak'))) { + $userName = (& git config --global --get user.name) + $email = (& git config --global --get user.email) + + Move-Item -Path (Join-Path $env:USERPROFILE '.gitconfig') -Destination (Join-Path $env:USERPROFILE '.gitconfig.bak') + + if ($userName -and $userName -ne '') { + & git.exe config --global user.name $userName + } + if ($email -and $email -ne '') { + & git.exe config --global user.email $email + } + } + + Get-Content $configIniFile | ForEach-Object { + if ($_.TrimStart().StartsWith('#')) { return } + $key, $value = $_.Split('=', 2) + Write-Verbose "git config --global $key $value" + & git.exe config --global $key "$value" + } +} + +function setupShellEnvs { + Write-Host "Setting cmd console properties:" + $consolePath = 'HKCU\Console' + & reg add $consolePath /v QuickEdit /d 0x1 /t REG_DWORD /f | Out-Null + & reg add $consolePath /v WindowSize /d 0x00320078 /t REG_DWORD /f | Out-Null + & reg add $consolePath /v ScreenBufferSize /d 0x23280078 /t REG_DWORD /f | Out-Null + & reg add $consolePath /v FontFamily /d 0x36 /t REG_DWORD /f | Out-Null + & reg add $consolePath /v HistoryBufferSize /d 0x64 /t REG_DWORD /f | Out-Null + & reg add $consolePath /v FaceName /d "Hack Nerd Font Mono" /t REG_SZ /f | Out-Null + & reg add $consolePath /v FontSize /d 0x00100000 /t REG_DWORD /f | Out-Null + + $win32rc = (Join-Path $PSScriptRoot (Join-Path 'win' 'win32-rc.cmd')) + Write-Host "Setting up cmd autorun: $win32rc" + & reg add "HKCU\Software\Microsoft\Command Processor" /v AutoRun /t REG_SZ /d $win32rc /f | Out-Null + + Write-Host "Configuring user home dir..." + $configDir = (Join-Path $env:USERPROFILE '.config') + New-Item -ItemType Directory -Path $configDir -ErrorAction SilentlyContinue | Out-Null + + $sshDir = (Join-Path $env:USERPROFILE '.ssh') + Remove-Item (Join-Path $sshDir 'config') -ErrorAction SilentlyContinue -Force | Out-Null + $openSsh = ((Join-Path $env:windir 'System32\OpenSSH\ssh.exe').Replace("\", "/")) + & git config --global core.sshCommand $openSsh +} + +function main { + param ( + [Parameter(Mandatory = $true)] [string] $verbAction + ) + + Write-Verbose "PS: $($PSVersionTable.PSVersion)-$($PSVersionTable.PSEdition)" + switch ($verbAction) { + 'clone' { + Write-Host + if (Test-Path (Join-Path $dotPath '.git')) { + Write-Host "Local git repo already exists, skipping." + main setup + return + } + + $rc = cloneDotfiles + if ($rc -ne 0) { + Write-Error "Cloning dotfiles failed, aborting." + return + } + + $script = (Join-Path $dotPath 'Documents\PowerShell\bootstrap.ps1') + Write-Host "Continue $script in child process" + Start-Process -PassThru -NoNewWindow -FilePath "powershell.exe" -ArgumentList "-NoProfile -File $script setup" | Wait-Process + } + + 'setup' { + Write-Host "Setting up..." + setup + installApps + setupShellEnvs + Write-Host "Done (setup)." + exit + } + + 'apps' { installApps } + + 'env' { setupShellEnvs } + } + + Write-Host "Done." +} + +main $verb diff --git a/windows/Users/install.bat b/windows/Users/install.bat new file mode 100644 index 0000000..89b3ac6 --- /dev/null +++ b/windows/Users/install.bat @@ -0,0 +1,11 @@ +@echo off +REM === Installing Dotfiles === + +REM Set execution policy for current user +powershell -NoProfile -Command "Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force" + +REM Run PowerShell profile (dotfiles) +powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" + +REM Run bootstrap script +powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\Documents\PowerShell\bootstrap.ps1" diff --git a/windows/install.bat b/windows/install.bat deleted file mode 100644 index 89b3ac6..0000000 --- a/windows/install.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off -REM === Installing Dotfiles === - -REM Set execution policy for current user -powershell -NoProfile -Command "Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force" - -REM Run PowerShell profile (dotfiles) -powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" - -REM Run bootstrap script -powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\Documents\PowerShell\bootstrap.ps1" -- cgit v1.2.3