Compare commits
153 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79e5bdf8ba | ||
|
|
b03d9b048a | ||
|
|
aea90aa8d6 | ||
|
|
d4ebc9e95d | ||
|
|
6ece4483e2 | ||
|
|
ba14511254 | ||
|
|
964cf9e9c6 | ||
|
|
8d56a351ff | ||
|
|
b2119f08f5 | ||
|
|
634aaacc55 | ||
|
|
61b44f826d | ||
|
|
9273261b34 | ||
|
|
e55dfdd10e | ||
|
|
59e40d62d0 | ||
|
|
f478e8a134 | ||
|
|
b634bf9d93 | ||
|
|
a10ade898a | ||
|
|
eb10364722 | ||
|
|
b0024cf2c4 | ||
|
|
91b0e8b0ed | ||
|
|
b997e90e78 | ||
|
|
4d8710d017 | ||
|
|
7f36b44fa8 | ||
|
|
483f761016 | ||
|
|
d55f0e64d4 | ||
|
|
f83f654c4a | ||
|
|
6a956dbd7e | ||
|
|
0929a442a5 | ||
|
|
895a5c0cb2 | ||
|
|
d7901af8f3 | ||
|
|
34f55a3659 | ||
|
|
606988bcf6 | ||
|
|
441f2ada22 | ||
|
|
29ea7012d7 | ||
|
|
67ac63ddcf | ||
|
|
c939c6ecb0 | ||
|
|
96493e059b | ||
|
|
cb7f2a06f4 | ||
|
|
99beda7a10 | ||
|
|
0c8bb2300a | ||
|
|
c09083d350 | ||
|
|
556f0ac51e | ||
|
|
1e4fc59a25 | ||
|
|
5ab6a9116d | ||
|
|
f33215382a | ||
|
|
cf5d3f83d6 | ||
|
|
91da711635 | ||
|
|
eec5e343d4 | ||
|
|
d69b640edc | ||
|
|
2ca870a889 | ||
|
|
a320cfd28c | ||
|
|
aa1b042767 | ||
|
|
7e8416d67c | ||
|
|
229b60b25d | ||
|
|
5700989321 | ||
|
|
56e1704e7e | ||
|
|
8268bbc2e1 | ||
|
|
5657659331 | ||
|
|
0d4a32e266 | ||
|
|
1c8f8d2a3d | ||
|
|
f6a65677df | ||
|
|
86a7865fb2 | ||
|
|
8b3bf4f14f | ||
|
|
4d6193f549 | ||
|
|
6ebac7b6dc | ||
|
|
d71dd36d56 | ||
|
|
3697cdfeee | ||
|
|
1e172cf21f | ||
|
|
6da7553c98 | ||
|
|
5a444c620b | ||
|
|
4a09fc3570 | ||
|
|
d706a10276 | ||
|
|
1fd2f422cd | ||
|
|
283e50547d | ||
|
|
15211a6297 | ||
|
|
8905b8d401 | ||
|
|
e9b437af4e | ||
|
|
330e237727 | ||
|
|
c56b2cd33a | ||
|
|
1aa5c6da45 | ||
|
|
9eb894cf59 | ||
|
|
3a4c2d7bd9 | ||
|
|
42cb5a316a | ||
|
|
536cdaa841 | ||
|
|
6cd9fad7ba | ||
|
|
829d854c3d | ||
|
|
b33a282740 | ||
|
|
73fc96166c | ||
|
|
00f7278115 | ||
|
|
956cf5aa49 | ||
|
|
877310e015 | ||
|
|
08bf877535 | ||
|
|
88e28a1d6c | ||
|
|
eb63fe259a | ||
|
|
6d97efc5c2 | ||
|
|
c567526eac | ||
|
|
ed210cc730 | ||
|
|
72f44ebcb9 | ||
|
|
f1d20ed163 | ||
|
|
02cf6bb3f3 | ||
|
|
5cd3897dfa | ||
|
|
fe4f2848ad | ||
|
|
4e89b3321a | ||
|
|
43b6ebf84f | ||
|
|
1ee9493bc0 | ||
|
|
8f0fc7397d | ||
|
|
4fa6fbda01 | ||
|
|
7177623104 | ||
|
|
487cf51abc | ||
|
|
ae31e9d39b | ||
|
|
9ba20b8ec8 | ||
|
|
9daefc2925 | ||
|
|
f0b4cb28f6 | ||
|
|
5f00f5cbbc | ||
|
|
d41fbf8a05 | ||
|
|
ebe49f1650 | ||
|
|
a3dced10e4 | ||
|
|
1e522c562b | ||
|
|
5ec299ff2d | ||
|
|
676ecc17e0 | ||
|
|
aa1b0018ab | ||
|
|
eabaab79c5 | ||
|
|
7a8bbb9771 | ||
|
|
85f2433ffc | ||
|
|
62c8d74a59 | ||
|
|
5e7b404daf | ||
|
|
91a1240408 | ||
|
|
e8c3d96f43 | ||
|
|
9417b25af1 | ||
|
|
a942f2133d | ||
|
|
533ed07ac8 | ||
|
|
09f35b5fd5 | ||
|
|
23a2ac394f | ||
|
|
50928e8e3b | ||
|
|
26827b0764 | ||
|
|
6c35d5b018 | ||
|
|
ab5600c9ba | ||
|
|
47dcc636d9 | ||
|
|
1768c0ac92 | ||
|
|
694fcdd8c1 | ||
|
|
0192f4d822 | ||
|
|
c641eea10a | ||
|
|
99de9a9854 | ||
|
|
3121c5eaed | ||
|
|
d02f757568 | ||
|
|
a693725949 | ||
|
|
5e19d0ca1a | ||
|
|
204b82144f | ||
|
|
91eefbd48b | ||
|
|
f86556a89d | ||
|
|
14e1dfd8db | ||
|
|
1d961c679e | ||
|
|
7026803415 |
56
.vscode/launch.json
vendored
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "PowerShell Pester Tests",
|
|
||||||
"script": "Import-Module -Name '.\\' -Force ; Invoke-Pester", // Change to '.\\ModuleName.psd1' if Git name different
|
|
||||||
"args": [""],
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "PowerShell Launch Current File",
|
|
||||||
"script": "${file}",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${file}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "PowerShell Launch Current File in Temporary Console",
|
|
||||||
"script": "${file}",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${file}",
|
|
||||||
"createTemporaryIntegratedConsole": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "PowerShell Launch Current File w/Args Prompt",
|
|
||||||
"script": "${file}",
|
|
||||||
"args": [
|
|
||||||
"${command:SpecifyScriptArgs}"
|
|
||||||
],
|
|
||||||
"cwd": "${file}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "attach",
|
|
||||||
"name": "PowerShell Attach to Host Process",
|
|
||||||
"processId": "${command:PickPSHostProcess}",
|
|
||||||
"runspaceId": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "PowerShell Interactive Session",
|
|
||||||
"cwd": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
119
Examples/AddImage/Add-ExcelImage.ps1
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
function Add-ExcelImage {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Adds an image to a worksheet in an Excel package.
|
||||||
|
.DESCRIPTION
|
||||||
|
Adds an image to a worksheet in an Excel package using the
|
||||||
|
`WorkSheet.Drawings.AddPicture(name, image)` method, and places the
|
||||||
|
image at the location specified by the Row and Column parameters.
|
||||||
|
|
||||||
|
Additional position adjustment can be made by providing RowOffset and
|
||||||
|
ColumnOffset values in pixels.
|
||||||
|
.EXAMPLE
|
||||||
|
$image = [System.Drawing.Image]::FromFile($octocat)
|
||||||
|
$xlpkg = $data | Export-Excel -Path $path -PassThru
|
||||||
|
$xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell
|
||||||
|
|
||||||
|
Where $octocat is a path to an image file, and $data is a collection of
|
||||||
|
data to be exported, and $path is the output path for the Excel document,
|
||||||
|
Add-Excel places the image at row 4 and column 6, resizing the column
|
||||||
|
and row as needed to fit the image.
|
||||||
|
.INPUTS
|
||||||
|
[OfficeOpenXml.ExcelWorksheet]
|
||||||
|
.OUTPUTS
|
||||||
|
None
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
# Specifies the worksheet to add the image to.
|
||||||
|
[Parameter(Mandatory, ValueFromPipeline)]
|
||||||
|
[OfficeOpenXml.ExcelWorksheet]
|
||||||
|
$WorkSheet,
|
||||||
|
|
||||||
|
# Specifies the Image to be added to the worksheet.
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[System.Drawing.Image]
|
||||||
|
$Image,
|
||||||
|
|
||||||
|
# Specifies the row where the image will be placed. Rows are counted from 1.
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateRange(1, [int]::MaxValue)]
|
||||||
|
[int]
|
||||||
|
$Row,
|
||||||
|
|
||||||
|
# Specifies the column where the image will be placed. Columns are counted from 1.
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateRange(1, [int]::MaxValue)]
|
||||||
|
[int]
|
||||||
|
$Column,
|
||||||
|
|
||||||
|
# Specifies the name to associate with the image. Names must be unique per sheet.
|
||||||
|
# Omit the name and a GUID will be used instead.
|
||||||
|
[Parameter()]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
# Specifies the number of pixels to offset the image on the Y-axis. A
|
||||||
|
# positive number moves the image down by the specified number of pixels
|
||||||
|
# from the top border of the cell.
|
||||||
|
[Parameter()]
|
||||||
|
[int]
|
||||||
|
$RowOffset = 1,
|
||||||
|
|
||||||
|
# Specifies the number of pixels to offset the image on the X-axis. A
|
||||||
|
# positive number moves the image to the right by the specified number
|
||||||
|
# of pixels from the left border of the cell.
|
||||||
|
[Parameter()]
|
||||||
|
[int]
|
||||||
|
$ColumnOffset = 1,
|
||||||
|
|
||||||
|
# Increase the column width and row height to fit the image if the current
|
||||||
|
# dimensions are smaller than the image provided.
|
||||||
|
[Parameter()]
|
||||||
|
[switch]
|
||||||
|
$ResizeCell
|
||||||
|
)
|
||||||
|
|
||||||
|
begin {
|
||||||
|
if ($IsWindows -eq $false) {
|
||||||
|
throw "This only works on Windows and won't run on $([environment]::OSVersion)"
|
||||||
|
}
|
||||||
|
|
||||||
|
<#
|
||||||
|
These ratios work on my machine but it feels fragile. Need to better
|
||||||
|
understand how row and column sizing works in Excel and what the
|
||||||
|
width and height units represent.
|
||||||
|
#>
|
||||||
|
$widthFactor = 1 / 7
|
||||||
|
$heightFactor = 3 / 4
|
||||||
|
}
|
||||||
|
|
||||||
|
process {
|
||||||
|
if ([string]::IsNullOrWhiteSpace($Name)) {
|
||||||
|
$Name = (New-Guid).ToString()
|
||||||
|
}
|
||||||
|
if ($null -ne $WorkSheet.Drawings[$Name]) {
|
||||||
|
Write-Error "A picture with the name `"$Name`" already exists in worksheet $($WorkSheet.Name)."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
<#
|
||||||
|
The row and column offsets of 1 ensures that the image lands just
|
||||||
|
inside the gray cell borders at the top left.
|
||||||
|
#>
|
||||||
|
$picture = $WorkSheet.Drawings.AddPicture($Name, $Image)
|
||||||
|
$picture.SetPosition($Row - 1, $RowOffset, $Column - 1, $ColumnOffset)
|
||||||
|
|
||||||
|
if ($ResizeCell) {
|
||||||
|
<#
|
||||||
|
Adding 1 to the image height and width ensures that when the
|
||||||
|
row and column are resized, the bottom right of the image lands
|
||||||
|
just inside the gray cell borders at the bottom right.
|
||||||
|
#>
|
||||||
|
$width = $widthFactor * ($Image.Width + 1)
|
||||||
|
$height = $heightFactor * ($Image.Height + 1)
|
||||||
|
$WorkSheet.Column($Column).Width = [Math]::Max($width, $WorkSheet.Column($Column).Width)
|
||||||
|
$WorkSheet.Row($Row).Height = [Math]::Max($height, $WorkSheet.Row($Row).Height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
Examples/AddImage/AddImage.ps1
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
if ($IsWindows -eq $false) {
|
||||||
|
throw "This only works on Windows and won't run on $([environment]::OSVersion)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Add-Type -AssemblyName System.Drawing
|
||||||
|
|
||||||
|
. $PSScriptRoot\Add-ExcelImage.ps1
|
||||||
|
|
||||||
|
$data = ConvertFrom-Csv @"
|
||||||
|
Region,State,Units,Price
|
||||||
|
West,Texas,927,923.71
|
||||||
|
North,Tennessee,466,770.67
|
||||||
|
East,Florida,520,458.68
|
||||||
|
East,Maine,828,661.24
|
||||||
|
West,Virginia,465,053.58
|
||||||
|
North,Missouri,436,235.67
|
||||||
|
South,Kansas,214,992.47
|
||||||
|
North,North Dakota,789,640.72
|
||||||
|
South,Delaware,712,508.55
|
||||||
|
"@
|
||||||
|
|
||||||
|
$path = "$PSScriptRoot/Add-Picture-test.xlsx"
|
||||||
|
Remove-Item $path -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$octocat = "$PSScriptRoot/Octocat.jpg"
|
||||||
|
$image = [System.Drawing.Image]::FromFile($octocat)
|
||||||
|
$xlpkg = $data | Export-Excel -Path $path -PassThru
|
||||||
|
$xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ($image) {
|
||||||
|
$image.Dispose()
|
||||||
|
}
|
||||||
|
if ($xlpkg) {
|
||||||
|
Close-ExcelPackage -ExcelPackage $xlpkg -Show
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Examples/AddImage/Octocat.jpg
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
33
Examples/AddImage/README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Add-ExcelImage Example
|
||||||
|
|
||||||
|
Adding pictures to an Excel worksheet is possible by calling the `AddPicture(name, image)`
|
||||||
|
method on the `Drawings` property of an `ExcelWorksheet` object.
|
||||||
|
|
||||||
|
The `Add-ExcelImage` example here demonstrates how to add a picture at a given
|
||||||
|
cell location, and optionally resize the row and column to fit the image.
|
||||||
|
|
||||||
|
## Running the example
|
||||||
|
|
||||||
|
To try this example, run the script `AddImage.ps1`. The `Add-ExcelImage`
|
||||||
|
function will be dot-sourced, and an Excel document will be created in the same
|
||||||
|
folder with a sample data set. The Octocat image will then be embedded into
|
||||||
|
Sheet1.
|
||||||
|
|
||||||
|
The creation of the Excel document and the `System.Drawing.Image` object
|
||||||
|
representing Octocat are properly disposed within a `finally` block to ensure
|
||||||
|
that the resources are released, even if an error occurs in the `try` block.
|
||||||
|
|
||||||
|
## Note about column and row sizing
|
||||||
|
|
||||||
|
Care has been taken in this example to get the image placement to be just inside
|
||||||
|
the cell border, and if the `-ResizeCell` switch is present, the height and width
|
||||||
|
of the row and column will be increased, if needed, so that the bottom right of
|
||||||
|
the image also lands just inside the cell border.
|
||||||
|
|
||||||
|
The Excel row and column sizes are measured in "point" units rather than pixels,
|
||||||
|
and a fixed multiplication factor is used to convert the size of the image in
|
||||||
|
pixels, to the corresponding height and width values in Excel.
|
||||||
|
|
||||||
|
It's possible that different DPI or text scaling options could result in
|
||||||
|
imperfect column and row sizing and if a better strategy is found for converting
|
||||||
|
the image dimensions to column and row sizes, this example will be updated.
|
||||||
54
Examples/Freeze/FreezePane.ps1
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Freeze the columns/rows to left and above the cell
|
||||||
|
|
||||||
|
$data = ConvertFrom-Csv @"
|
||||||
|
Region,State,Units,Price,Name,NA,EU,JP,Other
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46
|
||||||
|
"@
|
||||||
|
|
||||||
|
$xlfilename = "test.xlsx"
|
||||||
|
Remove-Item $xlfilename -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
<#
|
||||||
|
Freezes the top two rows and the two leftmost column
|
||||||
|
#>
|
||||||
|
|
||||||
|
$data | Export-Excel $xlfilename -Show -Title 'Sales Data' -FreezePane 3, 3
|
||||||
7
Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force
|
||||||
|
|
||||||
|
$xlfile = "$PSScriptRoot\yearlySales.xlsx"
|
||||||
|
|
||||||
|
$result = Import-Excel -Path $xlfile -WorksheetName * -NotAsDictionary
|
||||||
|
|
||||||
|
$result | Measure-Object
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force
|
||||||
|
|
||||||
|
$xlfile = "$PSScriptRoot\yearlySales.xlsx"
|
||||||
|
|
||||||
|
$result = Import-Excel -Path $xlfile -WorksheetName *
|
||||||
|
|
||||||
|
foreach ($sheet in $result.Values) {
|
||||||
|
$sheet
|
||||||
|
}
|
||||||
BIN
Examples/Import-Excel/yearlySales.xlsx
Normal file
9
Examples/ImportColumns/ImportColumns.ps1
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
try {Import-Module $PSScriptRoot\..\..\ImportExcel.psd1} catch {throw ; return}
|
||||||
|
|
||||||
|
# Create example file
|
||||||
|
$xlFile = "$PSScriptRoot\ImportColumns.xlsx"
|
||||||
|
Get-Process | Export-Excel -Path $xlFile
|
||||||
|
# -ImportColumns will also arrange columns
|
||||||
|
Import-Excel -Path $xlFile -ImportColumns @(1,3,2) -NoHeader -StartRow 1
|
||||||
|
# Get only pm, npm, cpu, id, processname
|
||||||
|
Import-Excel -Path $xlFile -ImportColumns @(6,7,12,25,46) | Format-Table -AutoSize
|
||||||
14
Examples/InvokeExcelQuery/Examples.ps1
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
try { Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 } catch { throw ; return }
|
||||||
|
|
||||||
|
$queries =
|
||||||
|
'select * from [sheet1$A:A]',
|
||||||
|
'select * from [sheet1$]',
|
||||||
|
'select * from [sheet1$A2:E11]',
|
||||||
|
'select F2,F5 from [sheet1$A2:E11]',
|
||||||
|
'select * from [sheet1$A2:E11] where F2 = "Grocery"',
|
||||||
|
'select F2 as [Category], F5 as [Discount], F5*2 as [DiscountPlus] from [sheet1$A2:E11]'
|
||||||
|
|
||||||
|
foreach ($query in $queries) {
|
||||||
|
"query: $($query)"
|
||||||
|
Invoke-ExcelQuery .\testOleDb.xlsx $query | Format-Table
|
||||||
|
}
|
||||||
BIN
Examples/InvokeExcelQuery/testOleDb.xlsx
Normal file
28
Examples/OpenExcelPackage/EnableFeatures.ps1
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# How to use Enable-ExcelAutoFilter and Enable-ExcelAutofit
|
||||||
|
|
||||||
|
try { Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 } catch { throw ; return }
|
||||||
|
|
||||||
|
$data = ConvertFrom-Csv @"
|
||||||
|
RegionInfo,StateInfo,Units,Price
|
||||||
|
West,Texas,927,923.71
|
||||||
|
North,Tennessee,466,770.67
|
||||||
|
East,Florida,520,458.68
|
||||||
|
East,Maine,828,661.24
|
||||||
|
West,Virginia,465,053.58
|
||||||
|
North,Missouri,436,235.67
|
||||||
|
South,Kansas,214,992.47
|
||||||
|
North,North Dakota,789,640.72
|
||||||
|
South,Delaware,712,508.55
|
||||||
|
"@
|
||||||
|
|
||||||
|
$xlfile = "$PSScriptRoot\enableFeatures.xlsx"
|
||||||
|
Remove-Item $xlfile -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
$data | Export-Excel $xlfile
|
||||||
|
|
||||||
|
$excel = Open-ExcelPackage $xlfile
|
||||||
|
|
||||||
|
Enable-ExcelAutoFilter -Worksheet $excel.Sheet1
|
||||||
|
Enable-ExcelAutofit -Worksheet $excel.Sheet1
|
||||||
|
|
||||||
|
Close-ExcelPackage $excel -Show
|
||||||
64
Examples/VBA/AddModuleMultipleWorksheetVBA.ps1
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
$xlfile = "$env:temp\test.xlsm"
|
||||||
|
Remove-Item $xlfile -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
ConvertFrom-Csv @"
|
||||||
|
Region,Item,TotalSold
|
||||||
|
West,screwdriver,98
|
||||||
|
West,kiwi,19
|
||||||
|
North,kiwi,47
|
||||||
|
West,screws,48
|
||||||
|
West,avocado,52
|
||||||
|
East,avocado,40
|
||||||
|
South,drill,61
|
||||||
|
North,orange,92
|
||||||
|
South,drill,29
|
||||||
|
South,saw,36
|
||||||
|
"@ | Export-Excel $xlfile -TableName 'Sales' -WorksheetName 'Sales' -AutoSize
|
||||||
|
|
||||||
|
$Excel = ConvertFrom-Csv @"
|
||||||
|
Supplier,Item,TotalBought
|
||||||
|
Hardware,screwdriver,98
|
||||||
|
Groceries,kiwi,19
|
||||||
|
Hardware,screws,48
|
||||||
|
Groceries,avocado,52
|
||||||
|
Hardware,drill,61
|
||||||
|
Groceries,orange,92
|
||||||
|
Hardware,drill,29
|
||||||
|
HArdware,saw,36
|
||||||
|
"@ | Export-Excel $xlfile -TableName 'Purchases' -WorksheetName 'Purchases' -PassThru -AutoSize
|
||||||
|
|
||||||
|
$wb = $Excel.Workbook
|
||||||
|
$wb.CreateVBAProject()
|
||||||
|
|
||||||
|
# Create a module with a sub to highlight the selected row & column of the active table.
|
||||||
|
# https://docs.microsoft.com/en-gb/office/vba/excel/Concepts/Cells-and-Ranges/highlight-the-active-cell-row-or-column
|
||||||
|
$codeModule = @"
|
||||||
|
Public Sub HighlightSelection(ByVal Target As Range)
|
||||||
|
' Clear the color of all the cells
|
||||||
|
Cells.Interior.ColorIndex = 0
|
||||||
|
If Target.Cells.Count > 1 Then Exit Sub
|
||||||
|
Application.ScreenUpdating = False
|
||||||
|
With ActiveCell
|
||||||
|
' Highlight the row and column that contain the active cell, within the current region
|
||||||
|
Range(Cells(.Row, .CurrentRegion.Column), Cells(.Row, .CurrentRegion.Columns.Count + .CurrentRegion.Column - 1)).Interior.ColorIndex = 38
|
||||||
|
Range(Cells(.CurrentRegion.Row, .Column), Cells(.CurrentRegion.Rows.Count + .CurrentRegion.Row - 1, .Column)).Interior.ColorIndex = 24
|
||||||
|
End With
|
||||||
|
Application.ScreenUpdating = True
|
||||||
|
End Sub
|
||||||
|
"@
|
||||||
|
|
||||||
|
$module = $wb.VbaProject.Modules.AddModule("PSExcelModule")
|
||||||
|
$module.Code = $codeModule
|
||||||
|
|
||||||
|
# Add a call to the row & column highlight sub on each worksheet.
|
||||||
|
$codeSheet = @"
|
||||||
|
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
|
||||||
|
HighlightSelection Target
|
||||||
|
End Sub
|
||||||
|
"@
|
||||||
|
|
||||||
|
foreach ($sheet in $wb.Worksheets) {
|
||||||
|
$sheet.CodeModule.Code = $codeSheet
|
||||||
|
}
|
||||||
|
|
||||||
|
Close-ExcelPackage $Excel -Show
|
||||||
41
Examples/VBA/AddWorksheetVBA.ps1
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
$xlfile = "$env:temp\test.xlsm"
|
||||||
|
Remove-Item $xlfile -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
$Excel = ConvertFrom-Csv @"
|
||||||
|
Region,Item,TotalSold
|
||||||
|
West,screwdriver,98
|
||||||
|
West,kiwi,19
|
||||||
|
North,kiwi,47
|
||||||
|
West,screws,48
|
||||||
|
West,avocado,52
|
||||||
|
East,avocado,40
|
||||||
|
South,drill,61
|
||||||
|
North,orange,92
|
||||||
|
South,drill,29
|
||||||
|
South,saw,36
|
||||||
|
"@ | Export-Excel $xlfile -TableName 'Sales' -WorksheetName 'Sales' -AutoSize -PassThru
|
||||||
|
|
||||||
|
$wb = $Excel.Workbook
|
||||||
|
$sheet = $wb.Worksheets["Sales"]
|
||||||
|
$wb.CreateVBAProject()
|
||||||
|
|
||||||
|
# Add a sub to the 'Worksheet_SelectionChange' event of the worksheet to highlight the selected row & column of the active table.
|
||||||
|
# https://docs.microsoft.com/en-gb/office/vba/excel/Concepts/Cells-and-Ranges/highlight-the-active-cell-row-or-column
|
||||||
|
$code = @"
|
||||||
|
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
|
||||||
|
' Clear the color of all the cells
|
||||||
|
Cells.Interior.ColorIndex = 0
|
||||||
|
If Target.Cells.Count > 1 Then Exit Sub
|
||||||
|
Application.ScreenUpdating = False
|
||||||
|
With ActiveCell
|
||||||
|
' Highlight the row and column that contain the active cell, within the current region
|
||||||
|
Range(Cells(.Row, .CurrentRegion.Column), Cells(.Row, .CurrentRegion.Columns.Count + .CurrentRegion.Column - 1)).Interior.ColorIndex = 38
|
||||||
|
Range(Cells(.CurrentRegion.Row, .Column), Cells(.CurrentRegion.Rows.Count + .CurrentRegion.Row - 1, .Column)).Interior.ColorIndex = 24
|
||||||
|
End With
|
||||||
|
Application.ScreenUpdating = True
|
||||||
|
End Sub
|
||||||
|
"@
|
||||||
|
|
||||||
|
$sheet.CodeModule.Code = $code
|
||||||
|
|
||||||
|
Close-ExcelPackage $Excel -Show
|
||||||
6
FAQ/How to Create an Empty Excel File.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Create an Empty Excel File
|
||||||
|
Use an empty string to export to an excel file.
|
||||||
|
```powershell
|
||||||
|
#Build an Excel file named: "file.xlsx" containing a worksheet: "MyWorksheet"
|
||||||
|
"" | Export-Excel -Path "C:\Test\file.xlsx" -WorksheetName "MyWorksheet"
|
||||||
|
```
|
||||||
41
FAQ/How to Read an Existing Excel File.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# How to Read an Existing Excel File
|
||||||
|
## Enumerate the Excel File Contents
|
||||||
|
```powershell
|
||||||
|
#Load the Excel file into a PSCustomObject
|
||||||
|
$ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Visual of Data Structure
|
||||||
|
The File C:\Test\file.xlsx contains
|
||||||
|

|
||||||
|
|
||||||
|
After loading this data into ```$ExcelFile``` the data is stored like:
|
||||||
|

|
||||||
|
|
||||||
|
## Other Common Operations
|
||||||
|
|
||||||
|
### Load a Column
|
||||||
|
```powershell
|
||||||
|
$SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "anotherHeader" -- data stored in an array
|
||||||
|
```
|
||||||
|
|
||||||
|
### Load a Row
|
||||||
|
```powershell
|
||||||
|
$SpecificRow = $ExcelFile[1] #Loads row at index 1. Index 1 is the first row instead of 0.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Map Contents to Hashtable to Interpret Data
|
||||||
|
Sometimes mapping to a Hashtable is more convenient to have access to common Hashtable operations. Enumerate a Hashtable with the row's data by:
|
||||||
|
```powershell
|
||||||
|
$HashTable = @{}
|
||||||
|
$SpecificRow= $ExcelFile[2]
|
||||||
|
$SpecificRow.psobject.properties | ForEach-Object {
|
||||||
|
$HashTable[$_.Name] = $_.Value
|
||||||
|
}
|
||||||
|
```
|
||||||
|
To then iterate through the enumerated Hashtable:
|
||||||
|
```powershell
|
||||||
|
ForEach ($Key in ($HashTable.GetEnumerator()) | Where-Object {$_.Value -eq "x"}){ #Only grabs a key where the value is "x"
|
||||||
|
#values accessible with $Key.Name or $Key.Value
|
||||||
|
}
|
||||||
|
```
|
||||||
34
FAQ/How to Write to an Existing Excel File.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Write to an Existing Excel File
|
||||||
|
### Enumerate the Excel File
|
||||||
|
The cmdlets ```Open-ExcelPackage``` and ```Close-ExcelPackage``` allow for direct modification to Excel file contents.
|
||||||
|
```powershell
|
||||||
|
$ExcelPkg = Open-ExcelPackage -Path "C:\Test\file.xlsx"
|
||||||
|
```
|
||||||
|
Contents of file.xlsx:
|
||||||
|

|
||||||
|
### Enumerate the Worksheet to View or Modify the Data
|
||||||
|
```powershell
|
||||||
|
$WorkSheet = $ExcelPkg.Workbook.Worksheets["sheet1"].Cells #open excel worksheet cells from worksheet "sheet1"
|
||||||
|
```
|
||||||
|
Visual of data structure:
|
||||||
|

|
||||||
|
A1 contains "someHeader", A2 contains "data1" etc.
|
||||||
|
### Modify a Specific Value in a File
|
||||||
|
Values can be accessed by row, column. Similar to a 2D array.
|
||||||
|
```powershell
|
||||||
|
$WorkSheet[1,4].Value = "New Column Header" #Starts at index 1 not 0
|
||||||
|
```
|
||||||
|
Contents of file.xlsx after modifying:
|
||||||
|

|
||||||
|
### Load Value at Specific Index
|
||||||
|
```powershell
|
||||||
|
$ValueAtIndex = $WorkSheet[2,1].Value #Loads the value at row 2, column A
|
||||||
|
```
|
||||||
|
```$ValueAtIndex``` now contains: 
|
||||||
|
### Save File After Modifying
|
||||||
|
The changes will not display in the Excel file until Close-ExcelPackage is called.
|
||||||
|
```powershell
|
||||||
|
Close-ExcelPackage $ExcelPkg #close and save changes made to the Excel file.
|
||||||
|
```
|
||||||
|
**Note**: If the file is currently in use, Close-ExcelPackage will return an error and will not save the information.
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
RootModule = 'ImportExcel.psm1'
|
RootModule = 'ImportExcel.psm1'
|
||||||
|
|
||||||
# Version number of this module.
|
# Version number of this module.
|
||||||
ModuleVersion = '7.1.2'
|
ModuleVersion = '7.5.1'
|
||||||
|
|
||||||
# ID used to uniquely identify this module
|
# ID used to uniquely identify this module
|
||||||
GUID = '60dd4136-feff-401a-ba27-a84458c57ede'
|
GUID = '60dd4136-feff-401a-ba27-a84458c57ede'
|
||||||
@@ -48,11 +48,14 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
|||||||
'ConvertTo-ExcelXlsx',
|
'ConvertTo-ExcelXlsx',
|
||||||
'Copy-ExcelWorksheet',
|
'Copy-ExcelWorksheet',
|
||||||
'DoChart',
|
'DoChart',
|
||||||
|
'Enable-ExcelAutoFilter',
|
||||||
|
'Enable-ExcelAutofit',
|
||||||
'Expand-NumberFormat',
|
'Expand-NumberFormat',
|
||||||
'Export-Excel',
|
'Export-Excel',
|
||||||
'Export-ExcelSheet',
|
'Export-ExcelSheet',
|
||||||
'Get-ExcelColumnName',
|
'Get-ExcelColumnName',
|
||||||
'Get-ExcelFileSummary',
|
'Get-ExcelFileSummary',
|
||||||
|
'Get-ExcelSheetDimensionAddress',
|
||||||
'Get-ExcelSheetInfo',
|
'Get-ExcelSheetInfo',
|
||||||
'Get-ExcelWorkbookInfo',
|
'Get-ExcelWorkbookInfo',
|
||||||
'Get-HtmlTable',
|
'Get-HtmlTable',
|
||||||
@@ -63,6 +66,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
|||||||
'Import-UPS',
|
'Import-UPS',
|
||||||
'Import-USPS',
|
'Import-USPS',
|
||||||
'Invoke-AllTests',
|
'Invoke-AllTests',
|
||||||
|
'Invoke-ExcelQuery',
|
||||||
'Invoke-Sum',
|
'Invoke-Sum',
|
||||||
'Join-Worksheet',
|
'Join-Worksheet',
|
||||||
'LineChart',
|
'LineChart',
|
||||||
@@ -78,7 +82,10 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
|||||||
'Open-ExcelPackage',
|
'Open-ExcelPackage',
|
||||||
'PieChart',
|
'PieChart',
|
||||||
'Pivot',
|
'Pivot',
|
||||||
'Remove-Worksheet'
|
'Read-Clipboard',
|
||||||
|
'Read-OleDbData',
|
||||||
|
'ReadClipboardImpl',
|
||||||
|
'Remove-Worksheet',
|
||||||
'Select-Worksheet',
|
'Select-Worksheet',
|
||||||
'Send-SQLDataToExcel',
|
'Send-SQLDataToExcel',
|
||||||
'Set-CellStyle',
|
'Set-CellStyle',
|
||||||
|
|||||||
25
Private/Invoke-ExcelReZipFile.ps1
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
function Invoke-ExcelReZipFile {
|
||||||
|
<#
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[OfficeOpenXml.ExcelPackage]$ExcelPackage
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Verbose -Message "Re-Zipping $($ExcelPackage.file) using .NET ZIP library"
|
||||||
|
try {
|
||||||
|
Add-Type -AssemblyName 'System.IO.Compression.Filesystem' -ErrorAction stop
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "The -ReZip parameter requires .NET Framework 4.5 or later to be installed. Recommend to install Powershell v4+"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
|
||||||
|
$null = [io.compression.zipfile]::ExtractToDirectory($ExcelPackage.File, $TempZipPath)
|
||||||
|
Remove-Item $ExcelPackage.File -Force
|
||||||
|
$null = [io.compression.zipfile]::CreateFromDirectory($TempZipPath, $ExcelPackage.File)
|
||||||
|
Remove-Item $TempZipPath -Recurse -Force
|
||||||
|
}
|
||||||
|
catch { throw "Error resizipping $path : $_" }
|
||||||
|
}
|
||||||
@@ -4,13 +4,15 @@ function Close-ExcelPackage {
|
|||||||
param (
|
param (
|
||||||
[parameter(Mandatory = $true, ValueFromPipeline = $true)]
|
[parameter(Mandatory = $true, ValueFromPipeline = $true)]
|
||||||
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
|
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
|
||||||
[switch]$Show,
|
[Switch]$Show,
|
||||||
[Switch]$NoSave,
|
[Switch]$NoSave,
|
||||||
$SaveAs,
|
$SaveAs,
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[String]$Password,
|
[String]$Password,
|
||||||
[switch]$Calculate
|
[Switch]$Calculate,
|
||||||
|
[Switch]$ReZip
|
||||||
)
|
)
|
||||||
|
|
||||||
if ( $NoSave) { $ExcelPackage.Dispose() }
|
if ( $NoSave) { $ExcelPackage.Dispose() }
|
||||||
else {
|
else {
|
||||||
if ($Calculate) {
|
if ($Calculate) {
|
||||||
@@ -27,6 +29,9 @@ function Close-ExcelPackage {
|
|||||||
else { $ExcelPackage.Save() }
|
else { $ExcelPackage.Save() }
|
||||||
$SaveAs = $ExcelPackage.File.FullName
|
$SaveAs = $ExcelPackage.File.FullName
|
||||||
}
|
}
|
||||||
|
if ($ReZip) {
|
||||||
|
Invoke-ExcelReZipFile -ExcelPackage $ExcelPackage
|
||||||
|
}
|
||||||
$ExcelPackage.Dispose()
|
$ExcelPackage.Dispose()
|
||||||
if ($Show) { Start-Process -FilePath $SaveAs }
|
if ($Show) { Start-Process -FilePath $SaveAs }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function ConvertFrom-ExcelSheet {
|
|||||||
[string[]]$AsDate = @()
|
[string[]]$AsDate = @()
|
||||||
)
|
)
|
||||||
|
|
||||||
$Path = (Resolve-Path $Path).Path
|
$Path = (Resolve-Path $Path).ProviderPath
|
||||||
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path
|
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path
|
||||||
$workbook = $xl.Workbook
|
$workbook = $xl.Workbook
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,15 @@ function ConvertFrom-ExcelToSQLInsert {
|
|||||||
[switch]$NoHeader,
|
[switch]$NoHeader,
|
||||||
[switch]$DataOnly,
|
[switch]$DataOnly,
|
||||||
[switch]$ConvertEmptyStringsToNull,
|
[switch]$ConvertEmptyStringsToNull,
|
||||||
[switch]$UseMsSqlSyntax
|
[switch]$UseMsSqlSyntax,
|
||||||
|
[Parameter(Mandatory = $false)]
|
||||||
|
$SingleQuoteStyle
|
||||||
)
|
)
|
||||||
|
|
||||||
$null = $PSBoundParameters.Remove('TableName')
|
$null = $PSBoundParameters.Remove('TableName')
|
||||||
$null = $PSBoundParameters.Remove('ConvertEmptyStringsToNull')
|
$null = $PSBoundParameters.Remove('ConvertEmptyStringsToNull')
|
||||||
$null = $PSBoundParameters.Remove('UseMsSqlSyntax')
|
$null = $PSBoundParameters.Remove('UseMsSqlSyntax')
|
||||||
|
$null = $PSBoundParameters.Remove('SingleQuoteStyle')
|
||||||
|
|
||||||
$params = @{} + $PSBoundParameters
|
$params = @{} + $PSBoundParameters
|
||||||
|
|
||||||
@@ -37,10 +40,15 @@ function ConvertFrom-ExcelToSQLInsert {
|
|||||||
if ($ConvertEmptyStringsToNull.IsPresent -and [string]::IsNullOrEmpty($record.$propertyName)) {
|
if ($ConvertEmptyStringsToNull.IsPresent -and [string]::IsNullOrEmpty($record.$propertyName)) {
|
||||||
'NULL'
|
'NULL'
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if ( $SingleQuoteStyle ) {
|
||||||
|
"'" + $record.$propertyName.ToString().Replace("'",${SingleQuoteStyle}) + "'"
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
"'" + $record.$propertyName + "'"
|
"'" + $record.$propertyName + "'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$targetValues = ($values -join ", ")
|
$targetValues = ($values -join ", ")
|
||||||
|
|
||||||
"INSERT INTO {0} ({1}) Values({2});" -f $TableName, $ColumnNames, $targetValues
|
"INSERT INTO {0} ({1}) Values({2});" -f $TableName, $ColumnNames, $targetValues
|
||||||
|
|||||||
16
Public/Enable-ExcelAutoFilter.ps1
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
function Enable-ExcelAutoFilter {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Enable the Excel AutoFilter
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Enable-ExcelAutoFilter $targetSheet
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[OfficeOpenXml.ExcelWorksheet]$Worksheet
|
||||||
|
)
|
||||||
|
|
||||||
|
$range = Get-ExcelSheetDimensionAddress $Worksheet
|
||||||
|
$Worksheet.Cells[$range].AutoFilter = $true
|
||||||
|
}
|
||||||
16
Public/Enable-ExcelAutofit.ps1
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
function Enable-ExcelAutofit {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Make all text fit the cells
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Enable-ExcelAutofit $excel.Sheet1
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[OfficeOpenXml.ExcelWorksheet]$Worksheet
|
||||||
|
)
|
||||||
|
|
||||||
|
$range = Get-ExcelSheetDimensionAddress $Worksheet
|
||||||
|
$Worksheet.Cells[$range].AutoFitColumns()
|
||||||
|
}
|
||||||
@@ -253,7 +253,8 @@
|
|||||||
else { $firstTimeThru = $true }
|
else { $firstTimeThru = $true }
|
||||||
}
|
}
|
||||||
|
|
||||||
process { if ($PSBoundParameters.ContainsKey("InputObject")) {
|
process {
|
||||||
|
if ($PSBoundParameters.ContainsKey("InputObject")) {
|
||||||
try {
|
try {
|
||||||
if ($null -eq $InputObject) { $row += 1 }
|
if ($null -eq $InputObject) { $row += 1 }
|
||||||
foreach ($TargetData in $InputObject) {
|
foreach ($TargetData in $InputObject) {
|
||||||
@@ -321,7 +322,8 @@
|
|||||||
$ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
|
$ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
|
||||||
$ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true
|
$ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true
|
||||||
}
|
}
|
||||||
elseif ($v -isnot [String] ) { #Other objects or null.
|
elseif ($v -isnot [String] ) {
|
||||||
|
#Other objects or null.
|
||||||
if ($null -ne $v) { $ws.Cells[$row, $ColumnIndex].Value = $v.toString() }
|
if ($null -ne $v) { $ws.Cells[$row, $ColumnIndex].Value = $v.toString() }
|
||||||
}
|
}
|
||||||
elseif ($v[0] -eq '=') {
|
elseif ($v[0] -eq '=') {
|
||||||
@@ -362,7 +364,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" }
|
catch { throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" }
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
end {
|
end {
|
||||||
if ($firstTimeThru -and $ws.Dimension) {
|
if ($firstTimeThru -and $ws.Dimension) {
|
||||||
@@ -386,7 +389,8 @@
|
|||||||
$headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
|
$headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
|
||||||
#using a slightly odd syntax otherwise header ends up as a 2D array
|
#using a slightly odd syntax otherwise header ends up as a 2D array
|
||||||
$ws.Cells[$headerRange].Value | ForEach-Object -Begin { $Script:header = @() } -Process { $Script:header += $_ }
|
$ws.Cells[$headerRange].Value | ForEach-Object -Begin { $Script:header = @() } -Process { $Script:header += $_ }
|
||||||
if ($PSBoundParameters.ContainsKey($TargetData)) { #if Export was called with data that writes no header start the range at $startRow ($startRow is data)
|
if ($PSBoundParameters.ContainsKey($TargetData)) {
|
||||||
|
#if Export was called with data that writes no header start the range at $startRow ($startRow is data)
|
||||||
$targetRow = $StartRow
|
$targetRow = $StartRow
|
||||||
}
|
}
|
||||||
else { $targetRow = $StartRow + 1 } #if Export was called without data to add names (assume $startRow is a header) or...
|
else { $targetRow = $StartRow + 1 } #if Export was called without data to add names (assume $startRow is a header) or...
|
||||||
@@ -400,7 +404,8 @@
|
|||||||
foreach ($c in 0..($LastCol - $StartColumn)) {
|
foreach ($c in 0..($LastCol - $StartColumn)) {
|
||||||
$targetRangeName = @($script:Header)[$c] #Let Add-ExcelName fix (and warn about) bad names
|
$targetRangeName = @($script:Header)[$c] #Let Add-ExcelName fix (and warn about) bad names
|
||||||
Add-ExcelName -RangeName $targetRangeName -Range $ws.Cells[$targetRow, ($StartColumn + $c ), $LastRow, ($StartColumn + $c )]
|
Add-ExcelName -RangeName $targetRangeName -Range $ws.Cells[$targetRow, ($StartColumn + $c ), $LastRow, ($StartColumn + $c )]
|
||||||
try {#this test can throw with some names, surpress any error
|
try {
|
||||||
|
#this test can throw with some names, surpress any error
|
||||||
if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress(($targetRangeName -replace '\W' , '_' ))) {
|
if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress(($targetRangeName -replace '\W' , '_' ))) {
|
||||||
Write-Warning -Message "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property."
|
Write-Warning -Message "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property."
|
||||||
}
|
}
|
||||||
@@ -515,7 +520,8 @@
|
|||||||
}
|
}
|
||||||
catch { Write-Warning -Message "Failed adding Freezing the panes in worksheet '$WorksheetName': $_" }
|
catch { Write-Warning -Message "Failed adding Freezing the panes in worksheet '$WorksheetName': $_" }
|
||||||
|
|
||||||
if ($PSBoundParameters.ContainsKey("BoldTopRow")) { #it sets bold as far as there are populated cells: for whole row could do $ws.row($x).style.font.bold = $true
|
if ($PSBoundParameters.ContainsKey("BoldTopRow")) {
|
||||||
|
#it sets bold as far as there are populated cells: for whole row could do $ws.row($x).style.font.bold = $true
|
||||||
try {
|
try {
|
||||||
if ($Title) {
|
if ($Title) {
|
||||||
$range = $ws.Dimension.Address -replace '\d+', ($StartRow + 1)
|
$range = $ws.Dimension.Address -replace '\d+', ($StartRow + 1)
|
||||||
@@ -621,7 +627,8 @@
|
|||||||
if ($c.ConditionalType) {
|
if ($c.ConditionalType) {
|
||||||
$cfParams = @{RuleType = $c.ConditionalType; ConditionValue = $c.Text ;
|
$cfParams = @{RuleType = $c.ConditionalType; ConditionValue = $c.Text ;
|
||||||
BackgroundColor = $c.BackgroundColor; BackgroundPattern = $c.PatternType ;
|
BackgroundColor = $c.BackgroundColor; BackgroundPattern = $c.PatternType ;
|
||||||
ForeGroundColor = $c.ConditionalTextColor}
|
ForeGroundColor = $c.ConditionalTextColor
|
||||||
|
}
|
||||||
if ($c.Range) { $cfParams.Range = $c.Range }
|
if ($c.Range) { $cfParams.Range = $c.Range }
|
||||||
else { $cfParams.Range = $ws.Dimension.Address }
|
else { $cfParams.Range = $ws.Dimension.Address }
|
||||||
Add-ConditionalFormatting -Worksheet $ws @cfParams
|
Add-ConditionalFormatting -Worksheet $ws @cfParams
|
||||||
@@ -672,21 +679,7 @@
|
|||||||
else { $pkg.Save() }
|
else { $pkg.Save() }
|
||||||
Write-Verbose -Message "Saved workbook $($pkg.File)"
|
Write-Verbose -Message "Saved workbook $($pkg.File)"
|
||||||
if ($ReZip) {
|
if ($ReZip) {
|
||||||
Write-Verbose -Message "Re-Zipping $($pkg.file) using .NET ZIP library"
|
Invoke-ExcelReZipFile -ExcelPackage $pkg
|
||||||
try {
|
|
||||||
Add-Type -AssemblyName 'System.IO.Compression.Filesystem' -ErrorAction stop
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Error "The -ReZip parameter requires .NET Framework 4.5 or later to be installed. Recommend to install Powershell v4+"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
|
|
||||||
$null = [io.compression.zipfile]::ExtractToDirectory($pkg.File, $TempZipPath)
|
|
||||||
Remove-Item $pkg.File -Force
|
|
||||||
$null = [io.compression.zipfile]::CreateFromDirectory($TempZipPath, $pkg.File)
|
|
||||||
}
|
|
||||||
catch {throw "Error resizipping $path : $_"}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$pkg.Dispose()
|
$pkg.Dispose()
|
||||||
|
|||||||
15
Public/Get-ExcelSheetDimensionAddress.ps1
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
function Get-ExcelSheetDimensionAddress {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Get the Excel address of the dimension of a sheet
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Get-ExcelSheetDimensionAddress $excel.Sheet1
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[OfficeOpenXml.ExcelWorksheet]$Worksheet
|
||||||
|
)
|
||||||
|
|
||||||
|
$Worksheet.Dimension.Address
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
[Alias('Sheet')]
|
[Alias('Sheet')]
|
||||||
[Parameter(Position = 1)]
|
[Parameter(Position = 1)]
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[String]$WorksheetName,
|
[String[]]$WorksheetName,
|
||||||
[Parameter(ParameterSetName = 'PathB' , Mandatory)]
|
[Parameter(ParameterSetName = 'PathB' , Mandatory)]
|
||||||
[Parameter(ParameterSetName = 'PackageB', Mandatory)]
|
[Parameter(ParameterSetName = 'PackageB', Mandatory)]
|
||||||
[String[]]$HeaderName ,
|
[String[]]$HeaderName ,
|
||||||
@@ -35,7 +35,9 @@
|
|||||||
[string[]]$AsText,
|
[string[]]$AsText,
|
||||||
[string[]]$AsDate,
|
[string[]]$AsDate,
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[String]$Password
|
[String]$Password,
|
||||||
|
[Int[]]$ImportColumns,
|
||||||
|
[Switch]$NotAsDictionary
|
||||||
)
|
)
|
||||||
end {
|
end {
|
||||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||||
@@ -62,6 +64,16 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if ($ImportColumns) {
|
||||||
|
$end = $sheet.Dimension.End.Column
|
||||||
|
# Check $ImportColumns
|
||||||
|
if ($ImportColumns[0] -le 0) { throw "The first entry in ImportColumns must be equal or greater 1" ; return }
|
||||||
|
# Check $StartColumn and $EndColumn
|
||||||
|
if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set, then individual StartColumn and EndColumn will be ignored." }
|
||||||
|
# Replace $Columns with $ImportColumns
|
||||||
|
$Columns = $ImportColumns
|
||||||
|
}
|
||||||
|
|
||||||
if ($HeaderName) {
|
if ($HeaderName) {
|
||||||
$i = 0
|
$i = 0
|
||||||
foreach ($H in $HeaderName) {
|
foreach ($H in $HeaderName) {
|
||||||
@@ -84,7 +96,7 @@
|
|||||||
|
|
||||||
foreach ($C in $Columns) {
|
foreach ($C in $Columns) {
|
||||||
#allow "False" or "0" to be column headings
|
#allow "False" or "0" to be column headings
|
||||||
$Worksheet.Cells[$StartRow, $C] | Where-Object {-not [string]::IsNullOrEmpty($_.Value) } | Select-Object @{N = 'Column'; E = { $C } }, Value
|
$sheet.Cells[$StartRow, $C] | Where-Object { -not [string]::IsNullOrEmpty($_.Value) } | Select-Object @{N = 'Column'; E = { $C } }, Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,15 +126,22 @@
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
#Select worksheet
|
#Select worksheet
|
||||||
if (-not $WorksheetName) { $Worksheet = $ExcelPackage.Workbook.Worksheets[1] }
|
if ($WorksheetName -eq '*') { $Worksheet = $ExcelPackage.Workbook.Worksheets }
|
||||||
|
elseif (-not $WorksheetName) { $Worksheet = $ExcelPackage.Workbook.Worksheets[1] }
|
||||||
elseif (-not ($Worksheet = $ExcelPackage.Workbook.Worksheets[$WorksheetName])) {
|
elseif (-not ($Worksheet = $ExcelPackage.Workbook.Worksheets[$WorksheetName])) {
|
||||||
throw "Worksheet '$WorksheetName' not found, the workbook only contains the worksheets '$($ExcelPackage.Workbook.Worksheets)'. If you only wish to select the first worksheet, please remove the '-WorksheetName' parameter." ; return
|
throw "Worksheet '$WorksheetName' not found, the workbook only contains the worksheets '$($ExcelPackage.Workbook.Worksheets)'. If you only wish to select the first worksheet, please remove the '-WorksheetName' parameter." ; return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$xlBook = [Ordered]@{}
|
||||||
|
foreach ($sheet in $Worksheet) {
|
||||||
|
$EndRow = 0
|
||||||
|
$EndColumn = 0
|
||||||
|
$targetSheetname = $sheet.Name
|
||||||
|
$xlBook["$targetSheetname"] = @()
|
||||||
#region Get rows and columns
|
#region Get rows and columns
|
||||||
#If we are doing dataonly it is quicker to work out which rows to ignore before processing the cells.
|
#If we are doing dataonly it is quicker to work out which rows to ignore before processing the cells.
|
||||||
if (-not $EndRow ) { $EndRow = $Worksheet.Dimension.End.Row }
|
if (-not $EndRow ) { $EndRow = $sheet.Dimension.End.Row }
|
||||||
if (-not $EndColumn) { $EndColumn = $Worksheet.Dimension.End.Column }
|
if (-not $EndColumn) { $EndColumn = $sheet.Dimension.End.Column }
|
||||||
$endAddress = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[$EndRow]C[$EndColumn]", 0, 0)
|
$endAddress = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[$EndRow]C[$EndColumn]", 0, 0)
|
||||||
if ($DataOnly) {
|
if ($DataOnly) {
|
||||||
#If we are using headers startrow will be the header-row so examine data from startRow + 1,
|
#If we are using headers startrow will be the header-row so examine data from startRow + 1,
|
||||||
@@ -134,7 +153,7 @@
|
|||||||
#using Hash tables: "we've seen it" is all we need, no need to worry about "seen it before" / "Seen it many times".
|
#using Hash tables: "we've seen it" is all we need, no need to worry about "seen it before" / "Seen it many times".
|
||||||
$colHash = @{ }
|
$colHash = @{ }
|
||||||
$rowHash = @{ }
|
$rowHash = @{ }
|
||||||
foreach ($cell in $Worksheet.Cells[$range]) {
|
foreach ($cell in $sheet.Cells[$range]) {
|
||||||
if ($null -ne $cell.Value ) { $colHash[$cell.Start.Column] = 1; $rowHash[$cell.Start.row] = 1 }
|
if ($null -ne $cell.Value ) { $colHash[$cell.Start.Column] = 1; $rowHash[$cell.Start.row] = 1 }
|
||||||
}
|
}
|
||||||
$rows = ( $StartRow..$EndRow ).Where( { $rowHash[$_] })
|
$rows = ( $StartRow..$EndRow ).Where( { $rowHash[$_] })
|
||||||
@@ -194,28 +213,43 @@
|
|||||||
foreach ($P in $PropertyNames) {
|
foreach ($P in $PropertyNames) {
|
||||||
$MatchTest = $TextColRegEx.Match($P.value)
|
$MatchTest = $TextColRegEx.Match($P.value)
|
||||||
if ($MatchTest.groups.name -eq "astext") {
|
if ($MatchTest.groups.name -eq "astext") {
|
||||||
$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text
|
$NewRow[$P.Value] = $sheet.Cells[$R, $P.Column].Text
|
||||||
}
|
}
|
||||||
elseif ($MatchTest.groups.name -eq "asdate" -and $Worksheet.Cells[$R, $P.Column].Value -is [System.ValueType]) {
|
elseif ($MatchTest.groups.name -eq "asdate" -and $sheet.Cells[$R, $P.Column].Value -is [System.ValueType]) {
|
||||||
$NewRow[$P.Value] = [datetime]::FromOADate(($Worksheet.Cells[$R, $P.Column].Value))
|
$NewRow[$P.Value] = [datetime]::FromOADate(($sheet.Cells[$R, $P.Column].Value))
|
||||||
}
|
}
|
||||||
else { $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value }
|
else { $NewRow[$P.Value] = $sheet.Cells[$R, $P.Column].Value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
foreach ($P in $PropertyNames) {
|
foreach ($P in $PropertyNames) {
|
||||||
$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value
|
$NewRow[$P.Value] = $sheet.Cells[$R, $P.Column].Value
|
||||||
# Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$($p.Value)' and value '$($Worksheet.Cells[$R, $P.Column].Value)'."
|
# Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$($p.Value)' and value '$($Worksheet.Cells[$R, $P.Column].Value)'."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[PSCustomObject]$NewRow
|
$xlBook["$targetSheetname"] += [PSCustomObject]$NewRow
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$WorksheetName': $_"; return }
|
catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$WorksheetName': $_"; return }
|
||||||
finally {
|
finally {
|
||||||
|
# $EndRow = 0
|
||||||
|
# $EndColumn = 0
|
||||||
if ($Path) { $stream.close(); $ExcelPackage.Dispose() }
|
if ($Path) { $stream.close(); $ExcelPackage.Dispose() }
|
||||||
|
|
||||||
|
if ($NotAsDictionary) {
|
||||||
|
foreach ($entry in $xlbook.GetEnumerator()) {
|
||||||
|
$entry.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($Worksheet.Count -eq 1) {
|
||||||
|
$xlBook["$targetSheetname"]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$xlBook
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
Public/Invoke-ExcelQuery.ps1
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#Requires -Version 5
|
||||||
|
function Invoke-ExcelQuery {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Helper method for executing Read-OleDbData with some basic defaults.
|
||||||
|
|
||||||
|
For additional help, see documentation for Read-OleDbData cmdlet.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Uses Read-OleDbData to execute a sql statement against a xlsx file. For finer grained control over the interaction, you may use that cmdlet. This cmdlet assumes a file path will be passed in and the connection string will be built with no headers and treating all results as text.
|
||||||
|
|
||||||
|
Running this command is equivalent to running the following:
|
||||||
|
|
||||||
|
$FullName = (Get-ChildItem $Path).FullName
|
||||||
|
Read-OleDbData `
|
||||||
|
-ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" `
|
||||||
|
-SqlStatement $Query
|
||||||
|
|
||||||
|
Note that this command uses the MICROSOFT.ACE.OLEDB provider and will not work without it.
|
||||||
|
|
||||||
|
If needed, please download the appropriate package from https://www.microsoft.com/en-us/download/details.aspx?id=54920.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Invoke-ExcelQuery .\test.xlsx 'select ROUND(F1) as [A1] from [sheet3$A1:A1]'
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
$Path = (Get-ChildItem 'test.xlsx').FullName
|
||||||
|
$Query = "select ROUND(F1) as [A] from [sheet1$A1:A1]"
|
||||||
|
Read-XlsxUsingOleDb -Path $Path -Query $Query
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
$ReadDataArgs = @{
|
||||||
|
Path = .\test.xlsx
|
||||||
|
Query = Get-Content query.sql -Raw
|
||||||
|
}
|
||||||
|
$Results = Invoke-ExcelQuery @ReadDataArgs
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
#The path to the file to open.
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[String] $Path, # var name consistent with Import-Excel
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[String] $Query # var name consistent with Invoke-Sqlcmd
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") {
|
||||||
|
Write-Error "Microsoft.ACE.OLEDB.12.0 provider is missing! Please install from https://www.microsoft.com/en-us/download/details.aspx?id=54920"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "System.Data.OleDb is not working or you are on an unsupported platform."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$FullName = (Get-ChildItem $Path).FullName
|
||||||
|
Read-OleDbData `
|
||||||
|
-ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" `
|
||||||
|
-SqlStatement $Query
|
||||||
|
}
|
||||||
@@ -35,7 +35,12 @@
|
|||||||
if ($pkgobj) {
|
if ($pkgobj) {
|
||||||
foreach ($w in $pkgobj.Workbook.Worksheets) {
|
foreach ($w in $pkgobj.Workbook.Worksheets) {
|
||||||
$sb = [scriptblock]::Create(('$this.workbook.Worksheets["{0}"]' -f $w.name))
|
$sb = [scriptblock]::Create(('$this.workbook.Worksheets["{0}"]' -f $w.name))
|
||||||
Add-Member -InputObject $pkgobj -MemberType ScriptProperty -Name $w.name -Value $sb
|
try {
|
||||||
|
Add-Member -InputObject $pkgobj -MemberType ScriptProperty -Name $w.name -Value $sb -ErrorAction Stop
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Warning "Could not add sheet $($w.name) as 'short cut', you need to access it via `$wb.Worksheets['$($w.name)'] "
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $pkgobj
|
return $pkgobj
|
||||||
}
|
}
|
||||||
|
|||||||
85
Public/Read-Clipboard.ps1
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#Requires -Version 5
|
||||||
|
function Read-Clipboard {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Read text from clipboard and pass to either ConvertFrom-Csv or ConvertFrom-Json.
|
||||||
|
Check out the how to video - https://youtu.be/dv2GOH5sbpA
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Read text from clipboard. It can read CSV or JSON. Plus, you can specify the delimiter and headers.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Read-Clipboard # Detects if the clipboard contains CSV, JSON, or Tab delimited data.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Read-Clipboard -Delimiter '|' # Converts data using a pipe delimiter
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Read-Clipboard -Header 'P1', 'P2', 'P3' # Specify the header columns to be used
|
||||||
|
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
$Delimiter,
|
||||||
|
$Header
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($IsLinux -or $IsMacOS) {
|
||||||
|
Write-Error "Read-Clipboard only runs on Windows"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$cvtParams = @{
|
||||||
|
Data = Get-Clipboard -Raw
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Delimiter) {
|
||||||
|
$cvtParams.Delimiter = $Delimiter
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Header) {
|
||||||
|
$cvtParams.Header = $Header
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadClipboardImpl @cvtParams
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReadClipboardImpl {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[String] $data,
|
||||||
|
$Delimiter,
|
||||||
|
$Header
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!$PSBoundParameters.ContainsKey('Delimiter') -and !$PSBoundParameters.ContainsKey('Header')) {
|
||||||
|
try {
|
||||||
|
ConvertFrom-Json $data
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$dataLines = @($data -split "`r`n?" | Select-Object -First 1)
|
||||||
|
|
||||||
|
if ($dataLines[0].indexOf(',') -gt -1) {
|
||||||
|
ConvertFrom-Csv $data
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ConvertFrom-Csv $data -Delimiter "`t"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$cvtParams = @{
|
||||||
|
InputObject = $data
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Delimiter) {
|
||||||
|
$cvtParams.Delimiter = $Delimiter
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Header) {
|
||||||
|
$cvtParams.Header = $Header
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertFrom-Csv @cvtParams
|
||||||
|
}
|
||||||
|
}
|
||||||
54
Public/Read-OleDbData.ps1
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#Requires -Version 5
|
||||||
|
function Read-OleDbData {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Read data from an OleDb source using dotnet classes. This allows for OleDb queries against excel spreadsheets. Examples will only be for querying xlsx files.
|
||||||
|
|
||||||
|
For additional documentation, see Microsoft's documentation on the System.Data OleDb namespace here:
|
||||||
|
https://docs.microsoft.com/en-us/dotnet/api/system.data.oledb
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Read data from an OleDb source using dotnet classes. This allows for OleDb queries against excel spreadsheets. Examples will only be for querying xlsx files using ACE.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Read-OleDbData `
|
||||||
|
-ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" `
|
||||||
|
-SqlStatement "select ROUND(F1) as [A] from [sheet1$A1:A1]"
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
$ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'"
|
||||||
|
$SqlStatement = "select ROUND(F1) as [A] from [sheet1$A1:A1]"
|
||||||
|
Read-OleDbData -ConnectionString $ConnectionString -SqlStatement $SqlStatement
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
$ReadDataArgs = @{
|
||||||
|
SqlStatement = Get-Content query.sql -Raw
|
||||||
|
ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'"
|
||||||
|
}
|
||||||
|
$Results = Read-OleDbData @ReadDataArgs
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[String] $ConnectionString,
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[String] $SqlStatement
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") {
|
||||||
|
Write-Warning "Microsoft.ACE.OLEDB.12.0 provider is missing! You will not be able to query Excel files without it. Please install from https://www.microsoft.com/en-us/download/details.aspx?id=54920"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "System.Data.OleDb is not working or you are on an unsupported platform."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$DataTable = new-object System.Data.DataTable
|
||||||
|
$DataAdapter = new-object System.Data.OleDb.OleDbDataAdapter $SqlStatement, $ConnectionString
|
||||||
|
$null = $DataAdapter.Fill($DataTable)
|
||||||
|
$null = $DataAdapter.Dispose()
|
||||||
|
$DataTable.Rows | Select-Object $DataTable.Columns.ColumnName
|
||||||
|
}
|
||||||
6
PublishToGallery.ps1
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
$p = @{
|
||||||
|
Name = "ImportExcel"
|
||||||
|
NuGetApiKey = $NuGetApiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
Publish-Module @p
|
||||||
30
README.md
@@ -1,15 +1,14 @@
|
|||||||
# README
|
# PowerShell + Excel = Better Together
|
||||||
|
|
||||||
### Donation
|
|
||||||
|
|
||||||
If this project helped you reduce the time to get your job done, let me know.
|
Automate Excel via PowerShell without having Excel installed. Runs on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier.
|
||||||
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCSB9YVPFSNCY)
|
<br/>
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
[](https://www.powershellgallery.com/packages/ImportExcel) [](https://www.powershellgallery.com/packages/ImportExcel) [](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt)
|
[](https://www.powershellgallery.com/packages/ImportExcel) [](https://www.powershellgallery.com/packages/ImportExcel) [](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt)
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
| CI System | Environment | Status |
|
| CI System | Environment | Status |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| Azure DevOps | Windows | [](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
|
| Azure DevOps | Windows | [](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
|
||||||
@@ -17,11 +16,22 @@ If this project helped you reduce the time to get your job done, let me know.
|
|||||||
| Azure DevOps | Ubuntu | [](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
|
| Azure DevOps | Ubuntu | [](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
|
||||||
| Azure DevOps | macOS | [](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
|
| Azure DevOps | macOS | [](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
|
||||||
|
|
||||||
PowerShell Import-Excel -
|
<br/>
|
||||||
|
|
||||||
Install from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ImportExcel/).
|
Install from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ImportExcel/).
|
||||||
|
|
||||||
This PowerShell Module allows you to read and write Excel files without installing Microsoft Excel on your system. No need to bother with the cumbersome Excel COM-object. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier.
|
```powershell
|
||||||
|
Install-Module -Name ImportExcel
|
||||||
|
```
|
||||||
|
### Donation
|
||||||
|
|
||||||
|
If this project helped you reduce the time to get your job done, let me know, send a coffee.
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCSB9YVPFSNCY)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -55,6 +65,10 @@ Plus, wiring the [PowerShell ScriptAnalyzer Excel report](https://github.com/dfi
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## What's new 7.1.3
|
||||||
|
|
||||||
|
- Changed to `ProviderPath`. Thanks [Trevor Walker](https://github.com/sporkabob)
|
||||||
|
|
||||||
## What's new 7.1.2
|
## What's new 7.1.2
|
||||||
|
|
||||||
- `Get-ExcelFileSummary` - Gets summary information on an Excel file like number of rows, columns, and more
|
- `Get-ExcelFileSummary` - Gets summary information on an Excel file like number of rows, columns, and more
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
|
#Requires -Modules Pester
|
||||||
|
|
||||||
|
if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) {
|
||||||
|
Import-Module $PSScriptRoot\..\ImportExcel.psd1
|
||||||
|
}
|
||||||
|
|
||||||
Describe "Import-Excel on a sheet with no headings" {
|
Describe "Import-Excel on a sheet with no headings" {
|
||||||
BeforeAll {
|
BeforeAll {
|
||||||
|
|
||||||
$xlfile = "TestDrive:\testImportExcel.xlsx"
|
$xlfile = "$PSScriptRoot\testImportExcel.xlsx"
|
||||||
$xlfileHeaderOnly = "TestDrive:\testImportExcelHeaderOnly.xlsx"
|
$xlfileHeaderOnly = "$PSScriptRoot\testImportExcelHeaderOnly.xlsx"
|
||||||
|
$xlfileImportColumns = "$PSScriptRoot\testImportExcelImportColumns.xlsx"
|
||||||
|
|
||||||
|
# Create $xlfile if it does not exist
|
||||||
|
if (!(Test-Path -Path $xlfile)) {
|
||||||
$xl = "" | Export-excel $xlfile -PassThru
|
$xl = "" | Export-excel $xlfile -PassThru
|
||||||
|
|
||||||
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A'
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A'
|
||||||
@@ -19,8 +28,10 @@ Describe "Import-Excel on a sheet with no headings" {
|
|||||||
Set-ExcelRange -Worksheet $xl.Sheet1 -Range C3 -Value 'I'
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range C3 -Value 'I'
|
||||||
|
|
||||||
Close-ExcelPackage $xl
|
Close-ExcelPackage $xl
|
||||||
|
}
|
||||||
|
|
||||||
# crate $xlfileHeaderOnly
|
# Create $xlfileHeaderOnly if it does not exist
|
||||||
|
if (!(Test-Path -Path $xlfileHeaderOnly)) {
|
||||||
$xl = "" | Export-excel $xlfileHeaderOnly -PassThru
|
$xl = "" | Export-excel $xlfileHeaderOnly -PassThru
|
||||||
|
|
||||||
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A'
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A'
|
||||||
@@ -30,6 +41,32 @@ Describe "Import-Excel on a sheet with no headings" {
|
|||||||
Close-ExcelPackage $xl
|
Close-ExcelPackage $xl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Create $xlfileImportColumns if it does not exist
|
||||||
|
if (!(Test-Path -Path $xlfileImportColumns)) {
|
||||||
|
$xl = "" | Export-Excel $xlfileImportColumns -PassThru
|
||||||
|
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range B1 -Value 'B'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range C1 -Value 'C'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range D1 -Value 'D'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range E1 -Value 'E'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range F1 -Value 'F'
|
||||||
|
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A2 -Value '1'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range B2 -Value '2'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range C2 -Value '3'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range D2 -Value '4'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range E2 -Value '5'
|
||||||
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range F2 -Value '6'
|
||||||
|
|
||||||
|
Close-ExcelPackage $xl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterAll {
|
||||||
|
Remove-Item $PSScriptRoot\testImportExcelSparse.xlsx -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
It "Import-Excel should have this shape" {
|
It "Import-Excel should have this shape" {
|
||||||
$actual = @(Import-Excel $xlfile)
|
$actual = @(Import-Excel $xlfile)
|
||||||
|
|
||||||
@@ -167,7 +204,7 @@ Describe "Import-Excel on a sheet with no headings" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It "Should" {
|
It "Should" {
|
||||||
$xlfile = "TestDrive:\testImportExcelSparse.xlsx"
|
$xlfile = "$PSScriptRoot\testImportExcelSparse.xlsx"
|
||||||
$xl = "" | Export-excel $xlfile -PassThru
|
$xl = "" | Export-excel $xlfile -PassThru
|
||||||
|
|
||||||
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'Chuck'
|
Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'Chuck'
|
||||||
@@ -197,6 +234,7 @@ Describe "Import-Excel on a sheet with no headings" {
|
|||||||
|
|
||||||
$actual.Count | Should -Be 1
|
$actual.Count | Should -Be 1
|
||||||
|
|
||||||
|
Remove-Item $xlfile
|
||||||
# Looks like -DataOnly does not handle empty columns
|
# Looks like -DataOnly does not handle empty columns
|
||||||
# $actual[0].FirstName | Should -BeExactly 'Jean-Claude'
|
# $actual[0].FirstName | Should -BeExactly 'Jean-Claude'
|
||||||
# $actual[0].SecondName | Should -BeExactly 'Vandamme'
|
# $actual[0].SecondName | Should -BeExactly 'Vandamme'
|
||||||
@@ -224,4 +262,139 @@ Describe "Import-Excel on a sheet with no headings" {
|
|||||||
$actual[0].P2 | Should -Be 'B'
|
$actual[0].P2 | Should -Be 'B'
|
||||||
$actual[0].P3 | Should -Be 'C'
|
$actual[0].P3 | Should -Be 'C'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns is used with the first column" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(1,2,4,5))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 4
|
||||||
|
$actualNames[0] | Should -Be 'A'
|
||||||
|
$actualNames[2] | Should -Be 'D'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 1
|
||||||
|
$actual[0].A | Should -Be 1
|
||||||
|
$actual[0].B | Should -Be 2
|
||||||
|
$actual[0].D | Should -Be 4
|
||||||
|
$actual[0].E | Should -Be 5
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns is used with the first column" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(1,3,4,5))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 4
|
||||||
|
$actualNames[0] | Should -Be 'A'
|
||||||
|
$actualNames[2] | Should -Be 'D'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 1
|
||||||
|
$actual[0].A | Should -Be 1
|
||||||
|
$actual[0].C | Should -Be 3
|
||||||
|
$actual[0].D | Should -Be 4
|
||||||
|
$actual[0].E | Should -Be 5
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns is used without the first column" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(2,3,6))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 3
|
||||||
|
$actualNames[0] | Should -Be 'B'
|
||||||
|
$actualNames[2] | Should -Be 'F'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 1
|
||||||
|
$actual[0].B | Should -Be 2
|
||||||
|
$actual[0].C | Should -Be 3
|
||||||
|
$actual[0].F | Should -Be 6
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns is used without the first column" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(2,5,6))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 3
|
||||||
|
$actualNames[0] | Should -Be 'B'
|
||||||
|
$actualNames[2] | Should -Be 'F'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 1
|
||||||
|
$actual[0].B | Should -Be 2
|
||||||
|
$actual[0].E | Should -Be 5
|
||||||
|
$actual[0].F | Should -Be 6
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns is used with only 1 column" {
|
||||||
|
$actual = @(Import-Excel $xlfile -ImportColumns @(2))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 1
|
||||||
|
$actualNames[0] | Should -Be 'B'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 2
|
||||||
|
$actual[0].B | Should -Be 'E'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns is used with only 1 column which is also the last" {
|
||||||
|
$actual = @(Import-Excel $xlfile -ImportColumns @(3))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 1
|
||||||
|
$actualNames[0] | Should -Be 'C'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 2
|
||||||
|
$actual[1].C | Should -Be 'I'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should import correct data if -ImportColumns contains all columns" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(1,2,3,4,5,6))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 6
|
||||||
|
$actualNames[0] | Should -Be 'A'
|
||||||
|
$actualNames[2] | Should -Be 'C'
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 1
|
||||||
|
$actual[0].A | Should -Be 1
|
||||||
|
$actual[0].B | Should -Be 2
|
||||||
|
$actual[0].C | Should -Be 3
|
||||||
|
$actual[0].D | Should -Be 4
|
||||||
|
$actual[0].E | Should -Be 5
|
||||||
|
$actual[0].F | Should -Be 6
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should ignore -StartColumn and -EndColumn if -ImportColumns is set aswell" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(5) -StartColumn 2 -EndColumn 7)
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 1
|
||||||
|
$actualNames[0] | Should -Be 'E'
|
||||||
|
|
||||||
|
$actual[0].E | Should -Be '5'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should arrange the columns if -ImportColumns is not in order" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(5,1,4))
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 3
|
||||||
|
$actualNames[0] | Should -Be 'E'
|
||||||
|
$actualNames[1] | Should -Be 'A'
|
||||||
|
$actualNames[2] | Should -Be 'D'
|
||||||
|
|
||||||
|
$actual[0].E | Should -Be '5'
|
||||||
|
$actual[0].A | Should -Be '1'
|
||||||
|
$actual[0].D | Should -Be '4'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should arrange the columns if -ImportColumns is not in order and -NoHeader is used" {
|
||||||
|
$actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(5,1,4) -NoHeader -StartRow 2)
|
||||||
|
$actualNames = $actual[0].psobject.properties.Name
|
||||||
|
|
||||||
|
$actualNames.Count | Should -Be 3
|
||||||
|
$actualNames[0] | Should -Be 'P1'
|
||||||
|
$actualNames[1] | Should -Be 'P2'
|
||||||
|
$actualNames[2] | Should -Be 'P3'
|
||||||
|
|
||||||
|
$actual[0].P1 | Should -Be '5'
|
||||||
|
$actual[0].P2 | Should -Be '1'
|
||||||
|
$actual[0].P3 | Should -Be '4'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
73
__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#Requires -Modules Pester
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positives')]
|
||||||
|
param()
|
||||||
|
|
||||||
|
Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force
|
||||||
|
|
||||||
|
Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets {
|
||||||
|
BeforeAll {
|
||||||
|
$xlFilename = "$PSScriptRoot\yearlySales.xlsx"
|
||||||
|
}
|
||||||
|
|
||||||
|
Context 'Test reading sheets' {
|
||||||
|
It 'Should read one sheet' {
|
||||||
|
$actual = Import-Excel $xlFilename
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 100
|
||||||
|
$actual[0].Month | Should -BeExactly "April"
|
||||||
|
$actual[99].Month | Should -BeExactly "April"
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should read two sheets' {
|
||||||
|
$actual = Import-Excel $xlFilename march, june
|
||||||
|
|
||||||
|
$actual.keys.Count | Should -Be 2
|
||||||
|
$actual["March"].Count | Should -Be 100
|
||||||
|
$actual["June"].Count | Should -Be 100
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should read all the sheets' {
|
||||||
|
$actual = Import-Excel $xlFilename *
|
||||||
|
|
||||||
|
$actual.keys.Count | Should -Be 12
|
||||||
|
|
||||||
|
$actual["January"].Count | Should -Be 100
|
||||||
|
$actual["February"].Count | Should -Be 100
|
||||||
|
$actual["March"].Count | Should -Be 100
|
||||||
|
$actual["April"].Count | Should -Be 100
|
||||||
|
$actual["May"].Count | Should -Be 100
|
||||||
|
$actual["June"].Count | Should -Be 100
|
||||||
|
$actual["July"].Count | Should -Be 100
|
||||||
|
$actual["August"].Count | Should -Be 100
|
||||||
|
$actual["September"].Count | Should -Be 100
|
||||||
|
$actual["October"].Count | Should -Be 100
|
||||||
|
$actual["November"].Count | Should -Be 100
|
||||||
|
$actual["December"].Count | Should -Be 100
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should throw if it cannot find the sheet' {
|
||||||
|
{ Import-Excel $xlFilename april, june, notthere } | Should -Throw
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should return an array not a dictionary' {
|
||||||
|
$actual = Import-Excel $xlFilename april, june -NotAsDictionary
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 200
|
||||||
|
$group = $actual | Group-Object month -NoElement
|
||||||
|
|
||||||
|
$group.Count | Should -Be 2
|
||||||
|
$group[0].Name | Should -BeExactly 'April'
|
||||||
|
$group[1].Name | Should -BeExactly 'June'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should read multiple sheets with diff number of rows correctly" {
|
||||||
|
$xlFilename = "$PSScriptRoot\construction.xlsx"
|
||||||
|
|
||||||
|
$actual = Import-Excel $xlFilename 2015, 2016
|
||||||
|
$actual.keys.Count | Should -Be 2
|
||||||
|
|
||||||
|
$actual["2015"].Count | Should -Be 12
|
||||||
|
$actual["2016"].Count | Should -Be 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
__tests__/ImportExcelTests/ReadMultipleXLSXFiles.tests.ps1
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positives')]
|
||||||
|
Param()
|
||||||
|
|
||||||
|
Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force
|
||||||
|
|
||||||
|
Describe "Test reading multiple XLSX files of differernt row count" -Tag ReadMultipleXLSX {
|
||||||
|
It "Should find these xlsx files" {
|
||||||
|
Test-Path -Path $PSScriptRoot\rows05.xlsx | Should -BeTrue
|
||||||
|
Test-Path -Path $PSScriptRoot\rows10.xlsx | Should -BeTrue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should find two xlsx files" {
|
||||||
|
(Get-ChildItem $PSScriptRoot\row*xlsx).Count | Should -Be 2
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should get 5 rows" {
|
||||||
|
(Import-Excel $PSScriptRoot\rows05.xlsx).Count | Should -Be 5
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should get 10 rows" {
|
||||||
|
(Import-Excel $PSScriptRoot\rows10.xlsx).Count | Should -Be 10
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should get 15 rows" {
|
||||||
|
$actual = Get-ChildItem $PSScriptRoot\row*xlsx | Import-Excel
|
||||||
|
|
||||||
|
$actual.Count | Should -Be 15
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should get 4 property names" {
|
||||||
|
$actual = Get-ChildItem $PSScriptRoot\row*xlsx | Import-Excel
|
||||||
|
|
||||||
|
$names = $actual[0].psobject.properties.name
|
||||||
|
$names.Count | Should -Be 4
|
||||||
|
|
||||||
|
$names[0] | Should -BeExactly "Region"
|
||||||
|
$names[1] | Should -BeExactly "State"
|
||||||
|
$names[2] | Should -BeExactly "Units"
|
||||||
|
$names[3] | Should -BeExactly "Price"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Should have the correct data" {
|
||||||
|
$actual = Get-ChildItem $PSScriptRoot\row*xlsx | Import-Excel
|
||||||
|
|
||||||
|
# rows05.xlsx
|
||||||
|
$actual[0].Region | Should -BeExactly "South"
|
||||||
|
$actual[0].Price | Should -Be 181.52
|
||||||
|
$actual[4].Region | Should -BeExactly "West"
|
||||||
|
$actual[4].Price | Should -Be 216.56
|
||||||
|
|
||||||
|
# rows10.xlsx
|
||||||
|
$actual[5].Region | Should -BeExactly "South"
|
||||||
|
$actual[5].Price | Should -Be 199.85
|
||||||
|
$actual[14].Region | Should -BeExactly "East"
|
||||||
|
$actual[14].Price | Should -Be 965.25
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
__tests__/ImportExcelTests/construction.xlsx
Normal file
BIN
__tests__/ImportExcelTests/rows05.xlsx
Normal file
BIN
__tests__/ImportExcelTests/rows10.xlsx
Normal file
BIN
__tests__/ImportExcelTests/yearlySales.xlsx
Normal file
39
__tests__/Open-ExcelPackage.tests.ps1
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#Requires -Modules Pester
|
||||||
|
|
||||||
|
if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) {
|
||||||
|
Import-Module $PSScriptRoot\..\ImportExcel.psd1
|
||||||
|
}
|
||||||
|
|
||||||
|
<#
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
Dispose
|
||||||
|
Equals
|
||||||
|
GetAsByteArray
|
||||||
|
GetHashCode
|
||||||
|
GetType
|
||||||
|
Load
|
||||||
|
Save
|
||||||
|
SaveAs
|
||||||
|
ToString
|
||||||
|
|
||||||
|
Properties
|
||||||
|
----------
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
Compression
|
||||||
|
DoAdjustDrawings
|
||||||
|
Encryption
|
||||||
|
File
|
||||||
|
Package
|
||||||
|
Stream
|
||||||
|
Workbook
|
||||||
|
#>
|
||||||
|
|
||||||
|
Describe "Test Open Excel Package" -Tag Open-ExcelPackage {
|
||||||
|
It "Should handle opening a workbook with Worksheet Names that will cause errors" {
|
||||||
|
$xlFilename = "$PSScriptRoot\UnsupportedWorkSheetNames.xlsx"
|
||||||
|
|
||||||
|
{ Open-ExcelPackage -Path $xlFilename -ErrorAction Stop } | Should -Not -Throw
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,9 +6,9 @@ param()
|
|||||||
describe "Consistent passing of ranges." {
|
describe "Consistent passing of ranges." {
|
||||||
BeforeAll {
|
BeforeAll {
|
||||||
$path = "TestDrive:\test.xlsx"
|
$path = "TestDrive:\test.xlsx"
|
||||||
if (-not (Get-command Get-Service -ErrorAction SilentlyContinue)) {
|
# if (-not (Get-command Get-Service -ErrorAction SilentlyContinue)) {
|
||||||
Function Get-Service { Import-Clixml $PSScriptRoot\Mockservices.xml }
|
Function Get-Service { Import-Clixml $PSScriptRoot\Mockservices.xml }
|
||||||
}
|
# }
|
||||||
}
|
}
|
||||||
Context "Conditional Formatting" {
|
Context "Conditional Formatting" {
|
||||||
it "accepts named ranges, cells['name'], worksheet + Name, worksheet + column " {
|
it "accepts named ranges, cells['name'], worksheet + Name, worksheet + column " {
|
||||||
|
|||||||
90
__tests__/Read-Clipboard.tests.ps1
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#Requires -Modules Pester
|
||||||
|
# if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) {
|
||||||
|
Import-Module $PSScriptRoot\..\ImportExcel.psd1 -Force
|
||||||
|
# }
|
||||||
|
Describe "Read Clipboard" -Tag "Read-Clipboard" {
|
||||||
|
|
||||||
|
It 'Should return $null if it cannot detect data format on the clipboard' {
|
||||||
|
$testData = 'abc'
|
||||||
|
$actual = ReadClipboardImpl $testData
|
||||||
|
$actual.Count | Should -Be 0
|
||||||
|
$actual | Should -BeNullOrEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should return converted csv data' {
|
||||||
|
$testData = @"
|
||||||
|
Region,State,Units,Price
|
||||||
|
West,Texas,927,923.71
|
||||||
|
North,Tennessee,466,770.67
|
||||||
|
East,Florida,520,458.68
|
||||||
|
"@
|
||||||
|
$actual = ReadClipboardImpl $testData
|
||||||
|
$actual.count | Should -Be 3
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should return converted tab delimited data' {
|
||||||
|
$testData = @"
|
||||||
|
YEAR PRESIDENT FIRST LADY VICE PRESIDENT
|
||||||
|
2021- Joseph R. Biden Jill Biden Kamala Harris
|
||||||
|
2017-2021 Donald J. Trump Melania Trump Mike Pence
|
||||||
|
2009-2017 Barack Obama Michelle Obama Joseph R. Biden
|
||||||
|
"@
|
||||||
|
$actual = ReadClipboardImpl $testData
|
||||||
|
$actual.count | Should -Be 3
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should return converted json data' {
|
||||||
|
$testData = @"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"YEAR": "2021-",
|
||||||
|
"PRESIDENT": "Joseph R. Biden",
|
||||||
|
"FIRST LADY": "Jill Biden",
|
||||||
|
"VICE PRESIDENT": "Kamala Harris"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"YEAR": "2017-2021",
|
||||||
|
"PRESIDENT": "Donald J. Trump",
|
||||||
|
"FIRST LADY": "Melania Trump",
|
||||||
|
"VICE PRESIDENT": "Mike Pence"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"YEAR": "2009-2017",
|
||||||
|
"PRESIDENT": "Barack Obama",
|
||||||
|
"FIRST LADY": "Michelle Obama",
|
||||||
|
"VICE PRESIDENT": "Joseph R. Biden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"@
|
||||||
|
$actual = ReadClipboardImpl $testData
|
||||||
|
$actual.count | Should -Be 3
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should return converted "|" delimited data' {
|
||||||
|
$testData = @"
|
||||||
|
Region|State|Units|Price
|
||||||
|
West|Texas|927|923.71
|
||||||
|
North|Tennessee|466|770.67
|
||||||
|
East|Florida|520|458.68
|
||||||
|
"@
|
||||||
|
$actual = ReadClipboardImpl $testData -Delimiter '|'
|
||||||
|
$actual.count | Should -Be 3
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Should return converted data with headers' {
|
||||||
|
$testData = @"
|
||||||
|
West,Texas,927,923.71
|
||||||
|
North,Tennessee,466,770.67
|
||||||
|
East,Florida,520,458.68
|
||||||
|
"@
|
||||||
|
|
||||||
|
$actual = ReadClipboardImpl $testData -Header 'P1', 'P2', 'p3', 'P4'
|
||||||
|
$actual.count | Should -Be 3
|
||||||
|
|
||||||
|
$propertyNames = $actual[0].psobject.Properties.Name
|
||||||
|
$propertyNames[0] | Should -BeExactly 'P1'
|
||||||
|
$propertyNames[1] | Should -BeExactly 'P2'
|
||||||
|
$propertyNames[2] | Should -BeExactly 'p3'
|
||||||
|
$propertyNames[3] | Should -BeExactly 'P4'
|
||||||
|
}
|
||||||
|
}
|
||||||
46
__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#Requires -Modules Pester
|
||||||
|
if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) {
|
||||||
|
Import-Module $PSScriptRoot\..\ImportExcel.psd1
|
||||||
|
}
|
||||||
|
|
||||||
|
$skip = $false
|
||||||
|
if ($IsLinux -or $IsMacOS) {
|
||||||
|
$skip = $true
|
||||||
|
Write-Warning "Invoke-ExcelQuery: Linux and MacOs are not supported. Skipping tests."
|
||||||
|
}else{
|
||||||
|
try {
|
||||||
|
if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") {
|
||||||
|
$skip = $true
|
||||||
|
Write-Warning "Invoke-ExcelQuery: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$skip = $true
|
||||||
|
Write-Warning "Invoke-ExcelQuery: Calls to System.Data.OleDb failed. Skipping tests."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" {
|
||||||
|
$PSDefaultParameterValues = @{ 'It:Skip' = $skip }
|
||||||
|
BeforeAll {
|
||||||
|
$tfp = "$PSScriptRoot\Read-OleDbData.xlsx"
|
||||||
|
}
|
||||||
|
Context "Basic Checks" {
|
||||||
|
It "Should have a valid Test file" {
|
||||||
|
Test-Path $tfp | Should -Be $true
|
||||||
|
}
|
||||||
|
It "Should have the Read-OleDbData command loaded" {
|
||||||
|
(Get-Command Read-OleDbData -ErrorAction SilentlyContinue) -ne $null | Should -Be $true
|
||||||
|
}
|
||||||
|
It "Should have the Invoke-ExcelQuery command loaded" {
|
||||||
|
(Get-Command Invoke-ExcelQuery -ErrorAction SilentlyContinue) -ne $null | Should -Be $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "Sheet1`$A1" {
|
||||||
|
It "Should return 1 result with a value of 1" {
|
||||||
|
$Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]"
|
||||||
|
@($Results).length + $Results.A1 | Should -Be 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
__tests__/Read-OleDbDataTests/Read-OleDbData.TestA.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
select
|
||||||
|
ROUND(F1) as [A1]
|
||||||
|
from
|
||||||
|
[sheet3$A1:A1]
|
||||||
7
__tests__/Read-OleDbDataTests/Read-OleDbData.TestB.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
select ROUND(F1) as [A1] from [sheet1$A1:A1]
|
||||||
|
union all select ROUND(F1) as [A1] from [sheet2$A1:A1]
|
||||||
|
union all select ROUND(F1) as [A1] from [sheet3$A1:A1]
|
||||||
|
union all select ROUND(F1) as [A1] from [sheet4$A1:A1]
|
||||||
|
union all select ROUND(F1) as [A1] from [sheet5$A1:A1]
|
||||||
|
union all select ROUND(F1) as [A1] from [sheet6$A1:A1]
|
||||||
|
union all select ROUND(F1) as [A1] from [sheet7$A1:A1]
|
||||||
4
__tests__/Read-OleDbDataTests/Read-OleDbData.TestC.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
select
|
||||||
|
*
|
||||||
|
from
|
||||||
|
[sheet1$A1:E10]
|
||||||
10
__tests__/Read-OleDbDataTests/Read-OleDbData.TestD.sql
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
select top 1
|
||||||
|
'All A1s' as [A1],
|
||||||
|
F1 as [Sheet1],
|
||||||
|
(select F1 FROM [sheet2$a1:a1]) as [Sheet2],
|
||||||
|
(select F1 FROM [sheet3$a1:a1]) as [Sheet3],
|
||||||
|
(select F1 FROM [sheet4$a1:a1]) as [Sheet4],
|
||||||
|
(select F1 FROM [sheet5$a1:a1]) as [Sheet5],
|
||||||
|
(select F1 FROM [sheet6$a1:a1]) as [Sheet6],
|
||||||
|
(select F1 FROM [sheet7$a1:a1]) as [Sheet7]
|
||||||
|
FROM [sheet1$a1:a1]
|
||||||
31
__tests__/Read-OleDbDataTests/Read-OleDbData.TestE.sql
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
select top 1
|
||||||
|
'All A1s Start from Sheet1' as [A1],
|
||||||
|
F1 as [Sheet1],
|
||||||
|
(select F1 FROM [sheet2$a1:a1]) as [Sheet2],
|
||||||
|
(select F1 FROM [sheet3$a1:a1]) as [Sheet3],
|
||||||
|
(select F1 FROM [sheet4$a1:a1]) as [Sheet4]
|
||||||
|
FROM [sheet1$a1:a1]
|
||||||
|
UNION ALL
|
||||||
|
select top 1
|
||||||
|
'All A1s Start from Sheet2' as [A1],
|
||||||
|
(select F1 FROM [sheet1$a1:a1]) as [Sheet1],
|
||||||
|
F1 as [Sheet2],
|
||||||
|
(select F1 FROM [sheet3$a1:a1]) as [Sheet3],
|
||||||
|
(select F1 FROM [sheet4$a1:a1]) as [Sheet4]
|
||||||
|
FROM [sheet2$a1:a1]
|
||||||
|
UNION ALL
|
||||||
|
select top 1
|
||||||
|
'All A1s Start from Sheet3' as [A1],
|
||||||
|
(select F1 FROM [sheet1$a1:a1]) as [Sheet1],
|
||||||
|
(select F1 FROM [sheet2$a1:a1]) as [Sheet2],
|
||||||
|
F1 as [Sheet3],
|
||||||
|
(select F1 FROM [sheet4$a1:a1]) as [Sheet4]
|
||||||
|
FROM [sheet3$a1:a1]
|
||||||
|
UNION ALL
|
||||||
|
select top 1
|
||||||
|
'All A1s Start from Sheet4' as [A1],
|
||||||
|
(select F1 FROM [sheet1$a1:a1]) as [Sheet1],
|
||||||
|
(select F1 FROM [sheet2$a1:a1]) as [Sheet2],
|
||||||
|
(select F1 FROM [sheet3$a1:a1]) as [Sheet3],
|
||||||
|
F1 as [Sheet4]
|
||||||
|
FROM [sheet4$a1:a1]
|
||||||
92
__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#Requires -Modules Pester
|
||||||
|
if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) {
|
||||||
|
Import-Module $PSScriptRoot\..\ImportExcel.psd1
|
||||||
|
}
|
||||||
|
|
||||||
|
$skip = $false
|
||||||
|
if ($IsLinux -or $IsMacOS) {
|
||||||
|
$skip = $true
|
||||||
|
Write-Warning "Read-OleDbData: Linux and MacOs are not supported. Skipping tests."
|
||||||
|
}else{
|
||||||
|
try {
|
||||||
|
if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") {
|
||||||
|
$skip = $true
|
||||||
|
Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$skip = $true
|
||||||
|
Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Describe "Read-OleDbData" -Tag "Read-OleDbData" {
|
||||||
|
$PSDefaultParameterValues = @{ 'It:Skip' = $skip }
|
||||||
|
BeforeAll {
|
||||||
|
$scriptPath = $PSScriptRoot
|
||||||
|
$tfp = "$scriptPath\Read-OleDbData.xlsx"
|
||||||
|
$cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'"
|
||||||
|
}
|
||||||
|
Context "Basic Tests" {
|
||||||
|
It "Should have a valid Test file" {
|
||||||
|
Test-Path $tfp | Should -Be $true
|
||||||
|
}
|
||||||
|
It "Should have the Read-OleDbData command loaded" {
|
||||||
|
(Get-Command Read-OleDbData -ErrorAction SilentlyContinue) -ne $null | Should -Be $true
|
||||||
|
}
|
||||||
|
It "Should be able to open spreadsheet" {
|
||||||
|
$null = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1"
|
||||||
|
$true | Should -Be $true
|
||||||
|
}
|
||||||
|
It "Should return PSCustomObject for single result" {
|
||||||
|
#multiple records will come back as Object[], but not going to test for that
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1"
|
||||||
|
$Results.GetType().Name | Should -Be 'PSCustomObject'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "Sheet1`$A1" {
|
||||||
|
It "Should return 1 result with a value of 1" {
|
||||||
|
$sql = "select ROUND(F1) as [A1] from [sheet1`$A1:A1]"
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql
|
||||||
|
@($Results).length + $Results.A1 | Should -Be 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "Sheet2`$A1" {
|
||||||
|
It "Should return 1 result with value of 2" {
|
||||||
|
$sql = "select ROUND(F1) as [A1] from [sheet2`$A1:A1]"
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql
|
||||||
|
@($Results).length + $Results.A1 | Should -Be 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "Sheet3`$A1, Sql from file" {
|
||||||
|
It "Should return 1 result with value of 3" {
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestA.sql" -raw)
|
||||||
|
@($Results).length + $Results.A1 | Should -Be 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "Sheets[1-7]`$A1, Sql from file" {
|
||||||
|
It "Should return 7 result with where sum values 1-6 = value 7" {
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestB.sql" -raw)
|
||||||
|
$a = $Results.A1
|
||||||
|
$a.length + ($a[0..5] | Measure-Object -sum).sum | Should -Be (7 + $a[6])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "Sheet1`$:A1:E10, Sql from file" {
|
||||||
|
#note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value
|
||||||
|
It "Should return 1 result with value of 1" {
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestC.sql" -raw)
|
||||||
|
@($Results).length + $Results.F1 | Should -Be 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record, and sql is in a file" {
|
||||||
|
It "should return one row with 8 columns" {
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestD.sql" -raw)
|
||||||
|
@($Results).length + @($Results.psobject.Properties).length | Should -Be 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record multiple times to create a range, and sql is in a file" {
|
||||||
|
It "should return 4 records with 5 columns" {
|
||||||
|
$Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestE.sql" -raw)
|
||||||
|
@($Results).length + @($Results[0].psobject.Properties).length | Should -Be 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
__tests__/Read-OleDbDataTests/Read-OleDbData.xlsx
Normal file
BIN
__tests__/UnsupportedWorkSheetNames.xlsx
Normal file
BIN
__tests__/testImportExcel.xlsx
Normal file
BIN
__tests__/testImportExcelHeaderOnly.xlsx
Normal file
BIN
__tests__/testImportExcelImportColumns.xlsx
Normal file
@@ -20,6 +20,25 @@ jobs:
|
|||||||
vmImage: 'windows-latest'
|
vmImage: 'windows-latest'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
# BEGIN - ACE support for Invoke-ExcelQuery testing
|
||||||
|
- task: Cache@2
|
||||||
|
inputs:
|
||||||
|
key: v2 | "$(Agent.OS)" | ace
|
||||||
|
path: ace
|
||||||
|
cacheHitVar: CACHE_RESTORED
|
||||||
|
displayName: Cache ACE
|
||||||
|
|
||||||
|
- bash: |
|
||||||
|
mkdir ./ace
|
||||||
|
curl -o ./ace/ace.exe https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe
|
||||||
|
displayName: 'Download ACE'
|
||||||
|
condition: ne(variables.CACHE_RESTORED, 'true')
|
||||||
|
|
||||||
|
- powershell: Start-Process ./ace/ace.exe -Wait -ArgumentList "/quiet /passive /norestart"
|
||||||
|
displayName: 'Install ACE for Invoke-ExcelQuery testing'
|
||||||
|
# END - ACE support for Invoke-ExcelQuery testing
|
||||||
|
|
||||||
- powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck'
|
- powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck'
|
||||||
displayName: 'Update Pester'
|
displayName: 'Update Pester'
|
||||||
- powershell: './CI/CI.ps1 -Test'
|
- powershell: './CI/CI.ps1 -Test'
|
||||||
@@ -49,6 +68,25 @@ jobs:
|
|||||||
vmImage: 'windows-latest'
|
vmImage: 'windows-latest'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
# BEGIN - ACE support for Invoke-ExcelQuery testing
|
||||||
|
- task: Cache@2
|
||||||
|
inputs:
|
||||||
|
key: v2 | "$(Agent.OS)" | ace
|
||||||
|
path: ace
|
||||||
|
cacheHitVar: CACHE_RESTORED
|
||||||
|
displayName: Cache ACE
|
||||||
|
|
||||||
|
- bash: |
|
||||||
|
mkdir ./ace
|
||||||
|
curl -o ./ace/ace.exe https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe
|
||||||
|
displayName: 'Download ACE'
|
||||||
|
condition: ne(variables.CACHE_RESTORED, 'true')
|
||||||
|
|
||||||
|
- powershell: Start-Process ./ace/ace.exe -Wait -ArgumentList "/quiet /passive /norestart"
|
||||||
|
displayName: 'Install ACE for Invoke-ExcelQuery testing'
|
||||||
|
# END - ACE support for Invoke-ExcelQuery testing
|
||||||
|
|
||||||
- pwsh: 'Install-Module -Name Pester -Force'
|
- pwsh: 'Install-Module -Name Pester -Force'
|
||||||
displayName: 'Update Pester'
|
displayName: 'Update Pester'
|
||||||
- pwsh: './CI/CI.ps1 -Test'
|
- pwsh: './CI/CI.ps1 -Test'
|
||||||
|
|||||||
101
changelog.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# v7.5.1
|
||||||
|
- Fixed `Import-Excel` - Reset `EndRow` and `EndColumn` in the correct place.
|
||||||
|
# v7.5.0
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Importing multiple files with Import-Excel by pipeline uses only the first file for the row count https://github.com/dfinke/ImportExcel/issues/1172
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
- Import-Excel now supports importing multiple sheets. It can either return a dictionary of all sheets, or as a single array of all sheets combined.
|
||||||
|
- `Import-Excel $xlfile *` # reads all sheets, returns all data in a dictionary
|
||||||
|
- `Import-Excel $xlfile * -NotAsDictionary` # reads all sheets, returns all data in a single array
|
||||||
|
- Added helper functions. Useful for working with an Excel package via `Open-ExcelPackage` or `-PassThru`
|
||||||
|
- `Enable-ExcelAutoFilter`
|
||||||
|
- `Enable-ExcelAutofit`
|
||||||
|
- `Get-ExcelSheetDimensionAddress`
|
||||||
|
|
||||||
|
# v7.4.2
|
||||||
|
|
||||||
|
- Thank you [James Mueller](https://github.com/jamesmmueller) Updated `ConvertFrom-ExcelToSQLInsert` to handle single quotes in the SQL statement.
|
||||||
|
|
||||||
|
- Thank you to Josh Hendricks
|
||||||
|
- Add images to spreadsheets. [Check it out](https://github.com/dfinke/ImportExcel/tree/master/Examples/AddImage)
|
||||||
|
- Catch up with him on [GitHub](https://github.com/joshooaj) and [Twitter](https://twitter.com/joshooaj) for the idea
|
||||||
|
|
||||||
|
# v7.4.1
|
||||||
|
|
||||||
|
- Implements: https://github.com/dfinke/ImportExcel/issues/1111
|
||||||
|
- Refactored ReZip into separate function
|
||||||
|
- Deletes temp folder after rezipping
|
||||||
|
- Added -ReZip to `Close-ExcelPackage`
|
||||||
|
|
||||||
|
# v7.4.0
|
||||||
|
|
||||||
|
- Thank you to [Max Goczall](https://github.com/muschebubusche) for this contribution!
|
||||||
|
- `ImportColumns` parameter added to `ImportExcel`. It is used to define which columns of the ExcelPackage should be imported.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Import-Excel -Path $xlFile -ImportColumns @(6,7,12,25,46)
|
||||||
|
```
|
||||||
|
|
||||||
|
# v7.3.1
|
||||||
|
|
||||||
|
- Added query Excel spreadsheets, with SQL queries!
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$query = 'select F2 as [Category], F5 as [Discount], F5*2 as [DiscountPlus] from [sheet1$A2:E11]'
|
||||||
|
|
||||||
|
Invoke-ExcelQuery .\testOleDb.xlsx $query
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Result
|
||||||
|
|
||||||
|
```
|
||||||
|
Category Discount DiscountPlus
|
||||||
|
-------- -------- ------------
|
||||||
|
Cosmetics 0.7 1.4
|
||||||
|
Grocery 0.3 0.6
|
||||||
|
Apparels 0.2 0.4
|
||||||
|
Electronics 0.1 0.2
|
||||||
|
Electronics 0 0
|
||||||
|
Apparels 0.8 1.6
|
||||||
|
Electronics 0.7 1.4
|
||||||
|
Cosmetics 0.6 1.2
|
||||||
|
Grocery 0.4 0.8
|
||||||
|
Grocery 0.3 0.6
|
||||||
|
```
|
||||||
|
|
||||||
|
- Thank you to Roy Ashbrook for the SQL query code. Catch up with Roy:
|
||||||
|
|
||||||
|
|Media|Link|
|
||||||
|
|---|---|
|
||||||
|
|twitter|https://twitter.com/royashbrook
|
||||||
|
|github|https://github.com/royashbrook
|
||||||
|
|linkedin|https://linkedin.com/in/royashbrook
|
||||||
|
|blog|https://ashbrook.io
|
||||||
|
|
||||||
|
# v7.3.0
|
||||||
|
|
||||||
|
- Fix throwing error when a Worksheet name collides with a method, or property name on the `OfficeOpenXml.ExcelPackage` package
|
||||||
|
|
||||||
|
# v7.2.3
|
||||||
|
|
||||||
|
- Fix inline help, thank you [Wes Stahler](https://github.com/stahler)
|
||||||
|
|
||||||
|
# v7.2.2
|
||||||
|
|
||||||
|
- Improved checks for Linux, Mac and PS 5.1
|
||||||
|
|
||||||
|
# v7.2.1
|
||||||
|
|
||||||
|
- Improve auto-detection of data on the clipboard
|
||||||
|
|
||||||
|
# v7.2.0
|
||||||
|
|
||||||
|
- Added `Read-Clipboard` support for Windows. Read text from clipboard. It can read CSV or JSON. Plus, you can specify the delimiter and headers.
|
||||||
|
|
||||||
|
### Check out the video
|
||||||
|
<a href="https://youtu.be/dv2GOH5sbpA"><img src="https://img.youtube.com/vi/dv2GOH5sbpA/0.jpg" width="400"></a>
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Examples
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Charts
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Multiplecharts
|
|
||||||
|
|
||||||
## PowerShell
|
|
||||||
|
|
||||||
```text
|
|
||||||
$xlFile = "$env:TEMP\ImportExcelExample.xlsx"
|
|
||||||
Remove-Item $xlFile -ErrorAction Ignore
|
|
||||||
|
|
||||||
$data = ConvertFrom-Csv @"
|
|
||||||
ID,Product,Quantity,Price,Total
|
|
||||||
12001,Nails,37,3.99,147.63
|
|
||||||
12002,Hammer,5,12.10,60.5
|
|
||||||
12003,Saw,12,15.37,184.44
|
|
||||||
12010,Drill,20,8,160
|
|
||||||
12011,Crowbar,7,23.48,164.36
|
|
||||||
"@
|
|
||||||
|
|
||||||
$chart1 = New-ExcelChartDefinition -YRange "Price" -XRange "Product" -Title "Item price" -NoLegend -Height 225
|
|
||||||
$chart2 = New-ExcelChartDefinition -YRange "Total "-XRange "Product" -Title "Total sales" -NoLegend -Height 225 -Row 9 -Column 15
|
|
||||||
$chart3 = New-ExcelChartDefinition -YRange "Quantity"-XRange "Product" -Title "Sales volume" -NoLegend -Height 225 -Row 15
|
|
||||||
|
|
||||||
$data | Export-Excel -Path $xlFile -AutoFilter -AutoNameRange -AutoSize -Show -ExcelChartDefinition $chart1,$chart2,$chart3
|
|
||||||
```
|
|
||||||
|
|
||||||
## Result
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Untitled
|
|
||||||
|
|
||||||
BIN
images/FAQ_Images/DataStructureExcelPkg.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
images/FAQ_Images/ExcelFileContents.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
images/FAQ_Images/ExcelFileContentsPostAdd.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
images/FAQ_Images/ExcelFileDebugImg.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
images/FAQ_Images/ValueAtIndexData.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
images/SQL-Spreadsheet.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -9,7 +9,7 @@ schema: 2.0.0
|
|||||||
|
|
||||||
## SYNOPSIS
|
## SYNOPSIS
|
||||||
|
|
||||||
Returns an ExcelPackage object for the specified XLSX fil.e
|
Returns an ExcelPackage object for the specified XLSX file.
|
||||||
|
|
||||||
## SYNTAX
|
## SYNTAX
|
||||||
|
|
||||||