Skip to content

Extend Edit Remote Mailbox (dev) with alias and GAL management#12

Open
SirTrek wants to merge 7 commits into
spgoodman:devfrom
SirTrek:feature/remote-mailbox-edit-dev
Open

Extend Edit Remote Mailbox (dev) with alias and GAL management#12
SirTrek wants to merge 7 commits into
spgoodman:devfrom
SirTrek:feature/remote-mailbox-edit-dev

Conversation

@SirTrek

@SirTrek SirTrek commented Jul 8, 2026

Copy link
Copy Markdown

Summary

dev already has a GET/POST /editremotemailbox page (nice rewrite — CDN assets, full edit pages for every recipient type). It covers DisplayName, PrimarySmtpAddress-as-identity, Alias (mail nickname), and RemoteRoutingAddress, but had no way to manage secondary SMTP proxy addresses, GAL visibility, or disabling a mailbox, and had no search/sort on any of its list pages. This PR adds all of that on top of dev's existing conventions (POST forms, CDN Bootstrap/feather, card layout):

  • Email Addresses card — lists all EmailAddresses proxy addresses (Primary vs Alias badge), an "Add alias" modal (Set-RemoteMailbox -EmailAddresses @{Add=...}), and a Remove button per alias (@{Remove=...})
  • Hidden from Address Lists card — one-click toggle for HiddenFromAddressListsEnabled
  • Danger Zone card — disable a Remote Mailbox (Disable-RemoteMailbox) behind a type-to-confirm control (must type the mailbox's PrimarySmtpAddress before the button enables), checked server-side too so it can't be bypassed client-side. Since the mailbox no longer exists afterward, it redirects to the Remote Mailboxes list (via a new Get-RemoteMailboxListPage helper) instead of showing an edit page for a gone identity.
  • Search and sort on every list page — Remote Mailboxes, Distribution Groups (both its tables), Contacts, Email Address Policies, and Accepted Domains all get a live search box and clickable/sortable column headers, via one new shared web/table-tools.js (pure client-side against rows already rendered by the server — no new routes, no data refetch).
  • Desktop launcherLaunch-ExchangeRecipientAdmin.bat (self-elevates via UAC, since the Exchange Management Tools assemblies need admin rights to load, which a plain double-clicked shortcut doesn't have) and Create-Shortcut.ps1 (one-time setup script that creates a Desktop shortcut, fully dynamic — no hardcoded paths/usernames).

Both alias/hidden/disable actions POST back to /editremotemailbox with an Action field and re-render with the mailbox's current state, so you see the result immediately instead of bouncing to the list (except disable, which necessarily goes to the list since the identity is gone). I factored the shared rendering into Get-RemoteMailboxEditPage/Get-RemoteMailboxListPage to avoid duplicating the proxy-address/GAL-badge HTML across every action — the one deviation from the rest of the script's style (which inlines everything per-route);

Also includes two small robustness fixes found while building/testing this:

  • The webserver's whole request loop ran inside one try/finally with no catch, so a client dropping its connection mid-response (e.g. "the specified network name is no longer available") took down the entire listener for all users. Same fix as my other PR (Add Remote Mailbox properties/alias/GAL/routing-address management #11) — dev has the identical loop and bug.
  • The type-to-confirm JS for disabling a mailbox depends on feather.replace() running first in the same <script> block; since dev's feather-icons <script> tag has no version pinned, an unrelated feather-icons API change on the CDN threw and silently blocked the confirm button from ever enabling. Wrapped it in try/catch so an icon-library hiccup can't take out unrelated functional JS again.

Related: #11 adds the same alias/GAL/disable functionality against main,

SirTrek added 2 commits July 8, 2026 14:07
The existing editremotemailbox page (GET/POST) only edited DisplayName,
PrimarySmtpAddress-as-identity, Alias (mail nickname), and
RemoteRoutingAddress. It had no way to manage secondary SMTP proxy
addresses or GAL visibility.

Adds:
- An Email Addresses card listing all EmailAddresses proxy addresses,
  with a modal to add a new alias (Set-RemoteMailbox -EmailAddresses
  @{Add=...}) and a Remove button per alias (@{Remove=...})
- A Hidden from Address Lists card with a one-click toggle for
  HiddenFromAddressListsEnabled

Both actions post back to /editremotemailbox with an Action field, and
the page re-renders with the mailbox's current state afterwards.
Factored the shared rendering logic (used by GET and by every POST
action) into Get-RemoteMailboxEditPage to avoid duplicating the
proxy-address/GAL-badge HTML building four times.
The whole request loop ran inside one try/finally with no catch, so
any exception writing a response (e.g. the client closes the
connection or navigates away before the write completes, surfacing
as "The specified network name is no longer available") propagated
out of the while loop and killed the entire listener for all users.

Wraps each request's handling in its own try/catch so a single failed
request is logged and the server keeps listening. Same issue and fix
as on main; ported here since dev has the identical request loop.
@SirTrek

SirTrek commented Jul 8, 2026

Copy link
Copy Markdown
Author

Update: this has now been tested against a live on-prem Exchange Management Tools install (Get-RemoteMailbox/Set-RemoteMailbox for viewing properties, adding/removing aliases, toggling HiddenFromAddressListsEnabled, and changing RemoteRoutingAddress) and works as expected.

SirTrek added 5 commits July 8, 2026 15:47
Adds a "Danger Zone" card to the Edit Remote Mailbox page with a
type-to-confirm control (must type the mailbox's PrimarySmtpAddress
before the Disable button enables) backed by a server-side check of
the same confirmation text, since the client-side JS is trivially
bypassable.

Disable-RemoteMailbox strips the Exchange attributes from the AD
object; it does not delete the Exchange Online mailbox itself. Since
the mailbox no longer exists afterward, the POST handler redirects to
the Remote Mailboxes list (via a new Get-RemoteMailboxListPage helper)
instead of re-rendering an edit page for an identity that's gone.

Local-only change, not opened as a PR upstream.
PowerShell's -eq/-ne string comparison is case-insensitive by default,
but the JS confirm-text check used strict !== (case-sensitive, no
trim). If the AD-stored PrimarySmtpAddress casing differed at all from
what the user typed, or there was stray whitespace, the button stayed
disabled even though the server-side check would have accepted it.

Trim and lowercase both sides of the JS comparison so it matches the
server's more forgiving behavior.
dev's feather-icons <script> tag has no version pinned, so it fetches
whatever's latest on the CDN at page-load time. If that version's API
shape changes, feather.replace() throws, and since it's the first
statement in the shared inline <script> block, the uncaught exception
stopped the type-to-confirm listener code right after it from ever
running - the Disable button stayed permanently disabled regardless
of the casing fix in the previous commit.

Wrap it in try/catch so an icon-library hiccup can't take out
unrelated functional JS again.
Adds web/table-tools.js, a small self-initializing script that finds
every table.table on the page and:
- inserts a search box above it that filters rows by substring match
  across the whole row's text
- makes non-empty column headers clickable to sort rows by that
  column's text, toggling ascending/descending with a ▲/▼ indicator

Wired into all five list pages (Remote Mailboxes, Distribution
Groups, Contacts, Email Address Policies, Accepted Domains) via one
added <script> tag each. Purely client-side against rows already
rendered by the server - no new PowerShell routes, no data refetch,
and it naturally handles distributiongroups.html's two tables since
it operates on every matching table on the page independently.
Launch-ExchangeRecipientAdmin.bat self-elevates via UAC (the Exchange
Management Tools assemblies require admin rights to load, which a
plain double-clicked shortcut doesn't have by default) and resolves
its own folder via %~dp0, so it works regardless of where this project
is placed or which user runs it.

Create-Shortcut.ps1 is a one-time setup script that creates a Desktop
.lnk pointing at the .bat, using the repo's icon if present and
falling back to the stock PowerShell icon otherwise (dev's asset
rewrite removed images/favicon.ico, so that fallback is needed here).

Both are fully dynamic (no hardcoded paths/usernames) - safe to
publish, verified against the actual file contents before committing.
@SirTrek

SirTrek commented Jul 9, 2026

Copy link
Copy Markdown
Author

Update: pushed several more commits since this was opened — disable-mailbox support, client-side search/sort on all list pages, and a desktop shortcut launcher, plus two small bug fixes found along the way. All tested against a live on-prem Exchange Management Tools install. Updated the PR description above to match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant