-
HavardBakke
- Service Provider
- Posts: 4
- Liked: never
- Joined: Sep 10, 2024 8:20 am
- Full Name: Havard Bakke
- Contact:
Powershell - List all users in job based on organization
Hello,
We are trying to export a list of all users for an organization with two jobs (Exchange split into its own job).
We are finding that getting a list without duplicates is practically impossible without manually going through it and removing duplicates or connecting it to other sources. (unless i am missing something).
This is specifically for users that are deleted in M365, since the currently active users can be queried and correlated against M365.
Objects like displayname and email does not always match between to two jobs when we pull the data with Get-VBOEntityData.
Having an option to pull this information based on the organization would be really helpful.
Get-VBOBackupItem will not work, since in the job the entire organization is selected and exclude is used on the resources it should not contain.
We are trying to export a list of all users for an organization with two jobs (Exchange split into its own job).
We are finding that getting a list without duplicates is practically impossible without manually going through it and removing duplicates or connecting it to other sources. (unless i am missing something).
This is specifically for users that are deleted in M365, since the currently active users can be queried and correlated against M365.
Objects like displayname and email does not always match between to two jobs when we pull the data with Get-VBOEntityData.
Having an option to pull this information based on the organization would be really helpful.
Get-VBOBackupItem will not work, since in the job the entire organization is selected and exclude is used on the resources it should not contain.
-
MaartenA
- Service Provider
- Posts: 135
- Liked: 51 times
- Joined: Oct 31, 2021 7:03 am
- Full Name: maarten
- Contact:
Re: Powershell - List all users in job based on organization
Get-VBOOrganizationUser can help you i think?
See https://helpcenter.veeam.com/docs/vbo36 ... html?ver=8
See https://helpcenter.veeam.com/docs/vbo36 ... html?ver=8
-
HavardBakke
- Service Provider
- Posts: 4
- Liked: never
- Joined: Sep 10, 2024 8:20 am
- Full Name: Havard Bakke
- Contact:
Re: Powershell - List all users in job based on organization
That command pulls the information from users that exist in the tennant from what i understand, it wont contain users deleted in the M365 tenant sadly.
-
Polina
- Veeam Software
- Posts: 3890
- Liked: 977 times
- Joined: Oct 21, 2011 11:22 am
- Full Name: Polina Vasileva
Re: Powershell - List all users in job based on organization
Hi Havard,
Sorry, I read it two times but still unsure which users you would like to list - those that are currently included into your backup jobs, those that are already protected/backed up, or those that are available for protection in your tenant organization?
Also, what is the end goal? Am I correct that you want to ensure that your job scopes do not overlap?
Sorry, I read it two times but still unsure which users you would like to list - those that are currently included into your backup jobs, those that are already protected/backed up, or those that are available for protection in your tenant organization?
Also, what is the end goal? Am I correct that you want to ensure that your job scopes do not overlap?
-
HavardBakke
- Service Provider
- Posts: 4
- Liked: never
- Joined: Sep 10, 2024 8:20 am
- Full Name: Havard Bakke
- Contact:
Re: Powershell - List all users in job based on organization
Hello Polina,
Our goal is to list out all users included in repos for organizations.
Exsisting users that are actively beeing backup up and users that have been deleted in M365 but are still retained in the backup.
For customers with only one repo this it works with just querying the repo, but for customers with split jobs we cannot find a way to do this without getting duplicates.
Our goal is to list out all users included in repos for organizations.
Exsisting users that are actively beeing backup up and users that have been deleted in M365 but are still retained in the backup.
For customers with only one repo this it works with just querying the repo, but for customers with split jobs we cannot find a way to do this without getting duplicates.
-
HavardBakke
- Service Provider
- Posts: 4
- Liked: never
- Joined: Sep 10, 2024 8:20 am
- Full Name: Havard Bakke
- Contact:
Re: Powershell - List all users in job based on organization
For anyone with the same issue, this is what we have so far.
It does not remove all duplicates, but it gets close.
It does not remove all duplicates, but it gets close.
Code: Select all
$org = Get-VBOOrganization -Name ""
$jobs = Get-VBOJob | Where-Object { $org.Id -eq $_.Organization.Id }
$repos = $jobs | ForEach-Object { $_.Repository } | Sort-Object -Property Id -Unique
#Union-Find for identity resolution
$parent = @{}
function Find-Root {
param([string]$x)
if (-not $parent.ContainsKey($x)) { $parent[$x] = $x }
while ($parent[$x] -ne $x) {
$parent[$x] = $parent[$parent[$x]] # path compression
$x = $parent[$x]
}
return $x
}
function Union-Keys {
param([string]$a, [string]$b)
$rootA = Find-Root $a
$rootB = Find-Root $b
if ($rootA -ne $rootB) {
# Prefer email-looking keys as root
if ($rootB -match '@' -and $rootA -notmatch '@') {
$parent[$rootA] = $rootB
} else {
$parent[$rootB] = $rootA
}
}
}
function Normalize {
param([string]$value)
if ([string]::IsNullOrWhiteSpace($value)) { return $null }
return $value.Trim().ToLower()
}
#Collect all raw records with their identifiers
# Each raw record: list of identifiers + data
$rawRecords = [System.Collections.Generic.List[hashtable]]::new()
# --- Org users first ---
#Write-Host "Loading M365 organization users..." -ForegroundColor Cyan
$orgUsers = Get-VBOOrganizationUser -Organization $org
#Write-Host "Loaded $($orgUsers.Count) org users" -ForegroundColor Green
foreach ($ou in $orgUsers) {
$ids = [System.Collections.Generic.List[string]]::new()
$email = Normalize $ou.Email
if (-not $email) { $email = Normalize $ou.UserName }
$name = Normalize $ou.DisplayName
if ($email) { $ids.Add($email) }
if ($name -and $name -ne $email) { $ids.Add($name) }
if ($ids.Count -eq 0) { continue }
$rawRecords.Add(@{
Identifiers = $ids
DisplayName = if (-not [string]::IsNullOrWhiteSpace($ou.DisplayName)) { $ou.DisplayName.Trim() } else { $null }
Email = if ($email) { $email } else { $null }
Source = "M365"
RepoName = $null
AccountType = $null
IsMailboxBackedUp = $false
MailboxBackedUpTime = $null
IsArchiveBackedUp = $false
IsOneDriveBackedUp = $false
OneDriveBackedUpTime = $null
IsPersonalSiteBackedUp = $false
})
}
# --- Repo entities ---
foreach ($repo in $repos) {
#Write-Host "Loading repo: $($repo.Name)" -ForegroundColor Cyan
$entities = Get-VBOEntityData -Type User -Repository $repo
foreach ($entity in $entities) {
$ids = [System.Collections.Generic.List[string]]::new()
$email = Normalize $entity.Email
$name = Normalize $entity.DisplayName
if ($email) { $ids.Add($email) }
if ($name -and $name -ne $email) { $ids.Add($name) }
if ($ids.Count -eq 0) { continue }
$rawRecords.Add(@{
Identifiers = $ids
DisplayName = if (-not [string]::IsNullOrWhiteSpace($entity.DisplayName)) { $entity.DisplayName.Trim() } else { $null }
Email = if ($email) { $email } else { $null }
Source = "Repo"
RepoName = $repo.Name
AccountType = if (-not [string]::IsNullOrWhiteSpace($entity.AccountType)) { $entity.AccountType } else { $null }
IsMailboxBackedUp = [bool]$entity.IsMailboxBackedUp
MailboxBackedUpTime = $entity.MailboxBackedUpTime
IsArchiveBackedUp = [bool]$entity.IsArchiveBackedUp
IsOneDriveBackedUp = [bool]$entity.IsOneDriveBackedUp
OneDriveBackedUpTime = $entity.OneDriveBackedUpTime
IsPersonalSiteBackedUp = [bool]$entity.IsPersonalSiteBackedUp
})
}
}
#Write-Host "`nTotal raw records collected: $($rawRecords.Count)" -ForegroundColor Gray
#Build union-find — link all identifiers per record
foreach ($record in $rawRecords) {
$ids = $record.Identifiers
# Ensure all ids for this record are in the same group
for ($i = 1; $i -lt $ids.Count; $i++) {
Union-Keys $ids[0] $ids[$i]
}
}
#Write-Host "Union-find built with $($parent.Count) identifiers" -ForegroundColor Gray
#Merge records by their root identity
$userMap = @{}
foreach ($record in $rawRecords) {
$root = Find-Root $record.Identifiers[0]
if (-not $userMap.ContainsKey($root)) {
$userMap[$root] = [PSCustomObject]@{
DisplayName = $null
Email = $null
AccountType = $null
InM365 = $false
IsMailboxBackedUp = $false
MailboxBackedUpTime = $null
IsArchiveBackedUp = $false
IsOneDriveBackedUp = $false
OneDriveBackedUpTime = $null
IsPersonalSiteBackedUp = $false
Repos = [System.Collections.Generic.List[string]]::new()
}
}
$entry = $userMap[$root]
# Display name: prefer real name over email-as-name
if ($record.DisplayName) {
if (-not $entry.DisplayName -or
($entry.DisplayName -match '@' -and $record.DisplayName -notmatch '@')) {
$entry.DisplayName = $record.DisplayName
}
}
# Email: grab from any source that has it
if ($record.Email -and $record.Email -match '@') {
if (-not $entry.Email) {
$entry.Email = $record.Email
}
}
# Account type: prefer specific (SharedMailbox) over generic (User)
if ($record.AccountType) {
if (-not $entry.AccountType -or
($entry.AccountType -eq 'User' -and $record.AccountType -ne 'User')) {
$entry.AccountType = $record.AccountType
}
}
# M365 presence
if ($record.Source -eq "M365") {
$entry.InM365 = $true
}
# Backup states (OR across all sources)
if ($record.IsMailboxBackedUp) { $entry.IsMailboxBackedUp = $true; $entry.MailboxBackedUpTime = $record.MailboxBackedUpTime }
if ($record.IsArchiveBackedUp) { $entry.IsArchiveBackedUp = $true }
if ($record.IsOneDriveBackedUp) { $entry.IsOneDriveBackedUp = $true; $entry.OneDriveBackedUpTime = $record.OneDriveBackedUpTime }
if ($record.IsPersonalSiteBackedUp) { $entry.IsPersonalSiteBackedUp = $true }
# Repos
if ($record.RepoName -and $entry.Repos -notcontains $record.RepoName) {
$entry.Repos.Add($record.RepoName)
}
}
#Results — only users that appear in at least one repo
$results = $userMap.Values |
Where-Object { $_.Repos.Count -gt 0 } |
ForEach-Object {
$_ | Add-Member -NotePropertyName 'AccountState' -NotePropertyValue $(
if ($_.InM365) { "Active" } else { "Deleted/Retained" }
) -PassThru
} |
Sort-Object AccountState, AccountType, DisplayName
# Summary
$active = ($results | Where-Object { $_.AccountState -eq "Active" }).Count
$deleted = ($results | Where-Object { $_.AccountState -eq "Deleted/Retained" }).Count
$userCount = ($results | Where-Object { $_.AccountType -eq 'User' }).Count
$sharedCount = ($results | Where-Object { $_.AccountType -and $_.AccountType -ne 'User' }).Count
#Write-Host "`n===== $($org.Name) =====" -ForegroundColor Green
#Write-Host "Total unique backed-up entities: $($results.Count)"
#Write-Host "Active in M365: $active"
#Write-Host "Deleted/Retained: $deleted"
#Write-Host "Users: $userCount"
#Write-Host "Shared Mailboxes: $sharedCount"
$results | Format-Table DisplayName, Email, AccountType, AccountState,
IsMailboxBackedUp, IsOneDriveBackedUp, IsPersonalSiteBackedUp,
@{ Name = 'Repos'; Expression = { $_.Repos -join ', ' } } -AutoSize
Who is online
Users browsing this forum: Semrush [Bot], Yann.S and 13 guests