Files
adusermanager/Scripts/UI-Tab-BatchTask.ps1

619 lines
29 KiB
PowerShell
Raw Permalink Normal View History

2025-09-15 13:46:19 +09:00
# ================================================================================
# 파일: Scripts/UI-Tab-BatchTask.ps1
# 역할: '일괄 작업 (CSV)' 탭 UI 및 기능 구현 (리팩토링 최종 완전판)
#
# 작성자: 양범진
# 버전: 1.13
# 생성일자: 2025-06-05
# 최종 수정일자: 2025-06-12
#
# 설명:
# - 가독성 향상을 위해 코드 포매팅, 주석 추가, 불필요한 콘솔 출력 제거.
# - 누락된 함수 정의를 복원하여 스크립트 실행 오류 최종 해결.
# - 모든 기능이 포함된 최종 안정화 버전.
# ================================================================================
#region '일괄 작업' 탭 UI 초기화 및 이벤트 핸들러
# --------------------------------------------------------------------------------
# 헬퍼 함수 정의
# --------------------------------------------------------------------------------
# 선택된 작업 유형에 따라 안내 메시지를 업데이트하는 함수
function Update-BatchGuide {
param($taskType)
# 작업 유형에 따라 다른 안내 텍스트를 설정
$guideText = switch ($taskType) {
"계정 생성" {
@"
** CSV로 계정 생성하기 **
'템플릿 다운로드' 받은 CSV 파일을 아래 형식에 맞게 작성하세요.
- **LastNameKr**: 사용자의 한글 (: )
- **FirstNameKr**: 사용자의 한글 이름 (: 길동)
- **AccountNameEn**: 로그인 ID (SamAccountName). 아래 규칙을 따라야 합니다.
- 소문자 영문과 숫자만 사용 가능
- 3자 이상, 20자 이하
- **Password**: 사용자의 초기 비밀번호.
- **OU_Name**: 사용자가 생성될 조직 단위(OU) 경로.
- 최상위 OU: `Dev`
- 하위 OU: `상위OU/하위OU` (: `Dev/Test001`)
"@
}
"계정 삭제" {
@"
** CSV로 계정 삭제하기 **
'템플릿 다운로드' 받은 CSV 파일을 아래 형식에 맞게 작성하세요.
- **SamAccountName**: 삭제할 사용자의 로그인 ID.
"@
}
}
# 안내 레이블의 텍스트를 업데이트
$script:batch_labelGuide.Text = $guideText.Trim()
}
# 'Dev/Test'와 같은 OU 경로를 'OU=Test,OU=Dev,DC=...' 형식의 DN(Distinguished Name)으로 변환하는 함수
function Convert-OUPathToDN {
param([string]$OUPath)
if (-not $OUPath) {
return $null
}
# '/'를 기준으로 경로를 분리하고, 빈 항목은 제거
$ouParts = $OUPath.Split('/') | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
# AD DN 형식에 맞게 순서를 뒤집음 (하위 OU가 먼저 오도록)
[array]::Reverse($ouParts)
# 각 부분을 'OU=이름' 형식으로 변환
$ouDNs = $ouParts | ForEach-Object { "OU=$_" }
# 쉼표로 연결하고 기본 도메인 DN을 추가하여 최종 DN 완성
return ($ouDNs -join ",") + ",$($script:CurrentADDomainDN)"
}
# --------------------------------------------------------------------------------
# 이벤트 핸들러 정의 (스크립트 블록)
# --------------------------------------------------------------------------------
# '작업 유형' 콤보박스 선택이 변경될 때 호출
$batch_TaskType_Changed = {
# UI 컨트롤 상태 초기화
$script:batch_dataGridView.DataSource = $null
$script:batch_textBoxCsvPath.Text = ""
$script:batch_buttonValidate.Enabled = $false
$script:batch_buttonExecute.Enabled = $false
$script:batch_progressBar.Value = 0
$script:batch_dataGridView.Visible = $false
$script:batch_labelGuide.Visible = $true
# 새 작업 유형에 맞는 안내 가이드 표시
Update-BatchGuide -taskType $script:batch_comboBoxTaskType.SelectedItem.ToString()
}
# '템플릿 다운로드' 버튼 클릭 시 호출
$batch_buttonDownloadTemplate_Click = {
$taskType = $script:batch_comboBoxTaskType.SelectedItem.ToString()
$headers = ""
$sampleData = ""
# 작업 유형에 따라 CSV 헤더와 샘플 데이터 설정
switch ($taskType) {
"계정 생성" {
$headers = "LastNameKr,FirstNameKr,AccountNameEn,Password,OU_Name"
$sampleData = "김,가네,mrkim,Password123!,Dev/Test001"
}
"계정 삭제" {
$headers = "SamAccountName"
$sampleData = "testuser"
}
default {
return # 지원하지 않는 작업 유형이면 종료
}
}
# 파일 저장 대화상자 생성
$sfd = New-Object System.Windows.Forms.SaveFileDialog
$sfd.Filter = "CSV 파일 (*.csv)|*.csv"
$sfd.FileName = "$($taskType)_template.csv"
if ($sfd.ShowDialog() -eq "OK") {
try {
# 헤더와 샘플 데이터를 포함한 CSV 콘텐츠 생성
$csvContent = @($headers, $sampleData)
# UTF8 인코딩으로 파일 저장
Set-Content -Path $sfd.FileName -Value $csvContent -Encoding UTF8
[System.Windows.Forms.MessageBox]::Show("샘플 데이터가 포함된 템플릿 파일이 저장되었습니다.`n$($sfd.FileName)", "저장 완료", "OK", "Information")
}
catch {
# 파일 저장 중 오류 발생 시 상세 오류 대화상자 표시
Show-DetailedErrorDialog -ErrorRecord $_
}
}
}
# '파일 찾아보기' 버튼 클릭 시 호출
$batch_buttonBrowseCsv_Click = {
# 파일 열기 대화상자 생성
$ofd = New-Object System.Windows.Forms.OpenFileDialog
$ofd.Filter = "CSV 파일 (*.csv)|*.csv"
if ($ofd.ShowDialog() -eq "OK") {
try {
# CSV 파일의 첫 줄(헤더)을 읽어옴
$headersInFile = (Get-Content -Path $ofd.FileName -TotalCount 1).Split(',') | ForEach-Object { $_.Trim('"') }
$taskType = $script:batch_comboBoxTaskType.SelectedItem.ToString()
# 현재 선택된 작업에 필요한 헤더 정의
$requiredHeaders = if ($taskType -eq "계정 생성") { @("LastNameKr", "FirstNameKr", "AccountNameEn", "Password", "OU_Name") } else { @("SamAccountName") }
# 파일의 헤더와 필요한 헤더가 일치하는지 비교
if (($headersInFile | Compare-Object -ReferenceObject $requiredHeaders -SyncWindow 0).Length -ne 0) {
[System.Windows.Forms.MessageBox]::Show("CSV 파일의 헤더가 선택된 작업 유형과 일치하지 않습니다.`n템플릿을 다운로드하여 형식을 확인해주세요.", "CSV 형식 오류", "OK", "Warning")
return
}
# 파일 경로 텍스트박스 업데이트 및 CSV 파일 가져오기
$script:batch_textBoxCsvPath.Text = $ofd.FileName
$csvData = Import-Csv -Path $ofd.FileName -Encoding UTF8
if ($csvData.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("CSV 파일에 데이터가 없습니다.", "알림", "OK", "Information")
return
}
# CSV 데이터를 표시할 DataTable 객체 생성
$dt = New-Object System.Data.DataTable
$csvData[0].PSObject.Properties.Name | ForEach-Object { $dt.Columns.Add($_) } | Out-Null
$dt.Columns.Add("결과") | Out-Null # 결과 표시를 위한 열 추가
# CSV의 각 행을 DataTable에 추가
foreach ($row in $csvData) {
$dr = $dt.NewRow()
foreach ($prop in $row.PSObject.Properties) {
$dr[$prop.Name] = $prop.Value
}
$dt.Rows.Add($dr)
}
# 데이터 그리드뷰에 DataTable 바인딩 및 UI 상태 업데이트
$script:batch_dataGridView.DataSource = $dt
$script:batch_dataGridView.Columns["결과"].ReadOnly = $true
$script:batch_dataGridView.Columns["결과"].DefaultCellStyle.BackColor = [System.Drawing.Color]::Gainsboro
Write-Log "$($csvData.Count)개의 항목을 CSV 파일에서 로드했습니다."
$script:batch_buttonValidate.Enabled = $true
$script:batch_buttonExecute.Enabled = $false
$script:batch_progressBar.Value = 0
$script:batch_dataGridView.Visible = $true
$script:batch_labelGuide.Visible = $false
}
catch {
# 파일 읽기 실패 등 예외 발생 시 상세 오류 대화상자 표시
Show-DetailedErrorDialog -ErrorRecord $_
$script:batch_buttonValidate.Enabled = $false
}
}
}
# 데이터 그리드뷰의 셀 값이 변경될 때 호출
$batch_dataGridView_CellValueChanged = {
param($src, $e)
$rowIndex = $e.RowIndex
$colIndex = $e.ColumnIndex
if ($rowIndex -ge 0 -and $colIndex -ge 0) {
$dataGridView = $src
# '결과' 열은 시스템이 업데이트하므로 사용자의 수정에 반응하지 않음
if ($dataGridView.Columns[$colIndex].Name -eq "결과") {
return
}
# 사용자가 데이터를 수정했음을 시각적으로 표시
$row = $dataGridView.Rows[$rowIndex]
$resultCell = $row.Cells["결과"]
if ($resultCell.Value -notlike "수정됨*") {
$resultCell.Value = "수정됨 (검사 필요)"
$row.DefaultCellStyle.BackColor = [System.Drawing.Color]::LightYellow
$script:batch_buttonExecute.Enabled = $false # 수정 후에는 다시 유효성 검사가 필요함
}
}
}
# 데이터 그리드뷰에 새 행을 추가할 때 호출 (컨텍스트 메뉴)
$batch_buttonAddRow_Click = {
param($src, $e)
$dataTable = $script:batch_dataGridView.DataSource
# 그리드에 데이터가 아직 없는 경우, DataTable을 새로 생성
if ($null -eq $dataTable) {
$taskType = $script:batch_comboBoxTaskType.SelectedItem.ToString()
$headers = if ($taskType -eq "계정 생성") { @("LastNameKr", "FirstNameKr", "AccountNameEn", "Password", "OU_Name") } else { @("SamAccountName") }
$dataTable = New-Object System.Data.DataTable
$headers | ForEach-Object { $dataTable.Columns.Add($_) } | Out-Null
$dataTable.Columns.Add("결과") | Out-Null
$script:batch_dataGridView.DataSource = $dataTable
$script:batch_dataGridView.Columns["결과"].ReadOnly = $true
$script:batch_dataGridView.Columns["결과"].DefaultCellStyle.BackColor = [System.Drawing.Color]::Gainsboro
$script:batch_dataGridView.Visible = $true
$script:batch_labelGuide.Visible = $false
$script:batch_buttonValidate.Enabled = $true
}
# 새 행을 추가하고 초기 상태 설정
$newRow = $dataTable.NewRow()
$newRow["결과"] = "신규 (검사 필요)"
$dataTable.Rows.Add($newRow)
# 새로 추가된 행으로 스크롤 이동
$script:batch_dataGridView.FirstDisplayedScrollingRowIndex = $script:batch_dataGridView.Rows.Count - 1
}
# 데이터 그리드뷰에서 선택된 행을 삭제할 때 호출 (컨텍스트 메뉴)
$batch_buttonDeleteRow_Click = {
param($src, $e)
$selectedRows = $script:batch_dataGridView.SelectedRows
if ($selectedRows.Count -eq 0) {
return
}
# 여러 행 삭제 시 인덱스 문제를 피하기 위해 역순으로 정렬 후 삭제
foreach ($row in $selectedRows | Sort-Object Index -Descending) {
if (-not $row.IsNewRow) {
$script:batch_dataGridView.Rows.Remove($row)
}
}
}
# '유효성 검사' 버튼 클릭 시 호출
$batch_buttonValidate_Click = {
$dataTable = $script:batch_dataGridView.DataSource
if ($null -eq $dataTable -or $dataTable.Rows.Count -eq 0) {
return
}
$taskType = $script:batch_comboBoxTaskType.SelectedItem.ToString()
$script:batch_buttonExecute.Enabled = $false
# 동기식으로 유효성 검사 스크립트 블록을 실행하고, 오류가 발생한 행의 수를 반환받음
$invalidRowsCount = Invoke-Synchronous -TriggerControl $this -StatusMessage "사전 유효성 검사를 수행합니다..." -RequiresAzureAD -ScriptBlock {
$invalidCount = 0
$totalCount = $dataTable.Rows.Count
$processedCount = 0
foreach ($dataRow in $dataTable.Rows) {
$processedCount++
$script:batch_progressBar.Value = ($processedCount / $totalCount) * 100
try {
if ($taskType -eq "계정 생성") {
# 필수 값, OU 경로, 계정명 중복 여부 등 검사
if (-not ($dataRow.LastNameKr -and $dataRow.FirstNameKr -and $dataRow.AccountNameEn -and $dataRow.OU_Name -and $dataRow.Password)) { throw "필수 열이 비어있습니다." }
$ouDN = Convert-OUPathToDN -OUPath $dataRow.OU_Name
if (-not (Get-ADOrganizationalUnit -Identity $ouDN -Server $script:Configuration.OnPremDomainController -ErrorAction SilentlyContinue)) { throw "OU 경로 '$($dataRow.OU_Name)'를 찾을 수 없습니다." }
$validationResult = Test-SamAccountName -AccountName $dataRow.AccountNameEn -CheckAzureAD
if (-not $validationResult.IsValid) { throw $validationResult.Reason }
}
elseif ($taskType -eq "계정 삭제") {
# 필수 값, 계정 존재 여부 검사
if (-not $dataRow.SamAccountName) { throw "필수 열(SamAccountName)이 비어있습니다." }
if (-not (Get-ADUser -Filter "SamAccountName -eq '$($dataRow.SamAccountName)'" -Server $script:Configuration.OnPremDomainController)) { throw "존재하지 않는 계정입니다." }
}
# 유효성 검사 통과 시 결과 업데이트
$dataRow["결과"] = "✅ 유효"
}
catch {
# 오류 발생 시 결과에 오류 메시지 기록
$errorMessage = $_.Exception.Message.Trim()
$dataRow["결과"] = "❌ 오류: $errorMessage"
$invalidCount++
}
}
# 스크립트 블록의 결과로 오류 개수 반환
return $invalidCount
}
# 그리드의 각 행을 결과에 따라 색상으로 구분
foreach ($row in $script:batch_dataGridView.Rows) {
$resultCell = $row.Cells["결과"]
if ($resultCell.Value -like "❌*") {
$row.DefaultCellStyle.BackColor = [System.Drawing.Color]::LightPink
}
else {
$row.DefaultCellStyle.BackColor = [System.Drawing.Color]::White
}
}
if ($invalidRowsCount -gt 0) {
$msg = "$($invalidRowsCount)개의 유효하지 않은 항목이 발견되었습니다. 그리드에서 오류 내용을 확인하고 CSV 파일을 수정한 후 다시 시도하세요."
[System.Windows.Forms.MessageBox]::Show($msg, "유효성 검사 실패", "OK", "Warning")
}
elseif ($invalidRowsCount -eq 0) { # 0일 경우에만 성공으로 간주
$script:batch_buttonExecute.Enabled = $true
[System.Windows.Forms.MessageBox]::Show("모든 항목이 유효합니다. '일괄 작업 실행' 버튼을 눌러 작업을 시작하세요.", "검사 완료", "OK", "Information")
}
}
# '일괄 작업 실행' 버튼 클릭 시 호출
$batch_buttonExecute_Click = {
$dataTable = $script:batch_dataGridView.DataSource
if ($null -eq $dataTable -or $dataTable.Rows.Count -eq 0) {
return
}
# 유효성 검사를 먼저 수행했는지 확인
if ([string]::IsNullOrWhiteSpace($dataTable.Rows[0]["결과"])) {
[System.Windows.Forms.MessageBox]::Show("먼저 '유효성 검사'를 실행하여 데이터의 유효성을 확인해야 합니다.", "검사 필요", "OK", "Warning")
return
}
# 오류가 있는 항목이 있는지 확인
$invalidRows = $dataTable.Select("[결과] LIKE '❌*'")
if ($invalidRows.Count -gt 0) {
[System.Windows.Forms.MessageBox]::Show("오류 항목이 존재합니다. 유효성 검사를 다시 수행하거나 CSV 파일을 수정해주세요.", "오류 발견", "OK", "Error")
return
}
# 실행할 유효한 항목이 있는지 확인
$validRows = $dataTable.Select("[결과] = '✅ 유효'")
if ($validRows.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("실행할 유효한 항목이 없습니다.", "작업 불가", "OK", "Information")
return
}
# 최종 실행 확인
$taskType = $script:batch_comboBoxTaskType.SelectedItem.ToString()
$confirmMsg = "유효한 $($validRows.Length)개 항목에 대해 '$taskType' 일괄 작업을 시작하시겠습니까?"
if ([System.Windows.Forms.MessageBox]::Show($confirmMsg, "최종 확인", "YesNo", "Question") -ne "Yes") {
return
}
# 동기식으로 일괄 작업 실행
Invoke-Synchronous -TriggerControl $this -StatusMessage "일괄 작업을 실행합니다..." -ScriptBlock {
$successfulSyncCount = 0
foreach ($dataRow in $validRows) {
try {
if ($taskType -eq "계정 생성") {
# AD 사용자 생성을 위한 파라미터 설정
$ouDN = Convert-OUPathToDN -OUPath $dataRow.OU_Name
$userPrincipalName = "$($dataRow.AccountNameEn)@$($script:Configuration.UPNSuffix)"
$params = @{
Name = "$($dataRow.LastNameKr)$($dataRow.FirstNameKr) [$($dataRow.AccountNameEn)]"
DisplayName = "$($dataRow.LastNameKr)$($dataRow.FirstNameKr) [$($dataRow.AccountNameEn)]"
SamAccountName = $dataRow.AccountNameEn
UserPrincipalName = $userPrincipalName
EmailAddress = $userPrincipalName
Path = $ouDN
GivenName = $dataRow.FirstNameKr
Surname = $dataRow.LastNameKr
AccountPassword = (ConvertTo-SecureString ($dataRow.Password) -AsPlainText -Force)
Enabled = $true
ChangePasswordAtLogon = $false
Server = $script:Configuration.OnPremDomainController
}
New-ADUser @params -ErrorAction Stop
}
elseif ($taskType -eq "계정 삭제") {
Remove-ADUser -Identity $dataRow.SamAccountName.Trim() -Confirm:$false -Server $script:Configuration.OnPremDomainController -ErrorAction Stop
}
# 작업 성공 시 결과 업데이트
$dataRow["결과"] = "✅ 처리 완료"
$successfulSyncCount++
}
catch {
# 작업 실패 시 결과에 오류 메시지 기록
$errorMessage = $_.Exception.Message.Trim()
$dataRow["결과"] = "❌ 실행 실패: $errorMessage"
}
}
# 성공적으로 처리된 건이 하나라도 있으면 AAD Connect Delta 동기화 실행
if ($successfulSyncCount -gt 0) {
Write-Log "$successfulSyncCount 건의 성공적인 작업에 대해 AAD Connect 동기화(Delta)를 시작합니다..."
Invoke-AadConnectSync -PolicyType Delta
}
}
# 그리드의 각 행을 최종 결과에 따라 색상으로 구분
foreach ($row in $script:batch_dataGridView.Rows) {
if ($row.Cells["결과"].Value -eq "✅ 처리 완료") {
$row.DefaultCellStyle.BackColor = [System.Drawing.Color]::PaleGreen
}
elseif ($row.Cells["결과"].Value -like "❌ 실행 실패*") {
$row.DefaultCellStyle.BackColor = [System.Drawing.Color]::OrangeRed
}
}
[System.Windows.Forms.MessageBox]::Show("일괄 작업이 완료되었습니다. 최종 결과는 그리드를 확인하세요.`n새로운 작업을 하시려면 다시 CSV 파일을 로드해주세요.", "작업 완료", "OK", "Information")
# 작업 완료 후 UI 상태 초기화
$script:batch_textBoxCsvPath.Text = ""
$script:batch_progressBar.Value = 0
$script:batch_buttonExecute.Enabled = $false
$script:batch_buttonValidate.Enabled = $false
}
# --------------------------------------------------------------------------------
# 이벤트 등록 함수
# --------------------------------------------------------------------------------
function Register-BatchTaskEvents {
# 각 컨트롤에 정의된 이벤트 핸들러(스크립트 블록)를 연결
$script:batch_comboBoxTaskType.add_SelectedIndexChanged($batch_TaskType_Changed)
$script:batch_buttonDownloadTemplate.add_Click($batch_buttonDownloadTemplate_Click)
$script:batch_buttonBrowseCsv.add_Click($batch_buttonBrowseCsv_Click)
$script:batch_buttonValidate.add_Click($batch_buttonValidate_Click)
$script:batch_buttonExecute.add_Click($batch_buttonExecute_Click)
$script:batch_dataGridView.add_CellValueChanged($batch_dataGridView_CellValueChanged)
# 데이터 그리드뷰의 우클릭 컨텍스트 메뉴 설정
$contextMenu = New-Object System.Windows.Forms.ContextMenuStrip
$menuItemAdd = New-Object System.Windows.Forms.ToolStripMenuItem("새 행 추가")
$menuItemDelete = New-Object System.Windows.Forms.ToolStripMenuItem("선택 행 삭제")
$menuItemAdd.Add_Click($batch_buttonAddRow_Click)
$menuItemDelete.Add_Click($batch_buttonDeleteRow_Click)
$contextMenu.Items.AddRange(@($menuItemAdd, $menuItemDelete)) | Out-Null
# 컨텍스트 메뉴가 열릴 때, 행이 선택된 경우에만 '삭제' 메뉴를 활성화
$contextMenu.Add_Opening({
param($src, $e)
$src.Items[1].Enabled = ($script:batch_dataGridView.SelectedRows.Count -gt 0)
})
$script:batch_dataGridView.ContextMenuStrip = $contextMenu
}
# --------------------------------------------------------------------------------
# 탭 UI 초기화 함수
# --------------------------------------------------------------------------------
function Initialize-BatchTaskTab {
Param(
[System.Windows.Forms.TabPage]$parentTab
)
# 메인 레이아웃 (TableLayoutPanel) 설정
$layout = New-Object System.Windows.Forms.TableLayoutPanel
$layout.Dock = "Fill"
$layout.Padding = [System.Windows.Forms.Padding](10)
$layout.ColumnCount = 4
$layout.RowCount = 4
$layout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 100))) | Out-Null
$layout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100))) | Out-Null
$layout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 150))) | Out-Null
$layout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 160))) | Out-Null
$layout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 40))) | Out-Null
$layout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 40))) | Out-Null
$layout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100))) | Out-Null
$layout.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 50))) | Out-Null
$parentTab.Controls.Add($layout) | Out-Null
# UI 컨트롤 생성
# 0행: 작업 유형 선택 영역
$labelTaskType = New-Object System.Windows.Forms.Label
$script:batch_comboBoxTaskType = New-Object System.Windows.Forms.ComboBox
$script:batch_buttonDownloadTemplate = New-Object System.Windows.Forms.Button
# 1행: CSV 파일 선택 영역
$labelCsvPath = New-Object System.Windows.Forms.Label
$script:batch_textBoxCsvPath = New-Object System.Windows.Forms.TextBox
$script:batch_buttonBrowseCsv = New-Object System.Windows.Forms.Button
# 2행: 데이터 표시 영역 (그리드뷰, 안내문)
$gridPanel = New-Object System.Windows.Forms.Panel
$script:batch_dataGridView = New-Object System.Windows.Forms.DataGridView
$script:batch_labelGuide = New-Object System.Windows.Forms.Label
# 3행: 진행률 및 실행 버튼 영역
$script:batch_progressBar = New-Object System.Windows.Forms.ProgressBar
$execButtonLayout = New-Object System.Windows.Forms.TableLayoutPanel
$script:batch_buttonValidate = New-Object System.Windows.Forms.Button
$script:batch_buttonExecute = New-Object System.Windows.Forms.Button
# UI 컨트롤 속성 설정
# - 작업 유형 레이블
$labelTaskType.Text = "작업 유형:"
$labelTaskType.Dock = "Fill"
$labelTaskType.TextAlign = "MiddleLeft"
# - 작업 유형 콤보박스
$script:batch_comboBoxTaskType.Dock = "Fill"
$script:batch_comboBoxTaskType.DropDownStyle = "DropDownList"
$script:batch_comboBoxTaskType.Items.AddRange(@("계정 생성", "계정 삭제")) | Out-Null
$script:batch_comboBoxTaskType.SelectedIndex = 0
# - 템플릿 다운로드 버튼
$script:batch_buttonDownloadTemplate.Text = "템플릿 다운로드(&D)"
$script:batch_buttonDownloadTemplate.Dock = "Fill"
# - CSV 파일 경로 레이블
$labelCsvPath.Text = "CSV 파일 경로:"
$labelCsvPath.Dock = "Fill"
$labelCsvPath.TextAlign = "MiddleLeft"
# - CSV 파일 경로 텍스트박스
$script:batch_textBoxCsvPath.Dock = "Fill"
$script:batch_textBoxCsvPath.ReadOnly = $true
# - 파일 찾아보기 버튼
$script:batch_buttonBrowseCsv.Text = "파일 찾아보기(&B)..."
$script:batch_buttonBrowseCsv.Dock = "Fill"
# - 그리드뷰를 담을 패널
$gridPanel.Dock = "Fill"
# - 데이터 그리드뷰
$script:batch_dataGridView.Dock = "Fill"
$script:batch_dataGridView.ReadOnly = $false
$script:batch_dataGridView.AllowUserToAddRows = $false
$script:batch_dataGridView.AllowUserToDeleteRows = $false
$script:batch_dataGridView.AutoSizeColumnsMode = "Fill"
$script:batch_dataGridView.Visible = $false
$script:batch_dataGridView.SelectionMode = "FullRowSelect"
# - 안내 가이드 레이블
$script:batch_labelGuide.Dock = "Fill"
$script:batch_labelGuide.TextAlign = "MiddleLeft"
$script:batch_labelGuide.Padding = New-Object System.Windows.Forms.Padding(20, 0, 0, 0)
$script:batch_labelGuide.Font = New-Object System.Drawing.Font("Malgun Gothic", 9.5)
$script:batch_labelGuide.ForeColor = [System.Drawing.Color]::DimGray
# - 진행률 표시줄
$script:batch_progressBar.Dock = "Fill"
$script:batch_progressBar.Maximum = 100
$script:batch_progressBar.Value = 0
# - 실행 버튼들을 담을 레이아웃
$execButtonLayout.Dock = "Fill"
$execButtonLayout.ColumnCount = 2
$execButtonLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 50))) | Out-Null
$execButtonLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 50))) | Out-Null
# - 유효성 검사 버튼
$script:batch_buttonValidate.Text = "유효성 검사(&V)"
$script:batch_buttonValidate.Dock = "Fill"
$script:batch_buttonValidate.Enabled = $false
# - 일괄 작업 실행 버튼
$script:batch_buttonExecute.Text = "일괄 작업 실행(&X)"
$script:batch_buttonExecute.Dock = "Fill"
$script:batch_buttonExecute.Enabled = $false
$script:batch_buttonExecute.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
# 컨트롤들을 메인 레이아웃에 배치
# 0행: 작업 유형 선택
$layout.Controls.Add($labelTaskType, 0, 0) | Out-Null
$layout.Controls.Add($script:batch_comboBoxTaskType, 1, 0) | Out-Null
$layout.SetColumnSpan($script:batch_comboBoxTaskType, 2)
$layout.Controls.Add($script:batch_buttonDownloadTemplate, 3, 0) | Out-Null
# 1행: CSV 파일 경로
$layout.Controls.Add($labelCsvPath, 0, 1) | Out-Null
$layout.Controls.Add($script:batch_textBoxCsvPath, 1, 1) | Out-Null
$layout.SetColumnSpan($script:batch_textBoxCsvPath, 2)
$layout.Controls.Add($script:batch_buttonBrowseCsv, 3, 1) | Out-Null
# 2행: 데이터 그리드 및 안내문
$gridPanel.Controls.Add($script:batch_dataGridView) | Out-Null
$gridPanel.Controls.Add($script:batch_labelGuide) | Out-Null
$layout.Controls.Add($gridPanel, 0, 2) | Out-Null
$layout.SetColumnSpan($gridPanel, 4)
# 3행: 진행률 및 실행 버튼
$execButtonLayout.Controls.Add($script:batch_buttonValidate, 0, 0) | Out-Null
$execButtonLayout.Controls.Add($script:batch_buttonExecute, 1, 0) | Out-Null
$layout.Controls.Add($script:batch_progressBar, 0, 3) | Out-Null
$layout.SetColumnSpan($script:batch_progressBar, 2)
$layout.Controls.Add($execButtonLayout, 2, 3) | Out-Null
$layout.SetColumnSpan($execButtonLayout, 2)
# 이벤트 핸들러 등록
Register-BatchTaskEvents
# 탭 초기화 시 '작업 유형 변경' 이벤트를 수동으로 호출하여 UI 초기 상태를 설정
$batch_TaskType_Changed.Invoke($null, $null)
}
#endregion
Write-Host "UI-Tab-BatchTask.ps1 로드 완료." -ForegroundColor Cyan