668 lines
24 KiB
PowerShell
668 lines
24 KiB
PowerShell
#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
|
|
$currentName = $env:COMPUTERNAME
|
|
$hostname = Read-Host "Enter new hostname (leave blank to keep current name [$currentName])"
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($hostname) -and $hostname -ne $currentName) {
|
|
try {
|
|
Rename-Computer -NewName $hostname -Force -ErrorAction Stop
|
|
Write-Host "Hostname changed to $hostname. It will take effect after reboot."
|
|
$global:hostnameChanged = $true
|
|
} catch {
|
|
Write-Warning "Failed to rename computer: $($_.Exception.Message)"
|
|
}
|
|
} else {
|
|
Write-Host "No valid hostname provided or hostname is already set to '$currentName'. Skipping rename."
|
|
}
|
|
|
|
# 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 {
|
|
if ($global:hostnameChanged -or $domainJoined) {
|
|
Write-Host "System changes require a 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 skipped. Please remember to reboot manually for changes to take effect."
|
|
}
|
|
} else {
|
|
Write-Host "No reboot required."
|
|
}
|
|
}
|
|
|
|
Confirm-And-Reboot
|
|
|
|
#endregion Main Script
|