base commit

This commit is contained in:
2025-06-09 17:06:12 +02:00
parent f03d173798
commit 76f28837c6

658
base.ps1 Normal file
View File

@@ -0,0 +1,658 @@
#region Script Parameters
param (
[switch]$Debug,
[switch]$Run
)
if ($Debug) {
$DebugPreference = "Continue"
}
# Ensure script runs with admin privileges
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Restarting script with elevated privileges..."
Start-Process powershell -ArgumentList "-ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Definition)`"" -Verb RunAs
exit
}
#endregion Script Parameters
#region Ensure WinGet is Updated with MSIXBUNDLE
# Function to download and install WinGet from MSIXBUNDLE
function Install-WinGetFromMSIXBUNDLE {
param (
[string]$url,
[string]$output
)
try {
Write-Host "Downloading WinGet from MSIXBUNDLE..."
Invoke-WebRequest -Uri $url -OutFile $output -ErrorAction Stop
Write-Host "Installing WinGet from MSIXBUNDLE..."
Add-AppxPackage -Path $output -ErrorAction Stop
Write-Host "WinGet installed successfully from MSIXBUNDLE."
return $true # Indicate success
} catch {
Write-Warning "Failed to install WinGet from MSIXBUNDLE: $($_.Exception.Message)"
return $false # Indicate failure
} finally {
# Clean up the downloaded file
if (Test-Path $output) {
Remove-Item $output -Force -ErrorAction SilentlyContinue
}
}
}
# Function to attempt WinGet source update
function Update-WinGetSources {
param (
[string]$url
)
try {
wRite-Host "Attempting to update WinGet sources..."
winget source update -ErrorAction Stop
Write-Host "WinGet sources updated successfully."
return $true #Indicate success
} catch {
Write-Warning "WinGet source update failed: $($_.Exception.Message)."
return $false # Indicate failure
}
}
# Function to check if a URL redirects to a .msixbundle file
function Test-UrlRedirectsToMSIXBUNDLE {
param (
[string]$url
)
try {
$response = Invoke-WebRequest -Uri $url -Method Head -UseBasicParsing -MaximumRedirection 0 -ErrorAction Stop
if ($response.StatusCode -eq 302 -or $response.StatusCode -eq 301) {
$redirectLocation = $response.Headers["Location"]
if ($redirectLocation -like "*.msixbundle") {
Write-Host "URL redirects to .msixbundle: $redirectLocation"
return $true
} else {
Write-Warning "URL does not redirect to .msixbundle. Redirects to: $redirectLocation"
return $false
}
} else {
Write-Warning "URL does not redirect. Status code: $($response.StatusCode)"
return $false
}
} catch {
Write-Warning "Error checking URL redirection: $($_.Exception.Message)"
return $false
}
}
# Define the aka.ms/getwinget URL
$msixBundleUrl = "https://aka.ms/getwinget"
# Specify the output file path
$msixBundleOutput = "$env:USERPROFILE\Downloads\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
# Attempt to update WinGet sources
$sourceUpdateResult = Update-WinGetSources -url $msixBundleUrl
# If updating sources failed, install from MSIXBUNDLE
if (-not $sourceUpdateResult) {
# Check if aka.ms/getwinget redirects to a .msixbundle file
$urlCheckResult = Test-UrlRedirectsToMSIXBUNDLE -url $msixBundleUrl
if ($urlCheckResult) {
Write-Warning "Attempting to install WinGet from MSIXBUNDLE using aka.ms/getwinget..."
$msixBundleInstallResult = Install-WinGetFromMSIXBUNDLE -url $msixBundleUrl -output $msixBundleOutput
if (-not $msixBundleInstallResult) {
Write-Error "Failed to install WinGet from MSIXBUNDLE. Script will continue, but WinGet may not function correctly."
}
} else {
Write-Error "aka.ms/getwinget does not redirect to a .msixbundle file. Cannot install WinGet."
}
}
#endregion Ensure WinGet is Updated with MSIXBUNDLE
#region Functions
# Function to prompt for input with a timeout
function Read-InputWithTimeout {
param (
[string]$Prompt,
[int]$TimeoutSeconds = 360 # 6 Minutes (6 * 60 seconds)
)
Write-Host $Prompt
$startTime = Get-Date
$input = $null # Initialize $input to null
while (((Get-Date) - $startTime).TotalSeconds -lt $TimeoutSeconds) {
if ($Host.UI.RawUI.KeyAvailable) {
$input = Read-Host
break # Exit the loop if input is received
}
Start-Sleep -Milliseconds 100 # Don't hog CPU
}
if (-not $input) {
Write-Host "Timeout expired or no input provided."
}
return $input
}
# Function to set registry value
function Set-RegistryValue {
param (
[string]$Path,
[string]$Name,
[object]$Value,
[ValidateSet(
"String",
"ExpandString",
"Binary",
"DWord",
"QWord",
"MultiString",
"Unknown"
)]
[string]$Type = "String"
)
try {
# Validate path format
if (-not $Path -match '^HK(LM|CU|CR|U):\\') {
throw "Invalid registry path format. Use HKLM:\ or HKCU:\ syntax"
}
# Create key if missing
if (-not (Test-Path $Path)) {
New-Item -Path $Path -Force | Out-Null
Write-Host "Created registry key: $Path"
}
# Set value with proper type handling
switch ($Type) {
"DWord" {
$Value = [int]$Value
}
"QWord" {
$Value = [long]$Value
}
"Binary" {
$Value = [byte[]]$Value
}
}
New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType $Type -Force -ErrorAction Stop
Write-Host "Set registry value: $Name = $Value ($Type) at $Path"
} catch {
Write-Warning "Registry operation failed: $_"
}
}
# Function to set Google NTP server
function Set-GoogleNTP {
Write-Host "Configuring time.google.com as NTP server..."
try {
# Configure NTP server
w32tm /config /manualpeerlist:"time.google.com" /syncfromflags:MANUAL
# Restart time service
Restart-Service -Name w32time -Force
# Force synchronization
w32tm /resync /force
Write-Host "Time synchronization completed successfully."
} catch {
Write-Host "Error configuring NTP: $($_.Exception.Message)"
}
}
# Function to get WinUtil Winget Latest
function Get-WinUtilWingetLatest {
try {
$wingetCmd = Get-Command winget -ErrorAction Stop
Write-Host "Updating WinGet using WinGet itself..."
$process = Start-Process -FilePath "winget" -ArgumentList "upgrade --id Microsoft.DesktopAppInstaller --silent --accept-package-agreements --accept-source-agreements" -Wait -NoNewWindow -PassThru
if ($process.ExitCode -ne 0) {
throw "WinGet upgrade failed with exit code $($process.ExitCode)"
}
return $true
} catch {
Write-Host "WinGet update failed: $($_.Exception.Message). Attempting to install manually..."
try {
$wingetUrl = "https://aka.ms/getwinget"
$tempFile = "$env:TEMP\Microsoft.DesktopAppInstaller.appxbundle"
Invoke-WebRequest -Uri $wingetUrl -OutFile $tempFile -ErrorAction Stop
Add-AppxPackage -Path $tempFile -ErrorAction Stop
# Check if WinGet is now available
if (Get-Command winget -ErrorAction SilentlyContinue) {
Write-Host "WinGet installed manually successfully."
return $true
} else {
Write-Error "WinGet manual install appeared to complete, but WinGet is not found."
return $false
}
} catch {
Write-Error "WinGet manual installation failed: $($_.Exception.Message)"
return $false
} finally {
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
}
}
}
# Function to find a window by title
function Find-WindowByTitle {
param (
[string]$Title
)
[System.Windows.Forms.Application]::OpenForms | Where-Object {$_.Text -like "*$Title*" }
}
# Function to click a button
function Click-Button {
param (
[System.Windows.Forms.Form]$Form,
[string]$ButtonText
)
$button = $Form.Controls | Where-Object {$_.GetType().Name -eq "Button" -and $_.Text -like "*$ButtonText*" }
if ($button) {
$button.PerformClick()
}
}
#endregion Functions
#region Main Script
# Set Enforce TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Ensure WinGet is Updated with MSIXBUNDLE
# Attempt to update WinGet sources
if($sourceUpdateResult = Update-WinGetSources -url $msixBundleUrl){
}
# If updating sources failed, install from MSIXBUNDLE
else{
# Check if aka.ms/getwinget redirects to a .msixbundle file
if($urlCheckResult = Test-UrlRedirectsToMSIXBUNDLE -url $msixBundleUrl)
{
Write-Warning "Attempting to install WinGet from MSIXBUNDLE using aka.ms/getwinget..."
if ($msixBundleInstallResult = Install-WinGetFromMSIXBUNDLE -url $msixBundleUrl -output $msixBundleOutput)
{
}
else
{
Write-Error "Failed to install WinGet from MSIXBUNDLE. Script will continue, but WinGet may not function correctly."
}
}
else
{
Write-Error "aka.ms/getwinget does not redirect to a .msixbundle file. Cannot install WinGet."
}
}
# Set Google NTP
Set-GoogleNTP
# Create DWORD value
Set-RegistryValue -Path "HKLM:\Software\Policies\Microsoft\Windows\AppInstaller" -Name "EnableBypassCertificatePinningForMicrosoftStore" -Value 1 -Type "DWord"
# Install or Update WinGet
#Write-Host "Installing or Updating WinGet..."
#Get-WinUtilWingetLatest
# Refresh environment variables
$ENV:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
# Define a list of applications to install
$apps = @(
@{
Name = "Google Chrome"
Id = "Google.Chrome"
}
@{
Name = "7-Zip"
Id = "7zip.7zip"
}
@{
Name = "Adobe Acrobat Reader"
Id = "Adobe.Acrobat.Reader.64-bit"
}
)
# Applications to remove
$delnow = @(
@{
Name = "Microsoft Copilot"
Id = "9NHT9RB2F4HD"
}
@{
Name = "AI Shell"
Id = "Microsoft.AIShell"
}
@{
Name = "Microsoft Teams"
Id = "Microsoft.Teams"
}
@{
Name = "Microsoft Teams classic"
Id = "Microsoft.Teams.Classic"
}
@{
Name = "Microsoft Teams"
Id = "Microsoft.Teams.Free"
}
@{
Name = "Microsoft Teams"
Id = "XP8BT8DW290MPQ"
}
@{
Name = "Microsoft 365 Copilot"
Id = "9WZDNCRD29V9"
}
@{
Name = "Outlook for Windows"
Id = "9NRX63209R7B"
}
)
# Check manufacturer and install appropriate update utility
$manufacturer = (Get-CIMInstance Win32_ComputerSystem).Manufacturer
if ($manufacturer -match "Dell") {
if (-not (winget list --id Dell.CommandUpdate -q)) {
Write-Host "Installing Dell Command Update..."
winget install --id Dell.CommandUpdate --silent --accept-package-agreements --accept-source-agreements
} else {
Write-Host "Dell Command Update is already installed. Skipping."
}
} elseif ($manufacturer -match "Lenovo") {
if (-not (winget list --id Lenovo.Vantage -q)) {
Write-Host "Installing Lenovo Vantage..."
winget install --id Lenovo.Vantage --silent --accept-package-agreements --accept-source-agreements
} else {
Write-Host "Lenovo Vantage is already installed. Skipping."
}
} elseif ($manufacturer -match "Samsung") {
Write-Host "Running Samsung bloatware removal script..."
# Run removal script twice as requested
foreach ($i in 1..2) {
Invoke-RestMethod -Uri "http://172.16.16.89/removesamsungapps.ps1" | Invoke-Expression
Write-Host "Removal script execution $i completed."
}
} else {
Write-Host "No specific manufacturer update tool available. Skipping."
}
# Install applications using WinGet
foreach ($app in $apps) {
Write-Host "Installing $($app.Name)..."
Start-Process powershell -ArgumentList "-Command winget install --id $($app.Id) --silent --accept-package-agreements --accept-source-agreements"
}
foreach ($app in $apps) {
Write-Host "Installing $($app.Name)..."
winget install --id $($app.Id) --silent --accept-package-agreements --accept-source-agreements
}
# Remove unwanted applications
foreach ($app in $delnow) {
Write-Host "Removing $($app.Name)..."
winget uninstall --id $($app.Id) --silent
}
#region Install Office via ODT
Write-Host "Installing Office via Office Deployment Tool..."
# Install Office Deployment Tool using WinGet
try {
Write-Host "Installing Office Deployment Tool..."
# Ensure WinGet is available and working before this step
$process = Start-Process -FilePath "winget" -ArgumentList "install --id Microsoft.OfficeDeploymentTool --silent --accept-package-agreements --accept-source-agreements" -Wait -NoNewWindow -PassThru
if ($process.ExitCode -eq 0) {
Write-Host "Office Deployment Tool installed successfully."
} else {
Write-Warning "Failed to install Office Deployment Tool via WinGet. Exit code: $($process.ExitCode)"
# Consider adding more robust error handling or alternative methods if WinGet fails
exit # Exit if ODT cannot be installed
}
} catch {
Write-Error "An error occurred while trying to install Office Deployment Tool via WinGet: $($_.Exception.Message)"
exit
}
# Define known ODT installation path
$odtInstallDir = "C:\Program Files\OfficeDeploymentTool"
$odtExePath = Join-Path $odtInstallDir "setup.exe"
# Verify ODT executable exists at the expected path
if (-not (Test-Path $odtExePath)) {
Write-Error "Office Deployment Tool executable not found at expected path: $odtExePath. Please verify the WinGet installation or the path."
# Attempt to find it dynamically as a fallback, though less reliable
Write-Host "Attempting to locate setup.exe dynamically..."
$dynamicOdtExe = Get-Command "setup.exe" -ErrorAction SilentlyContinue | Where-Object { $_.Source -like "*OfficeDeploymentTool*" } | Select-Object -First 1
if ($dynamicOdtExe) {
$odtExePath = $dynamicOdtExe.Source
$odtInstallDir = Split-Path $odtExePath
Write-Warning "Found ODT at a dynamic path: $odtExePath. Proceeding with this path."
} else {
Write-Error "Could not locate ODT setup.exe dynamically either. Exiting Office installation."
# Skip Office installation or exit script, depending on desired behavior
# For now, we'll just write the error and the script will continue to the 'finally' block for cleanup.
# To stop further script execution for Office install:
# return # if in a function, or exit if appropriate for the whole script
# For this specific block, we'll let it fall through to the catch/finally
throw "ODT setup.exe not found." # This will be caught by the outer try/catch
}
}
# Define paths for the configuration XML in a temporary directory
$tempDirForXml = Join-Path $env:TEMP "OfficeODTConfig" # Using a slightly different name to avoid conflict if old $tempDir exists
$configXmlPath = Join-Path $tempDirForXml "BeConfig.xml"
$officeConfigUrl = "https://bestorageshare.blob.core.windows.net/office/BeConfig.xml" # Ensure this is defined earlier or here
try {
# Create temporary directory for XML if it doesn't exist
if (-not (Test-Path $tempDirForXml)) {
New-Item -Path $tempDirForXml -ItemType Directory -Force | Out-Null
Write-Host "Created temporary directory for XML: $tempDirForXml"
}
# Download Office configuration XML
Write-Host "Downloading Office configuration XML from $($officeConfigUrl)..."
Invoke-WebRequest -Uri $officeConfigUrl -OutFile $configXmlPath -ErrorAction Stop
Write-Host "Successfully downloaded XML to: $configXmlPath"
# Run ODT to download and install Office
Write-Host "Running Office Deployment Tool from '$odtExePath' to configure/install Office using '$configXmlPath'..."
Write-Host "Working directory will be set to '$odtInstallDir'."
# Ensure the XML path is quoted in the arguments
$odtArguments = "/configure `"$configXmlPath`""
$process = Start-Process -FilePath $odtExePath -ArgumentList $odtArguments -Wait -NoNewWindow -PassThru -WorkingDirectory $odtInstallDir
if ($process.ExitCode -eq 0) {
Write-Host "Office Deployment Tool completed successfully."
} else {
Write-Warning "Office Deployment Tool exited with code $($process.ExitCode). Office installation may have failed."
Write-Warning "Check ODT logs (usually in %TEMP% or %windir%\Temp, e.g., MACHINENAME-YYYYMMDD-HHMM.log) for more details."
}
} catch {
Write-Error "Failed to configure or install Office via ODT: $($_.Exception.Message)"
# Additional details from the exception might be useful:
# if ($_.Exception.InnerException) { Write-Error "Inner Exception: $($_.Exception.InnerException.Message)" }
} finally {
# Clean up temporary XML file and directory
Write-Host "Cleaning up temporary Office ODT configuration files..."
if (Test-Path $tempDirForXml) {
Start-Sleep -Seconds 1 # Brief pause
Remove-Item $tempDirForXml -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Cleaned up temporary directory: $tempDirForXml"
}
}
#endregion Install Office via ODT
#region McAfee Removal
# More reliable detection of McAfee products via registry
function Is-McAfeeInstalled {
$mcafeeRegPaths = @(
"HKLM:\SOFTWARE\McAfee",
"HKLM:\SOFTWARE\WOW6432Node\McAfee"
)
foreach ($path in $mcafeeRegPaths) {
if (Test-Path $path) {
return $true
}
}
return $false
}
if (Is-McAfeeInstalled) {
Write-Host "McAfee is detected. Proceeding with removal..."
# Download McAfee Removal Tool
$mcafeeRemovalTool = "$env:TEMP\MCPR.exe"
try {
Write-Host "Downloading McAfee Removal Tool..."
Invoke-WebRequest -Uri "https://download.mcafee.com/products/licensed/cust_support_patches/MCPR.exe" -OutFile $mcafeeRemovalTool -ErrorAction Stop
Write-Host "Starting McAfee Removal Tool..."
# Start the removal tool
$process = Start-Process -FilePath $mcafeeRemovalTool -Wait -PassThru
if ($process.ExitCode -eq 0) {
Write-Host "McAfee Removal Tool completed successfully."
} else {
Write-Warning "McAfee Removal Tool exited with code $($process.ExitCode). Manual removal may be required."
}
} catch {
Write-Warning "Failed to download or run McAfee Removal Tool: $($_.Exception.Message)"
} finally {
# Clean up the downloaded removal tool
if (Test-Path $mcafeeRemovalTool) {
Remove-Item $mcafeeRemovalTool -Force -ErrorAction SilentlyContinue
}
}
} else {
Write-Host "McAfee is not detected. Skipping removal."
}
#endregion McAfee Removal
# Set hostname
$hostname = Read-Host "Enter new hostname (leave blank to keep current name)"
if (-not [string]::IsNullOrEmpty($hostname)) {
Rename-Computer -NewName $hostname -Force -PassThru
Write-Host "Hostname changed to $hostname. The system will now restart"
} else {
Write-Host "No hostname provided. Keeping the current hostname."
}
# Prompt for the Active Directory domain
$domain = Read-InputWithTimeout -Prompt "Enter the Active Directory domain name (leave blank for workgroup):" -TimeoutSeconds 360
if ($domain -match '\w+\.\w+') { # Basic validation for a domain-like format
Write-Host "Joining domain: $domain"
# Prompt for the DNS server IP
$dnsServer = Read-InputWithTimeout -Prompt "Enter the DNS server IP address:" -TimeoutSeconds 60
if ($dnsServer -match '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$') {
Write-Host "Setting DNS server to: $dnsServer"
# Get the network adapter
$adapter = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.IPEnabled -eq $true}
if ($adapter) {
try {
# Set the DNS server
$result = $adapter.SetDNSServerSearchOrder(@($dnsServer))
if ($result.ReturnValue -eq 0) {
Write-Host "DNS server set successfully."
} else {
Write-Warning "Failed to set DNS server. ReturnValue: $($result.ReturnValue)"
}
} catch {
Write-Warning "Error setting DNS server: $($_.Exception.Message)"
}
} else {
Write-Warning "No enabled network adapter found."
}
} else {
Write-Warning "Invalid DNS server IP address."
}
# Join the domain
try {
Add-Computer -DomainName $domain -Credential (Get-Credential) -ErrorAction Stop #removed restart, will perform later
Write-Host "Successfully joined domain: $domain. System will restart at the end of the script."
} catch {
Write-Warning "Failed to join domain: $($_.Exception.Message)"
}
} else {
Write-Host "No domain provided or invalid format. Skipping domain join and DNS configuration."
}
# Set password for user "admin" if it exists
if ($env:USERNAME -eq "admin") {
Write-Host "Setting password for user 'admin'..."
$securePassword = Read-Host "Enter password for 'admin'" -AsSecureString
$credential = New-Object System.Management.Automation.PSCredential("admin", $securePassword)
$credential.GetNetworkCredential().Password | Set-Content "$env:TEMP\temp_password.txt"
net user admin /passwordreq:yes | Out-Null
net user admin "$($credential.GetNetworkCredential().Password)" | Out-Null
Remove-Item "$env:TEMP\temp_password.txt" -Force -ErrorAction SilentlyContinue
Write-Host "Password for 'admin' has been set successfully.`n"
} else {
Write-Host "Current user is not 'admin'. Skipping password change.`n"
}
# Set suspension and screen turn-off time to unlimited
Write-Host "Setting suspension and screen turn-off time to unlimited..."
powercfg /change monitor-timeout-ac 0
powercfg /change monitor-timeout-dc 0
powercfg /change standby-timeout-ac 0
powercfg /change standby-timeout-dc 0
Write-Host "Suspension and screen turn-off time set to unlimited.`n"
# Update the system
Write-Host "Updating the system..."
try {
Start-Process -FilePath "powershell" -ArgumentList "-Command Install-WindowsUpdate -AcceptAll -AutoReboot" -Verb RunAs -Wait
Start-Process -FilePath "winget" -ArgumentList "upgrade --all" -Verb RunAs -Wait
Write-Host "System update completed successfully.`n"
} catch {
Write-Host "System update failed. Please check manually.`n"
}
Write-Host "All installations and updates completed. Restarting the system..."
# Restart computer
function Confirm-And-Reboot {
$response = Read-InputWithTimeout -Prompt "Do you want to reboot the computer now? (Y/N):" -TimeoutSeconds 600
if ($response -match '^(Y|y)$') {
Write-Host "Rebooting now..."
Restart-Computer
}
else {
Write-Host "Reboot cancelled. Please remember to reboot later if required."
}
}
Confirm-And-Reboot
#endregion Main Script