diff options
Diffstat (limited to 'linux/home/.config/powershell')
| -rw-r--r-- | linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1 | 14 | ||||
| -rw-r--r-- | linux/home/.config/powershell/bloatware.ps1 | 335 | ||||
| -rw-r--r-- | linux/home/.config/powershell/bootstrap.ps1 | 396 | ||||
| -rw-r--r-- | linux/home/.config/powershell/initialize.ps1 | 227 |
4 files changed, 972 insertions, 0 deletions
diff --git a/linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1 b/linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1 new file mode 100644 index 0000000..349f7ab --- /dev/null +++ b/linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1 @@ -0,0 +1,14 @@ +# Dotfiles special git command +function global:config { + git --git-dir="$env:USERPROFILE\.cfg" --work-tree="$env:USERPROFILE" $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/linux/home/.config/powershell/bloatware.ps1 b/linux/home/.config/powershell/bloatware.ps1 new file mode 100644 index 0000000..2c8dacb --- /dev/null +++ b/linux/home/.config/powershell/bloatware.ps1 @@ -0,0 +1,335 @@ +# 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): $_" + } +} + +# As a last step, disable UAC ------------------------ +New-ItemProperty -Path HKLM:Software\Microsoft\Windows\CurrentVersion\policies\system -Name EnableLUA -PropertyType DWord -Value 0 -Force + +# 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/linux/home/.config/powershell/bootstrap.ps1 b/linux/home/.config/powershell/bootstrap.ps1 new file mode 100644 index 0000000..73d53b5 --- /dev/null +++ b/linux/home/.config/powershell/bootstrap.ps1 @@ -0,0 +1,396 @@ +# Requires -RunAsAdministrator + +# Set execution policy to remote signed +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force + +# Set network category to private +Set-NetConnectionProfile -NetworkCategory Private + +# Variables +$dotfiles_url = 'https://github.com/srdusr/dotfiles.git' +$dotfiles_dir = "$HOME\.cfg" + +# Function to handle errors +function handle_error { + param ($message) + Write-Host $message -ForegroundColor Red + exit 1 +} + +# Logs +New-Item -Path $Env:USERPROFILE\Logs -ItemType directory -Force +Start-Transcript -Path $Env:USERPROFILE\Logs\Bootstrap.log +$ErrorActionPreference = 'SilentlyContinue' +Write-Host "Bootstrap.log generated in Logs\" + +# Function to check if the current session is elevated +function Test-IsAdmin { + $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal($currentUser) + return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +# Ensure the script is run as administrator +if (-not (Test-IsAdmin)) { + handle_error "This script must be run as an administrator." +} + +# Imports +. $HOME\.config\powershell\initialize.ps1 +. $HOME\.config\powershell\bloatware.ps1 + +# Configure PowerShell +Write-Host "Configuring PowerShell" +Write-Host "----------------------------------------" + +# Get the "MyDocuments" path for the current user, excluding OneDrive +$UserMyDocumentsPath = [System.Environment]::GetFolderPath('MyDocuments').Replace("OneDrive", "") + +$PowerShellProfileDirectory = "$UserMyDocumentsPath\PowerShell" +$PowerShellLegacySymlink = "$UserMyDocumentsPath\WindowsPowerShell" + +$PowerShellProfileTemplate = "$PSScriptRoot\$USERNAME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" +$env:PSModulePath = $env:PSModulePath -replace "\\OneDrive\\Documents\\WindowsPowerShell\\","\.powershell\" + +# Set documents path to user's local Documents folder +$documentsPath = "$UserMyDocumentsPath" +$powerShellProfileDir = "$documentsPath\PowerShell" + +# Output the chosen PowerShell profile directory +$PROFILE = "$powerShellProfileDir\Microsoft.PowerShell_profile.ps1" +Write-Host "PowerShell profile directory set to: $powerShellProfileDir" + +if (-not (Test-Path -Path $powerShellProfileDir)) { + New-Item -ItemType Directory -Path $powerShellProfileDir -Force +} + +New-Item -ItemType HardLink -Force ` + -Path "$powerShellProfileDir\Microsoft.PowerShell_profile.ps1" ` + -Target "$home\.config\powershell\Microsoft.PowerShell_profile.ps1" + +# Set environment variable +[System.Environment]::SetEnvironmentVariable('PowerShellProfileDir', $powerShellProfileDir, [System.EnvironmentVariableTarget]::User) + +Write-Host "PowerShell profile directory set to: $powerShellProfileDir" +Write-Host "Environment variable 'PowerShellProfileDir' set to: $powerShellProfileDir" + +# Verify profile sourcing +if (!(Test-Path -Path "$home\.config\powershell\Microsoft.PowerShell_profile.ps1")) { + handle_error "PowerShell profile does not exist. Please create it at $home\.config\powershell\Microsoft.PowerShell_profile.ps1" +} + +# Install Chocolatey if not installed +Write-Host "Installing Chocolatey" +Write-Host "----------------------------------------" + +if (-not (Get-Command choco -ErrorAction SilentlyContinue)) { + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + + # Check if Chocolatey installed successfully + if (-not (Get-Command choco -ErrorAction SilentlyContinue)) { + handle_error "Chocolatey installation failed." + } +} else { + Write-Host "Chocolatey is already installed." +} + +# Install Applications +Write-Host "Installing Applications" +Write-Host "----------------------------------------" + +# 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 + +# Load packages.yml +$packagesFile = "$HOME\packages.yml" +$packages = Get-Content $packagesFile | ConvertFrom-Yaml + +# Ensure 'windows' section exists and has applications listed +if ($packages.windows) { + foreach ($app in $packages.windows) { + # Check if the application is already installed + if (-not (choco list --local-only | Select-String -Pattern "^$app\s")) { + Write-Host "Installing $app" + choco install $app -y + + if ($LASTEXITCODE -ne 0) { + handle_error "Installation of $app failed." + } else { + Write-Host "$app installed successfully." + } + } else { + Write-Host "$app is already installed." + } + } +} else { + Write-Host "No applications specified under the 'windows' section in $packagesFile." +} + +# Set Chrome as default browser ------------------------ +#Add-Type -AssemblyName 'System.Windows.Forms' +#Start-Process $env:windir\system32\control.exe -ArgumentList '/name Microsoft.DefaultPrograms /page pageDefaultProgram\pageAdvancedSettings?pszAppName=google%20chrome' +#Sleep 2 +#[System.Windows.Forms.SendKeys]::SendWait("{TAB} {TAB}{TAB} ") +SetDefaultBrowser firefox + +# Refresh the environment variables +Write-Host "Refreshing environment variables" + +# Update the current session environment variables +Write-Host "Setting environment variables" -ForegroundColor Cyan +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +[System.Environment]::SetEnvironmentVariable("Path", $env:Path, [System.EnvironmentVariableTarget]::Process) +[Environment]::SetEnvironmentVariable("HOME", "$env:USERPROFILE", "User") +[Environment]::SetEnvironmentVariable("LC_ALL", "C.UTF-8", "User") +refreshenv + +# Add Git to PATH if it's installed via Chocolatey +Write-Host "Checking for Git installation" +$gitBinPath = "C:\Program Files\Git\bin" +$gitCmdPath = "C:\Program Files\Git\cmd" +$gitPaths = @($gitBinPath, $gitCmdPath) + +foreach ($path in $gitPaths) { + if (Test-Path $path) { + Write-Host "Adding $path to PATH" + [System.Environment]::SetEnvironmentVariable("Path", "$env:Path;$path", [System.EnvironmentVariableTarget]::Machine) + [System.Environment]::SetEnvironmentVariable("Path", "$env:Path;$path", [System.EnvironmentVariableTarget]::User) + [System.Environment]::SetEnvironmentVariable("Path", "$env:Path;$path", [System.EnvironmentVariableTarget]::Process) + } else { + Write-Host "$path does not exist." + } +} + +# Check if Git is installed +Write-Host "Checking for Git installation" +if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + handle_error "Git is not installed or not found in PATH after installation." +} else { + Write-Host "Git is installed and available in PATH." +} + +# Define the `config` alias in the current session +function global:config { + git --git-dir="$env:USERPROFILE\.cfg" --work-tree="$env:USERPROFILE" $args +} + +# Add .gitignore entries +Add-Content -Path "$HOME\.gitignore" -Value ".cfg" +Add-Content -Path "$HOME\.gitignore" -Value "install.bat" +Add-Content -Path "$HOME\.gitignore" -Value ".config/powershell/bootstrap.ps1" + +# Create symbolic links +Write-Host "Create symbolic links" +Write-Host "----------------------------------------" + +# Visual Studio Code settings.json +New-Item -Force -ItemType SymbolicLink $HOME\AppData\Roaming\Code\User\ -Name settings.json -Value $HOME\.config\Code\User\settings.json + +# Visual Studio Code keybindings +New-Item -Force -ItemType SymbolicLink $HOME\AppData\Roaming\Code\User\ -Name keybindings.json -Value $HOME\.config\Code\User\keybindings.json + +# Function to install dotfiles +function install_dotfiles { + if (Test-Path -Path $dotfiles_dir) { + config pull | Out-Null + $update = $true + } else { + git clone --bare $dotfiles_url $dotfiles_dir | Out-Null + $update = $false + } + + $std_err_output = config checkout 2>&1 + + if ($std_err_output -match "following untracked working tree files would be overwritten") { + if (-not $update) { + config checkout | Out-Null + } + } + config config status.showUntrackedFiles no + + git config --global include.path "$HOME\.gitconfig.aliases" + + 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 $dotfiles_dir." + } else { + handle_error "Mission failed." + } + } else { + handle_error "Aborted by user. Exiting..." + } +} + +install_dotfiles + +# Install python +Write-Host "Updating python packages" -ForegroundColor Cyan +python -m pip install --upgrade pip + +# Enable WSL feature +dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart +Write-Host "Enable WSL feature" +wsl --install -d ubuntu +wsl --set-default-version 2 + +# Enable Virtual Machine feature +#dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart +#Write-Host "Enable Virtual Machine feature" + +Write-Header "Installing Hyper-V" + +# Install Hyper-V +Write-Host "Installing Hyper-V and restart" +Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart +Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart +Install-WindowsFeature -Name Hyper-V -IncludeAllSubFeature -IncludeManagementTools -NoRestart + +# Configure Neovim +Write-Host "Configuring Neovim" +Write-Host "----------------------------------------" + +$neovimLocalPath = "$home\AppData\Local\nvim" +$neovimConfigPath = "$home\.config\nvim" + +# Check if nvim directory already exists in AppData\Local +if (-not (Test-Path -Path $neovimLocalPath)) { + New-Item -ItemType Junction -Force -Path $neovimLocalPath -Target $neovimConfigPath +} else { + Write-Host "Neovim directory ($neovimLocalPath) already exists." +} + +# Install Windows Terminal, and configure +Write-Host "Install Windows Terminal, and configure" +Write-Host "----------------------------------------" + +$windowsTerminalSettingsPath = "$home\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json" +$windowsTerminalConfigPath = "$home\.config\windows-terminal\settings.json" + +# Check if Windows Terminal settings.json already exists +if (Test-Path -Path $windowsTerminalSettingsPath) { + # Backup existing settings.json + Move-Item -Force $windowsTerminalSettingsPath "$windowsTerminalSettingsPath.old" +} else { + Write-Host "Windows Terminal settings.json not found, no need to backup." +} + +# Create a hard link to the settings.json file in .config\windows-terminal +New-Item -ItemType HardLink -Force -Path $windowsTerminalSettingsPath -Target $windowsTerminalConfigPath + +# Function to check if a registry key exists +function Test-RegistryKeyExists { + param ($path) + return (Test-Path $path -PathType Container) +} + +# Function to check if a registry property exists +function Test-RegistryPropertyExists { + param ($keyPath, $propertyName) + if (Test-Path $keyPath) { + $properties = Get-ItemProperty -Path $keyPath + return $properties.PSObject.Properties.Name -contains $propertyName + } + return $false +} + +# Registry Tweaks +Write-Host "Registry Tweaks" +Write-Host "----------------------------------------" + +# Show hidden files +$advancedKeyPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" +if (-not (Test-RegistryPropertyExists $advancedKeyPath "Hidden")) { + Set-ItemProperty -Path $advancedKeyPath -Name Hidden -Value 1 +} + +# Show file extensions in Windows Explorer +$hideFileExtPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" +if (-not (Test-RegistryPropertyExists $hideFileExtPath "HideFileExt")) { + Set-ItemProperty -Path $hideFileExtPath -Name HideFileExt -Value 0 +} + +# Never Combine taskbar buttons when the taskbar is full +$taskbarGlomLevelPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" +if (-not (Test-RegistryPropertyExists $taskbarGlomLevelPath "TaskbarGlomLevel")) { + Set-ItemProperty -Path $taskbarGlomLevelPath -Name TaskbarGlomLevel -Value 2 +} + +# Taskbar small icons +$taskbarSmallIconsPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" +if (-not (Test-RegistryPropertyExists $taskbarSmallIconsPath "TaskbarSmallIcons")) { + Set-ItemProperty -Path $taskbarSmallIconsPath -Name TaskbarSmallIcons -Value 1 +} + +# Set Windows to use UTC time instead of local time for system clock +$timeZoneInfoPath = "HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" +if (-not (Test-RegistryPropertyExists $timeZoneInfoPath "RealTimeIsUniversal")) { + Set-ItemProperty -Path $timeZoneInfoPath -Name RealTimeIsUniversal -Value 1 +} + +# Disable the search in taskbar +$searchBoxTaskbarPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Search" +if (-not (Test-RegistryPropertyExists $searchBoxTaskbarPath "SearchBoxTaskbarMode")) { + New-ItemProperty -Path $searchBoxTaskbarPath -Name SearchBoxTaskbarMode -Value 0 -Type DWord -Force +} + +# Dark mode: +$personalizePath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" +if (-not (Test-RegistryPropertyExists $personalizePath "AppsUseLightTheme")) { + Set-ItemProperty -Path $personalizePath -Name AppsUseLightTheme -Value 0 -Type Dword -Force +} +if (-not (Test-RegistryPropertyExists $personalizePath "SystemUsesLightTheme")) { + Set-ItemProperty -Path $personalizePath -Name SystemUsesLightTheme -Value 0 -Type Dword -Force +} + +# Restart explorer so the rest of the settings take effect: +Stop-Process -f -ProcessName explorer +Start-Process explorer.exe + +# Function to disable the Windows key +function Disable-WindowsKey { + $regPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Keyboard Layout" + $regName = "Scancode Map" + + # Binary data to remap the Windows key to F24 (an unused key) + $binaryValue = [byte[]]( + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x3A, 0x00, 0x5B, 0xE0, + 0x00, 0x00, 0x00, 0x00 + ) + + # Create the registry key if it doesn't exist + if (-not (Test-RegistryKeyExists $regPath)) { + New-Item -Path $regPath -Force | Out-Null + } + + # Set the Scancode Map value if it doesn't exist + if (-not (Test-RegistryPropertyExists $regPath $regName)) { + Set-ItemProperty -Path $regPath -Name $regName -Value $binaryValue + } + + Write-Output "Windows key has been disabled from opening the start menu. Please restart your computer for the changes to take effect." +} + +#Disable-WindowsKey + +Write-Host "Bootstrap script completed." +Write-Host "Please Restart." + +# Clean up Bootstrap.log +Write-Host "Clean up Bootstrap.log" +Stop-Transcript +$logSuppress = Get-Content $Env:USERPROFILE\Logs\Bootstrap.log | Where-Object { $_ -notmatch "Host Application: powershell.exe" } +$logSuppress | Set-Content $Env:USERPROFILE\Logs\Bootstrap.log -Force diff --git a/linux/home/.config/powershell/initialize.ps1 b/linux/home/.config/powershell/initialize.ps1 new file mode 100644 index 0000000..a616998 --- /dev/null +++ b/linux/home/.config/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/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 '.config\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 |
