Googleカレンダーのインポートファイルを、Excelファイルから作る。

## 背景など
予定をExcelファイルでいただき、手作業でGoogleカレンダーに入れていましたが、毎月入れるのがとても面倒なので、シェル化してみました。

## やりたいこと

- Excelファイルに、以下を入力したシートを準備。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90255/161d1159-c396-a20c-a13e-d90c44b1a305.png)

- シェル`ExcelToICS.ps1`を実行するバッチ`ExcelToICS.bat`を実行する。
- 指定したフォルダに、入力指定したExcelファイル数分、Googleカレンダーのインポートファイル`*.ICS`が作成される。
- Googleカレンダーのインポート画面からインポートする。(詳細はGoogleサイトで確認してください)
以上。

### 1. `ExcelToICS.bat` シェルを実行するためのバッチ を準備する。
大体の環境は、Powershellを実行するときに、以下のような画面が出てきます。
常に実行できるように変更する方法もありますが、このバッチを経由してシェルを呼び出すことで、そのようなことをする必要はなくなります。

```bat
@echo off
powershell -ExecutionPolicy Bypass -File "%~dp0ExcelToICS.ps1"
```

### 2. `ExcelToICS.ps1` Excelファイル→ICSファイル変換するシェルを作成する。
```powershell

Add-Type -AssemblyName System.Windows.Forms

# ファイル選択ダイアログを表示
$openFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$openFileDialog.Filter = "Excel Files (*.xlsx)|*.xlsx"
$openFileDialog.Title = "Excelファイルを選択してください"
$openFileDialog.Multiselect = $true

if ($openFileDialog.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) {
    Write-Host "ファイルが選択されませんでした。スクリプトを終了します。"
    exit
}

$excelFilePaths = $openFileDialog.FileNames

# 保存先フォルダ選択ダイアログを表示
$folderBrowserDialog = New-Object System.Windows.Forms.FolderBrowserDialog
$folderBrowserDialog.Description = "保存先フォルダを選択してください"

if ($folderBrowserDialog.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) {
    Write-Host "保存先フォルダが選択されませんでした。スクリプトを終了します。"
    exit
}

$outputFolder = $folderBrowserDialog.SelectedPath

foreach ($excelFilePath in $excelFilePaths) {
    $fileName = [System.IO.Path]::GetFileNameWithoutExtension($excelFilePath)
    $outputICS = [System.IO.Path]::Combine($outputFolder, "$fileName.ics")

    # Excelオブジェクトを作成
    $excel = New-Object -ComObject Excel.Application
    $excel.Visible = $false
    $workbook = $excel.Workbooks.Open($excelFilePath)
    $sheet = $workbook.Sheets.Item(1) # 最初のシートを選択

    # 最終行を取得
    $lastRow = $sheet.Cells($sheet.Rows.Count, 1).End(-4162).Row

    # ICSファイルの作成
    $icsContent = @()
    $icsContent += "BEGIN:VCALENDAR"
    $icsContent += "VERSION:2.0"
    $icsContent += "PRODID:-//Your Company//NONSGML Event//EN"

    # ExcelデータをICSに変換
    for ($i = 2; $i -le $lastRow; $i++) {
        $startDateStr = $sheet.Cells($i, 2).Value()
        $endDateStr = $sheet.Cells($i, 3).Value()
        
        if ($startDateStr -and $endDateStr) {
            $startDate = [datetime]::ParseExact($startDateStr, "yyyy/MM/dd HH:mm", $null)
            $endDate = [datetime]::ParseExact($endDateStr, "yyyy/MM/dd HH:mm", $null)
            
            $icsContent += "BEGIN:VEVENT"
            $icsContent += "DTSTART:" + ($startDate.ToString("yyyyMMddTHHmmss"))
            $icsContent += "DTEND:" + ($endDate.ToString("yyyyMMddTHHmmss"))
            $icsContent += "SUMMARY:" + $sheet.Cells($i, 1).Value()
            $icsContent += "LOCATION:" + $sheet.Cells($i, 4).Value()
            $icsContent += "END:VEVENT"
        }
    }

    # ICSファイルのフッター
    $icsContent += "END:VCALENDAR"
    $icsContent | Out-File -Encoding utf8 $outputICS

    # 後処理
    $workbook.Close($false)
    $excel.Quit()
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet)    | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)    | Out-Null

    Write-Host "ICSファイルが作成されました: $outputICS"
}

# メッセージボックスで表示
[System.Windows.Forms.MessageBox]::Show("ICSファイルが作成されました。", "完了", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
```

### 3.ExcelToICS.bat を実行する。

#### 入力ファイルの選択
バッチを起動すると、以下の画面が表示するので、入力ファイルを選択します。（複数選択可能）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90255/d1a927c3-f8f3-e281-89f0-298290454618.png)

### 出力先フォルダを選択

### 結果を確認する
出力したファイルのフルパスと、完了画面が表示されますので、`OK`ボタンを押下


以上！