Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [0.6.1] - 2026-02-17

### Added
- Intune enrollment detection: Windows hardening is now skipped if the device is already enrolled in Intune.
- Dedicated section for the Windows Spotlight fix under "Windows tweaks" with user instructions and reference to Fix-Spotlight.ps1.

### Changed
- Office/M365 is no longer installed via Winget if an Office or M365 package is already detected on the system.
- Dropped support for Windows 11 24H2; only 25H2+ (build 26200+) is now supported.
- Driver lists for Dell and HP are now embedded directly in the script for improved reliability (no more external JSON files).
- Application installation output now shows both the app name and its alias/ID for improved clarity.
- Theme configuration logging/output has been cleaned up to avoid duplicate or confusing messages.
- Hostname script now provides a clear message if no serial number is found (e.g., in a VM).

### Fixed
- Improved error handling for missing serial number during hostname setup.
- Various minor improvements to logging, error handling, and user messages.

---

## [0.6.0] - 2026-02-02

### Changed
Expand Down Expand Up @@ -165,6 +185,8 @@ First open-source release of WinDeploy - Windows Deployment Automation Toolkit.

---


[0.6.1]: https://github.com/Stensel8/WinDeploy/releases/tag/v0.6.1
[0.6.0]: https://github.com/Stensel8/WinDeploy/releases/tag/v0.6.0
[0.5.5]: https://github.com/Stensel8/WinDeploy/releases/tag/v0.5.5
[0.5.4]: https://github.com/Stensel8/WinDeploy/releases/tag/v0.5.4
Expand Down
10 changes: 0 additions & 10 deletions Docs/SupportedDellDevices.json

This file was deleted.

19 changes: 0 additions & 19 deletions Docs/SupportedHPDevices.json

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2025 Sten Tijhuis (Stensel8) and Contributors
Copyright (c) 2025 - 2026 Sten Tijhuis (Stensel8) and Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PowerShell 7.0+](https://img.shields.io/badge/PowerShell-7.0+-blue.svg)](https://github.com/PowerShell/PowerShell)
[![Windows 11](https://img.shields.io/badge/Windows-11-0078D6.svg)](https://www.microsoft.com/windows)
[![Windows 24H2/25H2](https://img.shields.io/badge/Windows-24H2/25H2-0078D6.svg)](https://www.microsoft.com/windows)
[![Windows 25H2](https://img.shields.io/badge/Windows-25H2-0078D6.svg)](https://www.microsoft.com/windows)


[![PSScriptAnalyzer](https://github.com/Stensel8/WinDeploy/actions/workflows/powershell.yml/badge.svg)](https://github.com/Stensel8/WinDeploy/actions/workflows/powershell.yml)
Expand Down Expand Up @@ -40,7 +40,7 @@ Choose how you want to deploy WinDeploy — pick the path that fits your environ

## Quick Start

**Prerequisites:** Windows 11 Pro 24H2+, PowerShell 7, internet connection
**Prerequisites:** Windows 11 Pro 25H2+, PowerShell 7, internet connection

### Option 1: USB Deployment (Fresh installs)
1. Create bootable Windows 11 USB
Expand Down
31 changes: 31 additions & 0 deletions Scripts/Deployment/Harden-Windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Continue'

# Check for Intune enrollment (pre-check)
function Test-IntuneEnrollment {
$enrollments = Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Enrollments' -ErrorAction SilentlyContinue
if ($enrollments.Count -eq 0) { return $false }
foreach ($enrollment in $enrollments) {
$guid = $enrollment.PSChildName
$erm = "HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked\$guid"
$policy = "HKLM:\SOFTWARE\Microsoft\PolicyManager\Providers\$guid"
$omadm = "HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\$guid"
$task = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\Microsoft\Windows\EnterpriseMgmt\$guid"
if ((Test-Path $erm) -and (Test-Path $policy) -and (Test-Path $omadm) -and (Test-Path $task)) {
return $true
}
}
return $false
}

if (Test-IntuneEnrollment) {
Write-Output "Device is already enrolled in Intune. Skipping hardening."
exit 0
}

# Only support Windows 11 25H2+ (build 26200+)
$os = Get-CimInstance Win32_OperatingSystem
$build = [int]$os.BuildNumber
if ($build -lt 26200) {
Write-Output "ERROR: Only Windows 11 25H2 (build 26200+) and newer are supported. Current build: $build. Exiting."
exit 1
}

Function Write-DeployLog {
param([string]$Message, [switch]$IsError)
$logDir = "C:\WinDeploy\Logs"
Expand Down Expand Up @@ -135,6 +165,7 @@ try {
if ($bitLockerStatus.ProtectionStatus -eq "Off") {
Enable-BitLocker -MountPoint "C:" -TpmProtector -EncryptionMethod XtsAes256 -UsedSpaceOnly -ErrorAction Stop
$appliedConfigs += "BitLocker encryption started"
Write-Output "WARNING: BitLocker will be enabled after the next reboot. Make sure to export your BitLocker recovery key!"
} else {
$appliedConfigs += "BitLocker already active"
}
Expand Down
93 changes: 56 additions & 37 deletions Scripts/Deployment/Install-Applications.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ Function Write-DeployLog {

try {


$Applications = @(
"Microsoft.VCRedist.2015+.x64",
"Microsoft.Office",
#"Adobe.Acrobat.Reader.64-bit", #Uncomment if you need Adobe Reader
"Microsoft.Teams",
"Microsoft.OneDrive",
"7zip.7zip",
"Microsoft.WindowsApp"
#"Microsoft.CompanyPortal" - Problematic package at this moment. Microsoft messed up the package. Use msstore version below instead. (exit code -2147024894)
@{Alias="Microsoft.VCRedist.2015+.x64"; Name="Microsoft Visual C++ 2015+ x64 Redistributable"},
@{Alias="Microsoft.Office"; Name="Microsoft Office"},
#@{Alias="Adobe.Acrobat.Reader.64-bit"; Name="Adobe Acrobat Reader 64-bit"},
@{Alias="Microsoft.Teams"; Name="Microsoft Teams"},
@{Alias="Microsoft.OneDrive"; Name="Microsoft OneDrive"},
@{Alias="7zip.7zip"; Name="7-Zip"},
@{Alias="Microsoft.WindowsApp"; Name="Windows App"}
#@{Alias="Microsoft.CompanyPortal"; Name="Company Portal"} # Problematic package at this moment.
)

#Note: Some applications fail to install. This is why we have a separate list for msstore apps.
$MsStoreApplications = @(
#"XPDP273C0XHQH2", #Adobe Acrobat Reader (msstore) #Uncomment if you need Adobe Reader
"XP8BT8DW290MPQ", # Microsoft Teams (msstore)
"9N1F85V9T8BN", # Windows App (msstore)
"9WZDNCRFJ3PZ", # Company Portal (msstore)
"9MZ95KL8MR0L" # Install this Windows app for improved screenshotting and recording capabilities.
@{Alias="XP8BT8DW290MPQ"; Name="Microsoft Teams (msstore)"},
@{Alias="9N1F85V9T8BN"; Name="Windows App (msstore)"},
@{Alias="9WZDNCRFJ3PZ"; Name="Company Portal (msstore)"},
@{Alias="9MZ95KL8MR0L"; Name="Screenshot/Recording App (msstore)"}
)

# Winget error codes that you may come across during installation. Note that these are not documented all well by Micrsoft. They documenent some of them, but not all.
Expand Down Expand Up @@ -251,31 +251,53 @@ try {
$OfficeFailed = $false

foreach ($app in $Applications) {
Write-DeployLog "Installing $app..."
$alias = $app.Alias
$name = $app.Name
# Improved Office detection
if ($alias -eq "Microsoft.Office") {
$officeDetected = $false
# Check registry for Office/M365
$officeRegPaths = @(
"HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration",
"HKLM:\SOFTWARE\Microsoft\Office\16.0\Common\InstallRoot",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
)
foreach ($regPath in $officeRegPaths) {
if (Test-Path $regPath) {
$officeDetected = $true
break
}
}
# Check installed products via CIM
$officeCim = Get-CimInstance -ClassName Win32_Product -Filter "Name LIKE '%Office%' OR Name LIKE '%Microsoft 365%'" -ErrorAction SilentlyContinue
if ($officeCim) {
$officeDetected = $true
}
if ($officeDetected) {
Write-DeployLog "Office/M365 already detected on system. Skipping $name ($alias) installation."
continue
}
}
Write-DeployLog "Installing $name ($alias)..."
try {
$output = & winget install --id $app --accept-package-agreements --accept-source-agreements 2>&1
$output = & winget install --id $alias --accept-package-agreements --accept-source-agreements 2>&1
$exitCode = $LASTEXITCODE
if ($exitCode -eq 0 -or $output -match "already installed|No available upgrade") {
Write-DeployLog "Installed $app"
Write-DeployLog "Installed $name ($alias)"
} else {
$description = $WingetErrorDescriptions[$exitCode]

if ($description) {

Write-DeployLog "Failed to install $app - $description (exit code $exitCode)" -IsError

Write-DeployLog "Failed to install $name ($alias) - $description (exit code $exitCode)" -IsError
} else {

Write-DeployLog "Failed to install $app (exit code $exitCode)" -IsError

Write-DeployLog "Failed to install $name ($alias) (exit code $exitCode)" -IsError
}
if ($app -eq "Microsoft.Office") {
if ($alias -eq "Microsoft.Office") {
$OfficeFailed = $true
}
}
} catch {
Write-DeployLog "Failed to install $app" -IsError
if ($app -eq "Microsoft.Office") {
Write-DeployLog "Failed to install $name ($alias)" -IsError
if ($alias -eq "Microsoft.Office") {
$OfficeFailed = $true
}
}
Expand Down Expand Up @@ -331,27 +353,24 @@ try {

Write-DeployLog "Installing Microsoft Store versions of the applications listed above..."
foreach ($app in $MsStoreApplications) {
Write-DeployLog "Installing msstore $app..."
$alias = $app.Alias
$name = $app.Name
Write-DeployLog "Installing msstore $name ($alias)..."
try {
$output = & winget install --id $app --accept-package-agreements --accept-source-agreements 2>&1
$output = & winget install --id $alias --accept-package-agreements --accept-source-agreements 2>&1
$exitCode = $LASTEXITCODE
if ($exitCode -eq 0 -or $output -match "already installed|No available upgrade") {
Write-DeployLog "Installed msstore $app"
Write-DeployLog "Installed msstore $name ($alias)"
} else {
$description = $WingetErrorDescriptions[$exitCode]

if ($description) {

Write-DeployLog "Failed to install msstore $app - $description (exit code $exitCode)" -IsError

Write-DeployLog "Failed to install msstore $name ($alias) - $description (exit code $exitCode)" -IsError
} else {

Write-DeployLog "Failed to install msstore $app (exit code $exitCode)" -IsError

Write-DeployLog "Failed to install msstore $name ($alias) (exit code $exitCode)" -IsError
}
}
} catch {
Write-DeployLog "Failed to install msstore $app" -IsError
Write-DeployLog "Failed to install msstore $name ($alias)" -IsError
}
}

Expand Down
68 changes: 7 additions & 61 deletions Scripts/Deployment/Install-Drivers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,68 +29,14 @@ try {

Write-DeployLog "System: $manufacturer $model"

# Load supported devices
$supportedDellDevices = @()
$supportedHPDevices = @()

$version = "testing"

$dellPath = "C:\WinDeploy\Download\SupportedDellDevices.json"
$hpPath = "C:\WinDeploy\Download\SupportedHPDevices.json"

# Ensure download directory exists
$downloadDir = Split-Path $dellPath
if (!(Test-Path $downloadDir)) {
New-Item -ItemType Directory -Path $downloadDir -Force | Out-Null
}

# Try to copy from local repo first
$dellLocal = Join-Path $PSScriptRoot "..\..\Docs\SupportedDellDevices.json"
$hpLocal = Join-Path $PSScriptRoot "..\..\Docs\SupportedHPDevices.json"

if (Test-Path $dellLocal) {
Copy-Item $dellLocal $dellPath -Force
Write-DeployLog "Copied SupportedDellDevices.json from local repo"
} elseif (!(Test-Path $dellPath)) {
$url = "https://raw.githubusercontent.com/Stensel8/WinDeploy/$version/Docs/SupportedDellDevices.json"
try {
Invoke-WebRequest -Uri $url -OutFile $dellPath -UseBasicParsing -ErrorAction Stop
Write-DeployLog "Downloaded SupportedDellDevices.json"
} catch {
Write-Warning "Failed to download SupportedDellDevices.json"
}
}

if (Test-Path $hpLocal) {
Copy-Item $hpLocal $hpPath -Force
Write-DeployLog "Copied SupportedHPDevices.json from local repo"
} elseif (!(Test-Path $hpPath)) {
$url = "https://raw.githubusercontent.com/Stensel8/WinDeploy/$version/Docs/SupportedHPDevices.json"
try {
Invoke-WebRequest -Uri $url -OutFile $hpPath -UseBasicParsing -ErrorAction Stop
Write-DeployLog "Downloaded SupportedHPDevices.json"
} catch {
Write-Warning "Failed to download SupportedHPDevices.json"
}
}

if (Test-Path $dellPath) {
try {
$supportedDellDevices = Get-Content $dellPath -Raw | ConvertFrom-Json | Where-Object { -not $_.StartsWith("//") }
Write-DeployLog "Loaded Dell list from $dellPath"
} catch {
Write-Warning "Failed to load Dell device list"
}
}

if (Test-Path $hpPath) {
try {
$supportedHPDevices = Get-Content $hpPath -Raw | ConvertFrom-Json | Where-Object { -not $_.StartsWith("//") }
Write-DeployLog "Loaded HP list from $hpPath"
} catch {
Write-Warning "Failed to load HP device list"
}
}
# Embed supported device lists (no more JSON dependency)
$supportedDellDevices = @(
"Latitude", "OptiPlex", "Precision", "XPS", "Venue", "Vostro"
)
$supportedHPDevices = @(
"EliteBook", "ProBook", "ZBook", "EliteDesk", "ProDesk", "EliteOne", "ProOne", "Z2", "Z4", "Z6", "Z8", "Elite Mini", "Elite Tower", "Elite SFF", "Engage One"
)

# Check if supported
$isSupported = $false
Expand Down
10 changes: 10 additions & 0 deletions Scripts/Deployment/Remove-Bloat.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,16 @@ try {

$SuccessMsg = "SUCCESS: Removed $Removed apps."
Write-DeployLog $SuccessMsg


Write-Output ""
Write-Output "========================================"
Write-Output " Additional scripts and tweaks..."
Write-Output "========================================"
Write-Output "Windows Spotlight: If you are experiencing issues with Windows Spotlight, ensure that Start menu recommendations are enabled."
Write-Output "If you are still experiencing issues and want to use the Spotlight features for dynamic wallpapers, use the Fix-Spotlight.ps1 script."
Write-Output "This script is available as an optional download: C:\WinDeploy\Download\Fix-Spotlight.ps1"

# Note: Bloatware may be reinstalled with future Windows Updates. For more control, consider using Winutil: https://github.com/ChrisTitusTech/winutil
Write-DeployLog "Note: Bloatware may be reinstalled with future Windows Updates. For more control, consider using Winutil: `e]8;;https://github.com/ChrisTitusTech/winutil`e\https://github.com/ChrisTitusTech/winutil`e]8;;`e\"
exit 0
Expand Down
6 changes: 6 additions & 0 deletions Scripts/Deployment/Set-HostName.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ Write-Output "Setting hostname."
try {
Write-DeployLog "=== Hostname Setup ==="


$Serial = (Get-CimInstance -ClassName Win32_BIOS).SerialNumber -replace '[^A-Z0-9]', ''
if ([string]::IsNullOrWhiteSpace($Serial) -or $Serial.Length -lt 5) {
Write-DeployLog "No valid serial number found. Unable to set hostname automatically. Please set the hostname manually." -IsError:$true
Write-Output "No serial number found. Please set the computer name manually."
exit 1
}
$LastFive = $Serial.Substring($Serial.Length - 5).ToUpper()
$Hostname = "PC-$LastFive"

Expand Down
Loading