Skip to content

Commit 5e6db25

Browse files
committed
Add scripts for managing Global Address List visibility and configuring DNS settings
- Created Set-HideFromGal.ps1 to hide or show mailboxes in the Global Address List (GAL) for multiple users, supporting Exchange Online, On-Premise Exchange, and Active Directory. - Implemented detailed parameter descriptions, error handling, and reporting features in Set-HideFromGal.ps1. - Added Set-DNS.ps1 to configure DNS server addresses for network adapters, including validation, backup, and rollback capabilities. - Enhanced logging and status messaging in both scripts for better user feedback and error tracking.
1 parent 84051bc commit 5e6db25

14 files changed

Lines changed: 3572 additions & 10 deletions
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# Invoke-UserSignOutAndBlock.ps1
2+
3+
## Overview
4+
5+
Immediately blocks sign-in, revokes all active sessions and refresh tokens, and optionally disables Entra ID-registered devices for one or more Microsoft 365 / Entra ID accounts. Designed for offboarding, incident response, and account compromise scenarios where rapid access revocation is required.
6+
7+
## Features
8+
9+
- **Block sign-in** — Sets `AccountEnabled = $false` so no new authentication attempts succeed
10+
- **Revoke sessions** — Calls Microsoft Graph to invalidate all refresh tokens and active sessions immediately
11+
- **Device reporting** — Lists all Entra ID-registered and Entra ID-joined devices owned by each account
12+
- **Device disablement** — Optionally sets `AccountEnabled = $false` on each owned device in Entra ID (`-DisableDevices`)
13+
- **Multiple input methods** — CSV file, in-memory array, or single UPN/Object ID
14+
- **WhatIf support** — Preview all actions without making changes
15+
- **Timestamped CSV results** — Full per-account report of every action taken
16+
17+
## Prerequisites
18+
19+
### PowerShell Version
20+
- PowerShell 5.1 or PowerShell 7+
21+
22+
### Required Modules
23+
24+
```powershell
25+
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
26+
Install-Module Microsoft.Graph.Users -Scope CurrentUser
27+
Install-Module Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser
28+
```
29+
30+
### Required Permissions (Microsoft Graph)
31+
32+
| Permission | Purpose |
33+
|---|---|
34+
| `User.ReadWrite.All` | Block sign-in, read user details |
35+
| `Directory.ReadWrite.All` | Revoke sign-in sessions |
36+
| `Device.ReadWrite.All` | Disable Entra ID-registered devices |
37+
38+
## Parameters
39+
40+
### Input Parameters (Mutually Exclusive)
41+
42+
| Parameter | Type | Description |
43+
|---|---|---|
44+
| `-CsvPath` | String | Path to CSV file. Required column: `Identity`. Optional column: `Reason`. |
45+
| `-UserArray` | Object[] | Array of PSCustomObjects/hashtables with at minimum an `Identity` property. |
46+
| `-Identity` | String | Single UPN or Entra Object ID for a one-off operation. |
47+
48+
### Behavior Switches
49+
50+
| Parameter | Description |
51+
|---|---|
52+
| `-DisableDevices` | Also disable all Entra ID-registered/joined devices owned by each account. Without this switch, devices are reported but not modified. |
53+
| `-SkipBlockSignIn` | Skip setting `AccountEnabled = $false`. Useful when you only want to revoke sessions. |
54+
| `-SkipRevokeSession` | Skip session revocation. Useful when you only want to block sign-in or disable devices. |
55+
| `-WhatIf` | Show what changes would be made without applying them. |
56+
57+
### Output
58+
59+
| Parameter | Default | Description |
60+
|---|---|---|
61+
| `-OutputDirectory` | `C:\Reports\CSV_Exports` | Directory where the results CSV is saved. |
62+
| `-GenerateTemplate` || Creates a blank CSV template and exits. |
63+
64+
## CSV Format
65+
66+
### Input CSV
67+
68+
```csv
69+
Identity,Reason
70+
jdoe@contoso.com,Offboarding - last day 2026-03-13
71+
jsmith@contoso.com,Account compromise - INC0012345
72+
```
73+
74+
| Column | Required | Description |
75+
|---|---|---|
76+
| `Identity` | Yes | UPN or Entra Object ID |
77+
| `Reason` | No | Logged to the results report for audit purposes |
78+
79+
### Output CSV Columns
80+
81+
| Column | Description |
82+
|---|---|
83+
| `Identity` | Input identity value |
84+
| `DisplayName` | Resolved display name from Entra ID |
85+
| `Reason` | Reason provided in input |
86+
| `SignInBlocked` | Success / Failed / Skipped / WhatIf |
87+
| `SessionsRevoked` | Success / Failed / Skipped / WhatIf |
88+
| `DevicesFound` | Count of Entra ID-registered devices |
89+
| `DevicesDisabled` | Count of devices disabled (requires `-DisableDevices`) |
90+
| `DeviceNames` | Pipe-delimited list of device names and OS |
91+
| `Status` | Success / CompletedWithErrors / Failed |
92+
| `ErrorDetails` | Error messages if any step failed |
93+
| `Timestamp` | Time the account was processed |
94+
95+
## Usage Examples
96+
97+
### Single Account — Block and Revoke Sessions
98+
99+
```powershell
100+
.\Invoke-UserSignOutAndBlock.ps1 -Identity "jdoe@contoso.com"
101+
```
102+
103+
### Single Account — Also Disable Devices
104+
105+
```powershell
106+
.\Invoke-UserSignOutAndBlock.ps1 -Identity "jdoe@contoso.com" -DisableDevices
107+
```
108+
109+
### Bulk from CSV
110+
111+
```powershell
112+
.\Invoke-UserSignOutAndBlock.ps1 -CsvPath "C:\Data\offboard.csv" -DisableDevices
113+
```
114+
115+
### From Array (scripted/automation scenarios)
116+
117+
```powershell
118+
$accounts = @(
119+
[PSCustomObject]@{ Identity = "jdoe@contoso.com"; Reason = "Offboarding" }
120+
[PSCustomObject]@{ Identity = "jsmith@contoso.com"; Reason = "Account compromise" }
121+
)
122+
.\Invoke-UserSignOutAndBlock.ps1 -UserArray $accounts -DisableDevices
123+
```
124+
125+
### Preview Without Making Changes
126+
127+
```powershell
128+
.\Invoke-UserSignOutAndBlock.ps1 -CsvPath "C:\Data\offboard.csv" -WhatIf
129+
```
130+
131+
### Generate CSV Template
132+
133+
```powershell
134+
.\Invoke-UserSignOutAndBlock.ps1 -GenerateTemplate -OutputDirectory "C:\Data"
135+
```
136+
137+
### Revoke Sessions Only (Don't Block Sign-In)
138+
139+
```powershell
140+
.\Invoke-UserSignOutAndBlock.ps1 -Identity "jdoe@contoso.com" -SkipBlockSignIn
141+
```
142+
143+
### Block Sign-In Only (Don't Revoke Sessions)
144+
145+
```powershell
146+
.\Invoke-UserSignOutAndBlock.ps1 -Identity "jdoe@contoso.com" -SkipRevokeSession
147+
```
148+
149+
## Important Behavior Notes
150+
151+
### Session Revocation vs. Access Token Expiry
152+
Revoking sessions invalidates all **refresh tokens** immediately — the user cannot silently renew access. However, existing short-lived **access tokens** (typically 1-hour lifetime) remain valid until they naturally expire. Blocking sign-in (`AccountEnabled = $false`) prevents any renewal of those tokens, so combining both actions is the most effective approach.
153+
154+
### Device Disablement Scope
155+
Disabling a device in Entra ID prevents it from authenticating to cloud services. However:
156+
- The user's **local Windows session** on the device is not immediately terminated
157+
- The device is **not wiped or retired** from Intune — use the Intune portal or a dedicated script for remote wipe
158+
159+
### What `-DisableDevices` Targets
160+
Only devices where the user is the **registered owner** in Entra ID are affected. Shared/unowned devices used by the account are not modified.
161+
162+
## Output
163+
164+
```
165+
Output file: C:\Reports\CSV_Exports\UserSignOutAndBlock_Results_YYYYMMDD_HHmmss.csv
166+
```
167+
168+
## Common Issues & Troubleshooting
169+
170+
### "The property 'Count' cannot be found on this object"
171+
This was a known issue with PowerShell 5.1 when `Get-MgUserOwnedDevice` returns a single object. Fixed in v1.0 by wrapping the result in `@()`.
172+
173+
### Module Not Found
174+
```powershell
175+
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Users, Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser
176+
```
177+
178+
### Insufficient Permissions
179+
Ensure the connecting account (or app registration) has `User.ReadWrite.All`, `Directory.ReadWrite.All`, and `Device.ReadWrite.All` granted in Entra ID.
180+
181+
### User Not Found
182+
The script will log a `Failed` status for accounts that cannot be resolved and continue processing remaining accounts.
183+
184+
## Version History
185+
186+
- **v1.0** (2026-03-13): Initial release — block sign-in, revoke sessions, report/disable devices; CSV/array/single input; WhatIf support
187+
188+
## See Also
189+
190+
- [Microsoft Docs: Revoke Sign-In Sessions](https://learn.microsoft.com/en-us/graph/api/user-revokesigninsessions)
191+
- [Microsoft Docs: Update User (AccountEnabled)](https://learn.microsoft.com/en-us/graph/api/user-update)
192+
- [Microsoft Docs: Update Device](https://learn.microsoft.com/en-us/graph/api/device-update)
193+
- [[Set-EmailToSharedAccount]] — Convert offboarded mailboxes to shared and remove licenses
194+
- [[Set-SMTPForward]] — Configure SMTP forwarding during offboarding or migration
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Set-EmailToSharedAccount.ps1
2+
3+
## Overview
4+
5+
Converts regular Exchange Online user mailboxes to Shared Mailboxes and removes all assigned Microsoft 365 licenses in bulk. Commonly used during offboarding, tenant migrations, and cost-reduction initiatives where accounts need to remain accessible but no longer require a paid license.
6+
7+
## Features
8+
9+
- **Bulk conversion** — CSV file, in-memory array, or single-identity input
10+
- **Mailbox type conversion**`Set-Mailbox -Type Shared` via Exchange Online
11+
- **License removal** — Strips all assigned SKUs via Microsoft Graph
12+
- **Already-shared detection** — Skips conversion if mailbox is already a Shared type (non-fatal warning)
13+
- **No-license graceful handling** — Skips license removal if no licenses are assigned (non-fatal)
14+
- **WhatIf support** — Simulate all changes without applying them
15+
- **Timestamped CSV report** — Full per-account results with conversion and license status
16+
- **Template generation**`-GenerateTemplate` creates a pre-formatted input CSV
17+
18+
## Prerequisites
19+
20+
### PowerShell Version
21+
- PowerShell 5.1 or later (PowerShell 7 recommended)
22+
23+
### Required Modules
24+
25+
```powershell
26+
Install-Module ExchangeOnlineManagement -Scope CurrentUser
27+
Install-Module Microsoft.Graph.Users -Scope CurrentUser # Only needed for license removal
28+
```
29+
30+
> **Note:** If using `-SkipLicenseRemoval`, only `ExchangeOnlineManagement` is required.
31+
32+
### Required Permissions
33+
34+
| Role | Purpose |
35+
|---|---|
36+
| Exchange Online Administrator _or_ Exchange Recipient Administrator | Convert mailbox type |
37+
| User Administrator _or_ License Administrator | Remove Microsoft 365 licenses |
38+
39+
## Parameters
40+
41+
### Input Parameters (Mutually Exclusive)
42+
43+
| Parameter | Type | Description |
44+
|---|---|---|
45+
| `-CsvPath` | String | Path to CSV file with an `Identity` column (UPN or primary SMTP). |
46+
| `-UserArray` | Object[] | Array of PSCustomObjects/hashtables with an `Identity` property. |
47+
| `-Identity` | String | Single UPN or primary SMTP for one-off conversion. |
48+
49+
### Behavior Options
50+
51+
| Parameter | Description |
52+
|---|---|
53+
| `-SkipLicenseRemoval` | Convert mailbox type only; do not remove licenses. Useful when license management is handled separately. |
54+
| `-WhatIf` | Simulate all changes without applying them. |
55+
56+
### Output
57+
58+
| Parameter | Default | Description |
59+
|---|---|---|
60+
| `-OutputDirectory` | `C:\Reports\CSV_Exports` | Directory where the results CSV is saved. |
61+
| `-GenerateTemplate` || Creates a blank CSV template and exits. |
62+
63+
## CSV Format
64+
65+
### Input CSV
66+
67+
```csv
68+
Identity
69+
jsmith@contoso.com
70+
agarcia@contoso.com
71+
departed@contoso.com
72+
```
73+
74+
Only the `Identity` column is required.
75+
76+
### Output CSV Columns
77+
78+
| Column | Description |
79+
|---|---|
80+
| `Identity` | Input identity value |
81+
| `MailboxConverted` | Success / AlreadyShared / WhatIf / No |
82+
| `LicensesRemoved` | Count of SKUs removed, or "Skipped" / "None" / "N/A" |
83+
| `LicensesSkipped` | Count of SKUs that failed removal |
84+
| `Status` | Success / PartialSuccess / Failed |
85+
| `Details` | Additional context for warnings or errors |
86+
| `Timestamp` | Time the account was processed |
87+
88+
## Usage Examples
89+
90+
### Single Account
91+
92+
```powershell
93+
.\Set-EmailToSharedAccount.ps1 -Identity "jsmith@contoso.com"
94+
```
95+
96+
### Single Account — Convert Only (Keep License)
97+
98+
```powershell
99+
.\Set-EmailToSharedAccount.ps1 -Identity "jsmith@contoso.com" -SkipLicenseRemoval
100+
```
101+
102+
### Bulk from CSV
103+
104+
```powershell
105+
.\Set-EmailToSharedAccount.ps1 -CsvPath "C:\Data\offboard.csv"
106+
```
107+
108+
### Bulk from CSV — Preview First
109+
110+
```powershell
111+
.\Set-EmailToSharedAccount.ps1 -CsvPath "C:\Data\offboard.csv" -WhatIf
112+
```
113+
114+
### From Array
115+
116+
```powershell
117+
$users = @(
118+
[PSCustomObject]@{ Identity = "alice@contoso.com" }
119+
[PSCustomObject]@{ Identity = "bob@contoso.com" }
120+
)
121+
.\Set-EmailToSharedAccount.ps1 -UserArray $users
122+
```
123+
124+
### Generate CSV Template
125+
126+
```powershell
127+
.\Set-EmailToSharedAccount.ps1 -GenerateTemplate -OutputDirectory "C:\Data"
128+
# Creates: C:\Data\SharedMailbox_Template.csv
129+
```
130+
131+
## Behavior Notes
132+
133+
### License Removal
134+
All SKUs assigned to the account are removed via `Set-MgUserLicense`. If the account has no licenses, this step is silently skipped and logged as "None" — it is not treated as an error.
135+
136+
### Already-Shared Mailboxes
137+
If the mailbox is already of type `SharedMailbox`, the conversion step is skipped with a warning. License removal still proceeds unless `-SkipLicenseRemoval` is specified.
138+
139+
### Partial Success
140+
If the mailbox conversion succeeds but license removal fails (or vice versa), the row is logged as `PartialSuccess` rather than `Failed`.
141+
142+
### Shared Mailbox License Requirements
143+
Shared mailboxes do not require a paid license as long as the total mailbox size stays under 50 GB. Above 50 GB, an Exchange Online Plan 2 license is required.
144+
145+
## Output
146+
147+
```
148+
Output file: C:\Reports\CSV_Exports\SharedMailbox_Results_YYYYMMDD_HHmmss.csv
149+
```
150+
151+
## Common Issues & Troubleshooting
152+
153+
### "Mailbox Not Found"
154+
Verify the UPN or primary SMTP is correct. The account must have an Exchange Online mailbox (not just an Entra ID account).
155+
156+
### License Removal Fails but Conversion Succeeds
157+
Check that the authenticated account has at least **User Administrator** or **License Administrator** role. The script logs these as `PartialSuccess` so they're easy to identify in the CSV.
158+
159+
### Module Not Found
160+
```powershell
161+
Install-Module ExchangeOnlineManagement, Microsoft.Graph.Users -Scope CurrentUser
162+
```
163+
164+
### No Write Permission to Output Directory
165+
Run the script as a user with write access to the output path, or specify a different `-OutputDirectory`.
166+
167+
## Version History
168+
169+
- **v1.0** (2026-03-13): Initial release — bulk shared mailbox conversion, license removal, CSV/array/single input, WhatIf support, template generation
170+
171+
## See Also
172+
173+
- [Microsoft Docs: Set-Mailbox](https://learn.microsoft.com/powershell/module/exchange/set-mailbox)
174+
- [Microsoft Docs: Assign/Remove Licenses via Graph](https://learn.microsoft.com/graph/api/user-assignlicense)
175+
- [[Invoke-UserSignOutAndBlock]] — Block sign-in and revoke sessions for offboarded accounts
176+
- [[Set-SMTPForward]] — Configure SMTP forwarding to redirect mail after conversion

0 commit comments

Comments
 (0)