Fix Display sync loop, PPKG deployment, dnsmasq cron, dpkg configure
- Monitor-IntuneProgress: Display PCs skip DSC phases entirely (no SAS token, no DSCInstall.log), complete after Phase 1 identity. Renderer hides Phase 2-5 for Display type. - Playbook: deploy PPKG files and run-enrollment.ps1 from USB to enrollment share. Bump dnsmasq restart cron from 15s to 30s. - build-usb.sh: copy enrollment/ directory (PPKGs) onto USB if present. - user-data: add dpkg --configure -a after offline .deb install to fix packages left in unconfigured state (cron, systemd-timesyncd). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,7 @@ autoinstall:
|
|||||||
cp /mnt/cidata/packages/*.deb /tmp/
|
cp /mnt/cidata/packages/*.deb /tmp/
|
||||||
dpkg -i /tmp/*.deb 2>/dev/null || true
|
dpkg -i /tmp/*.deb 2>/dev/null || true
|
||||||
dpkg -i /tmp/*.deb 2>/dev/null || true
|
dpkg -i /tmp/*.deb 2>/dev/null || true
|
||||||
|
dpkg --configure -a 2>/dev/null || true
|
||||||
if command -v nmcli >/dev/null; then
|
if command -v nmcli >/dev/null; then
|
||||||
systemctl enable NetworkManager
|
systemctl enable NetworkManager
|
||||||
fi
|
fi
|
||||||
@@ -78,6 +79,7 @@ autoinstall:
|
|||||||
if compgen -G "/mnt/usb/packages/*.deb" > /dev/null; then
|
if compgen -G "/mnt/usb/packages/*.deb" > /dev/null; then
|
||||||
dpkg -i /mnt/usb/packages/*.deb 2>/dev/null || true
|
dpkg -i /mnt/usb/packages/*.deb 2>/dev/null || true
|
||||||
dpkg -i /mnt/usb/packages/*.deb 2>/dev/null || true
|
dpkg -i /mnt/usb/packages/*.deb 2>/dev/null || true
|
||||||
|
dpkg --configure -a 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [ -f /mnt/usb/playbook/pxe_server_setup.yml ]; then
|
if [ -f /mnt/usb/playbook/pxe_server_setup.yml ]; then
|
||||||
cd /mnt/usb/playbook
|
cd /mnt/usb/playbook
|
||||||
|
|||||||
12
build-usb.sh
12
build-usb.sh
@@ -270,6 +270,18 @@ else
|
|||||||
echo " No boot-tools/ found (run prepare-boot-tools.sh first)"
|
echo " No boot-tools/ found (run prepare-boot-tools.sh first)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Copy enrollment directory (PPKGs, run-enrollment.ps1) if present
|
||||||
|
ENROLLMENT_DIR="$SCRIPT_DIR/enrollment"
|
||||||
|
if [ -d "$ENROLLMENT_DIR" ]; then
|
||||||
|
mkdir -p "$MOUNT_POINT/enrollment"
|
||||||
|
cp -r "$ENROLLMENT_DIR"/* "$MOUNT_POINT/enrollment/" 2>/dev/null || true
|
||||||
|
PPKG_COUNT=$(find "$MOUNT_POINT/enrollment" -name '*.ppkg' 2>/dev/null | wc -l)
|
||||||
|
ENROLL_SIZE=$(du -sh "$MOUNT_POINT/enrollment" | cut -f1)
|
||||||
|
echo " Copied enrollment/ ($ENROLL_SIZE, $PPKG_COUNT PPKGs)"
|
||||||
|
else
|
||||||
|
echo " No enrollment/ directory found (PPKGs can be uploaded via webapp later)"
|
||||||
|
fi
|
||||||
|
|
||||||
# Optionally copy WinPE deployment images
|
# Optionally copy WinPE deployment images
|
||||||
if [ -n "$WINPE_SOURCE" ] && [ -d "$WINPE_SOURCE" ]; then
|
if [ -n "$WINPE_SOURCE" ] && [ -d "$WINPE_SOURCE" ]; then
|
||||||
echo " Copying WinPE deployment content from $WINPE_SOURCE..."
|
echo " Copying WinPE deployment content from $WINPE_SOURCE..."
|
||||||
|
|||||||
@@ -306,6 +306,19 @@
|
|||||||
state: directory
|
state: directory
|
||||||
mode: '0777'
|
mode: '0777'
|
||||||
|
|
||||||
|
- name: "Deploy PPKG enrollment packages to enrollment share"
|
||||||
|
shell: cp -f {{ usb_mount }}/enrollment/*.ppkg /srv/samba/enrollment/ 2>/dev/null || true
|
||||||
|
args:
|
||||||
|
warn: false
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: "Deploy run-enrollment.ps1 to enrollment share"
|
||||||
|
copy:
|
||||||
|
src: "{{ usb_mount }}/shopfloor-setup/run-enrollment.ps1"
|
||||||
|
dest: /srv/samba/enrollment/run-enrollment.ps1
|
||||||
|
mode: '0644'
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: "Deploy shopfloor setup scripts to enrollment share"
|
- name: "Deploy shopfloor setup scripts to enrollment share"
|
||||||
copy:
|
copy:
|
||||||
src: "{{ usb_mount }}/shopfloor-setup/"
|
src: "{{ usb_mount }}/shopfloor-setup/"
|
||||||
@@ -674,7 +687,7 @@
|
|||||||
dest: /etc/cron.d/dnsmasq-restart
|
dest: /etc/cron.d/dnsmasq-restart
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
content: |
|
content: |
|
||||||
@reboot root /bin/sleep 15 && /usr/bin/systemctl restart dnsmasq.service
|
@reboot root /bin/sleep 30 && /usr/bin/systemctl restart dnsmasq.service
|
||||||
|
|
||||||
# --- Web Management App (Flask) ---
|
# --- Web Management App (Flask) ---
|
||||||
- name: "Create webapp directory"
|
- name: "Create webapp directory"
|
||||||
|
|||||||
@@ -480,44 +480,51 @@ function Format-Snapshot {
|
|||||||
$lines += " $(Mk $Snap.Phase1.IntuneEnrolled) Intune enrolled"
|
$lines += " $(Mk $Snap.Phase1.IntuneEnrolled) Intune enrolled"
|
||||||
$lines += " $(Mk $Snap.Phase1.EmTaskExists) EnterpriseMgmt sync tasks"
|
$lines += " $(Mk $Snap.Phase1.EmTaskExists) EnterpriseMgmt sync tasks"
|
||||||
$lines += " $(Mk $Snap.Phase1.PoliciesArriving) Policies arriving"
|
$lines += " $(Mk $Snap.Phase1.PoliciesArriving) Policies arriving"
|
||||||
$lines += ""
|
|
||||||
$lines += " Phase 2: SFLD configuration"
|
if (-not $skipDsc) {
|
||||||
$lines += " $(Mk $Snap.Phase2.SfldRoot) SFLD reg key"
|
$lines += ""
|
||||||
$lines += " $(Mk $Snap.Phase2.FunctionOk) Function set"
|
$lines += " Phase 2: SFLD configuration"
|
||||||
$lines += " $(Mk $Snap.Phase2.SasTokenOk) DSC SAS token configured"
|
$lines += " $(Mk $Snap.Phase2.SfldRoot) SFLD reg key"
|
||||||
$lines += ""
|
$lines += " $(Mk $Snap.Phase2.FunctionOk) Function set"
|
||||||
$lines += " Phase 3: DSC deployment + install"
|
$lines += " $(Mk $Snap.Phase2.SasTokenOk) DSC SAS token configured"
|
||||||
$lines += " $(Mk $Snap.Phase3.DeployLogExists) DSCDeployment.log present"
|
$lines += ""
|
||||||
$lines += " $(Mk $Snap.Phase3.DeployComplete) Pre-reboot deployment complete"
|
$lines += " Phase 3: DSC deployment + install"
|
||||||
$lines += " $(Mk $Snap.Phase3.InstallLogExists) DSCInstall.log present"
|
$lines += " $(Mk $Snap.Phase3.DeployLogExists) DSCDeployment.log present"
|
||||||
$lines += " $(Mk $Snap.Phase3.InstallComplete) Post-reboot install complete"
|
$lines += " $(Mk $Snap.Phase3.DeployComplete) Pre-reboot deployment complete"
|
||||||
$lines += ""
|
$lines += " $(Mk $Snap.Phase3.InstallLogExists) DSCInstall.log present"
|
||||||
$lines += " Phase 4: Custom scripts (auto-discovered)"
|
$lines += " $(Mk $Snap.Phase3.InstallComplete) Post-reboot install complete"
|
||||||
if (-not $Snap.Phase4 -or $Snap.Phase4.Count -eq 0) {
|
$lines += ""
|
||||||
$lines += " (no Install-*.log files yet in C:\Logs\SFLD)"
|
$lines += " Phase 4: Custom scripts (auto-discovered)"
|
||||||
} else {
|
if (-not $Snap.Phase4 -or $Snap.Phase4.Count -eq 0) {
|
||||||
foreach ($s in $Snap.Phase4) {
|
$lines += " (no Install-*.log files yet in C:\Logs\SFLD)"
|
||||||
$mark = switch ($s.Status) {
|
} else {
|
||||||
'done' { '[v]' }
|
foreach ($s in $Snap.Phase4) {
|
||||||
'running' { '[.]' }
|
$mark = switch ($s.Status) {
|
||||||
'failed' { '[!]' }
|
'done' { '[v]' }
|
||||||
'pending' { '[ ]' }
|
'running' { '[.]' }
|
||||||
default { '[?]' }
|
'failed' { '[!]' }
|
||||||
|
'pending' { '[ ]' }
|
||||||
|
default { '[?]' }
|
||||||
|
}
|
||||||
|
$detail = switch ($s.Status) {
|
||||||
|
'done' { "done $(Format-Age $s.Age) ago" }
|
||||||
|
'running' { "running, last update $(Format-Age $s.Age) ago" }
|
||||||
|
'failed' { "FAILED $(Format-Age $s.Age) ago" }
|
||||||
|
'pending' { "pending" }
|
||||||
|
default { "" }
|
||||||
|
}
|
||||||
|
$name = $s.Name.PadRight(22)
|
||||||
|
$lines += " $mark $name $detail"
|
||||||
}
|
}
|
||||||
$detail = switch ($s.Status) {
|
|
||||||
'done' { "done $(Format-Age $s.Age) ago" }
|
|
||||||
'running' { "running, last update $(Format-Age $s.Age) ago" }
|
|
||||||
'failed' { "FAILED $(Format-Age $s.Age) ago" }
|
|
||||||
'pending' { "pending" }
|
|
||||||
default { "" }
|
|
||||||
}
|
|
||||||
$name = $s.Name.PadRight(22)
|
|
||||||
$lines += " $mark $name $detail"
|
|
||||||
}
|
}
|
||||||
|
$lines += ""
|
||||||
|
$lines += " Phase 5: Final"
|
||||||
|
$lines += " $(Mk $Snap.Phase5.ConsumeCredsTask) SFLD - Consume Credentials task"
|
||||||
|
} else {
|
||||||
|
$lines += ""
|
||||||
|
$lines += " (DSC phases not applicable for $pcType)"
|
||||||
}
|
}
|
||||||
$lines += ""
|
|
||||||
$lines += " Phase 5: Final"
|
|
||||||
$lines += " $(Mk $Snap.Phase5.ConsumeCredsTask) SFLD - Consume Credentials task"
|
|
||||||
$lines += ""
|
$lines += ""
|
||||||
$sinceSync = ((Get-Date) - $LastSync).TotalSeconds
|
$sinceSync = ((Get-Date) - $LastSync).TotalSeconds
|
||||||
$untilNext = ($NextRetrigger - (Get-Date)).TotalSeconds
|
$untilNext = ($NextRetrigger - (Get-Date)).TotalSeconds
|
||||||
@@ -674,6 +681,20 @@ if ($AsTask -and (Test-Path -LiteralPath $syncCompleteMarker)) {
|
|||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# PC types that don't receive DSC (no SAS token, no DSCInstall.log).
|
||||||
|
# For these types, enrollment is "done" once Phase 1 (Identity) completes
|
||||||
|
# and policies start arriving - there is no Phase 2-5 to wait for.
|
||||||
|
$pcTypeFile = 'C:\Enrollment\pc-type.txt'
|
||||||
|
$noDscTypes = @('Display')
|
||||||
|
$skipDsc = $false
|
||||||
|
if (Test-Path $pcTypeFile) {
|
||||||
|
$pcType = (Get-Content $pcTypeFile -First 1).Trim()
|
||||||
|
if ($noDscTypes -contains $pcType) {
|
||||||
|
$skipDsc = $true
|
||||||
|
Write-Host "PC type '$pcType' does not use DSC - will complete after Phase 1."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$qrText = Build-QRCodeText
|
$qrText = Build-QRCodeText
|
||||||
$qrRefreshed = [bool]($qrText -notmatch 'not yet Azure AD joined')
|
$qrRefreshed = [bool]($qrText -notmatch 'not yet Azure AD joined')
|
||||||
@@ -705,6 +726,13 @@ try {
|
|||||||
Invoke-SetupComplete
|
Invoke-SetupComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# No-DSC types (Display, Lab): complete once Phase 1 identity is solid
|
||||||
|
if ($skipDsc -and $snap.Phase1.AzureAdJoined -and $snap.Phase1.IntuneEnrolled -and $snap.Phase1.PoliciesArriving) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Phase 1 complete - no DSC needed for $pcType. Finishing up." -ForegroundColor Green
|
||||||
|
Invoke-SetupComplete
|
||||||
|
}
|
||||||
|
|
||||||
# Reboot check (boot-loop-safe). Only prompt once Phase 1 (Identity),
|
# Reboot check (boot-loop-safe). Only prompt once Phase 1 (Identity),
|
||||||
# Phase 2 (SFLD config), and Phase 3's first two items (deploy log
|
# Phase 2 (SFLD config), and Phase 3's first two items (deploy log
|
||||||
# present + pre-reboot deployment complete) are all green. Don't rush
|
# present + pre-reboot deployment complete) are all green. Don't rush
|
||||||
|
|||||||
Reference in New Issue
Block a user