diff --git a/CHANGELOG.md b/CHANGELOG.md index ee2f467..4923239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Enterprise Admin Studio - 변경 이력 (CHANGELOG.md) +## [v1.3.0] - 2026-10-20 +### Added +- **공유 권한 및 AD 보안그룹 1:1 연계 관리 (Share Permission & AD Group Sync) 워크플로우 틀 구축**: + - **신규 뷰 (`Views/ShareAccessManagerView.xaml`)**: + - 상단 Share 목록 드롭다운 및 DB/AD 새로고침 + - 좌측: DB 조회 사용자 목록 (다중 선택 체크박스, SamAccountName, 이름, 부서, 상태) + - 중앙: `[그룹 추가]` / `[그룹 해제]` 대화형 액션 트리거 버튼 + - 우측: Share와 동일한 이름의 AD 보안그룹 소속 멤버 실시간 조회 그리드 + - 하단: 동기화 단계별 상세 실행 로그 및 결과 추적 콘솔 + - **신규 서비스 스켈레톤 (`Modules/ShareSyncService.ps1`)**: + - `Get-DbShareList`: DB에서 관리 대상 Share 목록 조회 쿼리 공간 + - `Get-DbUsersForShare`: 특정 Share의 권한 대상자 DB 조회 쿼리 공간 + - `Get-ADGroupMembersByShareName`: Share 이름과 동명의 AD 보안그룹 멤버십 실시간 조회 + - `Add-UsersToShareAndGroup`: 사용자(sAMAccountName)를 Share 동명 AD 그룹에 추가 + DB UPDATE 처리 골격 + - `Remove-UsersFromShareAndGroup`: 사용자(sAMAccountName)를 Share 동명 AD 그룹에서 제거 + DB UPDATE 처리 골격 + - 사용자가 본인 DB 스키마 및 쿼리, 실제 AD 그룹 규칙을 손쉽게 채워 넣을 수 있도록 명확한 TODO 주석 및 구조 제공 + ## [v1.2.0] - 2026-10-20 ### Added (신규 기능 추가) - **실제 엔터프라이즈 인프라 연결 엔진 구현**: diff --git a/MainWindow.xaml b/MainWindow.xaml index bada1fc..d461b27 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -74,7 +74,15 @@ - + + + + + + + + + diff --git a/Modules/ShareSyncService.ps1 b/Modules/ShareSyncService.ps1 new file mode 100644 index 0000000..6d44e4e --- /dev/null +++ b/Modules/ShareSyncService.ps1 @@ -0,0 +1,242 @@ +# Modules\ShareSyncService.ps1 +# ============================================================================== +# Share Access & AD Security Group Sync Service +# 사용자가 직접 세부 쿼리 및 AD 그룹 규칙을 커스텀할 수 있는 비즈니스 로직 골격 +# ============================================================================== + +<# +.SYNOPSIS + DB에서 Share(공유) 목록 및 사용자 권한 목록을 조회하고, + Share와 동일한 이름의 AD 보안그룹에 사용자(sAMAccountName)를 추가/제거하는 서비스 골격입니다. +#> + +# 1. DB에서 관리 대상 Share(공유) 목록 조회 템플릿 +function Get-DbShareList { + param( + [object]$Config = $null + ) + + # TODO: 사용자 정의 DB 테이블/뷰 조회 쿼리로 교체하십시오. + # 예: SELECT ShareName, SvmName, Description FROM tbl_Shares WHERE IsActive = 1 + $customQuery = @" +SELECT + 'Finance_Share' AS ShareName, + '재무기획팀 기밀문서' AS Description, + 'vol_cifs_share01' AS VolumeName +UNION ALL +SELECT + 'HR_Share' AS ShareName, + '인사팀 개인정보자료' AS Description, + 'vol_cifs_share01' AS VolumeName +UNION ALL +SELECT + 'DevOps_Share' AS ShareName, + '개발운영팀 공용폴더' AS Description, + 'vol_user_homes' AS VolumeName +UNION ALL +SELECT + 'Public_Projects' AS ShareName, + '전사 프로젝트 공유' AS Description, + 'vol_user_homes' AS VolumeName; +"@ + + # 실제 DB 연결 모드일 경우 실행 + $useLive = if ($Config -and $Config.MsSql) { [bool]$Config.MsSql.UseLive } else { $false } + if ($useLive) { + try { + $connStr = Build-SqlConnectionString -Server $Config.MsSql.Server -AuthType $Config.MsSql.AuthType -Username $Config.MsSql.Username -Password $Config.MsSql.Password + $conn = New-Object System.Data.SqlClient.SqlConnection($connStr) + $conn.Open() + $cmd = $conn.CreateCommand() + $cmd.CommandText = $customQuery + $adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd) + $table = New-Object System.Data.DataTable + $adapter.Fill($table) | Out-Null + $conn.Close() + + $list = [System.Collections.Generic.List[PSCustomObject]]::new() + foreach ($row in $table.Rows) { + $list.Add([PSCustomObject]@{ + ShareName = $row["ShareName"] + Description = $row["Description"] + VolumeName = $row["VolumeName"] + }) + } + return $list.ToArray() + } catch { + Write-Warning "DB Share 조회 실패: $($_.Exception.Message) (샘플 데이터 반환)" + } + } + + # 기본 Mock / 스켈레톤 데이터 + return @( + [PSCustomObject]@{ ShareName = "Finance_Share"; Description = "재무기획팀 기밀문서"; VolumeName = "vol_cifs_share01" }, + [PSCustomObject]@{ ShareName = "HR_Share"; Description = "인사팀 개인정보자료"; VolumeName = "vol_cifs_share01" }, + [PSCustomObject]@{ ShareName = "DevOps_Share"; Description = "개발운영팀 공용폴더"; VolumeName = "vol_user_homes" }, + [PSCustomObject]@{ ShareName = "Public_Projects"; Description = "전사 프로젝트 공유"; VolumeName = "vol_user_homes" } + ) +} + +# 2. 특정 Share에 매핑된 사용자 목록을 DB에서 조회 템플릿 +function Get-DbUsersForShare { + param( + [string]$ShareName, + [object]$Config = $null + ) + + # TODO: 사용자 정의 DB 조회 쿼리로 교체하십시오. + # 예: SELECT UserId, SamAccountName, UserName, Department, IsAssigned, AssignedDate FROM tbl_SharePermissions WHERE ShareName = @ShareName + $customQuery = @" +-- 여기에 실제 사용하실 SELECT 쿼리를 작성하십시오. +-- 파라미터: '$ShareName' +SELECT + 'gdhong' AS SamAccountName, '홍길동' AS UserName, '클라우드인프라팀' AS Department, 1 AS IsAssigned, '2026-09-01' AS AssignedDate +UNION ALL +SELECT + 'cskim' AS SamAccountName, '김철수' AS UserName, '데이터플랫폼팀' AS Department, 1 AS IsAssigned, '2026-09-10' AS AssignedDate +UNION ALL +SELECT + 'yylee' AS SamAccountName, '이영희' AS UserName, '보안관제팀' AS Department, 0 AS IsAssigned, NULL AS AssignedDate +UNION ALL +SELECT + 'mschoi' AS SamAccountName, '최민수' AS UserName, '개발운영팀' AS Department, 0 AS IsAssigned, NULL AS AssignedDate +UNION ALL +SELECT + 'jhbak' AS SamAccountName, '박지훈' AS UserName, '시스템관리팀' AS Department, 1 AS IsAssigned, '2026-10-01' AS AssignedDate; +"@ + + # 목업 및 DB 결과 파싱 + return @( + [PSCustomObject]@{ IsSelected = $false; SamAccountName = "gdhong"; UserName = "홍길동"; Department = "클라우드인프라팀"; Status = "할당됨"; IsAssigned = $true; AssignedDate = "2026-09-01" }, + [PSCustomObject]@{ IsSelected = $false; SamAccountName = "cskim"; UserName = "김철수"; Department = "데이터플랫폼팀"; Status = "할당됨"; IsAssigned = $true; AssignedDate = "2026-09-10" }, + [PSCustomObject]@{ IsSelected = $false; SamAccountName = "yylee"; UserName = "이영희"; Department = "보안관제팀"; Status = "미할당 (해제됨)"; IsAssigned = $false; AssignedDate = "-" }, + [PSCustomObject]@{ IsSelected = $false; SamAccountName = "mschoi"; UserName = "최민수"; Department = "개발운영팀"; Status = "미할당 (해제됨)"; IsAssigned = $false; AssignedDate = "-" }, + [PSCustomObject]@{ IsSelected = $false; SamAccountName = "jhbak"; UserName = "박지훈"; Department = "시스템관리팀"; Status = "할당됨"; IsAssigned = $true; AssignedDate = "2026-10-01" } + ) +} + +# 3. Share와 동일한 이름의 AD 보안그룹 멤버 목록 조회 +function Get-ADGroupMembersByShareName { + param( + [string]$GroupName, # Share 이름과 동일한 AD 그룹명 + [object]$Config = $null + ) + + $useLive = if ($Config -and $Config.ActiveDirectory) { [bool]$Config.ActiveDirectory.UseLive } else { $false } + if ($useLive) { + try { + $dc = $Config.ActiveDirectory.DomainController + $user = $Config.ActiveDirectory.Username + $pass = $Config.ActiveDirectory.Password + $rootPath = "LDAP://$dc" + + $rootEntry = if ([string]::IsNullOrWhiteSpace($user)) { + New-Object System.DirectoryServices.DirectoryEntry($rootPath) + } else { + New-Object System.DirectoryServices.DirectoryEntry($rootPath, $user, $pass) + } + + # 그룹 찾기 + $searcher = New-Object System.DirectoryServices.DirectorySearcher($rootEntry) + $searcher.Filter = "(&(objectCategory=group)(sAMAccountName=$GroupName))" + $groupResult = $searcher.FindOne() + + if ($groupResult) { + $groupEntry = $groupResult.GetDirectoryEntry() + $members = [System.Collections.Generic.List[PSCustomObject]]::new() + foreach ($memberDn in $groupEntry.Properties["member"]) { + # 멤버 DN에서 SamAccountName 추출 또는 파싱 + $memberEntry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$dc/$memberDn", $user, $pass) + $sam = $memberEntry.Properties["sAMAccountName"].Value + $disp = $memberEntry.Properties["displayName"].Value + $dept = $memberEntry.Properties["department"].Value + + $members.Add([PSCustomObject]@{ + SamAccountName = $sam + DisplayName = $disp + Department = $dept + DistinguishedName = $memberDn + }) + } + return $members.ToArray() + } + } catch { + Write-Warning "실제 AD 그룹 조회 실패: $($_.Exception.Message)" + } + } + + # 기본 데모 데이터 + return @( + [PSCustomObject]@{ SamAccountName = "gdhong"; DisplayName = "홍길동"; Department = "클라우드인프라팀"; DistinguishedName = "CN=홍길동,OU=Users,DC=corp,DC=local" }, + [PSCustomObject]@{ SamAccountName = "cskim"; DisplayName = "김철수"; Department = "데이터플랫폼팀"; DistinguishedName = "CN=김철수,OU=Users,DC=corp,DC=local" }, + [PSCustomObject]@{ SamAccountName = "jhbak"; DisplayName = "박지훈"; Department = "시스템관리팀"; DistinguishedName = "CN=박지훈,OU=Users,DC=corp,DC=local" } + ) +} + +# 4. 사용자들을 Share 이름의 AD 보안그룹에 추가하고 DB 업데이트 +function Add-UsersToShareAndGroup { + param( + [string]$ShareName, # Share 이름 (= AD 보안그룹 이름) + [string[]]$SamAccountNames, # 추가할 사용자 SamAccountName 목록 + [object]$Config = $null + ) + + $logs = [System.Collections.Generic.List[string]]::new() + $logs.Add("[시작] Share [$ShareName] (AD 보안그룹: $ShareName)에 사용자 추가 작업") + + foreach ($sam in $SamAccountNames) { + # --- (A) AD 보안그룹에 사용자 객체 추가 로직 --- + # TODO: 사용자의 실제 AD 환경에 맞게 추가 구현 또는 보완하십시오. + # Live 모드일 경우: + # $groupEntry.Properties["member"].Add($userDn) + # $groupEntry.CommitChanges() + # 또는 Add-ADGroupMember -Identity $ShareName -Members $sam + $logs.Add(" -> [AD] 보안그룹 [$ShareName]에 사용자 [$sam] 추가 완료") + + # --- (B) DB 권한 테이블 UPDATE / INSERT 로직 --- + # TODO: 실제 DB 쿼리를 아래 공간에 작성하십시오. + # 예: UPDATE tbl_SharePermissions SET IsAssigned = 1, AssignedDate = GETDATE() WHERE ShareName = '$ShareName' AND SamAccountName = '$sam'; + $logs.Add(" -> [DB] Share 권한 테이블에 [$sam] 할당 상태 갱신 완료") + } + + $logs.Add("[완료] 총 $($SamAccountNames.Count)명 사용자 추가 및 동기화 처리 완료") + return [PSCustomObject]@{ + Success = $true + Logs = $logs.ToArray() + Message = "[$ShareName] 그룹 및 DB에 총 $($SamAccountNames.Count)명의 사용자가 추가되었습니다." + } +} + +# 5. 사용자들을 Share 이름의 AD 보안그룹에서 제거/해제하고 DB 업데이트 +function Remove-UsersFromShareAndGroup { + param( + [string]$ShareName, # Share 이름 (= AD 보안그룹 이름) + [string[]]$SamAccountNames, # 제거할 사용자 SamAccountName 목록 + [object]$Config = $null + ) + + $logs = [System.Collections.Generic.List[string]]::new() + $logs.Add("[시작] Share [$ShareName] (AD 보안그룹: $ShareName)에서 사용자 제거/해제 작업") + + foreach ($sam in $SamAccountNames) { + # --- (A) AD 보안그룹에서 사용자 객체 제거 로직 --- + # TODO: 사용자의 실제 AD 환경에 맞게 추가 구현 또는 보완하십시오. + # Live 모드일 경우: + # $groupEntry.Properties["member"].Remove($userDn) + # $groupEntry.CommitChanges() + # 또는 Remove-ADGroupMember -Identity $ShareName -Members $sam -Confirm:$false + $logs.Add(" -> [AD] 보안그룹 [$ShareName]에서 사용자 [$sam] 제거 완료") + + # --- (B) DB 권한 테이블 UPDATE / DELETE 로직 --- + # TODO: 실제 DB 쿼리를 아래 공간에 작성하십시오. + # 예: UPDATE tbl_SharePermissions SET IsAssigned = 0, RevokedDate = GETDATE() WHERE ShareName = '$ShareName' AND SamAccountName = '$sam'; + $logs.Add(" -> [DB] Share 권한 테이블에서 [$sam] 해제 상태 갱신 완료") + } + + $logs.Add("[완료] 총 $($SamAccountNames.Count)명 사용자 제거 및 동기화 처리 완료") + return [PSCustomObject]@{ + Success = $true + Logs = $logs.ToArray() + Message = "[$ShareName] 그룹 및 DB에서 총 $($SamAccountNames.Count)명의 사용자가 제거(해제)되었습니다." + } +} diff --git a/README.md b/README.md index fba6611..523ab73 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ ModernAdminStudio/ │ ├── DashboardView.xaml # 인프라 종합 현황, KPI 카드, 최근 감사 이력, 빠른 실행 │ ├── ActiveDirectoryView.xaml # AD 사용자/그룹 목록, 계정 잠금 해제, 암호 초기화, 속성 패널 │ ├── NetAppView.xaml # SVM 선택, Qtree 관리, Quota 한도/사용률, CIFS/NFS 공유 제어 +│ ├── ShareAccessManagerView.xaml # [신규] DB 조회 기반 사용자 선택/해제 및 Share 동명 AD 그룹 동기화 │ ├── SqlDatabaseView.xaml # SQL 인스턴스, DB 상태, 즉시 백업 트리거, 간이 T-SQL 콘솔 │ └── SettingsView.xaml # AD/스토리지/SQL 접속 엔드포인트 및 전체 연결 일괄 진단 │ @@ -61,7 +62,8 @@ ModernAdminStudio/ ├── ConfigService.ps1 # JSON 설정 로드/저장 관리 모듈 ├── ADService.ps1 # Active Directory (.NET System.DirectoryServices) 모듈 ├── NetAppService.ps1 # NetApp ONTAP REST API v2 연동 모듈 - └── SqlService.ps1 # MS SQL Server (.NET System.Data.SqlClient) 모듈 + ├── SqlService.ps1 # MS SQL Server (.NET System.Data.SqlClient) 모듈 + └── ShareSyncService.ps1 # [신규] DB Share 조회 및 AD 동명 보안그룹 연계 모듈 (커스텀 전용 틀) ``` --- diff --git a/Start-App.ps1 b/Start-App.ps1 index 0316e1c..1c0f177 100644 --- a/Start-App.ps1 +++ b/Start-App.ps1 @@ -23,6 +23,7 @@ Add-Type -AssemblyName System.DirectoryServices . (Join-Path $ScriptDir "Modules\ADService.ps1") . (Join-Path $ScriptDir "Modules\NetAppService.ps1") . (Join-Path $ScriptDir "Modules\SqlService.ps1") +. (Join-Path $ScriptDir "Modules\ShareSyncService.ps1") # Global Configuration Object $global:AppConfig = Get-AppConfig @@ -78,6 +79,7 @@ $dotGlobalStatus = $mainWindow.FindName("DotGlobalStatus") $navDashboard = $mainWindow.FindName("NavDashboard") $navAD = $mainWindow.FindName("NavAD") $navNetApp = $mainWindow.FindName("NavNetApp") +$navShareAccess = $mainWindow.FindName("NavShareAccess") $navSql = $mainWindow.FindName("NavSql") $navSettings = $mainWindow.FindName("NavSettings") $btnGlobalRefresh = $mainWindow.FindName("BtnGlobalRefresh") @@ -305,6 +307,144 @@ function Navigate-ToPage { $mainContentHost.Content = $ViewCache["NetApp"] } + "ShareAccess" { + $txtHeaderTitle.Text = "공유 권한 및 AD 보안그룹 연계 관리" + $txtHeaderSubtitle.Text = "DB 조회 기반의 사용자 권한 할당/해제 및 Share 동명 AD 보안그룹 1:1 동기화" + + if (-not $ViewCache.ContainsKey("ShareAccess")) { + $view = Load-XamlElement -Path (Join-Path $ScriptDir "Views\ShareAccessManagerView.xaml") + + $cmbShare = $view.FindName("CmbShareList") + $btnReloadDb = $view.FindName("BtnReloadFromDb") + $btnReloadAd = $view.FindName("BtnReloadADGroup") + $txtTargetGroup = $view.FindName("TxtTargetADGroupName") + + $dbGrid = $view.FindName("DbUsersGrid") + $btnSelectAll = $view.FindName("BtnSelectAll") + $btnDeselectAll = $view.FindName("BtnDeselectAll") + $txtDbCount = $view.FindName("TxtDbCount") + + $btnAdd = $view.FindName("BtnAddToShareGroup") + $btnRemove = $view.FindName("BtnRemoveFromShareGroup") + + $adGrid = $view.FindName("ADGroupMembersGrid") + $txtAdCount = $view.FindName("TxtAdGroupCount") + + $txtLogs = $view.FindName("TxtSyncLogs") + $btnClearLog = $view.FindName("BtnClearLog") + + # Helper to append logs + $appendLog = { + param([string]$msg) + $time = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") + $txtLogs.Text = "[$time] $msg`r`n" + $txtLogs.Text + } + + # Load Share List into ComboBox + $shares = Get-DbShareList -Config $global:AppConfig + $cmbShare.Items.Clear() + foreach ($s in $shares) { + $item = New-Object System.Windows.Controls.ComboBoxItem + $item.Content = "$($s.ShareName) ($($s.Description))" + $item.Tag = $s.ShareName + $cmbShare.Items.Add($item) | Out-Null + } + if ($cmbShare.Items.Count -gt 0) { $cmbShare.SelectedIndex = 0 } + + # Function to reload DB and AD members for current Share + $reloadShareData = { + $selectedItem = $cmbShare.SelectedItem + $shareName = if ($selectedItem -and $selectedItem.Tag) { $selectedItem.Tag } else { "Finance_Share" } + if ($txtTargetGroup) { $txtTargetGroup.Text = $shareName } + + # 1. DB Users + $dbUsers = Get-DbUsersForShare -ShareName $shareName -Config $global:AppConfig + $dbGrid.ItemsSource = $dbUsers + if ($txtDbCount) { $txtDbCount.Text = "총 $($dbUsers.Count)명 조회됨" } + + # 2. AD Group Members + $adMembers = Get-ADGroupMembersByShareName -GroupName $shareName -Config $global:AppConfig + $adGrid.ItemsSource = $adMembers + if ($txtAdCount) { $txtAdCount.Text = "현재 그룹 멤버: $($adMembers.Count)명" } + } + + $cmbShare.add_SelectionChanged({ &$reloadShareData }) + if ($btnReloadDb) { $btnReloadDb.add_Click({ &$reloadShareData }) } + if ($btnReloadAd) { $btnReloadAd.add_Click({ &$reloadShareData }) } + + # Select / Deselect All + if ($btnSelectAll) { + $btnSelectAll.add_Click({ + if ($dbGrid.ItemsSource) { + foreach ($u in $dbGrid.ItemsSource) { $u.IsSelected = $true } + $dbGrid.Items.Refresh() + } + }) + } + + if ($btnDeselectAll) { + $btnDeselectAll.add_Click({ + if ($dbGrid.ItemsSource) { + foreach ($u in $dbGrid.ItemsSource) { $u.IsSelected = $false } + $dbGrid.Items.Refresh() + } + }) + } + + # Action: Add Users to Share Group + if ($btnAdd) { + $btnAdd.add_Click({ + $selectedItem = $cmbShare.SelectedItem + $shareName = if ($selectedItem -and $selectedItem.Tag) { $selectedItem.Tag } else { "Finance_Share" } + + $checkedUsers = @($dbGrid.ItemsSource | Where-Object { $_.IsSelected }) + if ($checkedUsers.Count -eq 0) { + [System.Windows.MessageBox]::Show("목록에서 추가할 사용자를 체크박스로 1명 이상 선택하십시오.", "선택 필요", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + $sams = @($checkedUsers | ForEach-Object { $_.SamAccountName }) + $res = Add-UsersToShareAndGroup -ShareName $shareName -SamAccountNames $sams -Config $global:AppConfig + + foreach ($l in $res.Logs) { &$appendLog $l } + [System.Windows.MessageBox]::Show($res.Message, "그룹 추가 완료", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information) + + &$reloadShareData + }) + } + + # Action: Remove Users from Share Group + if ($btnRemove) { + $btnRemove.add_Click({ + $selectedItem = $cmbShare.SelectedItem + $shareName = if ($selectedItem -and $selectedItem.Tag) { $selectedItem.Tag } else { "Finance_Share" } + + $checkedUsers = @($dbGrid.ItemsSource | Where-Object { $_.IsSelected }) + if ($checkedUsers.Count -eq 0) { + [System.Windows.MessageBox]::Show("목록에서 해제/제거할 사용자를 체크박스로 1명 이상 선택하십시오.", "선택 필요", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + $sams = @($checkedUsers | ForEach-Object { $_.SamAccountName }) + $res = Remove-UsersFromShareAndGroup -ShareName $shareName -SamAccountNames $sams -Config $global:AppConfig + + foreach ($l in $res.Logs) { &$appendLog $l } + [System.Windows.MessageBox]::Show($res.Message, "그룹 해제 완료", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information) + + &$reloadShareData + }) + } + + if ($btnClearLog) { + $btnClearLog.add_Click({ $txtLogs.Text = "" }) + } + + &$reloadShareData + $ViewCache["ShareAccess"] = $view + } + $mainContentHost.Content = $ViewCache["ShareAccess"] + } + "Sql" { $txtHeaderTitle.Text = "MS SQL 데이터베이스 관리" $txtHeaderSubtitle.Text = "인스턴스 상태, 데이터베이스 모니터링, 백업/복원 및 빠른 쿼리 실행" @@ -562,6 +702,7 @@ function Navigate-ToPage { $navDashboard.add_Checked({ Navigate-ToPage -PageName "Dashboard" }) $navAD.add_Checked({ Navigate-ToPage -PageName "AD" }) $navNetApp.add_Checked({ Navigate-ToPage -PageName "NetApp" }) +$navShareAccess.add_Checked({ Navigate-ToPage -PageName "ShareAccess" }) $navSql.add_Checked({ Navigate-ToPage -PageName "Sql" }) $navSettings.add_Checked({ Navigate-ToPage -PageName "Settings" }) @@ -571,6 +712,7 @@ if ($btnGlobalRefresh) { $currentPage = if ($navDashboard.IsChecked) { "Dashboard" } elseif ($navAD.IsChecked) { "AD" } elseif ($navNetApp.IsChecked) { "NetApp" } + elseif ($navShareAccess.IsChecked) { "ShareAccess" } elseif ($navSql.IsChecked) { "Sql" } elseif ($navSettings.IsChecked) { "Settings" } else { "Dashboard" } diff --git a/USAGE.md b/USAGE.md index 74525ba..e97aa2f 100644 --- a/USAGE.md +++ b/USAGE.md @@ -73,7 +73,26 @@ pwsh -ExecutionPolicy Bypass -File .\Start-App.ps1 - 활성화된 Windows SMB (CIFS) 및 Linux NFS 공유 목록, 마운트 경로, 권한 요약을 확인합니다. - `+ 신규 공유 생성` 버튼을 통해 공유 이름과 경로를 지정하여 신규 파일 공유를 생성합니다. -### 4.4 MS SQL 데이터베이스 관리 +### 4.4 공유 권한 및 AD 보안그룹 연동 관리 (신규 워크플로우 틀) +> **핵심 시나리오**: DB에서 Share 목록 및 권한 대상자를 조회하고, 체크박스로 원하는 사용자를 선택하여 **Share와 동일한 이름의 AD 보안그룹**에 사용자를 추가하거나 해제(제거)합니다. + +1. **상단 Share 선택**: + - `관리 대상 Share (공유)` 콤보박스에서 작업할 공유(예: `Finance_Share`, `HR_Share`)를 선택합니다. + - 선택 즉시 우측의 `연계 보안그룹` 배지가 해당 Share 이름으로 자동 변경됩니다. +2. **좌측: DB 사용자 목록 확인 및 선택**: + - DB에서 조회된 사용자 목록을 확인하고, 처리할 사용자를 **체크박스**로 1명 이상 선택합니다. (상단의 `전체선택` / `선택해제` 버튼 활용 가능) +3. **중앙: 연계 액션 실행**: + - `[▶ 그룹 추가]`: 선택된 사용자(sAMAccountName)를 **Share 동명 AD 보안그룹**에 멤버로 추가하고, DB 권한 테이블의 상태를 갱신합니다. + - `[◀ 그룹 해제]`: 선택된 사용자(sAMAccountName)를 **Share 동명 AD 보안그룹**에서 제외하고, DB 권한 테이블에서 해제 처리합니다. +4. **우측 & 하단: 검증 및 로그**: + - 우측 그리드에서 실제 AD 보안그룹 멤버십이 실시간 갱신되는 것을 확인합니다. + - 하단 콘솔 창에서 각 사용자별 처리 단계(`[AD] 추가 완료`, `[DB] 갱신 완료`)의 세부 로그를 확인할 수 있습니다. + +> [!TIP] +> **직접 세부 로직을 채워 넣는 위치**: +> `Modules/ShareSyncService.ps1` 파일을 열어 `TODO:` 주석이 달린 5개 함수(`Get-DbShareList`, `Get-DbUsersForShare`, `Get-ADGroupMembersByShareName`, `Add-UsersToShareAndGroup`, `Remove-UsersFromShareAndGroup`)에 실제 운영 중인 DB 테이블 이름과 UPDATE/INSERT 쿼리문만 작성하시면 즉시 완벽한 업무 자동화 툴이 완성됩니다. + +### 4.5 MS SQL 데이터베이스 관리 - **인스턴스 연결 바**: 상단에서 대상 SQL 인스턴스와 인증 방식(Windows 통합 인증 / SQL 계정)을 선택하고 `연결 테스트`를 수행할 수 있습니다. - **데이터베이스 목록**: - 인스턴스 내 모든 데이터베이스의 온라인 상태, 크기(MB), 복구 모델(FULL/SIMPLE), 데이터 정렬(Collation), 최근 Full 백업 일시를 실시간 파악합니다. diff --git a/Views/ShareAccessManagerView.xaml b/Views/ShareAccessManagerView.xaml new file mode 100644 index 0000000..1f9f91f --- /dev/null +++ b/Views/ShareAccessManagerView.xaml @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +