nordlo.partille.cblifecycle 0.3.0-rc.8
Handles creation, updates and deletion of computer objects representing chromebooks in Active Directory
No packages depend on nordlo.partille.cblifecycle.
Added
examples/Run-ChromebookProvisioning.ps1orchestration wrapper that runsInvoke-PKChromebookPreprovisionandInvoke-PKChromebookLifecyclein series, intended for a 30-minute Task Scheduler cadence. State-file alerting fires mail only onOK ↔ ERRORtransitions (no duplicate alerts when an error persists across many ticks), a named mutex plus the Task Scheduler "no concurrent instances" setting prevent overlap, and a retention pass prunesprocessed/failedartifacts older than-RetentionDayswhile the rolling log is rotated when it crosses-LogRotateSizeMB. Aggregates both functions' structured results into a single exit code.
Changed
examples/Run-ChromebookProvisioning.ps1now performs the Google Workspace device fetch as its first step viaGet-GoogleChromeDevice, writing the result to-CsvPath. New parameters:-ServiceAccountJsonPath,-ImpersonateEmail,-CustomerId,-GoogleFields. If the fetch fails or credentials are missing, the lifecycle pass is skipped (preprovision still runs because it does not depend on Google data) and the run ends with ERROR, which feeds into the existingOK↔ERRORmail transition -- no separateFETCH_FAILEDmail kind. Under-WhatIfthe fetch is skipped (it writes a file) but the rest of the wrapper runs dry as before. The summary text now starts with aGoogle fetchblock andERROR DETAILS:distinguishesGF:(Google fetch),PP:(preprovision) andLC:(lifecycle) so the operator can tell at a glance which step failed.- Wrapper defaults now anchor every path under
C:\CB-LifeCycle\(logs\,googledevices_in\,preprovision\,credentials\, plus state/lock files at the root), and the writable parent directories are auto-created at startup. README adds a "Standard-mapplayout" subsection plus a copy-pasteablemkdirrecipe. - Wrapper detects abnormal termination of the previous run (Task Scheduler force-kill, crash, BSOD, power loss) by checking for a leftover lock file at startup and fires a dedicated
ABNORMAL_ENDmail with the previous run's PID, start time, user and host. Independent of the OK/ERROR state machine so each kill event surfaces exactly once. - README section "Schemaläggning" covering the Task Scheduler recipe (including the 25-minute "stop the task if it runs longer than" setting that bounds hung runs), service-account permissions, the OK↔ERROR alerting table plus the
ABNORMAL_ENDnotification, single-instance lock semantics, and retention/rotation tuning knobs. - New exported function
Invoke-PKChromebookPreprovisionfor pre-creating AD computer accounts from a watched folder of serial-number lists (*.txt,*.lst,*.csvwithserial/serialNumbercolumn). Designed for school-start onboarding so devices can obtain a NPS/RADIUS certificate immediately after MDM enrollment, without waiting for the Google Admin Console export. Source files are moved toprocessed\(orfailed\) and accompanied by a per-file.log(one status line per serial) and-summary.txt(totals and error excerpts). Returns a structured result object withFilesProcessed,FilesFailed,SerialsRead,SerialsCreated,SerialsSkipped,GroupAddErrors,Errors,ErrorMessages,AdCountBefore/After. -DescriptionMarkerPrefixparameter (defaultPREPROVISIONED) on bothInvoke-PKChromebookPreprovisionandInvoke-PKChromebookLifecycle. Pre-provisioned accounts getDescription = "<prefix> <date> [<source-file>]". The lifecycle deletion pass excludes any account whose Description starts with the prefix, and logs a single summary line (event 1204) listing how many were protected.- "Claim" event on
Invoke-PKChromebookLifecycle: when an existing account whose Description starts with-DescriptionMarkerPrefixis matched against anACTIVECSV row, event 1142 is logged. The lifecycle's existing Description-diff path then overwrites the marker with the normalSchool - Class - Studentvalue, self-clearing the protection. - Event IDs 1150 / 1151 / 1152 / 1154 / 1160 / 1161 - preprovision created / create error / skipped (already in AD) / group-add / file OK / file failed.
- Return-object fields on
Invoke-PKChromebookLifecycle:Claimed,PreprovisionedProtected. - README section "Pre-provisionering" covering folder layout, txt/csv input formats, protection semantics and combined scheduled-task usage.
- SPN registration on
Invoke-PKChromebookLifecycle. Every account is ensured to carryhost/<serial>andhost/<serial>.<DnsDomain>onservicePrincipalName. SPNs are written atomically at creation viaNew-ADComputer -OtherAttributesand ensured on existing accounts viaSet-ADComputer -Add(add-only: other SPNs already on the object are left alone). AddsSpnsAddedto the return object andSPN additionsto the run summary. - Event IDs 1140 / 1141 - SPN added to AD account / error adding SPN.
-MatchAttributeparameter onInvoke-PKChromebookLifecycle(defaultextensionAttribute1) - AD attribute holding the Chromebook serial number, used as the identity key for matching and for TameMyCerts certificate-to-account resolution. Validated at startup against the AD schema (must exist and be single-valued) to catch typos.-SamAccountPrefixparameter (defaultCB-) - prefix for the generated SAM name.-Serverparameter - pins all AD operations to a single DC (defaults to the PDC emulator) to avoid replication-delay races between consecutive reads/writes.-OrgUnitGroupMapparameter - hashtable ofregex pattern -> single AD group. Devices whoseorgUnitPathmatches a pattern are added to the associated group; memberships are reconciled (a device is removed from a rule's group once itsorgUnitPathno longer matches). Reconciliation is bounded to groups listed in the map;-MemberOfgroups are still add-only. Conflicts between-MemberOfand-OrgUnitGroupMapthrow at startup. Invalid regex or missing groups also throw at startup.- Disable/re-enable lifecycle driven by CSV
statuscolumn. Non-ACTIVErows (e.g.DEPROVISIONED,DISABLED) disable the matching AD account if it exists; missing AD accounts for non-ACTIVEdevices are not created. Accounts whose CSV status returns toACTIVEare re-enabled. Inactive serials are excluded from the deletion pass (still present in CSV). - Return object fields:
Disabled,Reenabled,InactiveCount. - Event ID 1102 - legacy account detected (no value in
-MatchAttribute), create skipped to avoid duplicates. - Event IDs 1122 / 1123 - account removed from AD group (OU-rule reconcile) / error removing from group.
- Event IDs 1130 / 1131 - AD account disabled (CSV status not
ACTIVE) / error disabling. - Event IDs 1132 / 1133 - AD account re-enabled (CSV status returned to
ACTIVE) / error re-enabling. - README section on registering the Windows Event Log source manually (for scheduled-task service accounts without local admin).
Changed
Invoke-PKChromebookLifecyclenow matches AD accounts via-MatchAttributeinstead of byName/sAMAccountName. New accounts get a randomly generatedsAMAccountNameof the formCB-<11 hex chars>(14 characters), decoupled from the Chromebook serial number — which is now stored in the attribute named by-MatchAttribute. The 15-character NetBIOS limit applies only to the generated SAM name; serial numbers of any length are supported.DNSHostNameis built from<serialNumber>.<DnsDomain>(was<samName>.<DnsDomain>) so Google MDM WiFi profiles authenticate against the correct hostname at NPS/RADIUS. Cert-to-AD matching is unaffected — it still resolves via-MatchAttribute.- CSV gating column changed from
provisionStatus=PROVISIONEDtostatus=ACTIVEto match the actual Google Admin Console export schema. - Account creation is now atomic:
MatchAttributeand all-AttributeMapvalues are written viaNew-ADComputer -OtherAttributes, eliminating the previous create-then-set race that could leave orphan accounts. - Renamed
Get-GoogleChromeDevicestoGet-GoogleChromeDevice(singular noun per PowerShell conventions). File renamed to match.[OutputType]declared. - Upgraded module scaffold (build pipeline, VS Code tasks, PSScriptAnalyzer settings, generic tests) to the latest templates.
- Introduced
GitVersion.ymlfor automated versioning. - Event Log writes use
[System.Diagnostics.EventLog]::WriteEntry(...)instead ofWrite-EventLog(which was removed fromMicrosoft.PowerShell.Managementin PowerShell 7). Removed the now-unusedEventLogNameparameter fromWrite-CbLog.
Fixed
Invoke-PKChromebookPreprovisionno longer writes per-file.logand-summary.txtartifacts under-WhatIf. Those files imply concrete results (created / skipped serials, totals) and were misleading on dry runs. The rolling Write-CbLog audit trail is still written under-WhatIfper the entry below.- Log file writes (
Out-FileinWrite-CbLogand the run summary) no longer suppressed by-WhatIf— the audit trail is always written, even in dry runs. Import-Module ActiveDirectoryno longer emits implicit-remoting proxy-copyWhat if:noise under-WhatIf.$WhatIfPreferenceis temporarily cleared around the import (and restored immediately after) so the temporaryremoteIpMoProxy_*file copies don't inherit it. Wrapped intry/catchto surface a clear error if RSAT is missing.
Migration
- TameMyCerts policy must be repointed to
<DirectoryServicesAttribute>extensionAttribute1</DirectoryServicesAttribute>(or the attribute chosen via-MatchAttribute). Coordinated outside this module. - Existing accounts from prior versions are handled by delete-and-recreate, and require two runs because deletion happens after create/update inside a single invocation:
- Run 1 with
-EnableDeletion(add-ForceDeleteif over the safety threshold): legacy accounts trigger event 1102 and are skipped for creation, then removed by the deletion pass. - Run 2: legacy accounts are gone, new
CB-<hex>accounts are created.
- Run 1 with
- Tip: dry-run with
-WhatIf -EnableDeletionfirst to count legacy accounts before deciding on-ForceDelete. - Accounts already on the new
CB-<hex>scheme but with<samName>.<DnsDomain>DNSHostName will be migrated to<serial>.<DnsDomain>in-place on the next run (event 1110 with aDNSHostName: ... -> ...change). Expect a one-shot batch of "updated" accounts.
Known gaps
- No Pester tests covering the new naming behaviour (legacy detection, conflict guard, SAM prefix validation, DNSHostName regen). To follow up in a separate change.
This package has no dependencies.
| Version | Downloads | Last updated |
|---|---|---|
| 0.5.0-rc.1 | 2 | 07/01/2026 |
| 0.4.0-rc.3 | 2 | 07/01/2026 |
| 0.4.0-rc.2 | 1 | 07/01/2026 |
| 0.4.0-rc.1 | 2 | 07/01/2026 |
| 0.3.0 | 1 | 06/25/2026 |
| 0.3.0-rc.21 | 1 | 07/01/2026 |
| 0.3.0-rc.20 | 1 | 06/23/2026 |
| 0.3.0-rc.19 | 1 | 06/23/2026 |
| 0.3.0-rc.18 | 2 | 06/22/2026 |
| 0.3.0-rc.17 | 2 | 06/17/2026 |
| 0.3.0-rc.16 | 8 | 06/17/2026 |
| 0.3.0-rc.15 | 2 | 06/17/2026 |
| 0.3.0-rc.14 | 1 | 06/17/2026 |
| 0.3.0-rc.13 | 2 | 06/17/2026 |
| 0.3.0-rc.12 | 2 | 06/17/2026 |
| 0.3.0-rc.11 | 3 | 06/17/2026 |
| 0.3.0-rc.10 | 2 | 06/17/2026 |
| 0.3.0-rc.9 | 1 | 06/16/2026 |
| 0.3.0-rc.8 | 1 | 06/16/2026 |
| 0.3.0-rc.7 | 2 | 06/12/2026 |
| 0.3.0-rc.6 | 8 | 06/09/2026 |