S: drive mapping via HKLM\Run, autologon-count non-intervention, Phase 4 no-scripts handling

- Register-MapSfldShare.ps1: swap scheduled task for HKLM\Run entry. Task with -GroupId runs in session 0 with no HKCU, so /persistent:yes fails and the drive mapping isn't visible to Explorer. Run key fires at Explorer startup in the interactive user's session with full token + HKCU. Unregisters legacy 'GE Shopfloor Map S: Drive' task for PCs already imaged.
- Run-ShopfloorSetup.ps1: stop bumping AutoLogonCount (99 at start, 4 at end). Windows decrements per-logon and at 0 clears AutoAdminLogon + DefaultPassword, which nukes the lockdown-configured ShopFloor autologon. Re-enable-wired-NICs task now gates on Autologon_Remediation.log 'Autologon set for ShopFloor' instead of SFLD creds, so wired stays off through the whole Intune+DSC+lockdown chain.
- Monitor-IntuneProgress.ps1: Phase 4 treats 'no custom scripts' as COMPLETE when DSC install is done (was WAITING, which stalled the state machine on PC types without scripts). Push retrigger out to 15min when entering lockdown-wait so a stale 5min retrigger doesn't fire mid-Remediation. Removed the AutoLogonCount delete in Invoke-SetupComplete since we no longer set it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-04-16 17:42:22 -04:00
parent 2ab6055125
commit 6e85e19c85
3 changed files with 70 additions and 70 deletions

View File

@@ -1,12 +1,18 @@
# Register-MapSfldShare.ps1 - Stage Map-SfldShare.ps1 + register a logon
# task that maps S: for any user in BUILTIN\Users (SupportUser, ShopFloor,
# any future end-user accounts).
# Register-MapSfldShare.ps1 - Stage Map-SfldShare.ps1 + register an
# HKLM\Run entry that maps S: for any interactive user (SupportUser,
# ShopFloor, any future end-user accounts).
#
# Why HKLM\Run instead of a scheduled task: Run fires at Explorer
# startup in the logged-in user's interactive session with their full
# token + HKCU mounted. No principal/LogonType/group-SID plumbing, no
# "task fires in session 0 but drive not visible to Explorer" class of
# bugs. Works for every BUILTIN\Users member with no extra logic.
#
# Why not the vendor's ConsumeCredentials.ps1: it calls
# New-StoredCredential -Persist LocalMachine (needs admin) before net use.
# ShopFloor is non-admin, so the cred-store fails and net use has no auth.
# Our Map-SfldShare.ps1 reads HKLM creds directly and passes them inline
# to net use /user: -- no Credential Manager needed, works as Limited.
# New-StoredCredential -Persist LocalMachine (needs admin) before net
# use. ShopFloor is non-admin, so the cred-store fails and net use has
# no auth. Our Map-SfldShare.ps1 reads HKLM creds directly and passes
# them inline to net use /user: -- no Credential Manager needed.
$ErrorActionPreference = 'Continue'
@@ -14,6 +20,10 @@ $installRoot = 'C:\Program Files\GE\SfldShare'
$mapScript = Join-Path $installRoot 'Map-SfldShare.ps1'
$logDir = 'C:\Logs\SFLD'
$logFile = Join-Path $logDir 'register-mapshare.log'
$runKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
$runValue = 'GE Map SFLD Share'
$legacyTask = 'GE Shopfloor Map S: Drive'
if (-not (Test-Path $logDir)) { New-Item -Path $logDir -ItemType Directory -Force | Out-Null }
function Write-RegLog {
@@ -38,39 +48,30 @@ if (Test-Path $src) {
exit 1
}
# Remove the legacy scheduled task if it exists (left behind by older
# imaging runs that used the scheduled-task approach).
if (Get-ScheduledTask -TaskName $legacyTask -ErrorAction SilentlyContinue) {
try {
Unregister-ScheduledTask -TaskName $legacyTask -Confirm:$false -ErrorAction Stop
Write-RegLog "Removed legacy scheduled task '$legacyTask'"
} catch {
Write-RegLog "Failed to remove legacy task '$legacyTask': $_"
}
}
# Register HKLM\Run entry. Runs at Explorer startup for every
# interactive user in that user's session.
try {
$action = New-ScheduledTaskAction `
-Execute 'powershell.exe' `
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$mapScript`""
$command = '"{0}" -NoProfile -ExecutionPolicy Bypass -File "{1}"' -f `
"$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe", $mapScript
$trigger = New-ScheduledTaskTrigger -AtLogOn
# BUILTIN\Users + Limited: any logged-in user triggers it; action
# runs in that user's session so net use lands the drive in the
# right place.
$principal = New-ScheduledTaskPrincipal -GroupId 'S-1-5-32-545' -RunLevel Limited
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-StartWhenAvailable `
-ExecutionTimeLimit (New-TimeSpan -Minutes 5)
Write-RegLog "Registering 'GE Shopfloor Map S: Drive' (logon trigger, BUILTIN\Users -> $vendorScript)"
Register-ScheduledTask `
-TaskName 'GE Shopfloor Map S: Drive' `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Settings $settings `
-Force `
-Description 'Map SFLD share drives on any user logon using HKLM creds (parallel to the principal-restricted vendor task) so ShopFloor and other end-user accounts get S: mapped' `
-ErrorAction Stop | Out-Null
Write-RegLog 'Scheduled task registered'
if (-not (Test-Path $runKey)) {
New-Item -Path $runKey -Force | Out-Null
}
New-ItemProperty -Path $runKey -Name $runValue -Value $command -PropertyType String -Force | Out-Null
Write-RegLog "Set $runKey\$runValue = $command"
} catch {
Write-RegLog "FAILED to register task: $_"
Write-RegLog "FAILED to register Run key: $_"
exit 1
}

View File

@@ -601,13 +601,19 @@ function Format-Snapshot {
@{ Ok = $Snap.Phase3.InstallComplete; Failed = $false }
)
$p4HasFailed = $false; $p4AllDone = $true; $p4AnyStarted = $false
if ($Snap.Phase4 -and $Snap.Phase4.Count -gt 0) {
$p4HasScripts = ($Snap.Phase4 -and $Snap.Phase4.Count -gt 0)
if ($p4HasScripts) {
foreach ($s in $Snap.Phase4) {
if ($s.Status -eq 'failed') { $p4HasFailed = $true }
if ($s.Status -ne 'done') { $p4AllDone = $false }
if ($s.Status -ne 'pending') { $p4AnyStarted = $true }
}
} else { $p4AllDone = $false }
} else {
# No scripts discovered. If DSC install is already complete,
# there are simply no custom scripts for this image type --
# that's COMPLETE, not WAITING.
$p4AllDone = $Snap.Phase3.InstallComplete
}
$p4Status = if ($p4HasFailed) { 'FAILED' } elseif ($p4AllDone) { 'COMPLETE' } elseif ($p4AnyStarted) { 'IN PROGRESS' } else { 'WAITING' }
$p5Done = ($Snap.Phase5.ConsumeCredsTask -and $Snap.Phase5.CredsPopulated)
@@ -736,15 +742,6 @@ function Invoke-SetupComplete {
try { & $ConfigureScript -MachineNumberOnly } catch { Write-Warning "Configure-PC failed: $_" }
}
# Delete AutoLogonCount so it can't deplete and nuke ShopFloor's
# autologon. Run-ShopfloorSetup set it to 4 for the SupportUser
# imaging chain; Windows decrements per-logon and at 0 clears
# AutoAdminLogon + DefaultPassword, breaking the lockdown-set
# ShopFloor autologon. Removing the value entirely leaves the
# lockdown's Autologon.exe-configured autologon intact forever.
& reg.exe delete 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' /v AutoLogonCount /f 2>$null | Out-Null
Write-Host "Cleared AutoLogonCount (ShopFloor autologon will persist)."
# Reboot so Winlogon's new DefaultUserName=ShopFloor kicks in -
# autologon only fires at the logon boundary. Next boot brings up
# a clean ShopFloor session; this task will fire again for that
@@ -925,6 +922,12 @@ try {
}
$currentInterval = if ($waitingForLockdownOnly) { 15 } else { $RetriggerMinutes }
# If we just entered lockdown-wait and the existing countdown is
# shorter than 15 min, push it out immediately so we don't fire
# a stale 5-min retrigger mid-Remediation.
$minNext = $lastSync.AddMinutes($currentInterval)
if ($minNext -gt $nextRetrigger) { $nextRetrigger = $minNext }
if ((Get-Date) -ge $nextRetrigger) {
Write-Host ""
Write-Host "Re-triggering Intune sync..." -ForegroundColor Cyan