Skip to content

Commit 88a3f23

Browse files
committed
Add Clear-OnPremExchangeAttributes script for Exchange migration
- New script to remove on-premises Exchange attributes from AD accounts - Enables cloud mailbox provisioning in Exchange Online - Features: automatic backup, rollback capability, bulk processing - Supports single user, OU-based, or CSV bulk operations - Includes WhatIf testing and comprehensive error handling - Complete wiki documentation with examples and troubleshooting - Validated for public release: 2026-02-02
1 parent e8c0d8a commit 88a3f23

2 files changed

Lines changed: 1099 additions & 0 deletions

File tree

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# Clear-OnPremExchangeAttributes
2+
3+
## Overview
4+
Removes on-premises Exchange attributes from Active Directory user accounts to enable cloud mailbox provisioning in Exchange Online. This script is essential when decommissioning on-premises Exchange or migrating to a cloud-only Exchange Online environment without hybrid configuration.
5+
6+
## Features
7+
- **Pre-execution backup** of all Exchange attributes to CSV with base64 encoding for binary data
8+
- **Comprehensive attribute removal** including msExchMailboxGuid (primary blocker) and 18+ other Exchange attributes
9+
- **Rollback capability** using backup data with `-RestoreFromBackup` parameter
10+
- **Flexible targeting** - single user, OU-based, or CSV bulk import
11+
- **WhatIf support** for safe testing before execution
12+
- **Detailed logging** with timestamped status messages and color-coded output
13+
- **Automatic validation** checks before and after cleanup
14+
- **Summary reports** with execution statistics and next steps
15+
16+
## Prerequisites
17+
- **Active Directory PowerShell module** (RSAT tools)
18+
- **Domain Administrator or Account Operator permissions**
19+
- **PowerShell 5.1 or later**
20+
- **Network connectivity** to Active Directory domain controllers
21+
22+
## Parameters
23+
24+
### Required Parameters (choose one mode)
25+
- **Identity**: The SamAccountName, UserPrincipalName, or DistinguishedName of a single user to process
26+
- **SearchBase**: Active Directory OU to search for users (e.g., "OU=Users,OU=ToMigrate,DC=contoso,DC=com")
27+
- **InputFile**: Path to CSV file with users (must contain 'Identity' column)
28+
29+
### Optional Parameters
30+
- **OutputDirectory**: Directory for backups and reports (Default: `C:\Reports\ExchangeCleanup`)
31+
- **AttributesToRemove**: Specific Exchange attributes to remove (defaults to standard blocking attributes)
32+
- **BackupOnly**: Only creates backup without removing attributes (useful for assessment)
33+
- **RestoreFromBackup**: Path to backup CSV file for rollback operations
34+
- **WhatIf**: Shows what would happen without making changes
35+
- **Force**: Bypasses confirmation prompts (use with caution)
36+
- **ListAttributes**: Lists all Exchange-related attributes and exits
37+
38+
## Usage Examples
39+
40+
### Example 1: Test Single User (Recommended First Step)
41+
```powershell
42+
.\Clear-OnPremExchangeAttributes.ps1 -Identity "jsmith" -WhatIf
43+
```
44+
Tests removal of Exchange attributes without making changes. Review the attributes that would be removed.
45+
46+
### Example 2: Clean Single User
47+
```powershell
48+
.\Clear-OnPremExchangeAttributes.ps1 -Identity "jsmith"
49+
```
50+
Backs up and removes Exchange attributes for user jsmith. Requires typing `PROCEED` to confirm.
51+
52+
### Example 3: Assessment Only (Backup Without Removal)
53+
```powershell
54+
.\Clear-OnPremExchangeAttributes.ps1 -Identity "jsmith" -BackupOnly
55+
```
56+
Creates backup of Exchange attributes without removing them. Useful for auditing what attributes exist.
57+
58+
### Example 4: Bulk Processing from CSV
59+
```powershell
60+
# Create CSV with user identities
61+
$users = @('jsmith', 'mjones', 'bwilson')
62+
$users | ForEach-Object { [PSCustomObject]@{Identity=$_} } | Export-Csv "C:\temp\users.csv" -NoTypeInformation
63+
64+
# Process all users
65+
.\Clear-OnPremExchangeAttributes.ps1 -InputFile "C:\temp\users.csv"
66+
```
67+
Processes multiple users from CSV file. Type `PROCEED` when prompted to execute.
68+
69+
### Example 5: Process Entire OU
70+
```powershell
71+
.\Clear-OnPremExchangeAttributes.ps1 -SearchBase "OU=ToMigrate,OU=Users,DC=contoso,DC=com"
72+
```
73+
Backs up and removes Exchange attributes for all users in specified OU.
74+
75+
### Example 6: Force Execution (No Prompts)
76+
```powershell
77+
.\Clear-OnPremExchangeAttributes.ps1 -Identity "jsmith" -Force
78+
```
79+
Bypasses confirmation prompt. Use with caution in production.
80+
81+
### Example 7: Restore from Backup (Rollback)
82+
```powershell
83+
.\Clear-OnPremExchangeAttributes.ps1 -RestoreFromBackup "C:\Reports\ExchangeCleanup\ExchangeAttributes_Backup_20260202_143052.csv"
84+
```
85+
Restores Exchange attributes from previous backup. Requires typing `RESTORE` to confirm.
86+
87+
### Example 8: List Available Attributes
88+
```powershell
89+
.\Clear-OnPremExchangeAttributes.ps1 -ListAttributes
90+
```
91+
Displays all Exchange attributes that can be removed (default and extended lists).
92+
93+
## Output
94+
95+
### Console Output
96+
The script provides real-time color-coded status messages:
97+
- **Cyan** - Informational messages and headers
98+
- **Green** - Success messages with ✅ checkmark
99+
- **Yellow** - Warnings with ⚠️ symbol
100+
- **Red** - Errors with ❌ symbol
101+
102+
### Output File Locations
103+
Default output directory: `C:\Reports\ExchangeCleanup\`
104+
105+
Generated files follow timestamp pattern: `{Type}_{YYYYMMDD_HHmmss}.{ext}`
106+
107+
#### 1. Backup File (CSV)
108+
**Pattern**: `ExchangeAttributes_Backup_YYYYMMDD_HHmmss.csv`
109+
110+
**Example**: `ExchangeAttributes_Backup_20260202_143052.csv`
111+
112+
Contains complete backup of all Exchange attributes for processed users including:
113+
- Standard user properties (SamAccountName, UPN, DN, DisplayName, Enabled)
114+
- All Exchange attributes (msExchMailboxGuid, legacyExchangeDN, mailNickname, etc.)
115+
- Binary data encoded in base64 format
116+
- Backup timestamp
117+
118+
#### 2. Results File (CSV)
119+
**Pattern**: `ExchangeCleanup_Results_YYYYMMDD_HHmmss.csv`
120+
121+
**Example**: `ExchangeCleanup_Results_20260202_143052.csv`
122+
123+
Contains detailed results for each user:
124+
- `User`: SamAccountName
125+
- `RemovedCount`: Number of attributes successfully removed
126+
- `RemovedAttributes`: List of removed attribute names
127+
- `FailedAttributes`: List of attributes that failed to remove
128+
- `SkippedAttributes`: Attributes with no values
129+
- `Success`: Boolean indicating if operation succeeded
130+
131+
#### 3. Summary Report (TXT)
132+
**Pattern**: `ExchangeCleanup_Summary_YYYYMMDD_HHmmss.txt`
133+
134+
**Example**: `ExchangeCleanup_Summary_20260202_143052.txt`
135+
136+
Comprehensive summary including:
137+
- Operation statistics (total processed, successful, errors, skipped)
138+
- File locations for backup and results
139+
- Execution time and duration
140+
- Error details if any occurred
141+
- Next steps for completing migration
142+
143+
## Exchange Attributes Removed
144+
145+
### Default Attributes (Primary Blockers)
146+
These attributes prevent cloud mailbox provisioning:
147+
148+
- **msExchMailboxGuid** - Primary blocker, must be removed
149+
- **msExchArchiveGUID** - Archive mailbox identifier
150+
- **msExchRemoteRecipientType** - Remote recipient type flags
151+
- **msExchRecipientDisplayType** - Display type (1073741824 = user mailbox)
152+
- **msExchRecipientTypeDetails** - Detailed recipient type
153+
- **msExchUserCulture** - User locale settings
154+
- **msExchVersion** - Exchange schema version
155+
- **msExchMailboxSecurityDescriptor** - Mailbox permissions
156+
- **msExchMasterAccountSid** - Master account SID
157+
- **msExchPoliciesExcluded** - Policy exclusions
158+
- **msExchRecipientSoftDeletedStatus** - Soft delete status
159+
- **msExchUserAccountControl** - Account control flags
160+
- **msExchWhenMailboxCreated** - Mailbox creation timestamp
161+
- **mailNickname** - Exchange alias
162+
- **legacyExchangeDN** - Legacy distinguished name
163+
- **targetAddress** - Routing address
164+
- **msExchHomeServerName** - Home server path
165+
- **homeMDB** - Mailbox database location
166+
- **msExchMailboxTemplateLink** - Mailbox template reference
167+
168+
### Extended Attributes (Comprehensive Cleanup)
169+
Additional attributes removed with `-AttributesToRemove` parameter:
170+
171+
- msExchAddressBookFlags, msExchArchiveDatabaseLink, msExchArchiveName
172+
- msExchArchiveQuota, msExchArchiveWarnQuota, msExchBypassAudit
173+
- msExchBypassModerationLink, msExchDelegateListLink, msExchELCMailboxFlags
174+
- msExchHideFromAddressLists, msExchMailboxAuditEnable, msExchMailboxFolderSet
175+
- msExchMobileMailboxFlags, msExchProvisioningFlags, msExchRBACPolicyLink
176+
- msExchRecipientLimit, msExchRetentionComment, msExchRetentionURL
177+
- msExchSafeSendersHash, msExchTextMessagingState, msExchUMDtmfMap
178+
179+
## Common Issues & Troubleshooting
180+
181+
### Issue: "Active Directory PowerShell module is not installed"
182+
**Solution**: Install RSAT tools:
183+
```powershell
184+
# Windows 10/11
185+
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
186+
187+
# Windows Server
188+
Install-WindowsFeature RSAT-AD-PowerShell
189+
```
190+
191+
### Issue: "Cannot connect to Active Directory"
192+
**Solution**:
193+
- Ensure you're running from domain-joined machine
194+
- Verify network connectivity to domain controller
195+
- Check if you have appropriate permissions
196+
197+
### Issue: "No write permission to output directory"
198+
**Solution**:
199+
```powershell
200+
# Run with different output directory
201+
.\Clear-OnPremExchangeAttributes.ps1 -Identity "jsmith" -OutputDirectory "C:\temp\ExchangeCleanup"
202+
```
203+
204+
### Issue: "Could not find user: username"
205+
**Solution**:
206+
- Verify user exists in Active Directory
207+
- Check spelling of username
208+
- Try using UserPrincipalName or DistinguishedName instead
209+
210+
### Issue: "Successfully Cleaned: 0" with no errors
211+
**Cause**: Attributes may not have values or were already removed
212+
213+
**Solution**: Check backup CSV to see if attributes existed:
214+
```powershell
215+
Import-Csv "C:\Reports\ExchangeCleanup\ExchangeAttributes_Backup_*.csv" |
216+
Select-Object SamAccountName, msExchMailboxGuid, mailNickname, legacyExchangeDN |
217+
Format-List
218+
```
219+
220+
### Issue: Mailbox still won't provision after cleanup
221+
**Possible Causes**:
222+
1. Azure AD Connect hasn't synced changes yet
223+
2. User still has mailbox license assigned before attributes were cleared
224+
3. Deleted mailbox still in soft-deleted state in Exchange Online
225+
226+
**Solution**:
227+
```powershell
228+
# 1. Force Azure AD Connect sync
229+
Start-ADSyncSyncCycle -PolicyType Delta
230+
231+
# 2. Wait 15-30 minutes, then remove and reassign license
232+
233+
# 3. Check for soft-deleted mailboxes in Exchange Online
234+
Connect-ExchangeOnline
235+
Get-Mailbox -SoftDeletedMailbox -Identity "user@domain.com"
236+
```
237+
238+
## Rollback Procedure
239+
240+
If mailbox provisioning fails or you need to restore original state:
241+
242+
```powershell
243+
# Restore from backup
244+
.\Clear-OnPremExchangeAttributes.ps1 -RestoreFromBackup "C:\Reports\ExchangeCleanup\ExchangeAttributes_Backup_20260202_143052.csv"
245+
246+
# Type: RESTORE
247+
# Wait for completion
248+
249+
# Force Azure AD Connect sync
250+
Start-ADSyncSyncCycle -PolicyType Delta
251+
```
252+
253+
## Post-Cleanup Steps
254+
255+
### 1. Review Backup and Results
256+
```powershell
257+
# Check what was removed
258+
Import-Csv "C:\Reports\ExchangeCleanup\ExchangeCleanup_Results_*.csv" |
259+
Where-Object { $_.RemovedCount -gt 0 } |
260+
Format-Table User, RemovedCount, Success -AutoSize
261+
```
262+
263+
### 2. Force Azure AD Connect Sync (Hybrid Environments)
264+
```powershell
265+
# On Azure AD Connect server
266+
Start-ADSyncSyncCycle -PolicyType Delta
267+
```
268+
269+
### 3. Wait for Replication
270+
Allow 15-30 minutes for changes to replicate to Azure AD.
271+
272+
### 4. Assign Exchange Online Licenses
273+
```powershell
274+
Connect-MgGraph -Scopes "User.ReadWrite.All"
275+
276+
# Assign license (example)
277+
Set-MgUserLicense -UserId "jsmith@contoso.com" -AddLicenses @{SkuId="<License-SKU-ID>"} -RemoveLicenses @()
278+
```
279+
280+
### 5. Verify Mailbox Provisioning
281+
```powershell
282+
Connect-ExchangeOnline
283+
284+
# Check if mailbox exists
285+
Get-Mailbox -Identity "jsmith@contoso.com"
286+
287+
# May take 30-60 minutes for mailbox to provision
288+
```
289+
290+
### 6. Test Mail Flow
291+
Send test email to verify mailbox is functioning correctly.
292+
293+
## When to Use This Script
294+
295+
### Required Scenarios
296+
- **Decommissioning on-premises Exchange** after full migration to Exchange Online
297+
- **Moving to Exchange Online without hybrid** configuration
298+
- **Fixing orphaned Exchange attributes** from previous failed migrations
299+
- **Preparing users for cloud-only mailboxes** after data migration
300+
- **Resolving "mailbox already exists"** errors in Exchange Online
301+
302+
### Not Recommended For
303+
- **Active hybrid Exchange environments** - use proper migration tools instead
304+
- **Users with active on-premises mailboxes** - migrate data first
305+
- **Environments with Exchange Online Hybrid** - use New-MoveRequest
306+
- **Production without testing** - always test with -WhatIf first
307+
308+
## Important Warnings
309+
310+
⚠️ **Data Loss Prevention**:
311+
- Always backup before running (script does this automatically)
312+
- Test with `-WhatIf` first
313+
- Verify backup file was created successfully
314+
- This disconnects users from on-premises Exchange mailboxes
315+
316+
⚠️ **Prerequisites**:
317+
- Ensure all mailbox data has been migrated to Exchange Online
318+
- Verify users have appropriate Exchange Online licenses
319+
- Confirm Azure AD Connect is functioning properly (if hybrid)
320+
321+
⚠️ **Cannot Be Undone Without Backup**:
322+
- Once attributes are cleared, on-premises mailbox link is permanently broken
323+
- Use `-RestoreFromBackup` to rollback if needed
324+
- Keep backup files in secure location
325+
326+
## Related Scripts
327+
- [Get-ComprehensiveADReport.ps1](../../On%20Premise/Get-ComprehensiveADReport.md) - Assess AD environment before migration
328+
- [Get-MailboxPermissionsReport.ps1](../../Assessments/Microsoft365/Get-MailboxPermissionsReport.md) - Document mailbox permissions
329+
- [New-Office365Accounts.ps1](../../Office365/New-Office365Accounts.md) - Create Exchange Online mailboxes
330+
331+
## Version History
332+
- **v1.0** (2026-02-02): Initial release
333+
- Core functionality for removing Exchange attributes
334+
- Backup and restore capabilities
335+
- Support for single user, OU, and bulk CSV processing
336+
- WhatIf support and comprehensive error handling
337+
- Improved attribute detection for accurate removal
338+
339+
## See Also
340+
- [Microsoft: Decommission on-premises Exchange servers](https://docs.microsoft.com/en-us/exchange/decommission-on-premises-exchange)
341+
- [Microsoft: Exchange Online mailbox migration](https://docs.microsoft.com/en-us/exchange/mailbox-migration/mailbox-migration)
342+
- [Azure AD Connect sync](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sync-whatis)

0 commit comments

Comments
 (0)