2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

エクセルファイルのデータをPowerShellに取り込む

Last updated at Posted at 2020-04-21

はじめに

xls 形式のファイルは xlsx 形式で保存し直してください。 Windows10 以上で動きます。

成果物

Import-XlFile.ps1
Function Import-XlFile {
    Param(
        [Parameter(Mandatory=$True)]
        [string]$Path,
    
        [parameter(Mandatory=$False)]
        [string[]]$SheetName,
    
        [parameter(Mandatory=$False)]
        [switch]$ActiveSheet
    )
    
    $ErrorActionPreference = "STOP"
    
    $temp = $Env:Temp
    $xlsx = Get-Item -Path $Path
    $base = Join-Path $temp $xlsx.BaseName
    $zip = $base + ".zip"
    
    Copy-Item $xlsx $zip -Force
    Expand-Archive $zip -Destination $base -Force
    
    $workbook = [xml](Get-Content -Encoding UTF8 $base\xl\workbook.xml)
    $styles = [xml](Get-Content -Encoding UTF8 $base\xl\styles.xml)
    $sharedStrings = [xml](Get-Content -Encoding UTF8 $base\xl\sharedStrings.xml)
    
    $sheets = @{}
    $workbook.workbook.sheets.sheet | ForEach-Object {
        $xml = "$base\xl\worksheets\" + $_.Id.replace("rId","sheet") + ".xml"
        $sheets.add($_.name, $xml)
    }
    
    $SheetNames = @()
    if ($SheetName.Count -ne 0) {
        $SheetNames = $SheetName
    }
    
    if ($null -eq $SheetName -and -not $ActiveSheet) {
        $SheetNames += $workbook.workbook.sheets.sheet.Name
    }
    
    if ($ActiveSheet) {
        $activeIndex = $workbook.workbook.bookViews.workbookView.activeTab
        $activeTab = $workbook.workbook.sheets.sheet.Name[$activeIndex]
        if(-not $SheetNames.Contains($activeTab)) {
            $SheetNames += $activeTab
        }
    }
    
    $worksheets = @{}
    $SheetNames | ForEach-Object {
        $sn = $_
        $sheetData = [xml](Get-Content -Encoding UTF8 $sheets[$sn])
        $data = $sheetData.worksheet.sheetData.row | Where-Object {
            # for empty sheet
            $_
        } | ForEach-Object {
            $r = $_
            $row = New-Object psobject
            $r.c | ForEach-Object {
                $c = $_

                $address = $c.r -replace '[0-9]'
                $fmtId = $c.s | Where-Object { $_ } | ForEach-Object {
                    [int]$styles.styleSheet.cellXfs.xf[$c.s].numFmtId
                }
                $isDate = $fmtId | ForEach-Object {
                    if (13 -lt $_ -and $_ -lt 37) { return $true }
                    if (44 -lt $_ -and $_ -lt 48) { return $true }
                    if (49 -lt $_ -and $_ -lt 59) { return $true }
                    return $false
                }

                if ($c.t -eq "s") {
                    $value = $sharedStrings.sst.si.t[$c.v]
                } elseif ($isDate) {
                    [double]$serial = $c.v
                    if ($serial -ge 1) {
                        $dateSerial = [Math]::Floor($serial)
                        $date = ([datetime]"1900/1/1").AddDays($dateSerial - 2)
                        $timeSerial = $serial - $dateSerial
                    } else {
                        $date = [datetime]"1900/1/1"
                        $timeSerial = $serial
                    }
                    $value = $date.AddSeconds($timeSerial * 24 * 3600)
                } else {
                    $value = $c.v
                }

                # other?
                $row | Add-Member -Force -MemberType Noteproperty -Name $address -Value $value
            }
            return $row
        }
        $worksheets.add($sn, $data);
    }
    Remove-Item -Force -Recurse $base, $zip
    return $worksheets
}

使い方

. .\Import-XlFile.ps1
$worksheets = Import-XlFile -Path .\hogehoge\xlsx.xlsx -SheetName hoge, fuga, piyo
$worksheets
<#
Name          Value
-----         ------
hoge          {@{A=...; B=...}...}
fuga          {@{A=...; B=...}...}
piyo          {@{A=...; B=...}...}
# >

# シートデータの参照
$worksheets.hoge

おわりに

PowerShell v5(Windows10) で ZIP 展開が標準コマンドで実行できるようになったので、外部コマンドに頼らず COM も使わずにエクセルのデータを取り込むことができるようになった。以前までのやり方よりも依存関係が少なくなり、すっきりした。

自力で XML の解析を行ったことで Excel のシリアル値の流派が別れた理由を知ることができた。

免責

ちゃんとしたテストはやってません。
事務作業に利用しようと思っている程度なので大きな問題にはならないはずです。
文字列が入力されたセルが 1 つしかない場合は PowerShell のよくある問題により誤作動します。

参考資料

https://qiita.com/weal/items/f1d7690e60882d38d7d2
https://qiita.com/wagase/items/6444ce93a24aaaa74981

ImportExcel

追記です。ライブラリがあるというのを教えて頂きました
https://www.powershellgallery.com/packages/ImportExcel/

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?