HybridAD-Manager
A single pane of glass for managing Hybrid Active Directory and Microsoft Entra ID.
A Windows WPF desktop application modeled after Active Directory Users & Computers, extended with cloud-native tabs for Microsoft 365 and Entra ID management.
Features · Quick start · Configuration · Architecture · Development
⚠️ Work in progress — not production ready. This project is under active development and has not been thoroughly tested in production environments. Features may be incomplete, unstable, or subject to breaking changes.
HybridAD-Manager ends the context-switching between ADUC (dsa.msc), the Microsoft 365 admin center, and the Exchange admin center. One console shows on-premises Active Directory objects alongside their Microsoft Entra ID cloud state — sync status, licenses, mailbox settings, and proxy addresses — with live correlation between the two directories.
Features
| Area | What is included |
|---|---|
| Console shell | ADUC-style interface with menu bar, toolbar, domain/OU tree, details list with sorting and multi-select, context menus, status bar, and a custom XAML theme in the style of Windows 11 admin tools. |
| Active Directory | Domain discovery and OU tree walking via System.DirectoryServices; user, group, and computer retrieval; group membership management; enable, disable, delete, and move operations; LDAP-escaped global search by name, email, description, or phone. |
| Property sheets | 13-tab user property sheet: General, Address, Account, Profile, Telephones, Organization, Member Of, Dial-in, Environment, Hybrid Status, Licenses, Mailbox, and Email Addresses. |
| Microsoft Entra ID | MSAL.NET public-client authentication with OAuth2 + PKCE and MFA support, silent token refresh, and a platform-backed token cache (Windows DPAPI, with macOS Keychain and Linux Secret Service configuration in the cache helper). Microsoft Graph SDK v5 for all cloud operations. |
| Hybrid correlation | AD objects matched with Entra ID objects by UPN and immutable ID, with visual sync indicators for In Sync, Pending, Cloud-only, and Sync Error states. |
| Hybrid Status tab | Live sync state loaded lazily per object: Entra object ID, immutable ID, directory source, on-premises metadata (DN, domain, SAM, SID), and provisioning errors with error codes. |
| Force sync | Triggers an Azure AD Connect delta sync by invoking Start-ADSyncSyncCycle -PolicyType Delta through local PowerShell; requires the app to run on the Azure AD Connect server with the ADSync module installed. |
| Licenses tab | Visual SKU and service-plan grid for the signed-in tenant's subscribed SKUs, with assign/remove per user. |
| Mailbox tab | Auto-reply (automatic replies) editor, mail forwarding, and address-list visibility through the Graph mailbox settings API. |
| Email Addresses tab | proxyAddresses editor with validation and primary SMTP address management. |
| Find and saved queries | Global Find dialog (F3) with composable LDAP filters, plus saved queries persisted to JSON that surface in the tree under a Saved Queries node. |
| Bulk operations | Multi-select enable, disable, and delete from the list-view context menu, with confirmation dialogs. |
| CSV export | Export the current container or selected objects to CSV with full field coverage and proper escaping. |
| Keyboard and drag-and-drop | F5 refresh, F3 find, Ctrl+N new user, Ctrl+G new group, Ctrl+E export, Del delete; drag objects from the list onto tree OUs to move them, with target validation and confirmation. |
| Accessibility | 160 AutomationProperties.Name labels across the UI, tooltips on interactive elements, and a runtime high-contrast theme toggle in the View menu. |
| Resilience | Graceful fallback to built-in demo data (contoso.com) when no domain is reachable, global DispatcherUnhandledException handling, and a centralized dialog service for consistent messaging. |
| Packaging | MSIX manifest (Package.appxmanifest) with a single-file win-x64 publish profile; image assets and publisher identity are placeholders awaiting real values. |
Technology stack
| Layer | Technology |
|---|---|
| Framework | .NET 8, WPF (net8.0-windows), Windows-only |
| UI pattern | MVVM with CommunityToolkit.Mvvm 8.2.2 source generators |
| Dependency injection | Microsoft.Extensions.DependencyInjection 8.0.0 |
| AD connectivity | System.DirectoryServices 8.0.0 and System.DirectoryServices.AccountManagement 8.0.0 |
| Cloud API | Microsoft.Graph SDK 5.46.0 |
| Authentication | Microsoft.Identity.Client (MSAL.NET) 4.60.3 — OAuth2 + PKCE public client |
| Token cache | Microsoft.Identity.Client.Extensions.Msal 4.60.3 |
| Styling | Custom XAML resource dictionaries (colors, styles, data templates, high-contrast variant) |
Quick start
Prerequisites
- Windows 10 version 1809 (10.0.17763) or newer — Windows 11 recommended
- .NET 8 SDK to build; the .NET 8 desktop runtime to run
- Optional: line-of-sight to an Active Directory domain controller (the app falls back to demo data without one)
- Optional: a Microsoft Entra ID app registration for cloud features (see Configuration)
- Optional: Visual Studio 2022 or newer for a designer-friendly development experience
Build and run
git clone https://github.com/tunwinlat/HybridAD-Manager.git
cd HybridAD-Manager
dotnet restore
dotnet build
dotnet run --project HybridADManager
On first launch the app attempts to discover the current domain. If no domain controller is reachable, it loads demo contoso.com data so the full UI can be explored without any infrastructure.
The application icon and MSIX tile assets are committed under
HybridADManager/Resources/(app.ico,logo.png,StoreLogo.png,Square150x150Logo.png,Square44x44Logo.png). The placeholder publisher CN inPackage.appxmanifeststill needs replacing before building an MSIX package.
Publish a single-file executable
dotnet publish HybridADManager -c Release -r win-x64
The project is configured for PublishSingleFile with SelfContained=false, producing a single framework-dependent executable under bin\Release\net8.0-windows\win-x64\publish.
Configuration
Entra ID app registration
Cloud features (Hybrid Status, Licenses, Mailbox, Email Addresses, Force Sync) require signing in to Microsoft Graph. Register an application first:
- Open the Azure portal → Microsoft Entra ID → App registrations → New registration.
- Name it
HybridAD-Manager. - Supported account types: Accounts in this organizational directory only.
- Redirect URI: platform Public client/native (mobile & desktop) →
http://localhost. - Register, then copy the Application (client) ID.
- Under API permissions, add the Microsoft Graph delegated permissions:
User.Read.AllGroup.Read.AllDirectory.Read.AllOrganization.Read.All
- Click Grant admin consent.
Then set the client ID in HybridADManager/Services/IAuthenticationService.cs:
public class AuthenticationSettings
{
public string ClientId { get; set; } = "your-application-client-id-here";
public string TenantId { get; set; } = "common"; // or your tenant ID / domain
// ...
}
Note: The repository ships with the public Microsoft Graph Explorer client ID as a convenience placeholder so the sign-in flow can be tried immediately. It is not affiliated with this project — register and use your own app for any real tenant.
No other configuration files, secrets, or connection strings exist in the repository. Saved queries and the MSAL token cache live under %LocalAppData%\HybridADManager at runtime and are never committed.
Force sync prerequisites
The Force Sync button runs Start-ADSyncSyncCycle -PolicyType Delta via local PowerShell. It only succeeds when the app is executed on the Azure AD Connect server with the ADSync PowerShell module installed; otherwise it surfaces an explanatory error.
Architecture
flowchart LR
Admin[Administrator] --> Shell[MainWindow: menu, toolbar, tree/list, status bar]
Shell --> VMs[ViewModels: CommunityToolkit.Mvvm]
VMs --> ADSvc[ActiveDirectoryService]
VMs --> AuthSvc[AuthenticationService]
VMs --> GraphSvc[GraphService]
VMs --> Settings[SettingsService: saved queries JSON]
ADSvc --> LDAP[(On-premises Active Directory<br/>System.DirectoryServices / LDAP)]
AuthSvc --> MSAL[MSAL.NET public client<br/>OAuth2 + PKCE, token cache]
GraphSvc --> Graph[(Microsoft Graph v1.0<br/>users, groups, SKUs, mailbox, proxyAddresses)]
AuthSvc --> GraphSvc
GraphSvc --> Sync[Start-ADSyncSyncCycle<br/>via local PowerShell]
Data flow
DirectoryTreeViewModelloads the domain/OU tree from AD, falling back to demo data when no domain is reachable.ObjectListViewModelloads the objects of the selected node and, when signed in, correlates each object with Microsoft Graph by UPN to populate cloud metadata and sync indicators.- Opening an object shows the 13-tab property sheet; the Hybrid Status tab loads live sync state lazily on first open.
- Cloud mutations (license assignment, mailbox settings, proxy addresses) go through
GraphService; directory mutations (enable/disable/delete/move) go throughActiveDirectoryService.
Repository layout
HybridAD-Manager/
├── HybridADManager.sln # Visual Studio solution
├── HybridADManager/
│ ├── App.xaml / App.xaml.cs # Entry point, DI container, global exception handling
│ ├── MainWindow.xaml # Shell: menu, toolbar, tree/list split, status bar
│ ├── Package.appxmanifest # MSIX packaging manifest (placeholder assets)
│ ├── Models/ # DirectoryObject, HybridUser/Group/Computer, SyncStatus, SavedQuery
│ ├── Services/ # AD, MSAL auth, Graph, settings, and dialog services (+ interfaces)
│ ├── ViewModels/ # Main window, tree, list, find/saved-query dialogs, property-sheet tabs
│ ├── Views/ # Tree, list, property sheets (13 tabs), dialogs
│ └── Infrastructure/
│ ├── Converters/ # Value converters (visibility, icons, sync-status brushes)
│ ├── Helpers/ # CSV export helper
│ └── Themes/ # ADUC-style colors, styles, templates, high-contrast theme
├── plan.md # Original development plan
└── AGENTS.md # Guide for AI coding agents working on this repo
Development
| Command | Purpose |
|---|---|
dotnet restore |
Restore NuGet packages. |
dotnet build |
Build the solution (Debug). |
dotnet run --project HybridADManager |
Build and launch the app. |
dotnet publish HybridADManager -c Release -r win-x64 |
Produce a single-file framework-dependent executable. |
The codebase uses nullable reference types and implicit usings, MVVM source generators ([ObservableProperty], [RelayCommand]), and constructor-injected services registered in App.xaml.cs. All UI text, comments, and documentation are in English.
Security
- No credentials, secrets, or tenant identifiers are stored in code or configuration files.
- Authentication uses the OAuth2 public-client flow with PKCE; MFA is supported through the Microsoft identity platform.
- Tokens are cached through the MSAL extension cache with platform protection (Windows DPAPI).
- Cloud operations run under the signed-in administrator's own delegated permissions, so every action is attributable in the Entra ID audit logs.
Screenshots
Coming soon.
Contributing
This project is in early development. Feedback, bug reports, and pull requests are welcome.
- Fork the repository and create a focused branch.
- Verify
dotnet buildsucceeds and exercise the change against either a test domain or the built-in demo data. - Open a pull request describing the motivation and the verification performed.
License
HybridAD-Manager is licensed under the Mozilla Public License 2.0. Modifications to MPL-covered files must remain available under the MPL when distributed.
Acknowledgments
Inspired by the familiar experience of Active Directory Users & Computers and tools like Easy365Manager.