Skip to content

Commit 76c1b64

Browse files
committed
feat(orchestrator): add module tests, internalize summary, fix Fast Pester fallback, manifest prerelease
1 parent 17f68fa commit 76c1b64

12 files changed

Lines changed: 217 additions & 50 deletions

File tree

.github/workflows/build-orchestrator.yml

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,29 @@ on:
33
push:
44
tags:
55
- 'orchestrator-v*'
6-
pull_request:
7-
paths:
8-
- 'EasyPIM.Orchestrator/**'
6+
release:
7+
types: [published]
98

109
jobs:
1110
build-orchestrator:
1211
runs-on: windows-latest
1312
steps:
1413
- uses: actions/checkout@v1
14+
1515
- name: Install EasyPIM Core from Gallery
1616
run: Install-Module -Name EasyPIM -Force -Scope CurrentUser
1717
shell: pwsh
18+
1819
- name: Install Prerequisites
1920
run: .\build\vsts-prerequisites.ps1
20-
shell: powershell
21-
- name: Install EasyPIM Core from Gallery
22-
run: Install-Module -Name EasyPIM -Force -Scope CurrentUser
2321
shell: pwsh
2422

23+
- name: Validate
24+
run: .\build\vsts-validate.ps1
25+
shell: pwsh
2526

26-
- name: Build Orchestrator Only
27-
run: |
28-
if ("${{ github.event.before }}" -eq "0000000000000000000000000000000000000000") {
29-
Write-Host 'Tag push or first commit: running build.'
30-
.\EasyPIM.Orchestrator\build\vsts-build-orchestrator.ps1 -ApiKey $env:APIKEY
31-
} else {
32-
$changed = git diff --name-only ${{ github.event.before }} ${{ github.sha }} | Select-String -Pattern '^EasyPIM.Orchestrator/'
33-
if ($changed) { .\EasyPIM.Orchestrator\build\vsts-build-orchestrator.ps1 -ApiKey $env:APIKEY } else { Write-Host 'No Orchestrator changes detected, skipping build.' }
34-
}
27+
- name: Build Orchestrator
28+
run: .\EasyPIM.Orchestrator\build\vsts-build-orchestrator.ps1 -ApiKey $env:APIKEY
3529
shell: pwsh
3630
env:
3731
APIKEY: ${{ secrets.ApiKey }}
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
@{
22
RootModule = 'EasyPIM.Orchestrator.psm1'
3-
ModuleVersion = '0.1.0-beta1'
3+
ModuleVersion = '0.1.0'
44
GUID = 'b6f9b3c9-bc6a-4d4b-8c51-7c45d42157cd'
55
Author = 'Loïc MICHEL'
66
CompanyName = 'EasyPIM'
7-
Copyright = '(c) loicmichel. All rights reserved.'
7+
Copyright = '(c) Loïc MICHEL. All rights reserved.'
88
Description = 'Orchestrator for EasyPIM (Invoke-EasyPIMOrchestrator)'
99
PowerShellVersion = '5.1'
1010
RequiredModules = @('EasyPIM')
1111
FunctionsToExport = @(
1212
'Invoke-EasyPIMOrchestrator',
13-
'Test-PIMPolicyDrift'
13+
'Test-PIMPolicyDrift',
14+
'Test-PIMEndpointDiscovery'
1415
)
1516
AliasesToExport = @()
1617
CmdletsToExport = @()
17-
PrivateData = @{ PSData = @{
18+
PrivateData = @{ PSData =@{
1819
Tags = @('EasyPIM','Orchestrator')
1920
ProjectUri = 'https://github.com/kayasax/EasyPIM'
2021
LicenseUri = 'https://github.com/kayasax/EasyPIM/blob/main/LICENSE'
21-
ReleaseNotes = @'
22-
PRE-RELEASE: This is a beta version of the EasyPIM.Orchestrator module. It is not intended for production use and may change without notice.
23-
Use for testing and feedback only. Breaking changes may occur before the first stable release.
24-
'@
22+
Prerelease = 'beta4'
23+
ReleaseNotes = @'
24+
PRE-RELEASE: This is a beta version of the EasyPIM.Orchestrator module. It is not intended for production use and may change without notice.
25+
Use for testing and feedback only. Breaking changes may occur before the first stable release.
26+
'@
2527
} }
2628
}

EasyPIM.Orchestrator/EasyPIM.Orchestrator.psm1

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,20 @@ $easyPIMDir = Join-Path $root 'EasyPIM'
77
# Source public orchestrator functions locally from this module
88
$localFunctionFiles = @(
99
(Join-Path $PSScriptRoot 'functions/Invoke-EasyPIMOrchestrator.ps1'),
10-
(Join-Path $PSScriptRoot 'functions/Test-PIMPolicyDrift.ps1')
10+
(Join-Path $PSScriptRoot 'functions/Test-PIMPolicyDrift.ps1'),
11+
(Join-Path $PSScriptRoot 'functions/Test-PIMEndpointDiscovery.ps1')
1112
)
1213
foreach ($f in $localFunctionFiles) { if (Test-Path $f) { . $f } }
1314

1415

15-
# Source required internal helper from EasyPIM core (kept internal for now)
16-
$easyPIMInternalFiles = @(
17-
'internal/functions/EPO_Write-EasyPIMSummary.ps1'
18-
)
19-
foreach ($rel in $easyPIMInternalFiles) {
20-
$path = Join-Path $easyPIMDir $rel
21-
if (Test-Path $path) { . $path }
16+
# Load this module's own internal helpers
17+
foreach ($file in Get-ChildItem -Path (Join-Path $PSScriptRoot 'internal/functions') -Filter *.ps1 -Recurse) {
18+
. $file.FullName
2219
}
2320

2421
# Export only the public entrypoints
2522
Export-ModuleMember -Function @(
2623
'Invoke-EasyPIMOrchestrator',
27-
'Test-PIMPolicyDrift'
24+
'Test-PIMPolicyDrift',
25+
'Test-PIMEndpointDiscovery'
2826
)

EasyPIM.Orchestrator/build/vsts-build-orchestrator.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ if (-not $WorkingDirectory) {
2020
# Prepare publish folder
2121
Write-Host "Creating and populating publishing directory"
2222
$publishDir = New-Item -Path $WorkingDirectory -Name publish -ItemType Directory -Force
23-
Copy-Item -Path "$($WorkingDirectory)\EasyPIM.Orchestrator" -Destination $publishDir.FullName -Recurse -Force
23+
Copy-Item -Path $WorkingDirectory -Destination $publishDir.FullName -Recurse -Force
2424

2525
# Gather commands
2626
$text = @()
Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,118 @@
1-
# Moved from EasyPIM/internal/functions/EPO_Write-EasyPIMSummary.ps1
1+
function Write-EasyPIMSummary {
2+
[CmdletBinding()]
3+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")]
4+
param (
5+
[Parameter()]
6+
[PSCustomObject]$CleanupResults,
7+
8+
[Parameter()]
9+
[PSCustomObject]$AssignmentResults,
10+
11+
[Parameter()]
12+
[hashtable]$PolicyResults,
13+
14+
[Parameter()]
15+
[string]$PolicyMode = "delta"
16+
)
17+
18+
Write-Host "`n┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓" -ForegroundColor Green
19+
Write-Host "┃ OVERALL SUMMARY ┃" -ForegroundColor Green
20+
Write-Host "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛" -ForegroundColor Green
21+
22+
Write-Host "┌───────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor White
23+
Write-Host "│ ASSIGNMENT CREATIONS" -ForegroundColor White
24+
Write-Host "├───────────────────────────────────────────────────────────────────────────────┤" -ForegroundColor White
25+
26+
if ($null -ne $AssignmentResults) {
27+
$planned = if ($AssignmentResults.PSObject.Properties.Name -contains 'PlannedCreated') { $AssignmentResults.PlannedCreated } else { $null }
28+
Write-Host "│ ✅ Created : $($AssignmentResults.Created)" -ForegroundColor White
29+
if ($null -ne $planned) {
30+
Write-Host "│ 📝 Planned : $planned" -ForegroundColor White
31+
}
32+
Write-Host "│ ⏭️ Skipped : $($AssignmentResults.Skipped)" -ForegroundColor White
33+
Write-Host "│ ❌ Failed : $($AssignmentResults.Failed)" -ForegroundColor White
34+
} else {
35+
Write-Host "│ ✅ Created : 0" -ForegroundColor White
36+
Write-Host "│ ⏭️ Skipped : 0" -ForegroundColor White
37+
Write-Host "│ ❌ Failed : 0" -ForegroundColor White
38+
}
39+
Write-Host "└───────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor White
40+
41+
Write-Host "┌───────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor White
42+
Write-Host "│ POLICY OPERATIONS" -ForegroundColor White
43+
Write-Host "├───────────────────────────────────────────────────────────────────────────────┤" -ForegroundColor White
44+
45+
if ($null -ne $PolicyResults -and $null -ne $PolicyResults.Summary) {
46+
Write-Host "│ ✅ Applied : $($PolicyResults.Summary.Successful)" -ForegroundColor White
47+
Write-Host "│ ⏭️ Skipped : $($PolicyResults.Summary.Skipped)" -ForegroundColor White
48+
Write-Host "│ ❌ Failed : $($PolicyResults.Summary.Failed)" -ForegroundColor White
49+
Write-Host "│ 📋 Total : $($PolicyResults.Summary.TotalProcessed)" -ForegroundColor White
50+
} else {
51+
Write-Host "│ ✅ Applied : 0" -ForegroundColor White
52+
Write-Host "│ ⏭️ Skipped : 0" -ForegroundColor White
53+
Write-Host "│ ❌ Failed : 0" -ForegroundColor White
54+
Write-Host "│ 📋 Total : 0" -ForegroundColor White
55+
}
56+
Write-Host "└───────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor White
57+
58+
Write-Host "┌───────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor White
59+
Write-Host "│ CLEANUP OPERATIONS" -ForegroundColor White
60+
Write-Host "├───────────────────────────────────────────────────────────────────────────────┤" -ForegroundColor White
61+
62+
if ($null -ne $CleanupResults) {
63+
$kept = if ($null -ne $CleanupResults.KeptCount) { $CleanupResults.KeptCount }
64+
elseif ($null -ne $CleanupResults.Kept) { $CleanupResults.Kept }
65+
else { 0 }
66+
67+
$removed = if ($null -ne $CleanupResults.RemovedCount) { $CleanupResults.RemovedCount }
68+
elseif ($null -ne $CleanupResults.Removed) { $CleanupResults.Removed }
69+
else { 0 }
70+
71+
$skipped = if ($null -ne $CleanupResults.SkippedCount) { $CleanupResults.SkippedCount }
72+
elseif ($null -ne $CleanupResults.Skipped) { $CleanupResults.Skipped }
73+
else { 0 }
74+
75+
$protected = if ($null -ne $CleanupResults.ProtectedCount) { $CleanupResults.ProtectedCount }
76+
elseif ($null -ne $CleanupResults.Protected) { $CleanupResults.Protected }
77+
else { 0 }
78+
79+
Write-Host "│ ✅ Kept : $kept" -ForegroundColor White
80+
Write-Host "│ 🗑️ Removed : $removed" -ForegroundColor White
81+
if ($CleanupResults.PSObject.Properties.Name -contains 'WouldRemoveCount') {
82+
Write-Host "│ 🛈 WouldRemove: $($CleanupResults.WouldRemoveCount)" -ForegroundColor White
83+
if ($CleanupResults.PSObject.Properties.Name -contains 'WouldRemoveDetails' -and $CleanupResults.WouldRemoveDetails -and $CleanupResults.WouldRemoveDetails.Count -gt 0) {
84+
$previewSample = $CleanupResults.WouldRemoveDetails | Select-Object -First 5
85+
foreach($item in $previewSample){
86+
$sc = if ($item.Scope) { $item.Scope } else { '' }
87+
Write-Host "│ - $($item.RoleName) $sc $($item.PrincipalId)" -ForegroundColor DarkGray
88+
}
89+
if ($CleanupResults.WouldRemoveDetails.Count -gt 5) {
90+
Write-Host "│ ... (+$($CleanupResults.WouldRemoveDetails.Count - 5) more)" -ForegroundColor DarkGray
91+
}
92+
}
93+
if ($CleanupResults.PSObject.Properties.Name -contains 'WouldRemoveExportPath' -and $CleanupResults.WouldRemoveExportPath) {
94+
Write-Host "│ 📤 Export file: $($CleanupResults.WouldRemoveExportPath)" -ForegroundColor DarkGray
95+
}
96+
}
97+
Write-Host "│ ⏭️ Skipped : $skipped" -ForegroundColor White
98+
if ($protected -gt 0) {
99+
Write-Host "│ 🛡️ Protected: $protected" -ForegroundColor White
100+
}
101+
} else {
102+
Write-Host "│ ✅ Kept : 0" -ForegroundColor White
103+
Write-Host "│ 🗑️ Removed : 0" -ForegroundColor White
104+
Write-Host "│ ⏭️ Skipped : 0" -ForegroundColor White
105+
}
106+
Write-Host "└───────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor White
107+
108+
if ($script:EasyPIM_DeferredGroupPoliciesSummary) {
109+
$dg = $script:EasyPIM_DeferredGroupPoliciesSummary
110+
Write-Host "┌───────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor White
111+
Write-Host "│ DEFERRED GROUP POLICIES" -ForegroundColor White
112+
Write-Host "├───────────────────────────────────────────────────────────────────────────────┤" -ForegroundColor White
113+
Write-Host "│ ✅ Applied : $($dg.Applied)" -ForegroundColor White
114+
Write-Host "│ ⏳ Still Not Eligible: $($dg.StillNotEligible)" -ForegroundColor White
115+
Write-Host "│ ❌ Failed : $($dg.Failed)" -ForegroundColor White
116+
Write-Host "└───────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor White
117+
}
118+
}

EasyPIM/functions/_REMOVED_SHIMS_BACKUP/Invoke-EasyPIMOrchestrator.ps1

Whitespace-only changes.

EasyPIM/functions/_REMOVED_SHIMS_BACKUP/README.md

Whitespace-only changes.

EasyPIM/functions/_REMOVED_SHIMS_BACKUP/Test-PIMEndpointDiscovery.ps1

Whitespace-only changes.

EasyPIM/functions/_REMOVED_SHIMS_BACKUP/Test-PIMPolicyDrift.ps1

Whitespace-only changes.

tests/general/FileIntegrity.Tests.ps1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ Describe "Verifying integrity of module files" {
5252
[byte[]]$byte = Get-Content -AsByteStream -ReadCount 4 -TotalCount 4 -Path $Path
5353
}
5454

55+
# Handle empty or very short files safely
56+
if (-not $byte -or $byte.Length -lt 4) { return 'Unknown' }
57+
5558
if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf) { 'UTF8 BOM' }
5659
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff) { 'Unicode' }
5760
elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff) { 'UTF32' }
@@ -65,6 +68,8 @@ Describe "Verifying integrity of module files" {
6568
$allFiles = Get-ChildItem -Path $moduleRoot -Recurse -File |
6669
Where-Object { $_.Name -like '*.ps1' } |
6770
Where-Object { $_.FullName -notlike (Join-Path $moduleRoot 'tests\*') } |
71+
Where-Object { $_.FullName -notlike (Join-Path $moduleRoot 'functions\_REMOVED_SHIMS_BACKUP\*') } |
72+
Where-Object { $_.FullName -notlike (Join-Path $moduleRoot 'backup\_REMOVED_SHIMS_BACKUP\*') } |
6873
Where-Object { $_.FullName -notlike (Join-Path $testFolder '*') }
6974
$testFiles = @()
7075
if (Test-Path $testFolder) { $testFiles = Get-ChildItem -Path $testFolder -Recurse -File }

0 commit comments

Comments
 (0)