Created
February 20, 2026 11:31
-
-
Save win2000b/207d18f1a2a13b0aa844a11e1d117f1e to your computer and use it in GitHub Desktop.
Goes through CSV and unhides users in Exchange Online
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# ------------------------------------------------------------ | |
| UnhideFromGAL_FromExport_WithStatusCsv.ps1 | |
| Uses the export CSV from the proxy export (Identity,Type,Value). | |
| Processes UNIQUE identities and sets: | |
| HiddenFromAddressListsEnabled = $false | |
| Writes a status CSV in the same format as the import CSV log: | |
| Identity,Type,Value,Status,Message,Timestamp | |
| Hard-coded paths. | |
| Supports -WhatIf / -Confirm via ShouldProcess. | |
| Notes: | |
| - This will only "unhide" (set to false). It will not hide anyone. | |
| - Requires Get-Mailbox / Set-Mailbox rights. | |
| ------------------------------------------------------------- #> | |
| [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] | |
| param() | |
| # ---------------------------- | |
| # Hard-coded settings | |
| # ---------------------------- | |
| $InputCsv = "C:\Data\UnhideGAL.csv" | |
| $StatusCsv = "C:\Data\UnhideGAL_Status_{0}.csv" -f (Get-Date -Format "yyyyMMdd_HHmmss") | |
| # If your CSV is semicolon-delimited, set this to ';' otherwise ',' | |
| $Delimiter = ',' | |
| # ---------------------------- | |
| # Helpers | |
| # ---------------------------- | |
| function New-StatusRow { | |
| param( | |
| [string]$Identity, | |
| [string]$Type, | |
| [string]$Value, | |
| [string]$Status, | |
| [string]$Message | |
| ) | |
| [pscustomobject]@{ | |
| Identity = $Identity | |
| Type = $Type | |
| Value = $Value | |
| Status = $Status | |
| Message = $Message | |
| Timestamp = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") | |
| } | |
| } | |
| Write-Host "Reading identities from: $InputCsv" -ForegroundColor Cyan | |
| Write-Host "Writing status CSV to: $StatusCsv" -ForegroundColor Cyan | |
| if (-not (Test-Path $InputCsv)) { | |
| throw "Input CSV not found: $InputCsv" | |
| } | |
| # Import export file | |
| $rows = Import-Csv -Path $InputCsv -Delimiter $Delimiter | |
| if (-not $rows -or $rows.Count -eq 0) { | |
| throw "No rows found in CSV: $InputCsv" | |
| } | |
| # Validate required column exists | |
| $cols = $rows[0].PSObject.Properties.Name | |
| if ($cols -notcontains "Identity") { | |
| throw "CSV must contain column 'Identity'. Found: $($cols -join ', ')" | |
| } | |
| # Build a unique list of identities, while keeping a representative Type/Value for logging format | |
| $identityMap = @{} # Identity -> @{Type=; Value=} | |
| foreach ($r in $rows) { | |
| $id = ([string]$r.Identity).Trim() | |
| if ([string]::IsNullOrWhiteSpace($id)) { continue } | |
| if (-not $identityMap.ContainsKey($id)) { | |
| # Keep first seen Type/Value (if present) just for log shape | |
| $t = "" | |
| $v = "" | |
| if ($cols -contains "Type") { $t = ([string]$r.Type).Trim() } | |
| if ($cols -contains "Value") { $v = [string]$r.Value } | |
| $identityMap[$id] = @{ Type = $t; Value = $v } | |
| } | |
| } | |
| $statusOut = New-Object System.Collections.Generic.List[object] | |
| if ($identityMap.Keys.Count -eq 0) { | |
| $statusOut.Add((New-StatusRow -Identity "" -Type "" -Value "" -Status "Error" -Message "No valid Identity values found in CSV")) | |
| $statusOut | Export-Csv -Path $StatusCsv -NoTypeInformation -Encoding UTF8 | |
| throw "No valid Identity values found in CSV." | |
| } | |
| foreach ($id in ($identityMap.Keys | Sort-Object)) { | |
| $t = $identityMap[$id].Type | |
| $v = $identityMap[$id].Value | |
| try { | |
| # Get mailbox | |
| $mbx = Get-Mailbox -Identity $id -ErrorAction Stop | |
| # If already unhidden, record and skip | |
| if ($mbx.HiddenFromAddressListsEnabled -eq $false) { | |
| $statusOut.Add((New-StatusRow -Identity $id -Type $t -Value $v -Status "SkippedAlreadyUnhidden" -Message "HiddenFromAddressListsEnabled is already False")) | |
| continue | |
| } | |
| if ($PSCmdlet.ShouldProcess($id, "Set HiddenFromAddressListsEnabled to False (Unhide from GAL)")) { | |
| Set-Mailbox -Identity $id -HiddenFromAddressListsEnabled $false -ErrorAction Stop | |
| $statusOut.Add((New-StatusRow -Identity $id -Type $t -Value $v -Status "Updated" -Message "Mailbox unhidden from GAL (HiddenFromAddressListsEnabled=False)")) | |
| } | |
| else { | |
| $statusOut.Add((New-StatusRow -Identity $id -Type $t -Value $v -Status "WhatIf" -Message "Would unhide mailbox from GAL")) | |
| } | |
| } | |
| catch { | |
| $statusOut.Add((New-StatusRow -Identity $id -Type $t -Value $v -Status "Error" -Message $_.Exception.Message)) | |
| continue | |
| } | |
| } | |
| $statusOut | Export-Csv -Path $StatusCsv -NoTypeInformation -Encoding UTF8 | |
| Write-Host "Done. Status written to: $StatusCsv" -ForegroundColor Green |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment