Skip to content

Instantly share code, notes, and snippets.

@ritalin
Last active January 3, 2016 23:49
Show Gist options
  • Save ritalin/8538027 to your computer and use it in GitHub Desktop.
Save ritalin/8538027 to your computer and use it in GitHub Desktop.
function Get-ExcelData([parameter(Mandatory=$true, ValueFromPipeline=$true)]$files, [switch]$withHeader) {
function Get-ExcelData-Header([ref]$rowsRef) {
if (($withHeader) -and ($rowsRef.Value.Count -gt 0)) {
$row = $rowsRef.Value.item(1)
try {
$columns = $row.columns
try {
for ($c = 1; $c -le $columns.Count; ++$c) {
$col = $columns.item($c)
try {
$col.Text
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($col) | out-null
}
}
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($columns) | out-null
}
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($row) | out-null
}
}
else {
@()
}
}
function Get-ExcelData-Values([ref]$rowsRef) {
$fromIndex = if($withHeader) {2} else {1}
if ($rowsRef.Value.count -gt $fromIndex) {
for ($r = $fromIndex; $r -le $rowsRef.Value.count; ++$r) {
$row = $rowsRef.Value.item($r)
$columns = $row.Columns
try {
$values = for ($c = 1; $c -le $columns.Count; ++$c) {
$col = $columns.item($c)
try {
$col.Value()
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($col) | out-null
}
}
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($columns) | out-null
[Runtime.Interopservices.Marshal]::ReleaseComObject($row) | out-null
}
(,$values)
}
}
else {
@()
}
}
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
try {
$workBooks = $excel.Workbooks
try {
([array]$results) += foreach ($path in $files) {
$fileName = (new-object IO.FileInfo $path).baseName
$workBook = $workBooks.Open($path)
try {
$sheets = $workBook.workSheets
try {
$sheetCount = $sheets.Count
for ($i = 1; $i -le $sheetCount; ++$i) {
$sheet = $sheets.item($i)
$range = $sheet.usedRange
$rows = $range.rows
try {
new-object PSObject -property @{
file = $fileName;
name = $sheet.name;
headers = (Get-ExcelData-Header ([ref]$rows));
values = (Get-ExcelData-Values ([ref]$rows));
}
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($rows) | out-null
[Runtime.Interopservices.Marshal]::ReleaseComObject($range) | out-null
[Runtime.Interopservices.Marshal]::ReleaseComObject($sheet) | out-null
}
}
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($sheets) | out-null
}
}
finally {
$workBook.Close()
[Runtime.Interopservices.Marshal]::ReleaseComObject($workBook) | out-null
}
}
$results
}
finally {
[Runtime.Interopservices.Marshal]::ReleaseComObject($workBooks) | out-null
}
}
finally {
$excel.Quit()
[Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | out-null
}
}
function Merge-KV([array]$keys, [array]$values) {
$len = [Math]::min($keys.length, $values.length)
$o = new-object psobject
for ($i = 0; $i -lt $len; ++$i) {
add-member -inputobject $o -membertype noteproperty -name $keys[$i] -value $values[$i]
}
$o
}
function ConvertTo-Json(
[parameter(Mandatory=$true, ValueFromPipeline=$true)]$sources,
$indentSize = 4)
{
function processInternal($item, $indent) {
$map = @{
"Object[]" = { processArray $item $indent };
"PSCustomObject" = { processObject $item $indent };
}
if ($item -ne $null) {
$typeName = $item.getType().name
if ($map.containsKey($typeName)) {
return & ($map[$typeName])
}
else {
$n = $null
if ([decimal]::TryParse($item, [ref]$n)) {
return (" " * $indent) + $n
}
elseif ($item -is [datetime]) {
return (" " * $indent) + '"' + $item.ToString("yyyy-MM-ddThh:mm:ssZ") + '"'
}
}
}
(" " * $indent) + '"' + $item + '"'
}
function processArray([array]$items, $indent) {
$indentStr = " " * $indent
$results = foreach ($item in $items) {
processInternal $item ($indent+$indentSize)
}
"${indentStr}[`r`n$([string]::join(",`r`n", $results))`r`n${indentStr}]"
}
function processObject($obj, $indent) {
$indentStr = " " * $indent
$fields = $($obj | member -membertype noteproperty)
if ($fields.length -gt 0) {
$results = foreach ($field in $fields) {
$key = processInternal ($field.name) ($indent+$indentSize)
$value = processInternal $obj.$($field.name) ($indent+$indentSize)
"${key}: $($value.trim())"
}
"${indentStr}`{`r`n$([string]::join(",`r`n", $results))`r`n${indentStr}`}"
}
else {
"{}"
}
}
processInternal $sources 0
}
function Convert-Excel-To-Json($path) {
ls $path/*.xlsx | %{ $_.fullname } |
Get-ExcelData -withHeader | %{
$f = new-object IO.DirectoryInfo "${path}/$($_.file)"
$f.create()
$headers = $_.headers
,($_.values | % { merge-kv $headers $_ }) |
ConvertTo-Json |
out-file -encoding utf8 "$($f.fullName)/$($_.name).json"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment