Skip to content

Commit 1c0563f

Browse files
authored
Merge pull request #2544 from microsoft/users/bilong/fix-permissionexport
Fix ManagePublicFolderPermissions.ps1 -Export: Folder string inputs, Mailbox coercion, and loop variable shadow
2 parents 9566a2c + fd580f9 commit 1c0563f

1 file changed

Lines changed: 46 additions & 10 deletions

File tree

PublicFolders/ManagePublicFolderPermissions.ps1

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,35 @@ end {
187187

188188
if (-not $Mailbox) {
189189
Write-Host "No mailbox specified. Using the root public folder mailbox."
190-
$Mailbox = Get-Mailbox -PublicFolder (Get-OrganizationConfig -ErrorAction Stop).RootPublicFolderMailbox -ErrorAction Stop
190+
$rootPublicFolderMailbox = (Get-OrganizationConfig -ErrorAction Stop).RootPublicFolderMailbox
191+
$resolvedMailbox = Get-Mailbox -PublicFolder -Identity $rootPublicFolderMailbox -ErrorAction Stop
191192
} else {
192-
$Mailbox = Get-Mailbox -PublicFolder -Identity $Mailbox -ErrorAction Stop
193+
$resolvedMailbox = Get-Mailbox -PublicFolder -Identity $Mailbox -ErrorAction Stop
193194
}
194195

196+
# Get-Mailbox in ExchangeOnlineManagement returns a Microsoft.Exchange.Data.Directory.Management.Mailbox
197+
# whose ToString() returns an empty string. Assigning it back into the [string]-typed $Mailbox
198+
# parameter triggers PowerShell coercion that falls back to a property-bag dump
199+
# (@{Prop=Val; ...}) when ToString() is empty, and that malformed string breaks downstream
200+
# cmdlets. Extract a stable identifier explicitly instead.
201+
$mailboxForCmdlet = if ($resolvedMailbox.ExchangeGuid -and $resolvedMailbox.ExchangeGuid.Guid) {
202+
$resolvedMailbox.ExchangeGuid.Guid.ToString()
203+
} elseif (-not [string]::IsNullOrWhiteSpace([string]$resolvedMailbox.PrimarySmtpAddress)) {
204+
[string]$resolvedMailbox.PrimarySmtpAddress
205+
} elseif (-not [string]::IsNullOrWhiteSpace([string]$resolvedMailbox.Identity)) {
206+
[string]$resolvedMailbox.Identity
207+
} else {
208+
throw "Resolved public folder mailbox does not expose an ExchangeGuid, PrimarySmtpAddress, or Identity that can be used."
209+
}
210+
211+
$exportedFromValue = if (-not [string]::IsNullOrWhiteSpace([string]$resolvedMailbox.PrimarySmtpAddress)) {
212+
[string]$resolvedMailbox.PrimarySmtpAddress
213+
} else {
214+
$mailboxForCmdlet
215+
}
216+
217+
$Mailbox = $mailboxForCmdlet
218+
195219
if ($foldersToProcess.Count -lt 1) {
196220
Write-Host "Retrieving all public folders..."
197221
$foldersToProcess = Get-PublicFolder -Recurse -ResultSize Unlimited | Select-Object -Skip 1
@@ -206,26 +230,38 @@ end {
206230
$exportBatch = New-Object System.Collections.ArrayList
207231
$progressCount = 0
208232

209-
foreach ($folder in $foldersToProcess) {
233+
# NOTE: Use $currentFolder (not $folder) as the loop variable. The script parameter
234+
# is declared [object[]]$Folder, and PowerShell variable names are case-insensitive,
235+
# so assigning to $folder inside the loop re-coerces the iteration value back into
236+
# [object[]] - turning a string element into Object[1]{ "<string>" } on every iteration.
237+
foreach ($currentFolder in $foldersToProcess) {
210238
$progressCount++
211239

212-
if ($folder.Identity -eq "\" -or $folder.Identity -eq "\non_ipm_subtree") {
240+
# -Folder accepts public folder objects or identity strings. Resolve string inputs to
241+
# full folder objects so the rest of the loop can rely on Identity/EntryId/ContentMailboxName.
242+
if ($currentFolder -is [string]) {
243+
$currentFolder = Get-PublicFolder -Identity $currentFolder -ErrorAction Stop
244+
} elseif ($null -eq $currentFolder.Identity) {
245+
throw "Folder input must be a public folder object with an Identity property or a public folder identity string. Received an object of type '$($currentFolder.GetType().FullName)'."
246+
}
247+
248+
if ($currentFolder.Identity -eq "\" -or $currentFolder.Identity -eq "\non_ipm_subtree") {
213249
continue
214250
}
215251

216-
if ($alreadyExported.Contains($folder.Identity.ToString())) {
252+
if ($alreadyExported.Contains($currentFolder.Identity.ToString())) {
217253
continue
218254
}
219255

220256
Write-Progress -Activity "Processing public folders" -Status "Folder $progressCount of $($foldersToProcess.Count)" -PercentComplete (($progressCount / $foldersToProcess.Count) * 100)
221257

222-
$permissions = Get-PublicFolderClientPermission -Identity "$($folder.Identity)" -Mailbox $mailbox
258+
$permissions = Get-PublicFolderClientPermission -Identity "$($currentFolder.Identity)" -Mailbox $mailbox
223259
foreach ($perm in $permissions) {
224260
$exportBatch.Add([PSCustomObject]@{
225-
EntryId = $folder.EntryId
226-
FolderPath = $folder.Identity
227-
ContentMailboxName = $folder.ContentMailboxName
228-
ExportedFrom = $Mailbox.ToString()
261+
EntryId = $currentFolder.EntryId
262+
FolderPath = $currentFolder.Identity
263+
ContentMailboxName = $currentFolder.ContentMailboxName
264+
ExportedFrom = $exportedFromValue
229265
DisplayName = $perm.User.DisplayName
230266
PrimarySmtpAddress = $perm.User.RecipientPrincipal.PrimarySmtpAddress
231267
Guid = $perm.User.RecipientPrincipal.Guid

0 commit comments

Comments
 (0)