Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
163 commits
Select commit Hold shift + click to select a range
2fac58f
Add Azure SQL integration for Microsoft Graph data with temporal vers…
WimvandenHeijkant Dec 19, 2025
9d6f32b
Small fixes
WimvandenHeijkant Dec 19, 2025
6773d01
Refactor SQL functions to improve code reuse and separation of concerns
claude Dec 25, 2025
1e86078
Update README with architecture and design documentation
claude Dec 25, 2025
85096fd
Reorganize SQL functions into dedicated folder and simplify function …
WimvandenHeijkant Jan 2, 2026
6f0e313
Adding test
WimvandenHeijkant Jan 2, 2026
adf08ac
Adding tests
WimvandenHeijkant Jan 2, 2026
ee15205
Added testing
WimvandenHeijkant Jan 2, 2026
7d549e7
Add comprehensive CLAUDE.md documentation for AI assistants
claude Jan 3, 2026
dd378d4
Add Sync-FGGroup function and SQL helper functions for code reuse
claude Jan 3, 2026
92ab2b8
Add Sync-FGGroupMember function with composite key support
claude Jan 3, 2026
b91f6a5
Add Sync-FGGroupTransitiveMember function for nested group memberships
claude Jan 3, 2026
63a1762
Add Initialize-FGGroupMembershipViews for easy membership analysis
claude Jan 3, 2026
f634040
Add Sync-FGGroupEligibleMember and enhance membership views
claude Jan 3, 2026
7ea3e0a
Update README with comprehensive group sync documentation
claude Jan 3, 2026
dbabb98
Add comprehensive tests for group sync functions
claude Jan 4, 2026
b8aa1be
Refactor group ownership to many-to-many relationship
claude Jan 4, 2026
52ff38b
test results
WimvandenHeijkant Jan 4, 2026
04d6aa9
Fix SQL view creation when owners table doesn't exist
claude Jan 4, 2026
447dc2b
Add fast integration test for development speed
claude Jan 4, 2026
c72ff13
Results of integration test and integration test fast
WimvandenHeijkant Jan 5, 2026
f8efa04
Fix fast integration test table creation conflict
claude Jan 5, 2026
d186d66
Error log
WimvandenHeijkant Jan 5, 2026
86feb5d
Skip temporal table view test in fast integration test
claude Jan 5, 2026
eaffe72
Fix token expiration in sync functions for large environments
claude Jan 5, 2026
6f0f049
Test results
WimvandenHeijkant Jan 6, 2026
948aeda
Fix for additional properties
WimvandenHeijkant Jan 6, 2026
557c674
Fix critical token refresh bug and enhance test summaries
claude Jan 6, 2026
d6d1944
Add support for separate Azure and Graph tenant IDs
claude Jan 6, 2026
58b47ea
Update documentation and template for Azure.TenantId support
claude Jan 6, 2026
604635c
Test restults
WimvandenHeijkant Jan 6, 2026
95835a7
Merge pull request #2 from Fortigi/claude/update-claude-docs-dev-1eKUe
WimvandenHeijkant Jan 6, 2026
a3fee2b
Added Daily Sync scripts and docs
WimvandenHeijkant Jan 7, 2026
7b069e7
Results
WimvandenHeijkant Jan 7, 2026
98c7730
Results
WimvandenHeijkant Jan 7, 2026
875b784
Updates to fix deletes
WimvandenHeijkant Jan 9, 2026
eed48f0
Much faster
WimvandenHeijkant Jan 9, 2026
2fc0449
Fix incorrect PIM groups selection logic
claude Jan 9, 2026
05cb872
Add recursive membership view with path tracking
claude Jan 10, 2026
e61cfb4
Test results
WimvandenHeijkant Jan 10, 2026
650360e
Fix Graph API requirement: eligibilitySchedules requires filter param…
claude Jan 10, 2026
460f308
Merge pull request #5 from Fortigi/claude/fix-pim-groups-selection-IsEme
WimvandenHeijkant Jan 11, 2026
b7ca3ea
REmove old log files
WimvandenHeijkant Jan 11, 2026
6a75b29
Merge pull request #6 from Fortigi/claude/recursive-membership-view-u…
WimvandenHeijkant Jan 11, 2026
12aedc5
Fix SQL syntax error: Remove OPTION clause from view
claude Jan 11, 2026
0513b03
Merge pull request #7 from Fortigi/claude/recursive-membership-view-u…
WimvandenHeijkant Jan 11, 2026
8ab47e6
Add attribute mapping documentation generator
WimvandenHeijkant Jan 13, 2026
dc36960
Consolidate documentation and add attribute mapping function
WimvandenHeijkant Jan 15, 2026
17ef715
Remove old test/documentation files
WimvandenHeijkant Jan 15, 2026
165cabc
Integrate secure credential management into module
WimvandenHeijkant Jan 15, 2026
9e2f6aa
Reorganize module structure: create Sync and Config folders
WimvandenHeijkant Jan 15, 2026
c40f61f
Update README to reflect new Sync and Config folder structure
WimvandenHeijkant Jan 15, 2026
0f42933
Remove Daily-Sync.ps1 and add Start-FGSync integration tests
WimvandenHeijkant Jan 15, 2026
b295fea
Updates
WimvandenHeijkant Jan 15, 2026
348187d
Fix Test-Integration.ps1: import module before loading credentials
WimvandenHeijkant Jan 15, 2026
143e8f2
Updates
WimvandenHeijkant Jan 15, 2026
1d2bacc
Doen't write progress
WimvandenHeijkant Jan 15, 2026
ec8dade
Adding license
WimvandenHeijkant Jan 15, 2026
3209ab6
Final changes
WimvandenHeijkant Jan 16, 2026
7b9efe7
Add access package synchronization support
claude Jan 16, 2026
d265bfe
Add IST vs SOLL gap analysis views
claude Jan 16, 2026
94027d9
Add assignment method tracking (automatic vs requested vs admin)
claude Jan 16, 2026
318147b
Add access review tracking for access packages
claude Jan 16, 2026
212cb3f
Add approval timeline views for access package requests
claude Jan 16, 2026
7715a3b
Add support for access package policies, requests, and reviews to Sta…
claude Jan 17, 2026
a5071a0
Add config file support for new access package sync operations
claude Jan 17, 2026
38d51aa
Add comprehensive config documentation for access package sync
claude Jan 17, 2026
a89f7cb
Add comprehensive access package tests to Test-Integration.ps1
claude Jan 17, 2026
2522e5c
Add access package sync options to config template
claude Jan 17, 2026
edc7007
Logs
WimvandenHeijkant Jan 17, 2026
fae3ce3
Fix Graph API endpoints for access package sync operations
claude Jan 17, 2026
b33ba77
Lgos
WimvandenHeijkant Jan 17, 2026
5b0fdea
Fix resource role scope endpoint to use correct Graph API pattern
claude Jan 17, 2026
4bc402c
Merge branch 'claude/add-access-package-sync-at2vK' of http://127.0.0…
claude Jan 17, 2026
f20d395
Log
WimvandenHeijkant Jan 17, 2026
1dfa76e
Fix 3 critical errors in access package sync functions
claude Jan 17, 2026
19d98c3
New log
WimvandenHeijkant Jan 17, 2026
1146d53
Fix remaining Graph API property and validation errors
claude Jan 17, 2026
3cd7cf0
Fix GUID parsing syntax and duplicate key merge errors
claude Jan 17, 2026
4e80feb
Update README: Lead with governance insights and IST vs SOLL value
claude Jan 17, 2026
c74d836
Logs
WimvandenHeijkant Jan 18, 2026
71eab70
Merge branch 'claude/add-access-package-sync-at2vK' of https://github…
WimvandenHeijkant Jan 18, 2026
895725b
Fix resource role scope sync logging and remove transitive table depe…
claude Jan 18, 2026
bd9db42
Fix resource role scope sync: Handle composite IDs and correct proper…
claude Jan 19, 2026
f279390
Replace progress logging with Write-Progress in resource role scope sync
claude Jan 19, 2026
fe3924b
Fix duplicate key constraint violation in resource role scope sync
claude Jan 19, 2026
d182103
Fix PRIMARY KEY to support same role-scope in multiple packages
claude Jan 19, 2026
68f4426
Enhance error logging for failed scope retrieval
claude Jan 19, 2026
d491a31
Fix bulk delete to use composite PRIMARY KEY
claude Jan 19, 2026
c2105bc
Fix Invoke-FGSQLBulkDelete to support non-GUID key columns
claude Jan 19, 2026
92d01ea
Add deduplication to all access package sync functions
claude Jan 19, 2026
29ebbcb
Remove all deduplication logic - Graph API doesn't return duplicates
claude Jan 19, 2026
8e372e7
Fix view column names and always drop before recreating
claude Jan 19, 2026
449f67d
Fix Initialize-FGGroupMembershipViews to always drop views before rec…
claude Jan 19, 2026
b23cb05
Remove all transitive members functionality from group membership views
claude Jan 19, 2026
4f283a7
Add comprehensive vw_GraphGroupMembershipType view
claude Jan 19, 2026
1b6362f
Remove redundant vw_GraphGroupEligibleMembers view
claude Jan 19, 2026
961a087
Add performance optimizations for group membership views
claude Jan 19, 2026
2398ce7
Add automatic index creation to Start-FGSync
claude Jan 19, 2026
6ce38e1
Good old fashed bug fixes
WimvandenHeijkant Jan 19, 2026
63fdaae
Add retry logic for transient Graph API errors in resource role scope…
claude Jan 20, 2026
fed8e76
Fix MERGE statement to use composite PRIMARY KEY for resource role sc…
claude Jan 20, 2026
16dc844
Simplify access package views - remove 3 redundant views
claude Jan 20, 2026
c2fcb02
Remove 3 more redundant access package views
claude Jan 20, 2026
05ea158
Add diagnostics for assignment request MERGE failure
claude Jan 20, 2026
0df984d
Add progress reporting during Graph API fetch for assignment requests
claude Jan 20, 2026
a917374
Add centralized progress reporting to Invoke-FGGetRequest
claude Jan 20, 2026
0f342ad
Improve diagnostics for empty accessPackageId in assignment requests
claude Jan 20, 2026
fb78c20
Remove verbose diagnostic logging for duplicate request IDs
claude Jan 20, 2026
0c0bb13
Fix token validation in Start-FGSync to actually check validity
claude Jan 20, 2026
2fdb237
Remove log file
WimvandenHeijkant Jan 20, 2026
d01b68b
Add ConfigFile parameter support to Connect-FGSQLServer
claude Jan 20, 2026
e562552
Make firewall updates automatic by default in Connect-FGSQLServer
claude Jan 20, 2026
9e8b7c8
Fix recursive membership view to include all indirect members
claude Jan 20, 2026
74e0ad2
Fix Connect-FGSQLServer config file property paths
claude Jan 20, 2026
b4c0802
Rename view vw_GraphGroupMembershipType to vw_UserPermissionAssignments
claude Jan 20, 2026
736a981
Rename view vw_UserAccessPackageResources to vw_UserPermissionAssignm…
claude Jan 20, 2026
59bb056
PERFORMANCE: Optimize vw_GraphGroupMembersRecursive for large dataset…
claude Jan 20, 2026
52c4063
Restore depth and path columns to vw_GraphGroupMembersRecursive
claude Jan 20, 2026
f8ede9f
Fix SQL syntax error: Remove OPTION clause from view definition
claude Jan 20, 2026
f4a58ee
CRITICAL FIX: Use correct memberType value in recursive view
claude Jan 20, 2026
969d7ce
Add Update-FGGroupMembershipRecursive: Materialize recursive calculat…
claude Jan 20, 2026
8b90b53
Revert materialization approach: Keep view-based recursive calculations
claude Jan 20, 2026
642f7f2
Fix update firewall issue
WimvandenHeijkant Jan 20, 2026
8f27c19
Update CLAUDE.md documentation for access package sync feature
claude Jan 21, 2026
de1ad03
Merge pull request #10 from Fortigi/claude/add-access-package-sync-at2vK
WimvandenHeijkant Jan 21, 2026
e3b1f7b
Logs
WimvandenHeijkant Feb 2, 2026
1255222
Logs
WimvandenHeijkant Feb 2, 2026
6cb14cb
Add deduplication for access package assignments to fix MERGE failures
WimvandenHeijkant Feb 2, 2026
cdc1885
Add batching mode for Sync-FGGroupMember to reduce memory usage
WimvandenHeijkant Feb 3, 2026
e495141
Add Azure Automation Account setup function
WimvandenHeijkant Feb 4, 2026
fbb9c8a
Fix New-FGAzureAutomationAccount to read all settings from config file
WimvandenHeijkant Feb 4, 2026
5616d1b
Use Get-FGSecureConfigValue for encrypted credentials in automation s…
WimvandenHeijkant Feb 4, 2026
f1ee272
Set runbooks to use PowerShell 7.2 runtime
WimvandenHeijkant Feb 5, 2026
60b9704
Add RuntimeVersion parameter with default 7.2 for runbooks
WimvandenHeijkant Feb 5, 2026
586807d
Create runbooks by default, add -SkipRunbooks to opt out
WimvandenHeijkant Feb 5, 2026
0df7a89
Fix runbook creation: use -Type PowerShell72 instead of -RuntimeVersion
WimvandenHeijkant Feb 5, 2026
48db86a
Add SQL firewall check for Azure services with user approval
WimvandenHeijkant Feb 5, 2026
233bdf4
Fix SQL Server name case sensitivity issue
WimvandenHeijkant Feb 5, 2026
95b04a6
Add sync configuration support for runbooks (AdditionalAttributes, Fi…
WimvandenHeijkant Feb 5, 2026
34091e7
Lots of updates, should have commited more often
WimvandenHeijkant Feb 6, 2026
f85a643
Merge pull request #11 from Fortigi/feature/azure-automation-setup
WimvandenHeijkant Feb 6, 2026
d0b055f
Add New-FGConfig interactive config file wizard
claude Feb 6, 2026
217938d
Use Connect-AzAccount in New-FGConfig for interactive Azure discovery
claude Feb 6, 2026
072fd05
Simplify New-FGConfig: auto-detect tenant, auto-generate SQL password
claude Feb 6, 2026
558d2a3
Add default SQL Server name suggestion with random suffix
claude Feb 6, 2026
00ef621
Add automatic App Registration creation to New-FGConfig
claude Feb 6, 2026
d29eadc
Remove GroupTransitiveMembers from config wizard and templates
claude Feb 6, 2026
17acfbb
Add Azure resource provisioning to New-FGConfig wizard
claude Feb 9, 2026
c361e60
Fix GUID case mismatch between scopeOriginId and group IDs
claude Feb 9, 2026
9acff38
Also normalize scopeId and roleId GUIDs to uppercase
claude Feb 9, 2026
c20d7f1
Add resourceProvisioningOptions and groupTypeCalculated to group sync
claude Feb 9, 2026
2ffb99d
Merge pull request #13 from Fortigi/claude/fix-graph-guid-case-zv2ia
WimvandenHeijkant Feb 9, 2026
4da8752
Merge branch 'dev' into claude/add-sql-data-visualization-uyh0M
WimvandenHeijkant Feb 9, 2026
bd4c059
Merge pull request #14 from Fortigi/claude/add-sql-data-visualization…
WimvandenHeijkant Feb 9, 2026
c4bc43d
Fix New-FGConfig: add AuditLog.Read.All permission, default PIM to ye…
claude Feb 9, 2026
f77ff44
Add random suffix to Automation Account name for uniqueness
claude Feb 9, 2026
05caf2f
Fix SQL credential flow: ask for server selection before password
claude Feb 9, 2026
c36a1a7
Fix New-FGAzureAutomationAccount: stop on creation failure
claude Feb 9, 2026
4e183f6
Fix Start-FGSync: re-authenticate when config uses different Client ID
claude Feb 9, 2026
67a4b95
Simplify Start-FGSync: always get a fresh Graph token
claude Feb 9, 2026
785376b
Moving files around
WimvandenHeijkant Feb 9, 2026
0d2bfe4
Update CLAUDE.md and README.md documentation
claude Feb 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Config/*.json
.claude/
35 changes: 0 additions & 35 deletions Base/Get-FGAccessToken.ps1

This file was deleted.

395 changes: 395 additions & 0 deletions CLAUDE.md

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions Config/tenantname.json.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{
"_INFO": "Example Daily Sync configuration with Sync section configured",
"_NOTE": "This shows how to configure sync settings in the config file",
"_USAGE": "Copy this to config.production.json and customize for your environment",
"Azure": {
"TenantId": "yourtenant.onmicrosoft.com",
"SubscriptionId": "your-subscription-id",
"ResourceGroupName": "ResourceGroupName",
"Location": "northeurope",
"SQLServerName": "SQLServerName",
"DatabaseName": "GraphData",
"AdminUsername": "sqladmin",
"AdminUserPassword": "",
"AdminUserPassword_Encrypted": "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000f36f5b454c58b24899cddcf62bd1cfb100000000020000000000106600000001000020000000f61ff5e8b95960fc82c5f543c83ea72bd93bb3ef08f05b5e22a448886dd3d2f6000000000e8000000002000020000000ccc029b9093b11fcb51172e8ca742fc8372c2dd0c2686998fb32e221e8ddd6f330000000f54a3ebbb630a8dde6b79828b25483cd095d0654ed575becb28c05cbbf8fdca19e74119d51506292fb4f49af4c03674b400000004438efd79431a9db7320d1a75d69b24906f12ad1dcb142248e02aef8321789431a9a128631626b4be0285ac130679e2a6a3c74049599bc93f87a004149c22e41",
"AutomationAccountName": "aa-fortigraph"
},
"Graph": {
"TenantId": "yourtenant.onmicrosoft.com",
"ClientId": "your-clientid-guid",
"ClientSecret": "your-client-secret"
},
"Sync": {
"ScheduleTimeZone": "W. Europe Standard Time",
"Users": {
"Enabled": true,
"TableName": "GraphUsers",
"Filter": "",
"AdditionalAttributes": [
"streetAddress",
"usageLocation",
"state"
],
"Schedule": {
"Enabled": true,
"Time": "06:00",
"Frequency": "Daily"
}
},
"Groups": {
"Enabled": true,
"TableName": "GraphGroups",
"Filter": "",
"Schedule": {
"Enabled": true,
"Time": "06:00",
"Frequency": "Daily"
}
},
"GroupMembers": {
"Enabled": true,
"TableName": "GraphGroupMembers",
"Schedule": {
"Enabled": true,
"Time": "07:00",
"Frequency": "Daily"
}
},
"GroupEligibleMembers": {
"Enabled": true,
"_Comment": "PIM not configured in this environment"
},
"GroupOwners": {
"Enabled": true,
"TableName": "GraphGroupOwners"
},
"Catalogs": {
"Enabled": true,
"TableName": "GraphCatalogs",
"Schedule": {
"Enabled": true,
"Time": "06:00",
"Frequency": "Daily"
}
},
"AccessPackages": {
"Enabled": true,
"TableName": "GraphAccessPackages",
"Schedule": {
"Enabled": true,
"Time": "06:15",
"Frequency": "Daily"
}
},
"AccessPackageAssignments": {
"Enabled": true,
"TableName": "GraphAccessPackageAssignments",
"Schedule": [
{ "Enabled": true, "Time": "06:00", "Frequency": "Daily" },
{ "Enabled": true, "Time": "12:00", "Frequency": "Daily" },
{ "Enabled": true, "Time": "18:00", "Frequency": "Daily" }
]
},
"AccessPackageResourceRoleScopes": {
"Enabled": true,
"TableName": "GraphAccessPackageResourceRoleScopes"
},
"AccessPackageAssignmentPolicies": {
"Enabled": true,
"TableName": "GraphAccessPackageAssignmentPolicies"
},
"AccessPackageAssignmentRequests": {
"Enabled": true,
"TableName": "GraphAccessPackageAssignmentRequests"
},
"AccessPackageAccessReviews": {
"Enabled": true,
"TableName": "GraphAccessPackageAccessReviewDecisions"
},
"Views": {
"Enabled": true
},
"ParallelExecution": true
}
}
15 changes: 8 additions & 7 deletions FortigiGraph.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# Generated by: Wim van den Heijkant
#
# Generated on: 14/05/2025
# Generated on: 06/02/2026
#

@{
Expand All @@ -12,13 +12,13 @@
RootModule = '.\FortigiGraph.psm1'

# Version number of this module.
ModuleVersion = '1.1.20250514.1135'
ModuleVersion = '2.1.20260210.1200'

# Supported PSEditions
# CompatiblePSEditions = @()

# ID used to uniquely identify this module
GUID = '3b64129c-8150-499b-89e2-f0bcd297d27d'
GUID = '4ca6dcbd-25f6-419b-8ddf-b8fc36433a59'

# Author of this module
Author = 'Wim van den Heijkant'
Expand All @@ -27,7 +27,7 @@ Author = 'Wim van den Heijkant'
CompanyName = 'Fortigi'

# Copyright statement for this module
Copyright = '(c) Wim van den Heijkant. All rights reserved.'
Copyright = '(c) 2026 Wim van den Heijkant / Fortigi. Licensed under the MIT License.'

# Description of the functionality provided by this module
Description = 'PowerShell Module to assist with scripting against the Microsoft Graph. The sources for this module, including versioning can be found on GitHub: https://github.com/Fortigi/FortigiGraph'
Expand Down Expand Up @@ -95,13 +95,14 @@ PrivateData = @{
PSData = @{

# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @()
Tags = 'MicrosoftGraph', 'Graph', 'AzureAD', 'EntraID', 'SQL', 'Azure',
'IdentityGovernance'

# A URL to the license for this module.
# LicenseUri = ''
LicenseUri = 'https://github.com/Fortigi/FortigiGraph/blob/main/LICENSE'

# A URL to the main website for this project.
# ProjectUri = ''
ProjectUri = 'https://github.com/Fortigi/FortigiGraph'

# A URL to an icon representing this module.
# IconUri = ''
Expand Down
13 changes: 8 additions & 5 deletions FortigiGraph.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
# THIS FILE WILL NOT BE OVERWRITTEN WHEN NEW CONTENT IS PUBLISHED TO THIS MODULE

# Get public and private function definition files.
$base = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'base') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$generic = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'generic') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$specific = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'specific') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$base = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'functions\base') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$generic = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'functions\generic') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$specific = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'functions\specific') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$SQL = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'functions\SQL') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$sync = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'functions\Sync') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )
$automation = @( Get-ChildItem -Path (Join-Path $PSScriptRoot 'functions\Automation') -Include *.ps1 -Recurse -ErrorAction SilentlyContinue )

# Dot source base & generic function files
foreach ($import in @($base + $generic + $specific)) {
# Dot source all function files
foreach ($import in @($base + $generic + $specific + $SQL + $sync + $automation)) {
try {
. $import.fullname
}
Expand Down
Loading