# ================================================================================ # 파일: 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