2026-03-30 19:45:21 +00:00
|
|
|
#Requires -RunAsAdministrator
|
|
|
|
|
<#
|
|
|
|
|
.SYNOPSIS
|
|
|
|
|
MABDC Domain Join Script
|
|
|
|
|
.DESCRIPTION
|
|
|
|
|
Joins a Windows 11 Pro/Enterprise PC to the MABDC domain,
|
|
|
|
|
installs Chocolatey, adds the MABDC package feed, and
|
|
|
|
|
triggers auto-provisioning of all base packages.
|
|
|
|
|
.NOTES
|
|
|
|
|
Run as Administrator on a fresh Windows 11 Pro/Enterprise PC.
|
|
|
|
|
Requires internet access to dc1.mabdc.org and repo.mabdc.com.
|
|
|
|
|
#>
|
|
|
|
|
|
|
|
|
|
param(
|
|
|
|
|
[Parameter(Mandatory=$true)]
|
2026-03-30 20:34:26 +00:00
|
|
|
[ValidateSet("IT","Accounting","Design","Management","Teaching","Admin")]
|
2026-03-30 19:45:21 +00:00
|
|
|
[string]$Department,
|
|
|
|
|
|
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
|
|
|
[string]$PCName,
|
|
|
|
|
|
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
|
|
|
[string]$AdminUser = "Administrator",
|
|
|
|
|
|
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
|
|
|
[string]$DomainName = "mabdc.org"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
|
$LogFile = "C:\MABDC\Logs\domain-join.log"
|
2026-03-30 20:34:26 +00:00
|
|
|
$WebhookUrl = "https://webhooks.tasklet.ai/v1/public/webhook?token=64e387124cc212b5231a29d04c6e09aa"
|
2026-03-30 19:45:21 +00:00
|
|
|
|
|
|
|
|
function Write-Log {
|
|
|
|
|
param([string]$Message)
|
|
|
|
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
|
|
|
$entry = "[$timestamp] $Message"
|
|
|
|
|
Write-Host $entry -ForegroundColor Green
|
2026-03-30 20:34:26 +00:00
|
|
|
$null = New-Item -ItemType Directory -Path (Split-Path $LogFile) -Force -ErrorAction SilentlyContinue
|
2026-03-30 19:45:21 +00:00
|
|
|
Add-Content -Path $LogFile -Value $entry -ErrorAction SilentlyContinue
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
function Send-WebhookNotification {
|
|
|
|
|
param([hashtable]$Data)
|
|
|
|
|
try {
|
|
|
|
|
$body = $Data | ConvertTo-Json -Compress
|
|
|
|
|
Invoke-RestMethod -Uri $WebhookUrl -Method POST -Body $body -ContentType "application/json" -UseBasicParsing -ErrorAction SilentlyContinue | Out-Null
|
|
|
|
|
Write-Log "Webhook notification sent"
|
|
|
|
|
} catch {
|
|
|
|
|
Write-Log "Warning: Could not send webhook notification: $_"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 19:45:21 +00:00
|
|
|
# Pre-flight checks
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "=== MABDC Domain Join Script v1.1 ==="
|
2026-03-30 19:45:21 +00:00
|
|
|
Write-Log "Starting pre-flight checks..."
|
|
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
# Ensure log directory exists
|
|
|
|
|
$null = New-Item -ItemType Directory -Path "C:\MABDC\Logs" -Force -ErrorAction SilentlyContinue
|
|
|
|
|
|
2026-03-30 19:45:21 +00:00
|
|
|
# Check Windows edition
|
|
|
|
|
$edition = (Get-WindowsEdition -Online).Edition
|
|
|
|
|
if ($edition -match "Home|Core") {
|
|
|
|
|
Write-Host "ERROR: Windows 11 Home cannot join a domain. You need Pro or Enterprise." -ForegroundColor Red
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Windows Edition: $edition OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
|
|
|
|
|
# Check if already domain-joined
|
|
|
|
|
$currentDomain = (Get-WmiObject Win32_ComputerSystem).Domain
|
|
|
|
|
if ($currentDomain -eq $DomainName) {
|
|
|
|
|
Write-Log "PC is already joined to $DomainName. Skipping domain join."
|
|
|
|
|
} else {
|
|
|
|
|
Write-Log "Current domain: $currentDomain (will join $DomainName)"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Create MABDC directories
|
|
|
|
|
$dirs = @("C:\MABDC", "C:\MABDC\Config", "C:\MABDC\Logs", "C:\MABDC\Wallpapers", "C:\MABDC\Scripts", "C:\MABDC\Certs")
|
|
|
|
|
foreach ($dir in $dirs) {
|
|
|
|
|
if (!(Test-Path $dir)) {
|
|
|
|
|
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
|
|
|
|
Write-Log "Created $dir"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Set PC name if provided
|
|
|
|
|
if ($PCName) {
|
|
|
|
|
$currentName = $env:COMPUTERNAME
|
|
|
|
|
if ($currentName -ne $PCName) {
|
|
|
|
|
Rename-Computer -NewName $PCName -Force
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "PC renamed to $PCName (will apply after reboot)"
|
2026-03-30 19:45:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Configure DNS to point to AD server
|
|
|
|
|
Write-Log "Configuring DNS..."
|
|
|
|
|
$adapters = Get-NetAdapter | Where-Object Status -EQ 'Up'
|
|
|
|
|
foreach ($adapter in $adapters) {
|
|
|
|
|
Set-DnsClientServerAddress -InterfaceIndex $adapter.ifIndex -ServerAddresses ("159.195.41.59", "45.90.28.0")
|
|
|
|
|
Write-Log "DNS set on adapter: $($adapter.Name)"
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
# Flush DNS cache
|
|
|
|
|
Clear-DnsClientCache
|
|
|
|
|
Write-Log "DNS cache flushed"
|
|
|
|
|
|
2026-03-30 19:45:21 +00:00
|
|
|
# Test AD connectivity
|
|
|
|
|
Write-Log "Testing connection to AD server..."
|
|
|
|
|
$adTest = Test-NetConnection -ComputerName "dc1.mabdc.org" -Port 389 -WarningAction SilentlyContinue
|
|
|
|
|
if ($adTest.TcpTestSucceeded) {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "AD server reachable on LDAP (389) OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
} else {
|
|
|
|
|
Write-Log "WARNING: Cannot reach AD server on port 389. Trying port 636 (LDAPS)..."
|
|
|
|
|
$adTest2 = Test-NetConnection -ComputerName "dc1.mabdc.org" -Port 636 -WarningAction SilentlyContinue
|
|
|
|
|
if ($adTest2.TcpTestSucceeded) {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "AD server reachable on LDAPS (636) OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
} else {
|
|
|
|
|
Write-Host "ERROR: Cannot reach AD server. Check network/firewall." -ForegroundColor Red
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Join domain (if not already joined)
|
|
|
|
|
if ($currentDomain -ne $DomainName) {
|
|
|
|
|
Write-Log "Joining domain $DomainName..."
|
2026-03-30 20:34:26 +00:00
|
|
|
$cred = Get-Credential -Message "Enter domain admin credentials for $DomainName (e.g. MABDC\Administrator)"
|
2026-03-30 19:45:21 +00:00
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
# OU path: department sub-OU under Staff
|
|
|
|
|
$ouPath = "OU=$Department,OU=Staff,DC=mabdc,DC=org"
|
2026-03-30 19:45:21 +00:00
|
|
|
try {
|
2026-03-30 20:34:26 +00:00
|
|
|
Add-Computer -DomainName $DomainName -OUPath $ouPath -Credential $cred -Force -ErrorAction Stop
|
|
|
|
|
Write-Log "Successfully joined $DomainName in $ouPath OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
} catch {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Could not join with OU path ($ouPath), trying default OU..."
|
2026-03-30 19:45:21 +00:00
|
|
|
Add-Computer -DomainName $DomainName -Credential $cred -Force
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Successfully joined $DomainName (default OU) OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
}
|
2026-03-30 20:34:26 +00:00
|
|
|
} else {
|
|
|
|
|
Write-Log "Already in domain - skipping domain join"
|
2026-03-30 19:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Install Chocolatey
|
|
|
|
|
Write-Log "Installing Chocolatey package manager..."
|
|
|
|
|
if (!(Get-Command choco -ErrorAction SilentlyContinue)) {
|
|
|
|
|
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
|
|
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
|
|
|
|
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Chocolatey installed OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
} else {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Chocolatey already installed OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Refresh PATH
|
|
|
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
|
|
|
|
|
|
|
|
# Add MABDC Chocolatey source
|
|
|
|
|
Write-Log "Adding MABDC package repository..."
|
2026-03-30 20:34:26 +00:00
|
|
|
choco source add --name=mabdc --source="https://repo.mabdc.com/api/packages/mabdc/nuget/v2" --priority=1 -y 2>&1 | Out-Null
|
|
|
|
|
Write-Log "MABDC repo added OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
# Install base packages from public Chocolatey
|
|
|
|
|
Write-Log "Installing base packages..."
|
2026-03-30 19:45:21 +00:00
|
|
|
|
|
|
|
|
$basePackages = @(
|
2026-03-30 20:34:26 +00:00
|
|
|
@{name="googlechrome"; source="chocolatey"},
|
|
|
|
|
@{name="7zip"; source="chocolatey"},
|
|
|
|
|
@{name="notepadplusplus"; source="chocolatey"},
|
|
|
|
|
@{name="vlc"; source="chocolatey"}
|
2026-03-30 19:45:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
foreach ($pkg in $basePackages) {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Installing $($pkg.name)..."
|
|
|
|
|
choco install $pkg.name --source=$($pkg.source) -y --no-progress 2>&1 | Out-Null
|
2026-03-30 19:45:21 +00:00
|
|
|
if ($LASTEXITCODE -eq 0) {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "$($pkg.name) installed OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
} else {
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "WARNING: $($pkg.name) may have had issues (exit code: $LASTEXITCODE)"
|
2026-03-30 19:45:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
# Try MABDC-specific packages (optional - skip if not available)
|
|
|
|
|
Write-Log "Checking for MABDC department packages..."
|
|
|
|
|
$mabdcPackages = @("mabdc-base-config", "mabdc-wallpaper", "mabdc-rustdesk")
|
|
|
|
|
foreach ($pkg in $mabdcPackages) {
|
|
|
|
|
$available = choco search $pkg --source=mabdc --exact 2>&1 | Select-String -Pattern $pkg -Quiet
|
|
|
|
|
if ($available) {
|
|
|
|
|
choco install $pkg --source=mabdc -y --no-progress 2>&1 | Out-Null
|
|
|
|
|
Write-Log "$pkg installed OK"
|
|
|
|
|
} else {
|
|
|
|
|
Write-Log "Skipping $pkg (not yet published in MABDC repo)"
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-30 19:45:21 +00:00
|
|
|
|
|
|
|
|
# Set up auto-update scheduled task
|
|
|
|
|
Write-Log "Setting up automatic package updates..."
|
|
|
|
|
$action = New-ScheduledTaskAction -Execute "choco" -Argument "upgrade all -y --source=mabdc --no-progress"
|
|
|
|
|
$trigger = New-ScheduledTaskTrigger -Daily -At "2:00AM"
|
|
|
|
|
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -DontStopOnIdleEnd
|
|
|
|
|
Register-ScheduledTask -TaskName "MABDC-AutoUpdate" -Action $action -Trigger $trigger -Settings $settings -User "SYSTEM" -RunLevel Highest -Force | Out-Null
|
2026-03-30 20:34:26 +00:00
|
|
|
Write-Log "Auto-update scheduled for 2:00 AM daily OK"
|
2026-03-30 19:45:21 +00:00
|
|
|
|
|
|
|
|
# Save join metadata
|
|
|
|
|
$metadata = @{
|
2026-03-30 20:34:26 +00:00
|
|
|
pcName = $env:COMPUTERNAME
|
|
|
|
|
department = $Department
|
|
|
|
|
joinedAt = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
|
|
|
|
|
joinedBy = $env:USERNAME
|
2026-03-30 19:45:21 +00:00
|
|
|
windowsEdition = $edition
|
|
|
|
|
windowsVersion = [System.Environment]::OSVersion.Version.ToString()
|
2026-03-30 20:34:26 +00:00
|
|
|
domainName = $DomainName
|
|
|
|
|
ouPath = "OU=$Department,OU=Staff,DC=mabdc,DC=org"
|
|
|
|
|
status = "provisioned"
|
2026-03-30 19:45:21 +00:00
|
|
|
} | ConvertTo-Json -Depth 3
|
2026-03-30 20:34:26 +00:00
|
|
|
|
2026-03-30 19:45:21 +00:00
|
|
|
Set-Content -Path "C:\MABDC\Config\join-metadata.json" -Value $metadata -Force
|
|
|
|
|
|
2026-03-30 20:34:26 +00:00
|
|
|
# Notify webhook
|
|
|
|
|
Send-WebhookNotification -Data @{
|
|
|
|
|
event = "pc_provisioned"
|
|
|
|
|
pcName = $env:COMPUTERNAME
|
|
|
|
|
department = $Department
|
|
|
|
|
domain = $DomainName
|
|
|
|
|
status = "success"
|
|
|
|
|
timestamp = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Write-Host ""
|
|
|
|
|
Write-Host " =============================================" -ForegroundColor Cyan
|
|
|
|
|
Write-Host " MABDC Domain Join Complete!" -ForegroundColor Green
|
|
|
|
|
Write-Host " Domain : $DomainName" -ForegroundColor White
|
|
|
|
|
Write-Host " Department: $Department" -ForegroundColor White
|
|
|
|
|
Write-Host " PC Name : $env:COMPUTERNAME" -ForegroundColor White
|
|
|
|
|
Write-Host " OU : OU=$Department,OU=Staff" -ForegroundColor White
|
|
|
|
|
Write-Host " =============================================" -ForegroundColor Cyan
|
|
|
|
|
Write-Host ""
|
|
|
|
|
Write-Log "Provisioning complete."
|
|
|
|
|
|
|
|
|
|
$restart = Read-Host "Restart now to complete domain join? (Y/N)"
|
2026-03-30 19:45:21 +00:00
|
|
|
if ($restart -eq 'Y' -or $restart -eq 'y') {
|
|
|
|
|
Restart-Computer -Force
|
|
|
|
|
}
|