feat: add Batch Workstation & Ambiguity User Resolver dialog with Dry-Run preview and multi-parameter controls

This commit is contained in:
2026-10-20 20:56:22 +09:00
parent 932d247d37
commit 70341dce31
8 changed files with 892 additions and 4 deletions
+128
View File
@@ -0,0 +1,128 @@
# 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 "" }
return @($tokens | Select-Object -Unique)
}
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" }
)
$resolvedResults = [System.Collections.Generic.List[PSCustomObject]]::new()
foreach ($token in $Tokens) {
# 1. SamAccountName 정확 일치 우선 검색
$matchById = @($allPool | 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 = @($allPool | Where-Object { $_.DisplayName -ieq $token -or $_.DisplayName -like "*$token*" })
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()
}