ソフトウェア開発 / PowerShell / FolderStructureCreator
# ----------------------------------------------------------
# インポート
# ----------------------------------------------------------
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
. "${PSScriptRoot}\ExcelHelper.ps1"
# ----------------------------------------------------------
# 定数定義
# ----------------------------------------------------------
$EXCEL_BACKGROUND_COLOR_FIX_ROW = [Convert]::ToInt32("D9D9D9", 16)
$EXCEL_BACKGROUND_COLOR_FOLDER = [Convert]::ToInt32("CCFFFF", 16)
$EXCEL_COLUMN_SPAN = 5
# ----------------------------------------------------------
# グローバル変数定義
# ----------------------------------------------------------
$entries = New-Object System.Collections.ArrayList
# ----------------------------------------------------------
# メイン画面
# ----------------------------------------------------------
$form = New-Object System.Windows.Forms.Form
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog
$form.MaximizeBox = $false
$form.StartPosition = 'CenterScreen'
$form.Text = "フォルダー構成"
$form.Width = 640
$form.Height = 120
# ----------------------------------------------------------
#
# ----------------------------------------------------------
$bottomTableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
$bottomTableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Bottom
$bottomTableLayoutPanel.Height = 50
$bottomTableLayoutPanel.RowCount = 1
$bottomTableLayoutPanel.ColumnCount = 2
$bottomTableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100))) | Out-Null
$bottomTableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::AutoSize))) | Out-Null
$form.Controls.Add($bottomTableLayoutPanel)
# ----------------------------------------------------------
# 実行ボタン
# ----------------------------------------------------------
$executeButton = New-Object System.Windows.Forms.Button
$executeButton.Width = 80
$executeButton.Height = 30
$executeButton.Text = '実行'
$executeButton.Anchor = [System.Windows.Forms.AnchorStyles]::None
$executeButton.Margin = New-Object System.Windows.Forms.Padding(10, 0, 10, 0)
$bottomTableLayoutPanel.Controls.Add($executeButton, 1, 0)
# ----------------------------------------------------------
#
# ----------------------------------------------------------
$fillTableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
$fillTableLayoutPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
$fillTableLayoutPanel.Height = 50
$fillTableLayoutPanel.RowCount = 2
$fillTableLayoutPanel.ColumnCount = 2
$fillTableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 15))) | Out-Null
$fillTableLayoutPanel.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 85))) | Out-Null
$form.Controls.Add($fillTableLayoutPanel)
# ----------------------------------------------------------
#
# ----------------------------------------------------------
$targetLabel = New-Object System.Windows.Forms.Label
$targetLabel.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left
$targetLabel.Margin = New-Object System.Windows.Forms.Padding(5, 5, 5, 5)
$targetLabel.AutoSize = $true
$targetLabel.Text = 'パス'
$fillTableLayoutPanel.Controls.Add($targetLabel, 0, 0)
$targetTextBox = New-Object System.Windows.Forms.TextBox
$targetTextBox.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left
$targetTextBox.Margin = New-Object System.Windows.Forms.Padding(5, 5, 5, 5)
$targetTextBox.Width = 515
$targetTextBox.Text = ''
$targetTextBox.AllowDrop = $true
$fillTableLayoutPanel.Controls.Add($targetTextBox, 1, 0)
$targetTextBox.Add_DragDrop({
foreach ($filename in $_.Data.GetData([System.Windows.Forms.DataFormats]::FileDrop)) {
$targetTextBox.Text = $filename
break
}
})
$targetTextBox.Add_DragOver({
foreach ($filename in $_.Data.GetData([System.Windows.Forms.DataFormats]::FileDrop)) {
$_.Effect = [System.Windows.Forms.DragDropEffects]::All
}
})
# ----------------------------------------------------------
#
# ----------------------------------------------------------
$executeButton.Add_Click({
Create-FolderStructure -RootFolderPath $targetTextBox.Text
$form.TopMost = $true
[System.Windows.Forms.MessageBox]::Show($form, 'たいへんよくできました', '通知', 'OK', 'Information')
$form.TopMost = $false
})
# ----------------------------------------------------------
# Excel にフォルダー構成を出力します。
# ----------------------------------------------------------
function Write-ExcelFolderStructure {
$worksheet = Get-ExcelFirstWorksheet $workbook
$worksheet.Name = 'フォルダー構成'
$worksheet.Cells.ColumnWidth = 2
$excel.ActiveWindow.DisplayGridlines = $false
$maxIndentLevel = ($entries | ForEach-Object {$_.IndentLevel} | Measure-Object -Maximum).Maximum
$endsColumnIndex = ($maxIndentLevel * $EXCEL_COLUMN_SPAN) + $EXCEL_COLUMN_SPAN
$containerColumnIndex = $endsColumnIndex + 1
$startsDetailRowIndex = 2
$endsDetailRowIndex = $startsDetailRowIndex + $entries.Count - 1
# ----------------------------------------------------------
# ヘッダー
# ----------------------------------------------------------
$worksheet.Cells(1, 1).Value = 'ルート'
$outerBorderRange = $worksheet.Range($worksheet.Cells(1, 1), $worksheet.Cells(1, 1 + $EXCEL_COLUMN_SPAN - 1))
Draw-ExcelOuterBorder $outerBorderRange
$backGroundColorRange = $worksheet.Range($worksheet.Cells(1, 1), $worksheet.Cells(1, 1, + $EXCEL_COLUMN_SPAN - 1))
Set-ExcelCellBackgroundColor $backGroundColorRange $EXCEL_BACKGROUND_COLOR_FIX_ROW
for ($indentLevel = $firstIndentLevel; $indentLevel -le $maxIndentLevel; $indentLevel++) {
$columnIndex = 1 + ($indentLevel * $EXCEL_COLUMN_SPAN)
$worksheet.Cells(1, $columnIndex).Value = "第 ${indentLevel} 階層"
$outerBorderRange = $worksheet.Range($worksheet.Cells(1, $columnIndex), $worksheet.Cells(1, $columnIndex + $EXCEL_COLUMN_SPAN - 1))
Draw-ExcelOuterBorder $outerBorderRange
$backGroundColorRange = $worksheet.Range($worksheet.Cells(1, $columnIndex), $worksheet.Cells(1, $columnIndex + $EXCEL_COLUMN_SPAN - 1))
Set-ExcelCellBackgroundColor $backGroundColorRange $EXCEL_BACKGROUND_COLOR_FIX_ROW
}
# ----------------------------------------------------------
# 詳細
# ----------------------------------------------------------
$rowIndex = $startsDetailRowIndex
foreach ($entry in $entries) {
$olumnIndex = 1 + ($entry.IndexLevel * $EXCEL_COLUMN_SPAN)
$topLeftRange = $worksheet.Cells($rowIndex, $columnIndex)
$topLeftRange.Value = $entry.Name
if ($entry.IsContainer) {
$bottomRightRange = $worksheet.Cells($rowIndex + $entry.Count, $endsColumnIndex)
$outerBorderRange = $worksheet.Range($topLeftRange, $bottomRightRange)
Draw-ExcelOuterBorder $outerBorderRange
$bottomRightRange = $worksheet.Cells($rowIndex + $entry.Count, $columnIndex + $EXCEL_COLUMN_SPAN - 1)
$backGroundColorRange = $worksheet.Cells($topLeftRange, $bottomRightRange)
Set-ExcelCellBackgroundColor $backGroundColorRange $EXCEL_BACKGROUND_COLOR_FOLDER
$bottomRightRange = $worksheet.Cells($topLeftRange, $worksheet.Cells($rowIndex, $endsColumnIndex))
$backGroundColorRange = $worksheet.Range($topLeftRange, $bottomRightRange)
Set-ExcelCellBackgroundColor $backGroundColorRange $EXCEL_BACKGROUND_COLOR_FOLDER
} else {
$bottomRightRange = $worksheet.Cells($topLeftRange, $worksheet.Cells($rowIndex, $endsColumnIndex))
$outerBorderRange = $worksheet.Range($topLeftRange, $bottomRightRange)
Draw-ExcelOuterBorder $outerBorderRange
}
$rowIndex++
}
# ----------------------------------------------------------
# ウィンドウ枠を固定する
# ----------------------------------------------------------
$worksheet.Range('2:2').Select() | Out-Null
$excel.ActiveWindow.FreezePanes = $true
Release-ExcelComObjectSafely $worksheet
}
# ----------------------------------------------------------
# フォルダー構成を作成するのに必要な情報を収集します。
# ----------------------------------------------------------
function Set-FolderStructure {
param (
[string]$Path
,[int]$indentLevel = 0
)
$items = Get-ChildItem -Path $Path | Sort-Object @{Expression={$_.PSIsContainer}}, @{Expression={$_.Name}}
foreach ($item in $items) {
$count = 1
if ($item.PSIsContainer) {
$count = Get-ItemCountRecursive $item.FullName
}
$entry = @{
IndentLevel = $indentLevel;
FullName = $item.FullName;
Name = $item.Name;
LastWriteTime = $item.LastWriteTime;
IsContainer = $item.PSIsContainer;
Count = $count
}
$entries.Add($entry) | Out-Null
if ($item.PSIsContainer) {
Set-FolderStructure $item.FullName ($indentLevel + 1)
}
}
}
# ----------------------------------------------------------
# サブフォルダーを含めたフォルダーとファイルの数を取得します。
# ----------------------------------------------------------
function Get-ItemCountRecursive {
param (
$Path
)
return (Get-ChildItem -Path $Path -Recurse).Count
}
# ----------------------------------------------------------
# フォルダー構造を作成します。
# ----------------------------------------------------------
function Greate-FolderStructure {
param (
$RootFolderPath
)
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$rootFolder = Get-Item -Path $RootFolderPath
$entries.Clear()
$rootIndentLevel = 0
$entry = @{
IndentLevel = $rootIndentLevel;
FullName = $rootFolder.FullName;
Name = $rootFolder.Name;
LastWriteTime = $rootFolder.LastWriteTime;
IsContainer = $rootFolder.PSIsContainer;
Count = Get-ItemCountRecursive $rootFolder.FullName
}
$entries.Add($entry) | Out-Null
$firstIndentLevel = 1
Set-FolderStructure $rootFolder.FullName $firstIndentLevel
try {
$excel = New-ExcelApplication
$excel.Visible = $true
$workbook = Add-ExcelWorkbook $excel
Write-ExcelFolderStructure
Reset-ExcelViewState $workbook
} finally {
Release-ExcelComObjectSafely $workbook
Release-ExcelComObjectSafely $excel
}
Write-Host "処理時間:[$($stopwatch.ElapsedMilliseconds)]ms"
}
# ----------------------------------------------------------
# 画面表示
# ----------------------------------------------------------
$form.ShowDialog()