Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 119 additions & 8 deletions TeamViewerADConnector/Internal/ActiveDirectory.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ function Get-ActiveDirectoryGroup($root) {
}

function Get-ActiveDirectoryGroupMember($root, $recursive, $path) {

# Ask-once runtime state (script scope)
if (-not (Get-Variable EmailSuffixOverrideAsked -Scope Script -ErrorAction SilentlyContinue)) {
$script:EmailSuffixOverrideAsked = $false
$script:EmailSuffixOverride = ""
}

$searcher = New-Object System.DirectoryServices.DirectorySearcher

if ($root) {
Expand All @@ -29,19 +36,123 @@ function Get-ActiveDirectoryGroupMember($root, $recursive, $path) {
$searcher.Filter = "(&(objectClass=user)(memberOf=$path))"
}

$searcher.PropertiesToLoad.AddRange(@('name', 'mail', 'userAccountControl', 'proxyAddresses'))
$searcher.PropertiesToLoad.AddRange(@(
'name',
'mail',
'userPrincipalName',
'sAMAccountName',
'userAccountControl',
'proxyAddresses'
))

$searcher.PageSize = 1000
$searcher.SizeLimit = 10000

return $searcher.FindAll() | ForEach-Object { @{
Email = [string]($_.Properties.mail)
Name = [string]($_.Properties.name)
IsEnabled = [bool](($_.Properties.useraccountcontrol.Item(0) -BAND 2) -eq 0)
SecondaryEmails = $_.Properties.proxyaddresses | Select-String -Pattern '^smtp:(.*)$' -CaseSensitive -AllMatches | Select-Object -ExpandProperty Matches | `
Where-Object { $_.Groups.Count -gt 0 } | ForEach-Object { [string]($_.Groups[1].Value).Trim() }
} } | Where-Object { $_.Email -And $_.Name -And $_.IsEnabled }
function Is-EmailLike {
param([string]$Value)
if ([string]::IsNullOrWhiteSpace($Value)) { return $false }
return ($Value.Trim() -match '^[^@\s]+@[^@\s]+\.[^@\s]+$')
}

function Is-LocalEmail {
param([string]$Value)
if (-not (Is-EmailLike $Value)) { return $false }
return ($Value -match '@[^@]+\.local$')
}

function Get-SmtpProxyAddresses {
param($ProxyAddresses)

$out = @()
foreach ($addr in @($ProxyAddresses)) {
if ($addr -match '^(SMTP|smtp):(.*)$') {
$email = $Matches[2].Trim()
if ($email) { $out += $email }
}
}
return $out
}

$searcher.FindAll() | ForEach-Object {

$props = $_.Properties

$name = [string]$props.name
$upn = [string]$props.userprincipalname
$mail = [string]$props.mail
$sam = [string]$props.samaccountname

$enabled = (($props.useraccountcontrol[0] -band 2) -eq 0)
if (-not $enabled) { return }

# ---- Collect candidate emails ----
$candidates = @()

if (Is-EmailLike $upn) { $candidates += $upn }
if (Is-EmailLike $mail) { $candidates += $mail }

$candidates += Get-SmtpProxyAddresses $props.proxyaddresses

$candidates = $candidates | Select-Object -Unique

# ---- Guard rail: kill .local ----
$external = $candidates | Where-Object { -not (Is-LocalEmail $_) }

# ---- Primary selection ----
$primary = $null

if (Is-EmailLike $upn -and -not (Is-LocalEmail $upn)) {
$primary = $upn
}
elseif ($external.Count -gt 0) {
$primary = $external[0]
}

# ---- Optional runtime suffix override ----
if (-not $primary) {

if (-not $script:EmailSuffixOverrideAsked) {
$script:EmailSuffixOverrideAsked = $true

Write-Host ""
Write-Host "TeamViewer AD Sync" -ForegroundColor Cyan
Write-Host "No valid external email detected for some users." -ForegroundColor Yellow
Write-Host "Guard rail active: *.local will never sync." -ForegroundColor Yellow
Write-Host ""

$suffix = Read-Host "Optional fallback: enter email suffix (example: saracenenergy.com) or press Enter to skip"
$suffix = $suffix.Trim().TrimStart('@')

if ($suffix) {
$script:EmailSuffixOverride = $suffix
Write-Host "Fallback enabled: <samAccountName>@$suffix" -ForegroundColor Green
}
else {
Write-Host "Fallback disabled. Users without email will be skipped." -ForegroundColor Yellow
}
Write-Host ""
}

if ($script:EmailSuffixOverride -and $sam) {
$primary = "$sam@$($script:EmailSuffixOverride)"
}
}

if (-not $primary -or -not $name) { return }

# ---- Secondary emails (external only) ----
$secondary = $external | Where-Object { $_ -ne $primary }

@{
Email = $primary
Name = $name
IsEnabled = $true
SecondaryEmails = $secondary
}
}
}


function Select-ActiveDirectoryCommonName {
param([Parameter(ValueFromPipeline)] $path)
# Simplified version of a common-name parser.
Expand Down