# Modules\UserResolverService.ps1 # ============================================================================== # User Multi-Input Resolver & Ambiguity (동명이인) Detection Service # ============================================================================== <# .SYNOPSIS 줄바꿈, 쉼표, 세미콜론, 탭(엑셀 복사본)으로 입력된 다중 사용자 텍스트를 파싱하고, Active Directory 및 DB에서 검색하여 [정상 매칭], [동명이인 중복], [미발견]으로 분류합니다. #> function Parse-MultiUserInput { param([string]$RawInput) if ([string]::IsNullOrWhiteSpace($RawInput)) { return ,@() } # 쉼표, 세미콜론, 줄바꿈, 탭, 공백 등 모든 구분자로 분리 $tokens = $RawInput -split "[\r\n,;\t]+" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" } $uniqueTokens = @($tokens | Select-Object -Unique) return ,$uniqueTokens } function Resolve-UsersWithAmbiguityCheck { param( [string[]]$Tokens, [object]$Config = $null ) # 기본 AD 사용자 풀 (Live 모드 시 실제 AD 검색 가능, 현재는 풍부한 샘플 풀 + 동명이인 포함) $allPool = @( [PSCustomObject]@{ SamAccountName = "gdhong"; DisplayName = "홍길동"; Department = "클라우드인프라팀"; Title = "수석"; Mail = "gdhong@corp.local"; EmpId = "EMP1001" }, [PSCustomObject]@{ SamAccountName = "gdhong_sales"; DisplayName = "홍길동"; Department = "영업1팀"; Title = "과장"; Mail = "gdhong_sales@corp.local"; EmpId = "EMP1099" }, # 홍길동 동명이인! [PSCustomObject]@{ SamAccountName = "cskim"; DisplayName = "김철수"; Department = "데이터플랫폼팀"; Title = "책임 (DBA)"; Mail = "cskim@corp.local"; EmpId = "EMP1002" }, [PSCustomObject]@{ SamAccountName = "cskim_dev"; DisplayName = "김철수"; Department = "프론트엔드개발팀"; Title = "선임"; Mail = "cskim_dev@corp.local"; EmpId = "EMP1088" }, # 김철수 동명이인! [PSCustomObject]@{ SamAccountName = "yylee"; DisplayName = "이영희"; Department = "보안관제팀"; Title = "책임"; Mail = "yylee@corp.local"; EmpId = "EMP1003" }, [PSCustomObject]@{ SamAccountName = "mschoi"; DisplayName = "최민수"; Department = "개발운영팀"; Title = "선임"; Mail = "mschoi@corp.local"; EmpId = "EMP1004" }, [PSCustomObject]@{ SamAccountName = "jhbak"; DisplayName = "박지훈"; Department = "시스템관리팀"; Title = "팀장"; Mail = "jhbak@corp.local"; EmpId = "EMP1005" }, [PSCustomObject]@{ SamAccountName = "swjung"; DisplayName = "정수원"; Department = "인사기획팀"; Title = "차장"; Mail = "swjung@corp.local"; EmpId = "EMP1006" } ) $pool = $allPool if ($Config -and $Config.ActiveDirectory -and [bool]$Config.ActiveDirectory.UseLive -and (Get-Command Get-ADUserList -ErrorAction SilentlyContinue)) { try { $liveUsers = Get-ADUserList -Config $Config if ($liveUsers -and $liveUsers.Count -gt 0) { $pool = $liveUsers } } catch { Write-Warning "Live AD 사용자 풀 조회 실패, 기본 풀을 사용합니다: $($_.Exception.Message)" } } $resolvedResults = [System.Collections.Generic.List[PSCustomObject]]::new() foreach ($rawToken in $Tokens) { if ([string]::IsNullOrWhiteSpace($rawToken)) { continue } $token = $rawToken.Trim() # 1. SamAccountName 정확 일치 우선 검색 $matchById = @($pool | Where-Object { $_.SamAccountName -ieq $token }) if ($matchById.Count -eq 1) { $u = $matchById[0] $resolvedResults.Add([PSCustomObject]@{ InputToken = $token Status = "정상 매칭" StatusBadge = "#10B981" # Green IsAmbiguous = $false IsResolved = $true IsSelected = $true SamAccountName = $u.SamAccountName DisplayName = $u.DisplayName Department = $u.Department Title = $u.Title EmpId = $u.EmpId CandidateCount = 1 Note = "ID($token) 정확 일치" }) continue } # 2. 이름(DisplayName) 일치 검색 (동명이인 판정 - 와일드카드 안전 처리) $matchByName = @($pool | Where-Object { $_.DisplayName -ieq $token -or ($_.DisplayName -and ($_.DisplayName.IndexOf($token, [System.StringComparison]::OrdinalIgnoreCase) -ge 0)) }) if ($matchByName.Count -eq 1) { $u = $matchByName[0] $resolvedResults.Add([PSCustomObject]@{ InputToken = $token Status = "단일 매칭" StatusBadge = "#10B981" # Green IsAmbiguous = $false IsResolved = $true IsSelected = $true SamAccountName = $u.SamAccountName DisplayName = $u.DisplayName Department = $u.Department Title = $u.Title EmpId = $u.EmpId CandidateCount = 1 Note = "이름($token) 단일 사용자 확인" }) } elseif ($matchByName.Count -gt 1) { # 동명이인 다수 발견! -> 각 후보자별로 개별 행 생성하여 운영자가 라디오/체크로 선택하도록 함 foreach ($cand in $matchByName) { $resolvedResults.Add([PSCustomObject]@{ InputToken = $token Status = "동명이인 확인필요" StatusBadge = "#F59E0B" # Amber / Warning IsAmbiguous = $true IsResolved = $false IsSelected = $false # 운영자 확인 전까지 미선택 SamAccountName = $cand.SamAccountName DisplayName = $cand.DisplayName Department = $cand.Department Title = $cand.Title EmpId = $cand.EmpId CandidateCount = $matchByName.Count Note = "동명이인 $($matchByName.Count)명 중 1명 [부서: $($cand.Department) 확인필요]" }) } } else { # 미발견 $resolvedResults.Add([PSCustomObject]@{ InputToken = $token Status = "미발견 (계정 없음)" StatusBadge = "#EF4444" # Red IsAmbiguous = $false IsResolved = $false IsSelected = $false SamAccountName = "-" DisplayName = $token Department = "-" Title = "-" EmpId = "-" CandidateCount = 0 Note = "AD 및 DB에서 해당 ID/이름을 찾을 수 없음" }) } } return ,$resolvedResults.ToArray() }