Compare commits

..

242 Commits

Author SHA1 Message Date
dfinke
e6827ba2c5 Updated readme 2019-11-01 19:10:05 -04:00
dfinke
c6b188f915 bump version 2019-11-01 19:09:48 -04:00
dfinke
3f79a43dc4 Remove requires, formatting updated 2019-11-01 19:04:22 -04:00
Doug Finke
53e57b25a6 Merge pull request #706 from jhoneill/master
SQL -Force , import -asText , test fixes, better Linux behavior
2019-11-01 18:57:02 -04:00
Doug Finke
b87fcf6c08 Merge pull request #711 from uSlackr/patch-2
Adding test for Get-ColumnName for https://github.com/dfinke/ImportExcel/issues/708
2019-11-01 18:53:48 -04:00
Doug Finke
35066c0f5d Merge pull request #710 from uSlackr/patch-1
Fixes Column order issue for https://github.com/dfinke/ImportExcel/issues/708
2019-11-01 18:53:14 -04:00
uSlackr
912fc35693 Update Get-ExcelColumnName.Test.ps1 2019-11-01 17:15:27 -04:00
uSlackr
2711ad5522 Adding test for Get-ColumnName 2019-11-01 17:13:10 -04:00
uSlackr
79c3077162 Fixes Column order issue
Column letters were returned out of order.  Issue #708
2019-11-01 13:41:31 -04:00
jhoneill
24ca8da4c3 Merge remote-tracking branch 'upstream/master' 2019-11-01 01:57:47 +00:00
jhoneill
6b626e8f5f Better handling of autosize (again) 2019-11-01 01:57:04 +00:00
jhoneill
4d17a09537 Better .NET version detection 2019-11-01 01:56:11 +00:00
jhoneill
065fc2f1ad Better handling of linux autosize issue. 2019-10-31 15:48:49 +00:00
jhoneill
c71afe802e *Selective* -asText on import & 1 linux test bug 2019-10-31 15:47:44 +00:00
jhoneill
3284f592b9 -Force behavior clearer in Send-SQLData 2019-10-31 10:31:54 +00:00
jhoneill
5d92442488 New tests for import -asText and send-SQL -Force 2019-10-30 17:38:09 +00:00
jhoneill
fb9a592e9e Wasn't removing force from Param to passed thru 2019-10-30 16:16:41 +00:00
jhoneill
d2a378ffda Ensured tests the module in Azure CI 2019-10-30 11:55:54 +00:00
jhoneill
463944ae2d Added support for Send-SQLData -force 2019-10-30 10:59:45 +00:00
jhoneill
34fe2f429a Added support for Import-Excel -ASTEXT 2019-10-30 10:59:23 +00:00
jhoneill
f65e198986 Adaptation for V6 broke under V5. Fixed 2019-10-30 10:58:59 +00:00
dfinke
9e92f2dbc6 Refactored 2019-09-22 11:58:13 -04:00
dfinke
e45c07c40b Add ReadAllSheets example, update readme bump version 2019-09-22 11:43:47 -04:00
dfinke
fbae59b386 Bumped the version 2019-08-31 19:40:42 -04:00
dfinke
e3f3ae74a4 Updated appveyor badge 2019-08-29 19:15:20 -04:00
dfinke
fda61ca10f Updated badges 2019-08-29 18:55:18 -04:00
Doug Finke
29efd505ed Merge pull request #668 from ili101/TestsRebase
Tests improvments and Linux support
2019-08-29 18:43:14 -04:00
ili101
600d95199c Merge branch 'master' into TestsRebase 2019-08-30 01:29:00 +03:00
ili101
1ad80825ca Poke 2019-08-30 01:24:51 +03:00
dfinke
a2b322d45c Only run tests on Windows PS 5.1 2019-08-29 18:13:38 -04:00
ili101
bb9aa9233b Linux dependencies missing warning 2019-08-29 23:50:10 +03:00
ili101
591b854e2b Tests statuses improve 2019-08-29 01:53:07 +03:00
ili101
15eb2130b5 Mereg 2019-08-29 01:22:55 +03:00
ili101
ea8927394f Remove duplicate files with different case 2019-08-29 00:33:17 +03:00
ili101
cfd89f5afc Samples 2019-08-29 00:33:17 +03:00
ili101
3a6946466f xlsx case 2019-08-29 00:33:16 +03:00
ili101
89a59b1eba Samples tests workaround for Linux 2019-08-29 00:32:26 +03:00
ili101
8047631014 Linux Tests rm and macOS mono-libgdiplus 2019-08-29 00:31:46 +03:00
ili101
9458a29a6b Readme 2019-08-29 00:31:46 +03:00
ili101
ab2405edad Scope fixes for TestDrive 2019-08-29 00:31:45 +03:00
ili101
d1592f8739 Replace $env:TEMP 2019-08-29 00:30:22 +03:00
ili101
6650ecd5b8 FileList Case 2019-08-29 00:22:47 +03:00
ili101
b27f6bec3c Module.Template 2.0.2 2019-08-29 00:22:46 +03:00
dfinke
99f742fa8c Updated readme 2019-08-26 20:41:03 -04:00
dfinke
558070bb60 Bump version 2019-08-26 20:25:25 -04:00
Doug Finke
1e0dd763ca Merge pull request #666 from jhoneill/master
Cross platform test support
2019-08-26 19:58:06 -04:00
jhoneill
a783b9c8ca Fixes to tests to be run x-plaform 2019-08-27 00:31:30 +01:00
jhoneill
9abbe2983b Set-ExcelRange now handles autosize on non-windows 2019-08-27 00:30:56 +01:00
dfinke
0556e4947a Added examples to use Excel sparklines to show data trends 2019-08-26 18:38:30 -04:00
Doug Finke
859b1e5467 Merge pull request #664 from jhoneill/master
Fixes issues with newer EPPLus.
2019-08-26 18:29:08 -04:00
jhoneill
0f4e491076 Two lines went missing from a test. Put back. 2019-08-25 20:25:22 +01:00
jhoneill
b30a91d64f Merge remote-tracking branch 'upstream/master' 2019-08-25 18:39:53 +01:00
jhoneill
d1f794c933 Fixes around EPPlus update 2019-08-25 18:35:46 +01:00
dfinke
a016f069a5 Added Azure DevOps pipeline for three OSes 2019-08-25 12:04:14 -04:00
dfinke
fb16ec4677 Updated az yml to test on Linux and Mac 2019-08-25 08:55:43 -04:00
dfinke
1a51d38c0f Add image showing defaults 2019-08-21 17:37:19 -04:00
dfinke
554163a911 Update readme 2019-08-21 17:37:05 -04:00
dfinke
efd8dcd60a Bump version 2019-08-21 17:36:57 -04:00
Doug Finke
1c77bd31b5 Merge pull request #661 from ili101/Out-Excel
Out-Excel and -Now
2019-08-21 17:06:30 -04:00
ili101
35e013fe1d Reverted to Pester Old syntax 2019-08-18 22:37:24 +03:00
ili101
8ac9927cfa ParameterSets Tests and Out-Excel Example 2019-08-18 22:09:28 +03:00
ili101
9c305a1dae Change -Now default from -AutoFilter to -TableName 2019-08-17 08:03:52 +03:00
ili101
aa738629f7 Out-Excel 2019-08-17 06:29:59 +03:00
jhoneill
c1a26f4f4b Added Protect-Worksheet Tests 2019-08-16 14:14:31 +01:00
jhoneill
63f41ceaec WS protection & better control of export -now 2019-08-15 16:03:42 +01:00
dfinke
b82888527f Updated 2019-07-24 09:54:24 -04:00
dfinke
a3c71de190 Bump version 2019-07-24 09:54:20 -04:00
Doug Finke
f3a99f04ce Merge pull request #638 from jhoneill/master
Updates for copy sheet, clear all in Set-Excel range and fixing a password regression
2019-07-24 09:49:42 -04:00
jhoneill
f631a20269 Conflict resolution 2019-07-24 13:02:39 +01:00
jhoneill
dbd35721ee Fix broken test & regression re: passwords 2019-07-24 12:02:22 +01:00
jhoneill
8759070636 add clearall to set-ExcelRange; 2019-07-24 12:01:06 +01:00
Doug Finke
6259b8d091 Merge pull request #630 from 1DontEx1st/patch-1
Fix typo
2019-07-11 13:21:29 -04:00
1DontEx1st
7086c3707c Fix typo
Changed "Autofiler" to "Autofilter" in -Now description.
2019-07-11 12:01:36 -04:00
jhoneill
8b28172616 Refactored copy sheet and added pipe support 2019-07-09 19:10:51 +01:00
dfinke
abdd37b09e Updated readme and bumped version 2019-07-04 16:20:19 -04:00
Doug Finke
e1e855a823 Merge pull request #628 from dfinke/RelativePath
Added resolve-path and tests. #627; Commented out write-warning
2019-07-04 16:18:14 -04:00
dfinke
585d9686a6 Remove firstTimeThru check 2019-07-04 16:14:36 -04:00
dfinke
e87a6bdaf5 Add extension test back in 2019-07-04 12:16:44 -04:00
dfinke
5ded5111b4 Rename test 2019-07-04 12:16:34 -04:00
dfinke
914c61048b Moved back, CI has issues with $psscriptroot for xlsx 2019-07-04 12:03:05 -04:00
dfinke
25fb76d9b7 Remove test, put check in begin block 2019-07-04 11:59:15 -04:00
dfinke
7faa27a3b3 create xlsx before all in cwd 2019-07-04 11:53:59 -04:00
dfinke
5700be0684 works locally, not in the CI tho 2019-07-04 11:45:42 -04:00
dfinke
6d86108060 wip: remove param validation 2019-07-04 11:40:02 -04:00
dfinke
4581c2b3e9 Added resolve-path and tests. #627; Commented out write-warning 2019-07-04 11:18:28 -04:00
dfinke
142c31ccc1 Added image to readme 2019-06-18 14:56:00 -04:00
dfinke
b99b7ba799 Added chart trendline example 2019-06-18 14:47:14 -04:00
dfinke
17b5d2caec bump version 2019-06-18 14:47:14 -04:00
Doug Finke
6add16aa9f Merge pull request #615 from dfinke/EnableTrendLine
Initial pass at adding ChartTrendLine
2019-06-18 10:55:37 -04:00
dfinke
9aa0192ee6 Added and chart trendline example 2019-06-18 10:44:07 -04:00
dfinke
fa25d1ac06 Added tests for trendlines on charts 2019-06-18 10:31:37 -04:00
dfinke
8131eee50f Check if trendline was requested 2019-06-15 14:21:37 -04:00
dfinke
3ce485a144 Initial pass at adding ChartTrendLine 2019-06-13 15:38:28 -04:00
dfinke
bb1b413ada Updated 2019-06-11 17:24:28 -04:00
dfinke
08078410dc Added 2019-06-11 17:23:21 -04:00
dfinke
3edcc0bdfb Added pic link 2019-06-11 17:23:11 -04:00
dfinke
25081f84c1 Updated readme 2019-06-11 17:12:16 -04:00
dfinke
668e3c982c Image of New-ExcelStyle 2019-06-11 17:12:03 -04:00
dfinke
98cf7e03c1 Add Excel style example 2019-06-11 17:11:42 -04:00
dfinke
5b5c1c6fce Bump version 2019-06-11 17:11:22 -04:00
Doug Finke
4383916090 Merge pull request #610 from jhoneill/master
Style and read only
2019-06-11 16:13:22 -04:00
jhoneill
7c2bbf9595 Read-only imports + small test fix 2019-06-11 15:09:36 +01:00
jhoneill
48ca35b9ff Added -Style to export-Excel and -merge to set-excelRange 2019-06-05 21:17:35 +01:00
dfinke
68be3c3483 try again later 2019-05-31 12:43:45 -04:00
dfinke
78326b4258 again 2019-05-31 12:42:31 -04:00
dfinke
94b10b6f51 again 2019-05-31 12:41:25 -04:00
dfinke
8ac9815e83 test exclude again 2019-05-31 12:37:44 -04:00
dfinke
b3184d36a9 try exclude again 2019-05-31 12:36:45 -04:00
dfinke
e58265075a test exclude trigger 2019-05-31 12:32:19 -04:00
dfinke
453b2d8963 update trigger 2019-05-31 12:29:01 -04:00
dfinke
bc816851c9 Shouldn't trigger a build 2019-05-31 11:32:55 -04:00
dfinke
b0a68e3445 Don't trigger a build if examples get checked in 2019-05-31 11:29:28 -04:00
dfinke
8a1d0b0cf8 Added simple vba example 2019-05-31 11:21:44 -04:00
Doug Finke
26f55251e2 Update CustomReport.ps1 2019-05-31 10:13:03 -04:00
dfinke
0f9b308d53 Bump version 2019-05-26 14:46:57 -04:00
Doug Finke
847c9a1dc4 Merge pull request #602 from jhoneill/master
Allow import Excel to take packages not just paths
2019-05-24 20:38:52 -04:00
jhoneill
b488ffc700 Allow import Excel to take packages not just paths 2019-05-24 16:23:13 +01:00
dfinke
3ec2481750 Added Pivoting Pester Test Results 2019-05-06 12:14:33 -04:00
Doug Finke
2d26c854d9 Merge pull request #593 from jhoneill/master
added "Analyze this"
2019-05-06 10:51:55 -04:00
jhoneill
a4348ddca7 Merge branch 'master' of https://github.com/jhoneill/ImportExcel 2019-05-06 09:52:19 +01:00
jhoneill
6bfdea6d3e Example : Analyze_this 2019-05-06 09:52:12 +01:00
jhoneill
cfd3db5803 Example : Analyze_this 2019-05-06 09:43:38 +01:00
jhoneill
f20a9de3df New "Analyze-This" example 2019-05-03 12:45:30 -07:00
jhoneill
978e8d38b5 Added Example for PSScriptAnalyzer 2019-05-02 16:34:00 -07:00
Doug Finke
e7d2b528e5 Merge pull request #590 from jhoneill/master
Fixed case on file names, and applied a new rules from script analyzer
2019-05-01 16:22:42 -04:00
jhoneill
899a8215e5 Changed test from Get-Netadapter to CIM for v6 2019-05-01 11:24:36 -07:00
jhoneill
b06e9e35b7 Fixed file case errors impacting loading on Linux 2019-05-01 10:16:13 -07:00
jhoneill
6c7f00b031 Linted with the updated PSScriptAnalyzer. 2019-04-30 13:28:52 -07:00
dfinke
337af82ae2 Updated readme.md 2019-04-12 16:02:47 -04:00
Doug Finke
77ef2ebc40 Merge pull request #576 from ili101/FixDataTablePerformance
Double DataTable performance
2019-04-08 16:42:28 -04:00
ili101
92c97b25c3 Replace [void] with $null 2019-04-08 13:34:31 +03:00
ili101
52231254a5 Replace " | Out-Null" with "$null = " everywhere just in case it degrades performance in other places 2019-04-07 22:26:48 +03:00
ili101
494ac51ae5 Replace " | Out-Null" with "$null = " doble performance on DataTable 2019-04-07 22:11:31 +03:00
Doug Finke
0febb4a3c2 Merge pull request #575 from ili101/TableStyleFix
TableStyle is set to Medium6 but ignored
2019-04-07 14:47:06 -04:00
Doug Finke
62f0faa5c5 Merge pull request #574 from ili101/TestsFix
Fix Test accidentally closing focused window
2019-04-07 12:50:56 -04:00
ili101
1055bc41bf TableStyle is set to Medium6 but ignored 2019-04-07 18:16:35 +03:00
ili101
e100fa7a36 Fix Test accidentally closing focused window if focus not switched to Out-GridView. 2019-04-07 15:02:50 +03:00
dfinke
83bd387f98 Update what's new 2019-04-06 11:30:10 -04:00
dfinke
caf0059ef5 Bumped version, sorted function exports 2019-04-06 11:20:15 -04:00
Doug Finke
965831ba57 Merge pull request #573 from jhoneill/master
Perf improvements for Export-Excel
2019-04-06 11:13:47 -04:00
jhoneill
a49cab5efc Slimmed down send-sqlData - undid previous 2019-04-06 10:49:57 +01:00
jhoneill
17bcea15e8 Fixed a poss parameter set issue; 2019-04-06 00:21:48 +01:00
jhoneill
79fb29740d Rolled back readme for merge purposes 2019-04-04 18:03:49 +01:00
jhoneill
2984fe2ef5 Merge branch 'master' of https://github.com/jhoneill/ImportExcel 2019-04-04 18:01:31 +01:00
jhoneill
8734dbd26c Readme update 2019-04-04 18:01:26 +01:00
jhoneill
0211edf008 Readme update 2019-04-04 17:42:33 +01:00
jhoneill
552552b93d Perf improvments and direct table handling for Export Excel, 2019-04-04 17:08:05 +01:00
jhoneill
2229bfb3ed Moved Add-CellValue 2019-04-04 09:45:10 +01:00
Doug Finke
25e7962100 Merge pull request #564 from slestak/patch-1
Update Export-Excel.ps1 - Add-Worksheet help typo
2019-03-19 13:02:01 -04:00
Steve Romanow
6071f77218 Update Export-Excel.ps1
fix typo
2019-03-19 11:56:20 -04:00
dfinke
52b9333d7c added regions 2019-03-03 12:56:35 -05:00
dfinke
d3d8d76a71 fixed psm1. added .ps1 to Set-WorkSheetProtection 2019-03-02 14:03:26 -05:00
dfinke
f5f97fcd56 bumped the read up 100 ms 2019-03-02 13:24:19 -05:00
dfinke
6665c2952d fix readme 2019-03-02 13:17:22 -05:00
dfinke
31444320cb Updated 2019-03-02 13:15:16 -05:00
dfinke
d5734ff9b2 Pulled from the tests. Added additional rule 2019-03-02 13:13:53 -05:00
dfinke
4481637c21 spell check 2019-03-02 12:40:45 -05:00
dfinke
6caf247f5b bump version 2019-03-02 12:38:10 -05:00
Doug Finke
65641955ba Merge pull request #552 from jhoneill/master
Minor fixes and added data-validation support
2019-03-02 12:32:43 -05:00
jhoneill
f2c13949a4 Fixed Send-SQLData behavior with tables/ranges when adding to a sheet 2019-03-01 08:31:43 +00:00
jhoneill
878ca570fb Updated readme for recent commits 2019-02-28 07:42:22 +00:00
jhoneill
28fd5512bb Fixed broken tests 2019-02-25 20:53:11 +00:00
jhoneill
7e465e3729 Merge remote-tracking branch 'upstream/master' 2019-02-25 19:33:51 +00:00
jhoneill
22283604f8 Sync with DFinke's master 2019-02-25 18:14:46 +00:00
jhoneill
0c603afc0e improved handing of Hyperlinks in Export 2019-02-21 19:25:53 +00:00
Doug Finke
a4a989c556 Update Get-HtmlTable.ps1 2019-02-20 19:26:43 -05:00
dfinke
d94db666d7 Added module 2019-02-18 14:06:18 -05:00
dfinke
438be760f7 updated 2019-02-18 13:51:50 -05:00
dfinke
2949ecc173 update 2019-02-17 18:27:41 -05:00
dfinke
639ca738f6 rearrange 2019-02-17 18:27:36 -05:00
dfinke
736dd648f4 Updated git ignore 2019-02-17 15:36:05 -05:00
dfinke
acdbd4a618 added demo 2019-02-13 19:08:01 -05:00
dfinke
ad35d39850 Removed unneed tests 2019-02-13 16:23:37 -05:00
dfinke
e7afe166a4 Updated to point to new rest api for stock info 2019-02-02 16:58:57 -05:00
dfinke
37b076706e rename file 2019-02-02 16:58:57 -05:00
jhoneill
3303116658 Test for validation rules had un-necessary cleanup step which caused an error 2019-01-21 14:31:04 +00:00
jhoneill
89a8cb0469 Added data validation 2019-01-21 14:20:57 +00:00
Doug Finke
bb9f4c31a6 Delete ImportExcel-5.4.2-20181217155848.zip
not needed
2019-01-18 19:49:14 -05:00
Doug Finke
996d1246cf Merge pull request #523 from stahler/patch-1
Update Export-Excel.ps1
2019-01-11 21:08:24 -05:00
Wes Stahler
0bb08fcb20 Update Export-Excel.ps1 2019-01-11 20:49:08 -05:00
Doug Finke
d004019761 Merge pull request #520 from dfinke/FixCopyExcelWorksheetStreamClose-dcf
Fix Copy-ExcelWorkSheet so Remove-WorkSheet works. Resolves #516
2019-01-05 09:57:17 -05:00
dfinke
a54ca228e9 Resolves #516 2019-01-05 09:54:52 -05:00
dfinke
bb6ff474a8 updated readme 2019-01-05 09:53:38 -05:00
dfinke
86b5c13543 Close the $Stream so the xlsx won't be locked 2019-01-05 09:49:48 -05:00
dfinke
c2525b0348 Add tests to show the IOException: The process cannot access the file 2019-01-05 09:42:37 -05:00
dfinke
9625e4a8ac Update ReadME 2018-12-31 18:53:54 -05:00
dfinke
82177da695 Bump release 2018-12-31 18:53:45 -05:00
Doug Finke
b3f7a60be8 Merge pull request #517 from dfinke/FixAutoNameRange-dcf
Fix auto name range when a single property is incoming
2018-12-31 18:48:09 -05:00
dfinke
643610c267 Add test for a single property name 2018-12-31 18:45:26 -05:00
dfinke
bd7d70a050 Fix when only one property name is in the incoming data 2018-12-31 18:45:16 -05:00
Doug Finke
d1f41012a1 Merge pull request #514 from dfinke/AddRemoveWorksheet-dcf
Add Remove-Workseet
2018-12-30 09:42:53 -05:00
dfinke
0fbe9dbc9b update readme 2018-12-30 09:38:43 -05:00
dfinke
e0b2d15c53 bump version 2018-12-30 09:38:36 -05:00
dfinke
34c924ae19 Handles piping in the a list of xlsx files 2018-12-30 09:34:44 -05:00
dfinke
9217962306 Update and fix tests 2018-12-30 08:52:19 -05:00
dfinke
56acf56430 Add code to do removal 2018-12-30 08:52:11 -05:00
dfinke
ef9be471ab First test 2018-12-30 08:45:51 -05:00
dfinke
9db2bc068e Added to psm1 2018-12-30 08:29:18 -05:00
dfinke
9560ea83f9 updated 2018-12-20 09:15:25 -05:00
dfinke
9c79ba573c updated 2018-12-20 09:13:45 -05:00
Doug Finke
894e645a47 Update MultiplePivotTables.ps1 2018-12-20 09:01:21 -05:00
dfinke
f3dc390bfa Added example showing how to create mutiple pivottables on a single sheet 2018-12-17 16:00:40 -05:00
dfinke
f0f58f84a0 Added Timestamp Bucket example 2018-12-10 15:16:11 -05:00
dfinke
7ded24d2f9 updated with example for grouping numeric 2018-12-08 08:35:20 -05:00
dfinke
cf964e3e4f added grouping image for example 2018-12-08 08:32:20 -05:00
dfinke
8c5b3b2f5f Added Places and Points examples. Taken from unit tests 2018-12-07 18:08:50 -05:00
dfinke
8409adeeba Fix param names in tests 2018-12-07 14:42:04 -05:00
dfinke
153d4d8c45 bump version 2018-12-07 14:33:44 -05:00
dfinke
69f9ba7d17 Fix spelling for GroupNumber* params 2018-12-07 14:33:38 -05:00
dfinke
e4deb5801e fixed spelling 2018-12-07 13:25:20 -05:00
Doug Finke
1a74c0f0d0 Merge pull request #501 from jhoneill/master
Added Pivot table grouping
2018-12-07 13:17:40 -05:00
jhoneill
72e44da219 Put back DoTests and yml file. Updated readme for pivot groups 2018-12-06 21:38:13 +00:00
jhoneill
bef2f29651 Revert "Update DoTests.ps1"
This reverts commit c5cc018eb5.
2018-12-06 20:16:45 +00:00
jhoneill
787dda70ee Revert "Take verbose back out of DoTests"
This reverts commit 268d48ce3d.
2018-12-06 20:16:34 +00:00
jhoneill
285e9e4949 Revert "Update azure-pipelines.yml"
This reverts commit eca631670c.
2018-12-06 20:16:25 +00:00
jhoneill
01e3ea206d Revert "One more"
This reverts commit 284560e109.
2018-12-06 20:16:09 +00:00
jhoneill
6f3420d11e Revert "path fix"
This reverts commit 234615dfdb.
2018-12-06 20:15:45 +00:00
jhoneill
2981bf23b1 Added Pivot table grouping 2018-12-06 17:45:10 +00:00
jhoneill
c5cc018eb5 Update DoTests.ps1 2018-11-30 16:58:08 +00:00
jhoneill
268d48ce3d Take verbose back out of DoTests 2018-11-30 16:45:11 +00:00
jhoneill
eca631670c Update azure-pipelines.yml 2018-11-30 16:33:06 +00:00
jhoneill
284560e109 One more 2018-11-30 16:26:45 +00:00
jhoneill
234615dfdb path fix 2018-11-30 16:25:02 +00:00
jhoneill
d31cd04781 Merge remote-tracking branch 'upstream/master' 2018-11-30 16:20:01 +00:00
jhoneill
77481f2901 More of the same 2018-11-30 16:18:46 +00:00
jhoneill
54fec69f88 Merge branch 'master' of https://github.com/jhoneill/ImportExcel 2018-11-30 16:06:07 +00:00
jhoneill
1dc9a02d7d Updates to azure pipeline 2018-11-30 16:05:58 +00:00
azure-pipelines[bot]
f86fdbab22 Set up CI with Azure Pipelines 2018-11-30 14:46:43 +00:00
dfinke
66937db040 Did expand alias 2018-11-27 09:55:05 -05:00
dfinke
80520299aa Added Apply Style example 2018-11-27 09:44:15 -05:00
jhoneill
2753a6876a Better handling of Empry values when setting Columns/Rows 2018-11-27 11:03:06 +00:00
dfinke
ade442b18c animation for export stocks 2018-11-25 16:16:39 -05:00
dfinke
45ba112f73 bump version 2018-11-25 16:16:28 -05:00
dfinke
e1fe36699b Added Export-StocksToExcel 2018-11-25 16:16:16 -05:00
dfinke
b3f4b188da updated 2018-11-20 19:16:22 -05:00
dfinke
0ce75794e6 Added Mortgate Calculator 2018-11-20 13:21:04 -05:00
jhoneill
3afe2059e5 Added message to say title is ignored when exporting with -Append. 2018-11-20 10:52:29 +00:00
dfinke
66b7b64779 fix fontcolor 2018-11-19 18:50:13 -05:00
Doug Finke
d90cd6d2d0 Merge pull request #493 from jhoneill/master
TO Do #491 Done
2018-11-18 09:20:49 -05:00
jhoneill
1d1f266fb6 Better checks for invalid table names 2018-11-15 16:22:36 +00:00
jhoneill
4945b4d6e3 Fix to readme 2018-11-15 12:33:03 +00:00
jhoneill
21b5a11aca Trap invalid worksheet name in Set-ExcelRow/Column 2018-11-13 10:16:51 +00:00
120 changed files with 4831 additions and 3788 deletions

5
.gitignore vendored
View File

@@ -60,5 +60,8 @@ test.xlsx
testCCFMT.ps1 testCCFMT.ps1
testHide.ps1 testHide.ps1
ImportExcel.zip ImportExcel.zip
.vscode/launch.json .vscode/settings.json
~$*
InstallModule.ps1
PublishToGallery.ps1

56
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,56 @@
{
// 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": ""
}
]
}

View File

@@ -1,4 +1,9 @@
Function Add-ConditionalFormatting { try {
#ensure that color and font lookups are available
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
}
catch {}
Function Add-ConditionalFormatting {
<# <#
.Synopsis .Synopsis
Adds conditional formatting to all or part of a worksheet. Adds conditional formatting to all or part of a worksheet.
@@ -105,7 +110,7 @@
[OfficeOpenXml.ConditionalFormatting.eExcelConditionalFormattingRuleType]$RuleType , [OfficeOpenXml.ConditionalFormatting.eExcelConditionalFormattingRuleType]$RuleType ,
#Text color for matching objects #Text color for matching objects
[Parameter(ParameterSetName = "NamedRule")] [Parameter(ParameterSetName = "NamedRule")]
[Alias("ForegroundColour")] [Alias("ForegroundColour","FontColor")]
$ForegroundColor, $ForegroundColor,
#Color for databar type charts #Color for databar type charts
[Parameter(Mandatory = $true, ParameterSetName = "DataBar")] [Parameter(Mandatory = $true, ParameterSetName = "DataBar")]
@@ -185,7 +190,7 @@
$Address = "$($Address.Row):$($Address.Row)" $Address = "$($Address.Row):$($Address.Row)"
} }
elseif ($Address -is [OfficeOpenXml.ExcelColumn]) { elseif ($Address -is [OfficeOpenXml.ExcelColumn]) {
$Address = [OfficeOpenXml.ExcelAddress]::new(1,$address.ColumnMin,1,$address.ColumnMax).Address -replace '1','' $Address = (New-Object 'OfficeOpenXml.ExcelAddress' @(1, $address.ColumnMin, 1, $address.ColumnMax).Address) -replace '1',''
if ($Address -notmatch ':') {$Address = "$Address`:$Address"} if ($Address -notmatch ':') {$Address = "$Address`:$Address"}
} }
if ( $Address -is [string] -and $Address -match "!") {$Address = $Address -replace '^.*!',''} if ( $Address -is [string] -and $Address -match "!") {$Address = $Address -replace '^.*!',''}

99
AddDataValidation.ps1 Normal file
View File

@@ -0,0 +1,99 @@
Function Add-ExcelDataValidationRule {
<#
.Synopsis
Adds data validation to a range of cells
.Example
>
>Add-ExcelDataValidationRule -WorkSheet $PlanSheet -Range 'E2:E1001' -ValidationType Integer -Operator between -Value 0 -Value2 100 `
-ShowErrorMessage -ErrorStyle stop -ErrorTitle 'Invalid Data' -ErrorBody 'Percentage must be a whole number between 0 and 100'
This defines a validation rule on cells E2-E1001; it is an integer rule and requires a number between 0 and 100
If a value is input with a fraction, negative number, or positive number > 100 a stop dialog box appears.
.Example
>
>Add-ExcelDataValidationRule -WorkSheet $PlanSheet -Range 'B2:B1001' -ValidationType List -Formula 'values!$a$2:$a$1000'
-ShowErrorMessage -ErrorStyle stop -ErrorTitle 'Invalid Data' -ErrorBody 'You must select an item from the list'
This defines a list rule on Cells B2:1001, and the posible values are in a sheet named "values" at cells A2 to A1000
Blank cells in this range are ignored. If $ signs are left out of the fomrmula B2 would be checked against A2-A1000
B3, against A3-A1001, B4 against A4-A1002 up to B1001 beng checked against A1001-A1999
.Example
>
>Add-ExcelDataValidationRule -WorkSheet $PlanSheet -Range 'I2:N1001' -ValidationType List -ValueSet @('yes','YES','Yes')
-ShowErrorMessage -ErrorStyle stop -ErrorTitle 'Invalid Data' -ErrorBody "Select Yes or leave blank for no"
Similar to the previous example but this time provides a value set; Excel comparisons are case sesnsitive, hence 3 versions of Yes.
#>
[CmdletBinding()]
Param(
#The range of cells to be validate, e.g. "B2:C100"
[Parameter(ValueFromPipeline = $true,Position=0)]
[Alias("Address")]
$Range ,
#The worksheet where the cells should be validated
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
#An option corresponding to a choice from the 'Allow' pull down on the settings page in the Excel dialog. Any means "any allowed" i.e. no Validation
[ValidateSet('Any','Custom','DateTime','Decimal','Integer','List','TextLength','Time')]
$ValidationType,
#The operator to apply to Decimal, Integer, TextLength, DateTime and time fields, e.g. equal, between
[OfficeOpenXml.DataValidation.ExcelDataValidationOperator]$Operator = [OfficeOpenXml.DataValidation.ExcelDataValidationOperator]::equal ,
#For Decimal, Integer, TextLength, DateTime the [first] data value
$Value,
#When using the between operator, the second data value
$Value2,
#The [first] data value as a formula. Use absolute formulas $A$1 if (e.g.) you want all cells to check against the same list
$Formula,
#When using the between operator, the second data value as a formula
$Formula2,
#When using the list validation type, a set of values (rather than refering to Sheet!B$2:B$100 )
$ValueSet,
#Corresponds to the the 'Show Error alert ...' check box on error alert page in the Excel dialog
[switch]$ShowErrorMessage,
#Stop, Warning, or Infomation, corresponding to to the style setting in the Excel dialog
[OfficeOpenXml.DataValidation.ExcelDataValidationWarningStyle]$ErrorStyle,
#The title for the message box corresponding to to the title setting in the Excel dialog
[String]$ErrorTitle,
#The error message corresponding to to the Error message setting in the Excel dialog
[String]$ErrorBody,
#Corresponds to the the 'Show Input message ...' check box on input message page in the Excel dialog
[switch]$ShowPromptMessage,
#The prompt message corresponding to to the Input message setting in the Excel dialog
[String]$PromptBody,
#The title for the message box corresponding to to the title setting in the Excel dialog
[String]$PromptTitle,
#By default the 'Ignore blank' option will be selected, unless NoBlank is sepcified.
[String]$NoBlank
)
if ($Range -is [Array]) {
$null = $PSBoundParameters.Remove("Range")
$Range | Add-ExcelDataValidationRule @PSBoundParameters
}
else {
#We should accept, a worksheet and a name of a range or a cell address; a table; the address of a table; a named range; a row, a column or .Cells[ ]
if (-not $WorkSheet -and $Range.worksheet) {$WorkSheet = $Range.worksheet}
if ($Range.Address) {$Range = $Range.Address}
if ($Range -isnot [string] -or -not $WorkSheet) {Write-Warning -Message "You need to provide a worksheet and range of cells." ;return}
#else we assume Range is a range.
$validation = $WorkSheet.DataValidations."Add$ValidationType`Validation"($Range)
if ($validation.AllowsOperator) {$validation.Operator = $Operator}
if ($PSBoundParameters.ContainsKey('value')) {
$validation.Formula.Value = $Value
}
elseif ($Formula) {$validation.Formula.ExcelFormula = $Formula}
elseif ($ValueSet) {Foreach ($v in $ValueSet) {$validation.Formula.Values.Add($V)}}
if ($PSBoundParameters.ContainsKey('Value2')) {
$validation.Formula2.Value = $Value2
}
elseif ($Formula2) {$validation.Formula2.ExcelFormula = $Formula}
$validation.ShowErrorMessage = [bool]$ShowErrorMessage
$validation.ShowInputMessage = [bool]$ShowPromptMessage
$validation.AllowBlank = -not $NoBlank
if ($PromptTitle) {$validation.PromptTitle = $PromptTitle}
if ($ErrorTitle) {$validation.ErrorTitle = $ErrorTitle}
if ($PromptBody) {$validation.Prompt = $PromptBody}
if ($ErrorBody) {$validation.Error = $ErrorBody}
if ($ErrorStyle) {$validation.ErrorStyle = $ErrorStyle}
}
}

View File

@@ -27,6 +27,10 @@ if (Get-Command -Name register-argumentCompleter -ErrorAction SilentlyContinue)
Register-ArgumentCompleter -CommandName New-ConditionalText -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName New-ConditionalText -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName New-ConditionalText -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName New-ConditionalText -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName New-ConditionalText -ParameterName ConditionalTextColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName New-ConditionalText -ParameterName ConditionalTextColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName New-ExcelStyle -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName New-ExcelStyle -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName New-ExcelStyle -ParameterName BorderColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName New-ExcelStyle -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName FontColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName BorderColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName BorderColor -ScriptBlock $Function:ColorCompletion
@@ -37,5 +41,4 @@ if (Get-Command -Name register-argumentCompleter -ErrorAction SilentlyContinue)
Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName FontColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion
} }

View File

@@ -69,6 +69,8 @@
Only the unchanged rows are highlighted. Only the unchanged rows are highlighted.
#> #>
[cmdletbinding(DefaultParameterSetName)] [cmdletbinding(DefaultParameterSetName)]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification="Write host used for sub-warning level message to operator which does not form output")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification="False positives when initializing variable in begin block")]
Param( Param(
#First file to compare. #First file to compare.
[parameter(Mandatory=$true,Position=0)] [parameter(Mandatory=$true,Position=0)]
@@ -191,7 +193,7 @@
} }
} }
#if font color was specified, set it on changed properties where the same key appears in both sheets. #if font color was specified, set it on changed properties where the same key appears in both sheets.
if ($diff -and $FontColor -and ($propList -contains $Key) ) { if ($diff -and $FontColor -and (($propList -contains $Key) -or ($key -is [hashtable])) ) {
$updates = $diff.where({$_.SideIndicator -ne "=="}) | Group-object -Property $Key | Where-Object {$_.count -eq 2} $updates = $diff.where({$_.SideIndicator -ne "=="}) | Group-object -Property $Key | Where-Object {$_.count -eq 2}
if ($updates) { if ($updates) {
$XL1 = Open-ExcelPackage -path $Referencefile $XL1 = Open-ExcelPackage -path $Referencefile
@@ -219,11 +221,9 @@
} }
elseif ($diff -and $FontColor) {Write-Warning -Message "To match rows to set changed cells, you must specify -Key and it must match one of the included properties." } elseif ($diff -and $FontColor) {Write-Warning -Message "To match rows to set changed cells, you must specify -Key and it must match one of the included properties." }
#if nothing was found write a message which wont be redirected #if nothing was found write a message which will not be redirected
if (-not $diff) {Write-Host "Comparison of $Referencefile::$worksheet1 and $Differencefile::$WorkSheet2 returned no results." } if (-not $diff) {Write-Host "Comparison of $Referencefile::$worksheet1 and $Differencefile::$WorkSheet2 returned no results." }
if ($Show) { if ($Show) {
Start-Process -FilePath $Referencefile Start-Process -FilePath $Referencefile
if (-not $oneFile) { Start-Process -FilePath $Differencefile } if (-not $oneFile) { Start-Process -FilePath $Differencefile }

View File

@@ -35,15 +35,15 @@
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Opening Workbook and copying data" Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Opening Workbook and copying data"
$xlWbk = $xlApp.Workbooks.Open($Path) $xlWbk = $xlApp.Workbooks.Open($Path)
$xlWbk.Worksheets($workSheetname).Select() $xlWbk.Worksheets($workSheetname).Select()
$xlWbk.ActiveSheet.Range($range).Select() | Out-Null $null = $xlWbk.ActiveSheet.Range($range).Select()
$xlApp.Selection.Copy() | Out-Null $null = $xlApp.Selection.Copy()
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Saving copied data" Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Saving copied data"
# Get-Clipboard came in with PS5. Older versions can use [System.Windows.Clipboard] but it is ugly. # Get-Clipboard came in with PS5. Older versions can use [System.Windows.Clipboard] but it is ugly.
$image = Get-Clipboard -Format Image $image = Get-Clipboard -Format Image
$image.Save($destination, $Format) $image.Save($destination, $Format)
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Closing Excel" Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Closing Excel"
$xlWbk.ActiveSheet.Range("a1").Select() | Out-Null $null = $xlWbk.ActiveSheet.Range("a1").Select()
$xlApp.Selection.Copy() | Out-Null $null = $xlApp.Selection.Copy()
$xlApp.Quit() $xlApp.Quit()
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Completed Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Completed
if ($show) {Start-Process -FilePath $destination} if ($show) {Start-Process -FilePath $destination}

View File

@@ -3,7 +3,7 @@ function ConvertFrom-ExcelData {
.SYNOPSIS .SYNOPSIS
Reads data from a sheet, and for each row, calls a custom scriptblock with a list of property names and the row of data. Reads data from a sheet, and for each row, calls a custom scriptblock with a list of property names and the row of data.
.EXAMPLE .EXAMPLE
ConvertFrom-ExcelData .\testSQLGen.xlsx { ConvertFrom-ExcelData .\testSQLGen.xlsx {
param($propertyNames, $record) param($propertyNames, $record)

View File

@@ -50,7 +50,7 @@ Function ConvertTo-ExcelXlsx {
} }
$Excel.Visible = $false $Excel.Visible = $false
$Excel.Workbooks.Open($xlsFile.FullName) | Out-Null $null = $Excel.Workbooks.Open($xlsFile.FullName)
$Excel.ActiveWorkbook.SaveAs($xlsxPath, $xlFixedFormat) $Excel.ActiveWorkbook.SaveAs($xlsxPath, $xlFixedFormat)
$Excel.ActiveWorkbook.Close() $Excel.ActiveWorkbook.Close()
$Excel.Quit() $Excel.Quit()

View File

@@ -3,24 +3,27 @@
.SYNOPSIS .SYNOPSIS
Copies a worksheet between workbooks or within the same workbook. Copies a worksheet between workbooks or within the same workbook.
.DESCRIPTION .DESCRIPTION
Copy-ExcelWorkSheet takes Source and Destination workbook parameters; each can be the path to an XLSx file, an ExcelPackage object or an ExcelWorkbook object. Copy-ExcelWorkSheet takes a Source object which is either a worksheet,
The Source worksheet is specified by name or number (starting from 1), and the destination worksheet can be explicitly named, or a package, Workbook or path, in which case the source worksheet can be specified
or will follow the name of the source if no name is specified. by name or number (starting from 1).
The destination worksheet can be explicitly named, or will follow the name of the source if no name is specified.
The Destination workbook can be given as the path to an XLSx file, an ExcelPackage object or an ExcelWorkbook object.
.EXAMPLE .EXAMPLE
C:\> Copy-ExcelWorkSheet -SourceWorkbook Test1.xlsx -DestinationWorkbook Test2.xlsx C:\> Copy-ExcelWorkSheet -SourceWorkbook Test1.xlsx -DestinationWorkbook Test2.xlsx
This is the simplest version of the command: no source worksheet is specified so Copy-ExcelWorksheet uses the first sheet in the workbook This is the simplest version of the command: no source worksheet is specified so Copy-ExcelWorksheet uses the first sheet in the workbook
No Destination sheet is specified so the new worksheet will be the same as the one which is being copied. No Destination sheet is specified so the new worksheet will be the same as the one which is being copied.
.EXAMPLE .EXAMPLE
C:\> Copy-ExcelWorkSheet -SourceWorkbook Server1.xlsx -sourceWorksheet "Settings" -DestinationWorkbook Settings.xlsx -DestinationWorkSheet "Server1" C:\> Copy-ExcelWorkSheet -SourceWorkbook Server1.xlsx -sourceWorksheet "Settings" -DestinationWorkbook Settings.xlsx -DestinationWorksheet "Server1"
Here the Settings page from Server1's workbook is copied to the 'Server1" page of a "Settings" workbook. Here the Settings page from Server1's workbook is copied to the 'Server1" page of a "Settings" workbook.
.EXAMPLE .EXAMPLE
C:\> $excel = Open-ExcelPackage .\test.xlsx C:\> $excel = Open-ExcelPackage .\test.xlsx
C:\> Copy-ExcelWorkSheet -SourceWorkbook $excel -SourceWorkSheet "first" -DestinationWorkbook $excel -Show -DestinationWorkSheet Duplicate C:\> Copy-ExcelWorkSheet -SourceWorkbook $excel -SourceWorkSheet "first" -DestinationWorkbook $excel -Show -DestinationWorksheet Duplicate
This opens the workbook test.xlsx and copies the worksheet named "first" to a new worksheet named "Duplicate", This opens the workbook test.xlsx and copies the worksheet named "first" to a new worksheet named "Duplicate",
because -Show is specified the file is saved and opened in Excel because -Show is specified the file is saved and opened in Excel
.EXAMPLE .EXAMPLE
C:\> $excel = Open-ExcelPackage .\test.xlsx C:\> $excel = Open-ExcelPackage .\test.xlsx
C:\> Copy-ExcelWorkSheet -SourceWorkbook $excel -SourceWorkSheet 1 -DestinationWorkbook $excel -DestinationWorkSheet Duplicate C:\> Copy-ExcelWorkSheet -SourceWorkbook $excel -SourceWorkSheet 1 -DestinationWorkbook $excel -DestinationWorksheet Duplicate
C:\> Close-ExcelPackage $excel C:\> Close-ExcelPackage $excel
This is almost the same as the previous example, except source sheet is specified by position rather than name and This is almost the same as the previous example, except source sheet is specified by position rather than name and
because -Show is not specified, so other steps can be carried using the package object, at the end the file is saved by Close-ExcelPackage because -Show is not specified, so other steps can be carried using the package object, at the end the file is saved by Close-ExcelPackage
@@ -29,82 +32,99 @@
[CmdletBinding()] [CmdletBinding()]
param( param(
#An ExcelWorkbook or ExcelPackage object or the path to an XLSx file where the data is found. #An ExcelWorkbook or ExcelPackage object or the path to an XLSx file where the data is found.
[Parameter(Mandatory=$true)] [Parameter(Mandatory = $true,ValueFromPipeline=$true)]
$SourceWorkbook, [Alias('SourceWorkbook')]
$SourceObject,
#Name or number (starting from 1) of the worksheet in the source workbook (defaults to 1). #Name or number (starting from 1) of the worksheet in the source workbook (defaults to 1).
$SourceWorkSheet = 1 , $SourceWorkSheet = 1 ,
#An ExcelWorkbook or ExcelPackage object or the path to an XLSx file where the data should be copied. #An ExcelWorkbook or ExcelPackage object or the path to an XLSx file where the data should be copied.
[Parameter(Mandatory=$true)] [Parameter(Mandatory = $true)]
$DestinationWorkbook, $DestinationWorkbook,
#Name of the worksheet in the destination workbook; by default the same as the source worksheet's name. If the sheet exists it will be deleted and re-copied. #Name of the worksheet in the destination workbook; by default the same as the source worksheet's name. If the sheet exists it will be deleted and re-copied.
$DestinationWorkSheet, $DestinationWorksheet,
#if the destination is an excel package or a path, launch excel and open the file on completion. #if the destination is an excel package or a path, launch excel and open the file on completion.
[Switch]$Show [Switch]$Show
) )
#Special case - give the same path for source and destination worksheet begin {
if ($SourceWorkbook -is [System.String] -and $SourceWorkbook -eq $DestinationWorkbook) { #For the case where we are piped multiple sheets, we want to open the destination in the begin and close it in the end.
if (-not $DestinationWorkSheet) {Write-Warning -Message "You must specify a destination worksheet name if copying within the same workbook."; return} if ($DestinationWorkbook -is [OfficeOpenXml.ExcelPackage] ) {
else { if ($Show) {$package2 = $DestinationWorkbook}
Write-Verbose -Message "Copying " $DestinationWorkbook = $DestinationWorkbook.Workbook
$excel = Open-ExcelPackage -Path $SourceWorkbook }
if (-not $excel.Workbook.Worksheets[$Sourceworksheet]) { elseif ($DestinationWorkbook -is [string] -and ($DestinationWorkbook -ne $SourceObject)) {
Write-Warning -Message "Could not find Worksheet $sourceWorksheet in $sourceWorkbook" $package2 = Open-ExcelPackage -Create -Path $DestinationWorkbook
Close-ExcelPackage -ExcelPackage $excel -NoSave $DestinationWorkbook = $package2.Workbook
return }
} }
elseif ($excel.Workbook.Worksheets[$Sourceworksheet].name -eq $DestinationWorkSheet) { process {
Write-Warning -Message "The destination worksheet name is the same as the source. " #Special case - given the same path for source and destination worksheet
Close-ExcelPackage -ExcelPackage $excel -NoSave if ($SourceObject -is [System.String] -and $SourceObject -eq $DestinationWorkbook) {
return if (-not $DestinationWorksheet) {Write-Warning -Message "You must specify a destination worksheet name if copying within the same workbook."; return}
}
else { else {
$null = Add-WorkSheet -ExcelPackage $Excel -WorkSheetname $DestinationWorkSheet -CopySource ($excel.Workbook.Worksheets[$SourceWorkSheet]) Write-Verbose -Message "Copying "
Close-ExcelPackage -ExcelPackage $excel -Show:$Show $excel = Open-ExcelPackage -Path $SourceObject
return if (-not $excel.Workbook.Worksheets[$Sourceworksheet]) {
Write-Warning -Message "Could not find Worksheet $sourceWorksheet in $SourceObject"
Close-ExcelPackage -ExcelPackage $excel -NoSave
return
}
elseif ($excel.Workbook.Worksheets[$Sourceworksheet].name -eq $DestinationWorksheet) {
Write-Warning -Message "The destination worksheet name is the same as the source. "
Close-ExcelPackage -ExcelPackage $excel -NoSave
return
}
else {
$null = Add-WorkSheet -ExcelPackage $excel -WorkSheetname $DestinationWorksheet -CopySource ($excel.Workbook.Worksheets[$SourceWorkSheet])
Close-ExcelPackage -ExcelPackage $excel -Show:$Show
return
}
}
}
else {
if ($SourceObject -is [OfficeOpenXml.ExcelWorksheet]) {$sourceWs = $SourceObject}
elseif ($SourceObject -is [OfficeOpenXml.ExcelWorkbook]) {$sourceWs = $SourceObject.Worksheets[$SourceWorkSheet]}
elseif ($SourceObject -is [OfficeOpenXml.ExcelPackage] ) {$sourceWs = $SourceObject.Workbook.Worksheets[$SourceWorkSheet]}
else {
$SourceObject = (Resolve-Path $SourceObject).ProviderPath
try {
Write-Verbose "Opening worksheet '$Worksheetname' in Excel workbook '$SourceObject'."
$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $SourceObject, 'Open', 'Read' , 'ReadWrite'
$package1 = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream
$sourceWs = $Package1.Workbook.Worksheets[$SourceWorkSheet]
}
catch {Write-Warning -Message "Could not open $SourceObject - the error was '$($_.exception.message)' " ; return}
}
if (-not $sourceWs) {Write-Warning -Message "Could not find worksheet '$Sourceworksheet' in the source workbook." ; return}
else {
try {
if ($DestinationWorkbook -isnot [OfficeOpenXml.ExcelWorkbook]) {
Write-Warning "Not a valid workbook" ; return
}
#check if we have a destination sheet name and set one if not. Because we might loop round check $psBoundParameters, not the variable.
if (-not $PSBoundParameters['DestinationWorksheet']) {
#if we are piped files, use the file name without the extension as the destination sheet name, Otherwise use the source sheet name
if ($_ -is [System.IO.FileInfo]) {$DestinationWorksheet = $_.name -replace '\.xlsx$', '' }
else { $DestinationWorksheet = $sourceWs.Name}
}
if ($DestinationWorkbook.Worksheets[$DestinationWorksheet]) {
Write-Verbose "Destination workbook already has a sheet named '$DestinationWorksheet', deleting it."
$DestinationWorkbook.Worksheets.Delete($DestinationWorksheet)
}
Write-Verbose "Copying '$($sourcews.name)' from $($SourceObject) to '$($DestinationWorksheet)' in $($PSBoundParameters['DestinationWorkbook'])"
$null = Add-WorkSheet -ExcelWorkbook $DestinationWorkbook -WorkSheetname $DestinationWorksheet -CopySource $sourceWs
#Leave the destination open but close the source - if we're copying more than one sheet we'll re-open it and live with the inefficiency
if ($stream) {$stream.Close() }
if ($package1) {Close-ExcelPackage -ExcelPackage $package1 -NoSave }
}
catch {Write-Warning -Message "Could not write to sheet '$DestinationWorksheet' in the destination workbook. Error was '$($_.exception.message)'" ; return}
} }
} }
} }
else { end {
if ($SourceWorkbook -is [OfficeOpenXml.ExcelWorkbook]) {$sourcews=$SourceWorkbook.Worksheets[$SourceWorkSheet]} #OK Now we can close the destination package
elseif ($SourceWorkbook -is [OfficeOpenXml.ExcelPackage] ) {$sourcews=$SourceWorkbook.Workbook.Worksheets[$SourceWorkSheet]} if ($package2) {Close-ExcelPackage -ExcelPackage $package2 -Show:$Show }
else { if ($Show -and -not $package2) {
$SourceWorkbook = (Resolve-Path $SourceWorkbook).ProviderPath Write-Warning -Message "-Show only works if the Destination workbook is given as a file path or an ExcelPackage object."
try {
Write-Verbose "Opening worksheet '$Worksheetname' in Excel workbook '$SourceWorkbook'."
$Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $SourceWorkbook, 'Open', 'Read' ,'ReadWrite'
$Package1 = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream
$sourceWs = $Package1.Workbook.Worksheets[$SourceWorkSheet]
}
catch {Write-Warning -Message "Could not open $SourceWorkbook" ; return}
}
if (-not $sourceWs) {Write-Warning -Message "Could not find worksheet '$Sourceworksheet' in the source workbook." ; return}
else {
try {
if ($DestinationWorkbook -is [OfficeOpenXml.ExcelWorkbook]) {
$wb = $DestinationWorkbook
}
elseif ($DestinationWorkbook -is [OfficeOpenXml.ExcelPackage] ) {
$wb = $DestinationWorkbook.workbook
if ($show) {$package2 =$DestinationWorkbook}
}
else {
$package2 = Open-ExcelPackage -Create -Path $DestinationWorkbook
$wb = $package2.Workbook
}
if (-not $DestinationWorkSheet) {$DestinationWorkSheet = $SourceWs.Name}
if ($wb.Worksheets[$DestinationWorkSheet]) {
Write-Verbose "Destination workbook already has a sheet named '$DestinationWorkSheet', deleting it."
$wb.Worksheets.Delete($DestinationWorkSheet)
}
Write-Verbose "Copying $($SourceWorkSheet) from $($SourceWorkbook) to $($DestinationWorkSheet) in $($DestinationWorkbook)"
$null = Add-WorkSheet -ExcelWorkbook $wb -WorkSheetname $DestinationWorkSheet -CopySource $sourceWs
if ($package1) {Close-ExcelPackage -ExcelPackage $Package1 -NoSave }
if ($package2) {Close-ExcelPackage -ExcelPackage $Package2 -Show:$show }
if ($show -and $DestinationWorkbook -is [OfficeOpenXml.ExcelWorkbook]) {
Write-Warning -Message "-Show only works if the Destination workbook is given as a file path or an ExcelPackage object."
}
}
catch {Write-Warning -Message "Could not write to sheet '$DestinationWorkSheet' in the destination workbook" ; return}
} }
} }
} }

View File

@@ -1,28 +0,0 @@
param(
[Switch]$DontCreateZip
)
##
# Used in Appveyor.yml
##
$PSVersionTable.PSVersion
## Create the zip before the tests run
## Otherwise the EPPlus.dll is in use after the Pester run
$ModuleVersion = (Get-Content -Raw .\ImportExcel.psd1) | Invoke-Expression | ForEach-Object ModuleVersion
if (!$DontCreateZip) {
$dest = "ImportExcel-{0}-{1}.zip" -f $ModuleVersion, (Get-Date).ToString("yyyyMMddHHmmss")
Compress-Archive -Path . -DestinationPath .\$dest
}
if ($null -eq (Get-Module -ListAvailable pester)) {
Install-Module -Name Pester -Repository PSGallery -Force -Scope CurrentUser
}
$result = Invoke-Pester -Script $PSScriptRoot\__tests__ -Verbose -PassThru
if ($result.FailedCount -gt 0) {
throw "$($result.FailedCount) tests failed."
}

Binary file not shown.

View File

@@ -0,0 +1,21 @@
# Creates a worksheet, addes a chart and then a Linear trendline
$xlfile = "$env:TEMP\trendLine.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$data = ConvertFrom-Csv @"
Region,Item,TotalSold
West,screws,60
South,lemon,48
South,apple,71
East,screwdriver,70
East,kiwi,32
West,screwdriver,1
South,melon,21
East,apple,79
South,apple,68
South,avocado,73
"@
$cd = New-ExcelChartDefinition -XRange Region -YRange TotalSold -ChartType ColumnClustered -ChartTrendLine Linear
$data | Export-Excel $xlfile -ExcelChartDefinition $cd -AutoNameRange -Show

View File

@@ -0,0 +1,27 @@
$xlfile = "$env:TEMP\visitors.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$data = ConvertFrom-Csv @"
Week, TotalVisitors
1,11916
2,11665
3,13901
4,15444
5,21592
6,15057
7,26187
8,20662
9,28935
10,32443
"@
$cd = New-ExcelChartDefinition `
-XRange Week `
-YRange TotalVisitors `
-Title "No. Of Visitors" `
-ChartType ColumnClustered `
-NoLegend `
-ChartTrendLine Linear
$data | Export-Excel $xlfile -Show -AutoNameRange -AutoSize -TableName Visitors -ExcelChartDefinition $cd

View File

@@ -1,6 +1,6 @@
try {. $PSScriptRoot\..\..\LoadPSD1.ps1} catch {} try {. $PSScriptRoot\..\..\LoadPSD1.ps1} catch {}
$f = ".\dashboard.xlsx" $f = "$env:temp\dashboard.xlsx"
Remove-Item $f -ErrorAction Ignore Remove-Item $f -ErrorAction Ignore
$data = @" $data = @"
@@ -51,7 +51,7 @@ Set-Format -Address $sheet1.Cells["E2:G2"] -BorderBottom $BorderBottom -BorderCo
Set-Format -Address $sheet1.Cells["I2:K2"] -BorderBottom $BorderBottom -BorderColor $BorderColor Set-Format -Address $sheet1.Cells["I2:K2"] -BorderBottom $BorderBottom -BorderColor $BorderColor
Set-Format -Address $sheet1.Cells["M2:O2"] -BorderBottom $BorderBottom -BorderColor $BorderColor Set-Format -Address $sheet1.Cells["M2:O2"] -BorderBottom $BorderBottom -BorderColor $BorderColor
Set-Format -Address $sheet1.Cells["A2:C8"] -FontColor GrayText Set-Format -Address $sheet1.Cells["A2:C8"] -FontColor Gray
$HorizontalAlignment = "Center" $HorizontalAlignment = "Center"
Set-Format -Address $sheet1.Cells["F1"] -HorizontalAlignment $HorizontalAlignment -Bold -Value Revenue Set-Format -Address $sheet1.Cells["F1"] -HorizontalAlignment $HorizontalAlignment -Bold -Value Revenue
@@ -69,4 +69,4 @@ Set-Format -Address $sheet1.Cells["I10"] -Formula "=Sum(I3:I8)" -Bold
Set-Format -Address $sheet1.Cells["M10"] -Formula "=Sum(M3:M8)" -Bold Set-Format -Address $sheet1.Cells["M10"] -Formula "=Sum(M3:M8)" -Bold
Set-Format -Address $sheet1.Cells["O10"] -Formula "=Sum(O3:O8)" -Bold Set-Format -Address $sheet1.Cells["O10"] -Formula "=Sum(O3:O8)" -Bold
Close-ExcelPackage $excel -Show Close-ExcelPackage $excel -Show

View File

@@ -0,0 +1,89 @@
<#
This is an example on how to customize Export-Excel to your liking.
First select a name for your function, in ths example its "Out-Excel" you can even set the name to "Export-Excel".
You can customize the following things:
1. To add parameters to the function define them in "param()", here I added "Preset1" and "Preset2".
The parameters need to be removed after use (see comments and code below).
2. To remove parameters from the function add them to the list under "$_.Name -notmatch", I removed "Now".
3. Add your custom code, here I defined what the Presets do:
Preset1 configure the TableStyle, name the table depending on WorksheetName and FreezeTopRow.
Preset2 will set AutoFilter and add the Title "Daily Report".
(see comments and code below).
#>
Function Out-Excel {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param(
[switch]
${Preset1},
[switch]
${Preset2}
)
DynamicParam {
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
foreach ($P in (Get-Command -Name Export-Excel).Parameters.values.where( { $_.Name -notmatch 'Verbose|Debug|Action$|Variable$|Buffer$|Now' })) {
$paramDictionary.Add($P.Name, [System.Management.Automation.RuntimeDefinedParameter]::new( $P.Name, $P.ParameterType, $P.Attributes ) )
}
return $paramDictionary
}
begin {
try {
# Run you custom code here if it need to run before calling Export-Excel.
$PSBoundParameters['Now'] = $true
if ($Preset1) {
$PSBoundParameters['TableStyle'] = 'Medium7'
$PSBoundParameters['FreezeTopRow'] = $true
if ($PSBoundParameters['WorksheetName'] -and -not $PSBoundParameters['TableName']) {
$PSBoundParameters['TableName'] = $PSBoundParameters['WorksheetName'] + '_Table'
}
}
elseif ($Preset2) {
$PSBoundParameters['Title'] = 'Daily Report'
$PSBoundParameters['AutoFilter'] = $true
}
# Remove the extra params we added as Export-Excel will not know what to do with them:
$null = $PSBoundParameters.Remove('Preset1')
$null = $PSBoundParameters.Remove('Preset2')
# The rest of the code was auto generated.
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) {
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Excel', [System.Management.Automation.CommandTypes]::Function)
# You can add a pipe after @PSBoundParameters to manipulate the output.
$scriptCmd = { & $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline()
$steppablePipeline.Begin($PSCmdlet)
}
catch {
throw
}
}
process {
try {
$steppablePipeline.Process($_)
}
catch {
throw
}
}
end {
try {
$steppablePipeline.End()
}
catch {
throw
}
}
<#
.ForwardHelpTargetName Export-Excel
.ForwardHelpCategory Function
#>
}

View File

@@ -0,0 +1,85 @@
#region Setup
<#
This examples demos three types of validation:
* Creating a list using a PowerShell array
* Creating a list data from another Excel Worksheet
* Creating a rule for numbers to be between 0 an 10000
Run the script then try"
* Add random data in Column B
* Then choose from the drop down list
* Add random data in Column C
* Then choose from the drop down list
* Add .01 in column F
#>
try {. $PSScriptRoot\..\..\LoadPSD1.ps1} catch {}
$path = "$Env:TEMP\DataValidation.xlsx"
Remove-Item $path -ErrorAction SilentlyContinue
$data = ConvertFrom-Csv -InputObject @"
ID,Region,Product,Quantity,Price
12001,North,Nails,37,3.99
12002,South,Hammer,5,12.10
12003,East,Saw,12,15.37
12010,West,Drill,20,8
12011,North,Crowbar,7,23.48
"@
# Export the raw data
$excelPackage = $Data |
Export-Excel -WorksheetName "Sales" -Path $path -PassThru
# Creates a sheet with data that will be used in a validation rule
$excelPackage = @('Chisel', 'Crowbar', 'Drill', 'Hammer', 'Nails', 'Saw', 'Screwdriver', 'Wrench') |
Export-excel -ExcelPackage $excelPackage -WorksheetName Values -PassThru
#endregion
#region Creating a list using a PowerShell array
$ValidationParams = @{
WorkSheet = $excelPackage.sales
ShowErrorMessage = $true
ErrorStyle = 'stop'
ErrorTitle = 'Invalid Data'
}
$MoreValidationParams = @{
Range = 'B2:B1001'
ValidationType = 'List'
ValueSet = @('North', 'South', 'East', 'West')
ErrorBody = "You must select an item from the list."
}
Add-ExcelDataValidationRule @ValidationParams @MoreValidationParams
#endregion
#region Creating a list data from another Excel Worksheet
$MoreValidationParams = @{
Range = 'C2:C1001'
ValidationType = 'List'
Formula = 'values!$a$1:$a$10'
ErrorBody = "You must select an item from the list.`r`nYou can add to the list on the values page" #Bucket
}
Add-ExcelDataValidationRule @ValidationParams @MoreValidationParams
#endregion
#region Creating a rule for numbers to be between 0 an 10000
$MoreValidationParams = @{
Range = 'F2:F1001'
ValidationType = 'Integer'
Operator = 'between'
Value = 0
Value2 = 10000
ErrorBody = 'Quantity must be a whole number between 0 and 10000'
}
Add-ExcelDataValidationRule @ValidationParams @MoreValidationParams
#endregion
#region Close Package
Close-ExcelPackage -ExcelPackage $excelPackage -Show
#endregion

View File

@@ -0,0 +1,24 @@
$data = ConvertFrom-Csv @'
Item,Quantity,Price,Total Cost
Footballs,9,21.95,197.55
Cones,36,7.99,287.64
Shin Guards,14,10.95,153.3
Turf Shoes,22,79.95,1758.9
Baseballs,68,7.99,543.32
Baseball Gloves,31,65.00,2015.00
Baseball Bats,38,159.00,6042.00
'@
$f = "$env:TEMP\styles.xlsx"
Remove-Item $f -ErrorAction SilentlyContinue
$pkg = $data | Export-Excel -Path $f -AutoSize -PassThru
$ws = $pkg.Workbook.Worksheets["Sheet1"]
Set-ExcelRange -WorkSheet $ws -Range "A2:C6" -BackgroundColor PeachPuff -FontColor Purple -FontSize 12 -Width 12
Set-ExcelRange -WorkSheet $ws -Range "D2:D6" -BackgroundColor WhiteSmoke -FontColor Orange -Bold -FontSize 12 -Width 12
Set-ExcelRange -WorkSheet $ws -Range "A1:D1" -BackgroundColor BlueViolet -FontColor Wheat -FontSize 12 -Width 12
Set-ExcelRange -WorkSheet $ws -Range "A:A" -Width 15
Close-ExcelPackage -ExcelPackage $pkg -Show

View File

@@ -0,0 +1,101 @@
Race,Date,FinishPosition,Driver,GridPosition,Team,Points
Australian,25/03/2018,1,Sebastian Vettel,3,Ferrari,25
Australian,25/03/2018,2,Lewis Hamilton,1,Mercedes,18
Australian,25/03/2018,3,Kimi Räikkönen,2,Ferrari,15
Australian,25/03/2018,4,Daniel Ricciardo,8,Red Bull Racing-TAG Heuer,12
Australian,25/03/2018,5,Fernando Alonso,10,McLaren-Renault,10
Australian,25/03/2018,6,Max Verstappen,4,Red Bull Racing-TAG Heuer,8
Australian,25/03/2018,7,Nico Hülkenberg,7,Renault,6
Australian,25/03/2018,8,Valtteri Bottas,15,Mercedes,4
Australian,25/03/2018,9,Stoffel Vandoorne,11,McLaren-Renault,2
Australian,25/03/2018,10,Carlos Sainz,9,Renault,1
Bahrain,08/04/2018,1,Sebastian Vettel,1,Ferrari,25
Bahrain,08/04/2018,2,Valtteri Bottas,3,Mercedes,18
Bahrain,08/04/2018,3,Lewis Hamilton,9,Mercedes,15
Bahrain,08/04/2018,4,Pierre Gasly,5,STR-Honda,12
Bahrain,08/04/2018,5,Kevin Magnussen,6,Haas-Ferrari,10
Bahrain,08/04/2018,6,Nico Hülkenberg,7,Renault,8
Bahrain,08/04/2018,7,Fernando Alonso,13,McLaren-Renault,6
Bahrain,08/04/2018,8,Stoffel Vandoorne,14,McLaren-Renault,4
Bahrain,08/04/2018,9,Marcus Ericsson,17,Sauber-Ferrari,2
Bahrain,08/04/2018,10,Esteban Ocon,8,Force India-Mercedes,1
Chinese,15/04/2018,1,Daniel Ricciardo,6,Red Bull Racing-TAG Heuer,25
Chinese,15/04/2018,2,Valtteri Bottas,3,Mercedes,18
Chinese,15/04/2018,3,Kimi Räikkönen,2,Ferrari,15
Chinese,15/04/2018,4,Lewis Hamilton,4,Mercedes,12
Chinese,15/04/2018,5,Max Verstappen,5,Red Bull Racing-TAG Heuer,10
Chinese,15/04/2018,6,Nico Hülkenberg,7,Renault,8
Chinese,15/04/2018,7,Fernando Alonso,13,McLaren-Renault,6
Chinese,15/04/2018,8,Sebastian Vettel,1,Ferrari,4
Chinese,15/04/2018,9,Carlos Sainz,9,Renault,2
Chinese,15/04/2018,10,Kevin Magnussen,11,Haas-Ferrari,1
Azerbaijan,29/04/2018,1,Lewis Hamilton,2,Mercedes,25
Azerbaijan,29/04/2018,2,Kimi Räikkönen,6,Ferrari,18
Azerbaijan,29/04/2018,3,Sergio Pérez,8,Force India-Mercedes,15
Azerbaijan,29/04/2018,4,Sebastian Vettel,1,Ferrari,12
Azerbaijan,29/04/2018,5,Carlos Sainz,9,Renault,10
Azerbaijan,29/04/2018,6,Charles Leclerc,13,Sauber-Ferrari,8
Azerbaijan,29/04/2018,7,Fernando Alonso,12,McLaren-Renault,6
Azerbaijan,29/04/2018,8,Lance Stroll,10,Williams-Mercedes,4
Azerbaijan,29/04/2018,9,Stoffel Vandoorne,16,McLaren-Renault,2
Azerbaijan,29/04/2018,10,Brendon Hartley,19,STR-Honda,1
Spanish,13/05/2018,1,Lewis Hamilton,1,Mercedes,25
Spanish,13/05/2018,2,Valtteri Bottas,2,Mercedes,18
Spanish,13/05/2018,3,Max Verstappen,5,Red Bull Racing-TAG Heuer,15
Spanish,13/05/2018,4,Sebastian Vettel,3,Ferrari,12
Spanish,13/05/2018,5,Daniel Ricciardo,6,Red Bull Racing-TAG Heuer,10
Spanish,13/05/2018,6,Kevin Magnussen,7,Haas-Ferrari,8
Spanish,13/05/2018,7,Carlos Sainz,9,Renault,6
Spanish,13/05/2018,8,Fernando Alonso,8,McLaren-Renault,4
Spanish,13/05/2018,9,Sergio Pérez,15,Force India-Mercedes,2
Spanish,13/05/2018,10,Charles Leclerc,14,Sauber-Ferrari,1
Monaco,27/05/2018,1,Daniel Ricciardo,1,Red Bull Racing-TAG Heuer,25
Monaco,27/05/2018,2,Sebastian Vettel,2,Ferrari,18
Monaco,27/05/2018,3,Lewis Hamilton,3,Mercedes,15
Monaco,27/05/2018,4,Kimi Räikkönen,4,Ferrari,12
Monaco,27/05/2018,5,Valtteri Bottas,5,Mercedes,10
Monaco,27/05/2018,6,Esteban Ocon,6,Force India-Mercedes,8
Monaco,27/05/2018,7,Pierre Gasly,10,STR-Honda,6
Monaco,27/05/2018,8,Nico Hülkenberg,11,Renault,4
Monaco,27/05/2018,9,Max Verstappen,20,Red Bull Racing-TAG Heuer,2
Monaco,27/05/2018,10,Carlos Sainz,8,Renault,1
Canadian,10/06/2018,1,Sebastian Vettel,1,Ferrari,25
Canadian,10/06/2018,2,Valtteri Bottas,2,Mercedes,18
Canadian,10/06/2018,3,Max Verstappen,3,Red Bull Racing-TAG Heuer,15
Canadian,10/06/2018,4,Daniel Ricciardo,6,Red Bull Racing-TAG Heuer,12
Canadian,10/06/2018,5,Lewis Hamilton,4,Mercedes,10
Canadian,10/06/2018,6,Kimi Räikkönen,5,Ferrari,8
Canadian,10/06/2018,7,Nico Hülkenberg,7,Renault,6
Canadian,10/06/2018,8,Carlos Sainz,9,Renault,4
Canadian,10/06/2018,9,Esteban Ocon,8,Force India-Mercedes,2
Canadian,10/06/2018,10,Charles Leclerc,13,Sauber-Ferrari,1
French,24/06/2018,1,Lewis Hamilton,1,Mercedes,25
French,24/06/2018,2,Max Verstappen,4,Red Bull Racing-TAG Heuer,18
French,24/06/2018,3,Kimi Räikkönen,6,Ferrari,15
French,24/06/2018,4,Daniel Ricciardo,5,Red Bull Racing-TAG Heuer,12
French,24/06/2018,5,Sebastian Vettel,3,Ferrari,10
French,24/06/2018,6,Kevin Magnussen,9,Haas-Ferrari,8
French,24/06/2018,7,Valtteri Bottas,2,Mercedes,6
French,24/06/2018,8,Carlos Sainz,7,Renault,4
French,24/06/2018,9,Nico Hülkenberg,12,Renault,2
French,24/06/2018,10,Charles Leclerc,8,Sauber-Ferrari,1
Austrian,01/07/2018,1,Max Verstappen,4,Red Bull Racing-TAG Heuer,25
Austrian,01/07/2018,2,Kimi Räikkönen,3,Ferrari,18
Austrian,01/07/2018,3,Sebastian Vettel,6,Ferrari,15
Austrian,01/07/2018,4,Romain Grosjean,5,Haas-Ferrari,12
Austrian,01/07/2018,5,Kevin Magnussen,8,Haas-Ferrari,10
Austrian,01/07/2018,6,Esteban Ocon,11,Force India-Mercedes,8
Austrian,01/07/2018,7,Sergio Pérez,15,Force India-Mercedes,6
Austrian,01/07/2018,8,Fernando Alonso,20,McLaren-Renault,4
Austrian,01/07/2018,9,Charles Leclerc,17,Sauber-Ferrari,2
Austrian,01/07/2018,10,Marcus Ericsson,18,Sauber-Ferrari,1
British,08/07/2018,1,Sebastian Vettel,2,Ferrari,25
British,08/07/2018,2,Lewis Hamilton,1,Mercedes,18
British,08/07/2018,3,Kimi Räikkönen,3,Ferrari,15
British,08/07/2018,4,Valtteri Bottas,4,Mercedes,12
British,08/07/2018,5,Daniel Ricciardo,6,Red Bull Racing-TAG Heuer,10
British,08/07/2018,6,Nico Hülkenberg,11,Renault,8
British,08/07/2018,7,Esteban Ocon,10,Force India-Mercedes,6
British,08/07/2018,8,Fernando Alonso,13,McLaren-Renault,4
British,08/07/2018,9,Kevin Magnussen,7,Haas-Ferrari,2
British,08/07/2018,10,Sergio Pérez,12,Force India-Mercedes,1
1 Race Date FinishPosition Driver GridPosition Team Points
2 Australian 25/03/2018 1 Sebastian Vettel 3 Ferrari 25
3 Australian 25/03/2018 2 Lewis Hamilton 1 Mercedes 18
4 Australian 25/03/2018 3 Kimi Räikkönen 2 Ferrari 15
5 Australian 25/03/2018 4 Daniel Ricciardo 8 Red Bull Racing-TAG Heuer 12
6 Australian 25/03/2018 5 Fernando Alonso 10 McLaren-Renault 10
7 Australian 25/03/2018 6 Max Verstappen 4 Red Bull Racing-TAG Heuer 8
8 Australian 25/03/2018 7 Nico Hülkenberg 7 Renault 6
9 Australian 25/03/2018 8 Valtteri Bottas 15 Mercedes 4
10 Australian 25/03/2018 9 Stoffel Vandoorne 11 McLaren-Renault 2
11 Australian 25/03/2018 10 Carlos Sainz 9 Renault 1
12 Bahrain 08/04/2018 1 Sebastian Vettel 1 Ferrari 25
13 Bahrain 08/04/2018 2 Valtteri Bottas 3 Mercedes 18
14 Bahrain 08/04/2018 3 Lewis Hamilton 9 Mercedes 15
15 Bahrain 08/04/2018 4 Pierre Gasly 5 STR-Honda 12
16 Bahrain 08/04/2018 5 Kevin Magnussen 6 Haas-Ferrari 10
17 Bahrain 08/04/2018 6 Nico Hülkenberg 7 Renault 8
18 Bahrain 08/04/2018 7 Fernando Alonso 13 McLaren-Renault 6
19 Bahrain 08/04/2018 8 Stoffel Vandoorne 14 McLaren-Renault 4
20 Bahrain 08/04/2018 9 Marcus Ericsson 17 Sauber-Ferrari 2
21 Bahrain 08/04/2018 10 Esteban Ocon 8 Force India-Mercedes 1
22 Chinese 15/04/2018 1 Daniel Ricciardo 6 Red Bull Racing-TAG Heuer 25
23 Chinese 15/04/2018 2 Valtteri Bottas 3 Mercedes 18
24 Chinese 15/04/2018 3 Kimi Räikkönen 2 Ferrari 15
25 Chinese 15/04/2018 4 Lewis Hamilton 4 Mercedes 12
26 Chinese 15/04/2018 5 Max Verstappen 5 Red Bull Racing-TAG Heuer 10
27 Chinese 15/04/2018 6 Nico Hülkenberg 7 Renault 8
28 Chinese 15/04/2018 7 Fernando Alonso 13 McLaren-Renault 6
29 Chinese 15/04/2018 8 Sebastian Vettel 1 Ferrari 4
30 Chinese 15/04/2018 9 Carlos Sainz 9 Renault 2
31 Chinese 15/04/2018 10 Kevin Magnussen 11 Haas-Ferrari 1
32 Azerbaijan 29/04/2018 1 Lewis Hamilton 2 Mercedes 25
33 Azerbaijan 29/04/2018 2 Kimi Räikkönen 6 Ferrari 18
34 Azerbaijan 29/04/2018 3 Sergio Pérez 8 Force India-Mercedes 15
35 Azerbaijan 29/04/2018 4 Sebastian Vettel 1 Ferrari 12
36 Azerbaijan 29/04/2018 5 Carlos Sainz 9 Renault 10
37 Azerbaijan 29/04/2018 6 Charles Leclerc 13 Sauber-Ferrari 8
38 Azerbaijan 29/04/2018 7 Fernando Alonso 12 McLaren-Renault 6
39 Azerbaijan 29/04/2018 8 Lance Stroll 10 Williams-Mercedes 4
40 Azerbaijan 29/04/2018 9 Stoffel Vandoorne 16 McLaren-Renault 2
41 Azerbaijan 29/04/2018 10 Brendon Hartley 19 STR-Honda 1
42 Spanish 13/05/2018 1 Lewis Hamilton 1 Mercedes 25
43 Spanish 13/05/2018 2 Valtteri Bottas 2 Mercedes 18
44 Spanish 13/05/2018 3 Max Verstappen 5 Red Bull Racing-TAG Heuer 15
45 Spanish 13/05/2018 4 Sebastian Vettel 3 Ferrari 12
46 Spanish 13/05/2018 5 Daniel Ricciardo 6 Red Bull Racing-TAG Heuer 10
47 Spanish 13/05/2018 6 Kevin Magnussen 7 Haas-Ferrari 8
48 Spanish 13/05/2018 7 Carlos Sainz 9 Renault 6
49 Spanish 13/05/2018 8 Fernando Alonso 8 McLaren-Renault 4
50 Spanish 13/05/2018 9 Sergio Pérez 15 Force India-Mercedes 2
51 Spanish 13/05/2018 10 Charles Leclerc 14 Sauber-Ferrari 1
52 Monaco 27/05/2018 1 Daniel Ricciardo 1 Red Bull Racing-TAG Heuer 25
53 Monaco 27/05/2018 2 Sebastian Vettel 2 Ferrari 18
54 Monaco 27/05/2018 3 Lewis Hamilton 3 Mercedes 15
55 Monaco 27/05/2018 4 Kimi Räikkönen 4 Ferrari 12
56 Monaco 27/05/2018 5 Valtteri Bottas 5 Mercedes 10
57 Monaco 27/05/2018 6 Esteban Ocon 6 Force India-Mercedes 8
58 Monaco 27/05/2018 7 Pierre Gasly 10 STR-Honda 6
59 Monaco 27/05/2018 8 Nico Hülkenberg 11 Renault 4
60 Monaco 27/05/2018 9 Max Verstappen 20 Red Bull Racing-TAG Heuer 2
61 Monaco 27/05/2018 10 Carlos Sainz 8 Renault 1
62 Canadian 10/06/2018 1 Sebastian Vettel 1 Ferrari 25
63 Canadian 10/06/2018 2 Valtteri Bottas 2 Mercedes 18
64 Canadian 10/06/2018 3 Max Verstappen 3 Red Bull Racing-TAG Heuer 15
65 Canadian 10/06/2018 4 Daniel Ricciardo 6 Red Bull Racing-TAG Heuer 12
66 Canadian 10/06/2018 5 Lewis Hamilton 4 Mercedes 10
67 Canadian 10/06/2018 6 Kimi Räikkönen 5 Ferrari 8
68 Canadian 10/06/2018 7 Nico Hülkenberg 7 Renault 6
69 Canadian 10/06/2018 8 Carlos Sainz 9 Renault 4
70 Canadian 10/06/2018 9 Esteban Ocon 8 Force India-Mercedes 2
71 Canadian 10/06/2018 10 Charles Leclerc 13 Sauber-Ferrari 1
72 French 24/06/2018 1 Lewis Hamilton 1 Mercedes 25
73 French 24/06/2018 2 Max Verstappen 4 Red Bull Racing-TAG Heuer 18
74 French 24/06/2018 3 Kimi Räikkönen 6 Ferrari 15
75 French 24/06/2018 4 Daniel Ricciardo 5 Red Bull Racing-TAG Heuer 12
76 French 24/06/2018 5 Sebastian Vettel 3 Ferrari 10
77 French 24/06/2018 6 Kevin Magnussen 9 Haas-Ferrari 8
78 French 24/06/2018 7 Valtteri Bottas 2 Mercedes 6
79 French 24/06/2018 8 Carlos Sainz 7 Renault 4
80 French 24/06/2018 9 Nico Hülkenberg 12 Renault 2
81 French 24/06/2018 10 Charles Leclerc 8 Sauber-Ferrari 1
82 Austrian 01/07/2018 1 Max Verstappen 4 Red Bull Racing-TAG Heuer 25
83 Austrian 01/07/2018 2 Kimi Räikkönen 3 Ferrari 18
84 Austrian 01/07/2018 3 Sebastian Vettel 6 Ferrari 15
85 Austrian 01/07/2018 4 Romain Grosjean 5 Haas-Ferrari 12
86 Austrian 01/07/2018 5 Kevin Magnussen 8 Haas-Ferrari 10
87 Austrian 01/07/2018 6 Esteban Ocon 11 Force India-Mercedes 8
88 Austrian 01/07/2018 7 Sergio Pérez 15 Force India-Mercedes 6
89 Austrian 01/07/2018 8 Fernando Alonso 20 McLaren-Renault 4
90 Austrian 01/07/2018 9 Charles Leclerc 17 Sauber-Ferrari 2
91 Austrian 01/07/2018 10 Marcus Ericsson 18 Sauber-Ferrari 1
92 British 08/07/2018 1 Sebastian Vettel 2 Ferrari 25
93 British 08/07/2018 2 Lewis Hamilton 1 Mercedes 18
94 British 08/07/2018 3 Kimi Räikkönen 3 Ferrari 15
95 British 08/07/2018 4 Valtteri Bottas 4 Mercedes 12
96 British 08/07/2018 5 Daniel Ricciardo 6 Red Bull Racing-TAG Heuer 10
97 British 08/07/2018 6 Nico Hülkenberg 11 Renault 8
98 British 08/07/2018 7 Esteban Ocon 10 Force India-Mercedes 6
99 British 08/07/2018 8 Fernando Alonso 13 McLaren-Renault 4
100 British 08/07/2018 9 Kevin Magnussen 7 Haas-Ferrari 2
101 British 08/07/2018 10 Sergio Pérez 12 Force India-Mercedes 1

View File

@@ -0,0 +1,10 @@
$xlfile = "$env:TEMP\Points.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$PivotTableDefinition = New-PivotTableDefinition -Activate -PivotTableName Points `
-PivotRows Driver, Date -PivotData @{Points = "SUM"} -GroupDateRow Date -GroupDatePart Years, Months
Import-Csv "$PSScriptRoot\First10Races.csv" |
Select-Object Race, @{n = "Date"; e = {[datetime]::ParseExact($_.date, "dd/MM/yyyy", (Get-Culture))}}, FinishPosition, Driver, GridPosition, Team, Points |
Export-Excel $xlfile -Show -AutoSize -PivotTableDefinition $PivotTableDefinition

View File

@@ -0,0 +1,10 @@
$xlfile = "$env:TEMP\Places.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$PivotTableDefinition = New-PivotTableDefinition -Activate -PivotTableName Places `
-PivotRows Driver, FinishPosition -PivotData @{Date = "Count"} -GroupNumericRow FinishPosition -GroupNumericMin 1 -GroupNumericMax 25 -GroupNumericInterval 3
Import-Csv "$PSScriptRoot\First10Races.csv" |
Select-Object Race, @{n = "Date"; e = {[datetime]::ParseExact($_.date, "dd/MM/yyyy", (Get-Culture))}}, FinishPosition, Driver, GridPosition, Team, Points |
Export-Excel $xlfile -Show -AutoSize -PivotTableDefinition $PivotTableDefinition

View File

@@ -0,0 +1,39 @@
$data = ConvertFrom-Csv @"
Timestamp,Tenant
10/29/2018 3:00:00.123,1
10/29/2018 3:00:10.456,1
10/29/2018 3:01:20.389,1
10/29/2018 3:00:30.222,1
10/29/2018 3:00:40.143,1
10/29/2018 3:00:50.809,1
10/29/2018 3:01:00.193,1
10/29/2018 3:01:10.555,1
10/29/2018 3:01:20.739,1
10/29/2018 3:01:30.912,1
10/29/2018 3:01:40.989,1
10/29/2018 3:01:50.545,1
10/29/2018 3:02:00.999,1
"@ | Select-Object @{n = 'Timestamp'; e = {get-date $_.timestamp}}, tenant, @{n = 'Bucket'; e = { - (get-date $_.timestamp).Second % 30}}
$f = "$env:temp\pivottest.xlsx"
Remove-Item $f -ErrorAction SilentlyContinue
$pivotDefParams = @{
PivotTableName = 'Timestamp Buckets'
PivotRows = @('Timestamp', 'Tenant')
PivotData = @{'Bucket' = 'count'}
GroupDateRow = 'TimeStamp'
GroupDatePart = @('Hours', 'Minutes')
Activate = $true
}
$excelParams = @{
PivotTableDefinition = New-PivotTableDefinition @pivotDefParams
Path = $f
WorkSheetname = "Log Data"
AutoSize = $true
AutoFilter = $true
Show = $true
}
$data | Export-Excel @excelParams

View File

@@ -0,0 +1,26 @@
param(
$PesterTestsPath = "$PSScriptRoot\..\..\..\__tests__\"
)
$xlfile = "$env:Temp\testResults.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$xlparams = @{
Path = $xlfile
InputObject = (Invoke-Pester -Script $PesterTestsPath -PassThru).TestResult | Sort-Object describe
WorksheetName = 'FullResults'
IncludePivotTable = $true
PivotRows = 'Describe'
PivotColumns = 'Passed'
PivotData = @{'Passed' = 'Count' }
IncludePivotChart = $true
ChartType = 'BarClustered'
AutoSize = $true
AutoFilter = $true
Activate = $true
}
Export-Excel -Show @xlparams

View File

@@ -0,0 +1,62 @@
<#
.Synopsis
Runs PsScriptAnalyzer against one or more folders and pivots the results to form a report.
.Example
Analyze_this.ps1
Invokes script analyzer on the current directory; creates a file in $env:temp and opens it in Excel
.Example
Analyze_this.ps1 -xlfile ..\mymodule.xlsx -quiet
Invokes script analyzer on the current directory; creates a file in the parent directory but does not open it
.Example
"." , (dir 'C:\Program Files\WindowsPowerShell\Modules\ImportExcel\') | .\examples\ScriptAnalyzer\Analyze_this.ps1
run from a developemnt directory for importExcel it will produce a report for that directory compared against installed versions
this creates the file in the default location and opens it
#>
[CmdletBinding()]
param (
[parameter(ValueFromPipeline = $true)]
$Path = $PWD,
$xlfile = "$env:TEMP\ScriptAnalyzer.xlsx",
$ChartType = 'BarClustered' ,
$PivotColumns = 'Location',
[switch]$Quiet
)
begin {
Remove-Item -Path $xlfile -ErrorAction SilentlyContinue
$xlparams = @{
Path = $xlfile
WorksheetName = 'FullResults'
AutoSize = $true
AutoFilter = $true
Activate = $true
Show = (-not $Quiet)
}
$pivotParams = @{
PivotTableName = 'BreakDown'
PivotData = @{RuleName = 'Count' }
PivotRows = 'Severity', 'RuleName'
PivotColumns = 'Location'
PivotTotals = 'Rows'
}
$dirsToProcess = @()
}
process {
if ($path.fullName) {$dirsToProcess += $path.fullName}
elseif ($path.path) {$dirsToProcess += $path.Path}
else {$dirsToProcess += $path}
}
end {
$pivotParams['-PivotChartDefinition'] = New-ExcelChartDefinition -ChartType $chartType -Column (1 + $dirsToProcess.Count) -Title "Script analysis" -LegendBold
$xlparams['PivotTableDefinition'] = New-PivotTableDefinition @pivotParams
$dirsToProcess | ForEach-Object {
$dirName = (Resolve-Path -Path $_) -replace "^.*\\(.*?)\\(.*?)$", '$1-$2'
Write-Progress -Activity "Running Script Analyzer" -CurrentOperation $dirName
Invoke-ScriptAnalyzer -Path $_ -ErrorAction SilentlyContinue |
Add-Member -MemberType NoteProperty -Name Location -Value $dirName -PassThru
} | Export-Excel @xlparams
Write-Progress -Activity "Running Script Analyzer" -Completed
}

View File

@@ -0,0 +1,55 @@
<#
Fixed Rate Loan/Mortgage Calculator in Excel
#>
param(
$Amount = 400000,
$InterestRate = .065,
$Term = 30
)
function New-CellData {
param(
$Range,
$Value,
$Format
)
$setFormatParams = @{
WorkSheet = $ws
Range = $Range
NumberFormat = $Format
}
if ($Value -is [string] -and $Value.StartsWith('=')) {
$setFormatParams.Formula = $Value
}
else {
$setFormatParams.Value = $Value
}
Set-Format @setFormatParams
}
$f = "$PSScriptRoot\mortgage.xlsx"
Remove-Item $f -ErrorAction SilentlyContinue
$pkg = "" | Export-Excel $f -Title 'Fixed Rate Loan Payments' -PassThru -AutoSize
$ws = $pkg.Workbook.Worksheets["Sheet1"]
New-CellData A3 'Amount'
New-CellData B3 $Amount '$#,##0'
New-CellData A4 "Interest Rate"
New-CellData B4 $InterestRate 'Percentage'
New-CellData A5 "Term (Years)"
New-CellData B5 $Term
New-CellData D3 "Monthly Payment"
New-CellData F3 "=-PMT(F4, B5*12, B3)" '$#,##0.#0'
New-CellData D4 "Monthly Rate"
New-CellData F4 "=((1+B4)^(1/12))-1" 'Percentage'
Close-ExcelPackage $pkg -Show

View File

@@ -0,0 +1,23 @@
# ConvertFrom-Excel
''
.\test.xlsx
Import-Excel .\test.xlsx | ft
ConvertFrom-Excel -ExcelFile .\test.xlsx -outFile .\targetout.html
# Create a column definition
$columnOptions = @()
$columnOptions += New-ColumnOption -ColumnName Progress -formatter progress
ConvertFrom-Excel -ExcelFile .\test.xlsx -outFile .\targetout.html -columnOptions $columnOptions
$columnOptions += New-ColumnOption Activity -formatter lineFormatter
ConvertFrom-Excel -ExcelFile .\test.xlsx -outFile .\targetout.html -columnOptions $columnOptions
$columnOptions += New-ColumnOption -ColumnName Rating -formatter star
$columnOptions += New-ColumnOption Driver -formatter tickCross
ConvertFrom-Excel -ExcelFile .\test.xlsx -outFile .\targetout.html -columnOptions $columnOptions
ConvertFrom-Excel -ExcelFile .\test.xlsx -outFile .\targetout.html -columnOptions $columnOptions -groupBy Gender

View File

@@ -0,0 +1,216 @@
## Start-Demo.ps1
##################################################################################################
## This is an overhaul of Jeffrey Snover's original Start-Demo script by Joel "Jaykul" Bennett
##
## I've switched it to using ReadKey instead of ReadLine (you don't have to hit Enter each time)
## As a result, I've changed the names and keys for a lot of the operations, so that they make
## sense with only a single letter to tell them apart (sorry if you had them memorized).
##
## I've also been adding features as I come across needs for them, and you'll contribute your
## improvements back to the PowerShell Script repository as well.
##################################################################################################
## Revision History (version 3.3)
## 3.3.3 Fixed: Script no longer says "unrecognized key" when you hit shift or ctrl, etc.
## Fixed: Blank lines in script were showing as errors (now printed like comments)
## 3.3.2 Fixed: Changed the "x" to match the "a" in the help text
## 3.3.1 Fixed: Added a missing bracket in the script
## 3.3 - Added: Added a "Clear Screen" option
## - Added: Added a "Rewind" function (which I'm not using much)
## 3.2 - Fixed: Put back the trap { continue; }
## 3.1 - Fixed: No Output when invoking Get-Member (and other cmdlets like it???)
## 3.0 - Fixed: Commands which set a variable, like: $files = ls
## - Fixed: Default action doesn't continue
## - Changed: Use ReadKey instead of ReadLine
## - Changed: Modified the option prompts (sorry if you had them memorized)
## - Changed: Various time and duration strings have better formatting
## - Enhance: Colors are settable: prompt, command, comment
## - Added: NoPauseAfterExecute switch removes the extra pause
## If you set this, the next command will be displayed immediately
## - Added: Auto Execute mode (FullAuto switch) runs the rest of the script
## at an automatic speed set by the AutoSpeed parameter (or manually)
## - Added: Automatically append an empty line to the end of the demo script
## so you have a chance to "go back" after the last line of you demo
##################################################################################################
##
param(
$file=".\demo.txt",
[int]$command=0,
[System.ConsoleColor]$promptColor="Yellow",
[System.ConsoleColor]$commandColor="White",
[System.ConsoleColor]$commentColor="Green",
[switch]$FullAuto,
[int]$AutoSpeed = 3,
[switch]$NoPauseAfterExecute
)
$RawUI = $Host.UI.RawUI
$hostWidth = $RawUI.BufferSize.Width
# A function for reading in a character
function Read-Char() {
$_OldColor = $RawUI.ForeGroundColor
$RawUI.ForeGroundColor = "Red"
$inChar=$RawUI.ReadKey("IncludeKeyUp")
# loop until they press a character, so Shift or Ctrl, etc don't terminate us
while($inChar.Character -eq 0){
$inChar=$RawUI.ReadKey("IncludeKeyUp")
}
$RawUI.ForeGroundColor = $_OldColor
return $inChar.Character
}
function Rewind($lines, $index, $steps = 1) {
$started = $index;
$index -= $steps;
while(($index -ge 0) -and ($lines[$index].Trim(" `t").StartsWith("#"))){
$index--
}
if( $index -lt 0 ) { $index = $started }
return $index
}
$file = Resolve-Path $file
while(-not(Test-Path $file)) {
$file = Read-Host "Please enter the path of your demo script (Crtl+C to cancel)"
$file = Resolve-Path $file
}
Clear-Host
$_lines = Get-Content $file
# Append an extra (do nothing) line on the end so we can still go back after the last line.
$_lines += "Write-Host 'The End'"
$_starttime = [DateTime]::now
$FullAuto = $false
Write-Host -nonew -back black -fore $promptColor $(" " * $hostWidth)
Write-Host -nonew -back black -fore $promptColor @"
<Demo Started :: $(split-path $file -leaf)>$(' ' * ($hostWidth -(18 + $(split-path $file -leaf).Length)))
"@
Write-Host -nonew -back black -fore $promptColor "Press"
Write-Host -nonew -back black -fore Red " ? "
Write-Host -nonew -back black -fore $promptColor "for help.$(' ' * ($hostWidth -17))"
Write-Host -nonew -back black -fore $promptColor $(" " * $hostWidth)
# We use a FOR and an INDEX ($_i) instead of a FOREACH because
# it is possible to start at a different location and/or jump
# around in the order.
for ($_i = $Command; $_i -lt $_lines.count; $_i++)
{
# Put the current command in the Window Title along with the demo duration
$Dur = [DateTime]::Now - $_StartTime
$RawUI.WindowTitle = "$(if($dur.Hours -gt 0){'{0}h '})$(if($dur.Minutes -gt 0){'{1}m '}){2}s {3}" -f
$dur.Hours, $dur.Minutes, $dur.Seconds, $($_Lines[$_i])
# Echo out the commmand to the console with a prompt as though it were real
Write-Host -nonew -fore $promptColor "[$_i]$([char]0x2265) "
if ($_lines[$_i].Trim(" ").StartsWith("#") -or $_lines[$_i].Trim(" ").Length -le 0) {
Write-Host -fore $commentColor "$($_Lines[$_i]) "
continue
} else {
Write-Host -nonew -fore $commandColor "$($_Lines[$_i]) "
}
if( $FullAuto ) { Start-Sleep $autoSpeed; $ch = [char]13 } else { $ch = Read-Char }
switch($ch)
{
"?" {
Write-Host -Fore $promptColor @"
Running demo: $file
(n) Next (p) Previous
(q) Quit (s) Suspend
(t) Timecheck (v) View $(split-path $file -leaf)
(g) Go to line by number
(f) Find lines by string
(a) Auto Execute mode
(c) Clear Screen
"@
$_i-- # back a line, we're gonna step forward when we loop
}
"n" { # Next (do nothing)
Write-Host -Fore $promptColor "<Skipping Line>"
}
"p" { # Previous
Write-Host -Fore $promptColor "<Back one Line>"
while ($_lines[--$_i].Trim(" ").StartsWith("#")){}
$_i-- # back a line, we're gonna step forward when we loop
}
"a" { # EXECUTE (Go Faster)
$AutoSpeed = [int](Read-Host "Pause (seconds)")
$FullAuto = $true;
Write-Host -Fore $promptColor "<eXecute Remaining Lines>"
$_i-- # Repeat this line, and then just blow through the rest
}
"q" { # Quit
Write-Host -Fore $promptColor "<Quiting demo>"
$_i = $_lines.count;
break;
}
"v" { # View Source
$lines[0..($_i-1)] | Write-Host -Fore Yellow
$lines[$_i] | Write-Host -Fore Green
$lines[($_i+1)..$lines.Count] | Write-Host -Fore Yellow
$_i-- # back a line, we're gonna step forward when we loop
}
"t" { # Time Check
$dur = [DateTime]::Now - $_StartTime
Write-Host -Fore $promptColor $(
"{3} -- $(if($dur.Hours -gt 0){'{0}h '})$(if($dur.Minutes -gt 0){'{1}m '}){2}s" -f
$dur.Hours, $dur.Minutes, $dur.Seconds, ([DateTime]::Now.ToShortTimeString()))
$_i-- # back a line, we're gonna step forward when we loop
}
"s" { # Suspend (Enter Nested Prompt)
Write-Host -Fore $promptColor "<Suspending demo - type 'Exit' to resume>"
$Host.EnterNestedPrompt()
$_i-- # back a line, we're gonna step forward when we loop
}
"g" { # GoTo Line Number
$i = [int](Read-Host "line number")
if($i -le $_lines.Count) {
if($i -gt 0) {
# extra line back because we're gonna step forward when we loop
$_i = Rewind $_lines $_i (($_i-$i)+1)
} else {
$_i = -1 # Start negative, because we step forward when we loop
}
}
}
"f" { # Find by pattern
$match = $_lines | Select-String (Read-Host "search string")
if($match -eq $null) {
Write-Host -Fore Red "Can't find a matching line"
} else {
$match | % { Write-Host -Fore $promptColor $("[{0,2}] {1}" -f ($_.LineNumber - 1), $_.Line) }
if($match.Count -lt 1) {
$_i = $match.lineNumber - 2 # back a line, we're gonna step forward when we loop
} else {
$_i-- # back a line, we're gonna step forward when we loop
}
}
}
"c" {
Clear-Host
$_i-- # back a line, we're gonna step forward when we loop
}
"$([char]13)" { # on enter
Write-Host
trap [System.Exception] {Write-Error $_; continue;}
Invoke-Expression ($_lines[$_i]) | out-default
if(-not $NoPauseAfterExecute -and -not $FullAuto) {
$null = $RawUI.ReadKey("NoEcho,IncludeKeyUp") # Pause after output for no apparent reason... ;)
}
}
default
{
Write-Host -Fore Green "`nKey not recognized. Press ? for help, or ENTER to execute the command."
$_i-- # back a line, we're gonna step forward when we loop
}
}
}
$dur = [DateTime]::Now - $_StartTime
Write-Host -Fore $promptColor $(
"<Demo Complete -- $(if($dur.Hours -gt 0){'{0}h '})$(if($dur.Minutes -gt 0){'{1}m '}){2}s>" -f
$dur.Hours, $dur.Minutes, $dur.Seconds, [DateTime]::Now.ToLongTimeString())
Write-Host -Fore $promptColor $([DateTime]::now)
Write-Host

View File

@@ -0,0 +1,80 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Out-TabulatorView</title>
</head>
<body>
<script type="text/javascript" src="file:///C:\Program Files\WindowsPowerShell\Modules\OutTabulatorView\js\jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="file:///C:\Program Files\WindowsPowerShell\Modules\OutTabulatorView\js\jquery-ui.min.js"></script>
<script type="text/javascript" src="file:///C:\Program Files\WindowsPowerShell\Modules\OutTabulatorView\js\tabulator.min.js"></script>
<script type="text/javascript" src="file:///C:\Program Files\WindowsPowerShell\Modules\OutTabulatorView\js\jquery.sparkline.min.js"></script>
<link href="file:///C:\Program Files\WindowsPowerShell\Modules\OutTabulatorView\css\tabulator.min.css" rel="stylesheet">
<div id="example-table"></div>
<script type="text/javascript">
var lineFormatter = function(cell, formatterParams){
setTimeout(function(){ //give cell enough time to be added to the DOM before calling sparkline formatter
cell.getElement().sparkline(cell.getValue(), {width:"100%", type:"line", disableTooltips:true});
}, 10);
};
var tabledata = [{"Name":"Alan Francis","Progress":90,"Activity":[4,17,11,7,6,12,14,13,11,10,9,6,11,12,0,5,12,14,18,11],"Gender":"male","Rating":3,"Color":"blue","dob":"07/08/1972","Driver":"true"},{"Name":"Brendon Philips","Progress":100,"Activity":[3,7,9,1,4,8,2,6,4,2,1,3,1,3,3,1,1,3,1,3],"Gender":"male","Rating":1,"Color":"orange","dob":"01/08/1980","Driver":""},{"Name":"Christine Lobowski","Progress":42,"Activity":[1,2,5,4,1,16,4,2,1,3,3,7,9,1,4,8,2,6,4,2],"Gender":"female","Rating":0,"Color":"green","dob":"22/05/1982","Driver":"true"},{"Name":"Ed White","Progress":70,"Activity":[20,17,15,11,16,9,4,17,11,12,0,5,12,14,18,11,12,14,20,12],"Gender":"male","Rating":0,"Color":"yellow","dob":"19/06/1976","Driver":""},{"Name":"Emily Sykes","Progress":42,"Activity":[11,15,19,20,17,16,16,5,3,2,1,2,3,4,5,4,2,5,9,8],"Gender":"female","Rating":1,"Color":"maroon","dob":"11/11/1970","Driver":""},{"Name":"Emma Netwon","Progress":40,"Activity":[3,7,9,1,4,8,3,7,9,1,4,8,2,6,4,2,2,6,4,2],"Gender":"female","Rating":4,"Color":"brown","dob":"07/10/1963","Driver":"true"},{"Name":"Frank Harbours","Progress":38,"Activity":[20,17,15,11,16,9,12,14,20,12,11,7,6,12,14,13,11,10,9,6],"Gender":"male","Rating":4,"Color":"red","dob":"12/05/1966","Driver":1},{"Name":"Gemma Jane","Progress":60,"Activity":[4,17,11,12,0,5,12,14,18,11,11,15,19,20,17,16,16,5,3,2],"Gender":"female","Rating":0,"Color":"red","dob":"22/05/1982","Driver":"true"},{"Name":"Hannah Farnsworth","Progress":30,"Activity":[1,2,5,4,1,16,10,12,14,16,13,9,7,11,10,13,4,2,1,3],"Gender":"female","Rating":1,"Color":"pink","dob":"11/02/1991","Driver":""},{"Name":"James Newman","Progress":73,"Activity":[1,20,5,3,10,13,17,15,9,11,1,2,3,4,5,4,2,5,9,8],"Gender":"male","Rating":5,"Color":"red","dob":"22/03/1998","Driver":""},{"Name":"Jamie Newhart","Progress":23,"Activity":[11,7,6,12,14,13,11,10,9,6,4,17,11,12,0,5,12,14,18,11],"Gender":"male","Rating":3,"Color":"green","dob":"14/05/1985","Driver":"true"},{"Name":"Jenny Green","Progress":56,"Activity":[11,15,19,20,17,15,11,16,9,12,14,20,12,20,17,16,16,5,3,2],"Gender":"female","Rating":4,"Color":"indigo","dob":"12/11/1998","Driver":"true"},{"Name":"John Phillips","Progress":80,"Activity":[11,7,6,12,14,1,20,5,3,10,13,17,15,9,1,13,11,10,9,6],"Gender":"male","Rating":1,"Color":"green","dob":"24/09/1950","Driver":"true"},{"Name":"Margret Marmajuke","Progress":16,"Activity":[1,3,1,3,3,1,1,3,1,3,20,17,15,11,16,9,12,14,20,12],"Gender":"female","Rating":5,"Color":"yellow","dob":"31/01/1999","Driver":""},{"Name":"Martin Barryman","Progress":20,"Activity":[1,2,3,4,5,4,11,7,6,12,14,13,11,10,9,6,2,5,9,8],"Gender":"male","Rating":5,"Color":"violet","dob":"04/04/2001","Driver":""},{"Name":"Mary May","Progress":1,"Activity":[10,12,14,16,13,9,7,11,10,13,1,2,5,4,1,16,4,2,1,3],"Gender":"female","Rating":2,"Color":"blue","dob":"14/05/1982","Driver":"true"},{"Name":"Oli Bob","Progress":12,"Activity":[1,20,5,3,10,13,17,15,9,11,10,12,14,16,13,9,7,11,10,13],"Gender":"male","Rating":1,"Color":"red","dob":"19/02/1984","Driver":1},{"Name":"Paul Branderson","Progress":60,"Activity":[1,3,1,3,3,1,11,15,19,20,17,16,16,5,3,2,1,3,1,3],"Gender":"male","Rating":5,"Color":"orange","dob":"01/01/1982","Driver":""},{"Name":"Victoria Bath","Progress":20,"Activity":[10,12,14,16,13,9,7,1,2,3,4,5,4,2,5,9,8,11,10,13],"Gender":"female","Rating":2,"Color":"purple","dob":"22/03/1986","Driver":null}]
$("#example-table").tabulator(
{
"outFile": ".\\targetout.html",
"columns": [
{
"field": "Name",
"title": "Name"
},
{
"field": "Progress",
"title": "Progress",
"formatter": "progress"
},
{
"field": "Activity",
"title": "Activity",
"formatter": lineFormatter
},
{
"field": "Gender",
"title": "Gender"
},
{
"field": "Rating",
"title": "Rating",
"formatter": "star"
},
{
"field": "Color",
"title": "Color"
},
{
"field": "dob",
"title": "dob"
},
{
"field": "Driver",
"title": "Driver",
"formatter": "tickCross"
}
],
"groupBy": "Gender"
});
$("#example-table").tabulator("setData", tabledata);
</script>
</body>
</html>

View File

@@ -0,0 +1,9 @@
[CmdletBinding()]
param($outFile = "$PSScriptRoot\targetout.html")
$columnOptions = @()
$columnOptions += New-ColumnOption -ColumnName Progress -formatter progress
$columnOptions += New-ColumnOption -ColumnName Activity -formatter lineFormatter
ConvertFrom-Excel -ExcelFile $PSScriptRoot\test.xlsx -outFile $PSScriptRoot\targetout.html -columnOptions $columnOptions

View File

@@ -0,0 +1,55 @@
$data = ConvertFrom-Csv @"
Region,Date,Fruit,Sold
North,1/1/2017,Pears,50
South,1/1/2017,Pears,150
East,4/1/2017,Grapes,100
West,7/1/2017,Bananas,150
South,10/1/2017,Apples,200
North,1/1/2018,Pears,100
East,4/1/2018,Grapes,200
West,7/1/2018,Bananas,300
South,10/1/2018,Apples,400
"@ | Select-Object -Property Region, @{n = "Date"; e = {[datetime]::ParseExact($_.Date, "M/d/yyyy", (Get-Culture))}}, Fruit, Sold
$xlfile = "$env:temp\multiplePivotTables.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$excel = $data | Export-Excel $xlfile -PassThru -AutoSize -TableName FruitData
$pivotTableParams = @{
PivotTableName = "ByRegion"
Address = $excel.Sheet1.cells["F1"]
SourceWorkSheet = $excel.Sheet1
PivotRows = echo Region Fruit Date
PivotData = @{'sold' = 'sum'}
PivotTableStyle = 'Light21'
GroupDateRow = "Date"
GroupDatePart = echo Years Quarters
}
$pt = Add-PivotTable @pivotTableParams -PassThru
#$pt.RowHeaderCaption ="By Region,Fruit,Date"
$pt.RowHeaderCaption = "By " + ($pivotTableParams.PivotRows -join ",")
$pivotTableParams.PivotTableName = "ByFruit"
$pivotTableParams.Address = $excel.Sheet1.cells["J1"]
$pivotTableParams.PivotRows = echo Fruit Region Date
$pt = Add-PivotTable @pivotTableParams -PassThru
$pt.RowHeaderCaption = "By Fruit,Region"
$pivotTableParams.PivotTableName = "ByDate"
$pivotTableParams.Address = $excel.Sheet1.cells["N1"]
$pivotTableParams.PivotRows = echo Date Region Fruit
$pt = Add-PivotTable @pivotTableParams -PassThru
$pt.RowHeaderCaption = "By Date,Region,Fruit"
$pivotTableParams.PivotTableName = "ByYears"
$pivotTableParams.Address = $excel.Sheet1.cells["S1"]
$pivotTableParams.GroupDatePart = echo Years
$pt = Add-PivotTable @pivotTableParams -PassThru
$pt.RowHeaderCaption = "By Years,Region"
Close-ExcelPackage $excel -Show

View File

@@ -0,0 +1,54 @@
param(
[Parameter(Mandatory)]
$path
)
$sheet1 = ConvertFrom-Csv @"
Region,Item,TotalSold
West,melon,27
North,avocado,21
West,kiwi,84
East,melon,23
North,kiwi,8
North,nail,29
North,kiwi,46
South,nail,83
East,pear,10
South,avocado,40
"@
$sheet2 = ConvertFrom-Csv @"
Region,Item,TotalSold
West,lemon,24
North,hammer,41
East,nail,87
West,lemon,68
North,screwdriver,9
North,drill,76
West,lime,28
West,pear,78
North,apple,95
South,melon,40
"@
$sheet3 = ConvertFrom-Csv @"
Region,Item,TotalSold
South,drill,100
East,saw,22
North,saw,5
West,orange,78
East,saw,27
North,screwdriver,57
South,hammer,66
East,saw,62
West,nail,98
West,nail,98
"@
Remove-Item $path -ErrorAction SilentlyContinue
$sheet1 | Export-Excel $path -WorksheetName Sheet1
$sheet2 | Export-Excel $path -WorksheetName Sheet2
$sheet3 | Export-Excel $xlfile -WorksheetName Sheet3
$path

View File

@@ -0,0 +1,19 @@
# Get-ExcelSheets
param(
[Parameter(Mandatory)]
$path
)
$hash = @{ }
$e = Open-ExcelPackage $path
foreach ($sheet in $e.workbook.worksheets) {
$hash[$sheet.name] = Import-Excel -ExcelPackage $e -WorksheetName $sheet.name
}
Close-ExcelPackage $e -NoSave
$hash

View File

@@ -0,0 +1,4 @@
$xlfile = "$env:TEMP\MultipleSheets.xlsx"
.\GenerateXlsx.ps1 $xlfile
.\Get-ExcelSheets.ps1 $xlfile

View File

@@ -0,0 +1,25 @@
try { . $PSScriptRoot\..\..\LoadPSD1.ps1 } catch { }
$xlfile = "$env:TEMP\SalesByQuarter.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$data = ConvertFrom-Csv @"
Region,Q1,Q2,Q3,Q4,YTDPerformance
Asia,1400,7200,5700,6900
Europe,3400,2300,9400,7300
Midwest,4700,9300,3700,8600
Northeast,2300,4300,4600,5600
"@
$excel = $data | Export-Excel $xlfile -Passthru -AutoSize -TableName SalesByQuarter
$ws = $excel.Sheet1
Set-Format -WorkSheet $ws -Range "B2:E5" -NumberFormat "$#,##0" -AutoSize
$sparkLineType = "line"
$null = $ws.SparklineGroups.Add( $sparkLineType, $ws.Cells["F2"], $ws.Cells["B2:E2"] )
$null = $ws.SparklineGroups.Add( $sparkLineType, $ws.Cells["F3"], $ws.Cells["B3:E3"] )
$null = $ws.SparklineGroups.Add( $sparkLineType, $ws.Cells["F4"], $ws.Cells["B4:E4"] )
$null = $ws.SparklineGroups.Add( $sparkLineType, $ws.Cells["F5"], $ws.Cells["B5:E5"] )
Close-ExcelPackage $excel -Show

View File

@@ -0,0 +1,99 @@
try { . $PSScriptRoot\..\..\LoadPSD1.ps1 } catch { }
class data {
[datetime]$Date
[Double]$AUD
[Double]$CAD
[Double]$CHF
[Double]$DKK
[Double]$EUR
[Double]$GBP
[Double]$HKD
[Double]$JPY
[Double]$MYR
[Double]$NOK
[Double]$NZD
[Double]$RUB
[Double]$SEK
[Double]$THB
[Double]$TRY
[Double]$USD
}
[data[]]$data = ConvertFrom-Csv @"
Date,AUD,CAD,CHF,DKK,EUR,GBP,HKD,JPY,MYR,NOK,NZD,RUB,SEK,THB,TRY,USD
2016-03-01,6.17350,6.42084,8.64785,1.25668,9.37376,12.01683,1.11067,0.07599,2.06900,0.99522,5.69227,0.11665,1.00000,0.24233,2.93017,8.63185
2016-03-02,6.27223,6.42345,8.63480,1.25404,9.35350,12.14970,1.11099,0.07582,2.07401,0.99311,5.73277,0.11757,1.00000,0.24306,2.94083,8.63825
2016-03-07,6.33778,6.38403,8.50245,1.24980,9.32373,12.05756,1.09314,0.07478,2.07171,0.99751,5.77539,0.11842,1.00000,0.23973,2.91088,8.48885
2016-03-08,6.30268,6.31774,8.54066,1.25471,9.36254,12.03361,1.09046,0.07531,2.05625,0.99225,5.72501,0.11619,1.00000,0.23948,2.91067,8.47020
2016-03-09,6.32630,6.33698,8.46118,1.24399,9.28125,11.98879,1.08544,0.07467,2.04128,0.98960,5.71601,0.11863,1.00000,0.23893,2.91349,8.42945
2016-03-10,6.24241,6.28817,8.48684,1.25260,9.34350,11.99193,1.07956,0.07392,2.04500,0.98267,5.58145,0.11769,1.00000,0.23780,2.89150,8.38245
2016-03-11,6.30180,6.30152,8.48295,1.24848,9.31230,12.01194,1.07545,0.07352,2.04112,0.98934,5.62335,0.11914,1.00000,0.23809,2.90310,8.34510
2016-03-15,6.19790,6.21615,8.42931,1.23754,9.22896,11.76418,1.07026,0.07359,2.00929,0.97129,5.49278,0.11694,1.00000,0.23642,2.86487,8.30540
2016-03-16,6.18508,6.22493,8.41792,1.23543,9.21149,11.72470,1.07152,0.07318,2.01179,0.96907,5.49138,0.11836,1.00000,0.23724,2.84767,8.31775
2016-03-17,6.25214,6.30642,8.45981,1.24327,9.26623,11.86396,1.05571,0.07356,2.01706,0.98159,5.59544,0.12024,1.00000,0.23543,2.87595,8.18825
2016-03-18,6.25359,6.32400,8.47826,1.24381,9.26976,11.91322,1.05881,0.07370,2.02554,0.98439,5.59067,0.12063,1.00000,0.23538,2.86880,8.20950
"@
$xlfile = "$env:TEMP\sparklines.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$excel = $data | Export-Excel $xlfile -WorksheetName SEKRates -AutoSize -PassThru
# Add a column sparkline for all currencies
Set-Format -WorkSheet $excel.SEKRates -Range "A2:A12" -NumberFormat "yyyy-mm-dd" -AutoSize
Set-Format -WorkSheet $excel.SEKRates -Range A15 -Value Column -AutoSize
$sparklineCol = $excel.SEKRates.SparklineGroups.Add(
"Column",
$excel.SEKRates.Cells["B15:Q15"],
$excel.SEKRates.Cells["B2:Q12"]
)
$sparklineCol.High = $true
$sparklineCol.ColorHigh.SetColor("Red")
# Add a line sparkline for all currencies
Set-Format -WorkSheet $excel.SEKRates -Range A16 -Value Line -AutoSize
$sparklineLine = $excel.SEKRates.SparklineGroups.Add(
"Line",
$excel.SEKRates.Cells["B16:Q16"],
$excel.SEKRates.Cells["B2:Q12"]
)
$sparklineLine.DateAxisRange = $excel.SEKRates.Cells["A2:A12"]
# Add some more random values and add a stacked sparkline.
Set-Format -WorkSheet $excel.SEKRates -Range A17 -Value Stacked -AutoSize
$numbers = 2, -1, 3, -4, 8, 5, -12, 18, 99, 1, -4, 12, -8, 9, 0, -8
$col = 2 # Column B
foreach ($n in $numbers) {
$excel.SEKRates.Cells[17, $col++].Value = $n
}
$sparklineStacked = $excel.SEKRates.SparklineGroups.Add(
"Stacked",
$excel.SEKRates.Cells["R17"],
$excel.SEKRates.Cells["B17:Q17"]
)
$sparklineStacked.High = $true
$sparklineStacked.ColorHigh.SetColor("Red")
$sparklineStacked.Low = $true
$sparklineStacked.ColorLow.SetColor("Green")
$sparklineStacked.Negative = $true
$sparklineStacked.ColorNegative.SetColor("Blue")
Set-Format -WorkSheet $excel.SEKRates -Range "A15:A17" -Bold -Height 50 -AutoSize
$v = @"
High - Red
Low - Green
Negative - Blue
"@
Set-Format -WorkSheet $excel.SEKRates -Range S17 -Value $v -WrapText -Width 20 -HorizontalAlignment Center -VerticalAlignment Center
Close-ExcelPackage $excel -Show

View File

@@ -1,25 +1,24 @@
<#
Revisit I think yahoo deprecated their service
#>
function Get-StockInfo { function Get-StockInfo {
param( param(
$stock, [Parameter(Mandatory)]
[datetime]$startDate, $symbols,
[datetime]$endDate [ValidateSet('open', 'close', 'high', 'low', 'avgTotalVolume')]
$dataPlot = "close"
) )
Process { $xlfile = "$env:TEMP\stocks.xlsx"
rm $xlfile -ErrorAction Ignore
if (!$endDate) { $endDate = $startDate} $result = Invoke-RestMethod "https://api.iextrading.com/1.0/stock/market/batch?symbols=$($symbols)&types=quote&last=1"
$baseUrl = "http://query.yahooapis.com/v1/public/yql?q=" $symbolCount = $symbols.Split(",").count
$q = @"
select * from yahoo.finance.historicaldata where symbol = "$($stock)" and startDate = "$($startDate.ToString('yyyy-MM-dd'))" and endDate = "$($endDate.ToString('yyyy-MM-dd'))"
"@
$suffix = "&env=store://datatables.org/alltableswithkeys&format=json"
$r = Invoke-RestMethod ($baseUrl + $q + $suffix)
$r.query.results.quote
}
} $ecd = New-ExcelChartDefinition -Row 1 -Column 1 -SeriesHeader $dataPlot `
-XRange symbol -YRange $dataPlot `
-Title "$($dataPlot)`r`n As Of $((Get-Date).ToShortDateString())"
$(foreach ($name in $result.psobject.Properties.name) {
$result.$name.quote
}) | Export-Excel $xlfile -AutoNameRange -AutoSize -Show -ExcelChartDefinition $ecd -StartRow 21 -StartColumn 2
}

View File

@@ -1,20 +0,0 @@
<#
Revisit I think yahoo deprecated their service
#>
# try {. $PSScriptRoot\..\..\LoadPSD1.ps1} catch {}
# $Symbol = "MSFT"
# . .\Get-StockInfo.ps1
# Remove-Item *.xlsx -ErrorAction Ignore
# $chart = New-ExcelChart -XRange Date -YRange Volume `
# -ChartType ColumnStacked `
# -Column 9 -Title "$Symbol Volume"
# Get-StockInfo $Symbol 11/2 11/30 |
# Export-Excel .\stocks.xlsx -Show `
# -AutoSize -AutoNameRange `
# -ExcelChartDefinition $chart

View File

@@ -0,0 +1,3 @@
. $PSScriptRoot\Get-StockInfo.ps1
Get-StockInfo -symbols "msft,ibm,ge,xom,aapl" -dataPlot avgTotalVolume

View File

@@ -0,0 +1,35 @@
try { . $PSScriptRoot\..\..\LoadPSD1.ps1 } catch { }
$xlfile = "$env:TEMP\test.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$data = ConvertFrom-Csv @"
Region,Item,TotalSold
North,melon,38
South,screwdriver,21
South,peach,33
South,saw,81
South,kiwi,70
North,orange,59
North,avocado,25
South,lime,48
South,nail,83
North,apple,2
"@
$styleParams = @{
FontSize = 13
Bold = $true
}
$styles = $(
New-ExcelStyle -BackgroundColor LightBlue -FontSize 14 -Bold -Range "A1:H1" -HorizontalAlignment Center -Merge
New-ExcelStyle -BackgroundColor LimeGreen -Range "B10" @styleParams
New-ExcelStyle -BackgroundColor PeachPuff -Range "B5" @styleParams
New-ExcelStyle -BackgroundColor Orange -Range "B8" @styleParams
New-ExcelStyle -BackgroundColor Red -Range "B12" @styleParams
)
$reportTitle = "This is a report Title"
$data | Export-Excel $xlfile -Show -AutoSize -AutoFilter -Title $reportTitle -Style $styles

View File

@@ -0,0 +1,23 @@
# https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/NewExcelStyle.png
try { . $PSScriptRoot\..\..\LoadPSD1.ps1 } catch { }
$xlfile = "$env:TEMP\test.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
$data = ConvertFrom-Csv @"
Region,Item,TotalSold
North,melon,38
South,screwdriver,21
South,peach,33
South,saw,81
South,kiwi,70
North,orange,59
North,avocado,25
South,lime,48
South,nail,83
North,apple,2
"@
$reportTitle = "This is a report Title"
$style = New-ExcelStyle -BackgroundColor LightBlue -FontSize 14 -Bold -Range "A1:H1" -HorizontalAlignment Center -Merge
$data | Export-Excel $xlfile -Show -AutoSize -AutoFilter -Title $reportTitle -Style $style

View File

@@ -0,0 +1,90 @@
function ConvertTo-PesterTest {
param(
[parameter(Mandatory)]
$XlFilename,
$WorksheetName = 'Sheet1'
)
$testFileName = "{0}.tests.ps1" -f (get-date).ToString("yyyyMMddHHmmss")
$records = Import-Excel $XlFilename
$params = @{}
$blocks = $(foreach ($record in $records) {
foreach ($propertyName in $record.psobject.properties.name) {
if ($propertyName -notmatch 'ExpectedResult|QueryString') {
$params.$propertyName = $record.$propertyName
}
}
if ($record.QueryString) {
$params.Uri += "?{0}" -f $record.QueryString
}
@"
it "Should have the expected result '$($record.ExpectedResult)'" {
`$target = '$($params | ConvertTo-Json -compress)' | ConvertFrom-Json
`$target.psobject.Properties.name | ForEach-Object {`$p=@{}} {`$p.`$_=`$(`$target.`$_)}
Invoke-RestMethod @p | Should Be '$($record.ExpectedResult)'
}
"@
})
@"
Describe "Tests from $($XlFilename) in $($WorksheetName)" {
$($blocks)
}
"@ | Set-Content -Encoding Ascii $testFileName
[PSCustomObject]@{
TestFileName = (Get-ChildItem $testFileName).FullName
}
}
function Show-PesterResult {
param(
[Parameter(ValueFromPipelineByPropertyName, Mandatory)]
$TestFileName
)
Begin {
$xlfilename = ".\test.xlsx"
Remove-Item $xlfilename -ErrorAction SilentlyContinue
$ConditionalText = @()
$ConditionalText += New-ConditionalText -Range "Result" -Text failed -BackgroundColor red -ConditionalTextColor black
$ConditionalText += New-ConditionalText -Range "Result" -Text passed -BackgroundColor green -ConditionalTextColor black
$ConditionalText += New-ConditionalText -Range "Result" -Text pending -BackgroundColor gray -ConditionalTextColor black
$xlParams = @{
Path = $xlfilename
WorkSheetname = 'PesterTests'
ConditionalText = $ConditionalText
PivotRows = 'Result', 'Name'
PivotData = @{'Result' = 'Count'}
IncludePivotTable = $true
AutoSize = $true
AutoNameRange = $true
AutoFilter = $true
Show = $true
}
}
End {
$(foreach ($result in (Invoke-Pester -Script $TestFileName -PassThru -Show None).TestResult) {
[PSCustomObject][Ordered]@{
Description = $result.Describe
Name = $result.Name
Result = $result.Result
Messge = $result.FailureMessage
StackTrace = $result.StackTrace
}
}) | Export-Excel @xlParams
}
}

View File

@@ -1,40 +1,32 @@
function Show-PesterResults { function Show-PesterResults {
$xlfilename=".\test.xlsx" $xlfilename = ".\test.xlsx"
rm $xlfilename -ErrorAction Ignore Remove-Item $xlfilename -ErrorAction Ignore
$ConditionalText = @() $ConditionalText = @()
$ConditionalText += New-ConditionalText -Range "Result" -Text failed -BackgroundColor red -ConditionalTextColor black $ConditionalText += New-ConditionalText -Range "Result" -Text failed -BackgroundColor red -ConditionalTextColor black
$ConditionalText += New-ConditionalText -Range "Result" -Text passed -BackgroundColor green -ConditionalTextColor black $ConditionalText += New-ConditionalText -Range "Result" -Text passed -BackgroundColor green -ConditionalTextColor black
$ConditionalText += New-ConditionalText -Range "Result" -Text pending -BackgroundColor gray -ConditionalTextColor black $ConditionalText += New-ConditionalText -Range "Result" -Text pending -BackgroundColor gray -ConditionalTextColor black
$xlParams = @{ $xlParams = @{
Path=$xlfilename Path = $xlfilename
WorkSheetname = 'PesterTests' WorkSheetname = 'PesterTests'
ConditionalText=$ConditionalText ConditionalText = $ConditionalText
PivotRows = 'Description' PivotRows = 'Result', 'Name'
PivotColumns = 'Result' PivotData = @{'Result' = 'Count'}
PivotData = @{'Result'='Count'} IncludePivotTable = $true
IncludePivotTable = $true AutoSize = $true
#IncludePivotChart = $true AutoNameRange = $true
#NoLegend = $true AutoFilter = $true
#ShowPercent = $true Show = $true
#ShowCategory = $true
AutoSize = $true
AutoNameRange = $true
AutoFilter = $true
Show = $true
} }
$(foreach($result in (Invoke-Pester -PassThru -Show None).TestResult) { $(foreach ($result in (Invoke-Pester -PassThru -Show None).TestResult) {
[PSCustomObject]@{
[PSCustomObject]@{ Description = $result.Describe
Description = $result.Describe Name = $result.Name
Name = $result.Name Result = $result.Result
#Time = $result.Time Messge = $result.FailureMessage
Result = $result.Result StackTrace = $result.StackTrace
Messge = $result.FailureMessage }
StackTrace = $result.StackTrace }) | Sort-Object Description | Export-Excel @xlParams
}
}) | Sort Description | Export-Excel @xlParams
} }

View File

@@ -1,5 +1,3 @@
try {. $PSScriptRoot\..\..\LoadPSD1.ps1} catch {}
function Test-APIReadXls { function Test-APIReadXls {
param( param(
[parameter(Mandatory)] [parameter(Mandatory)]
@@ -7,6 +5,8 @@ function Test-APIReadXls {
$WorksheetName = 'Sheet1' $WorksheetName = 'Sheet1'
) )
$testFileName = "{0}.tests.ps1" -f (get-date).ToString("yyyyMMddHHmmss")
$records = Import-Excel $XlFilename $records = Import-Excel $XlFilename
$params = @{} $params = @{}
@@ -35,15 +35,11 @@ function Test-APIReadXls {
"@ "@
}) })
$testFileName = "{0}.tests.ps1" -f (get-date).ToString("yyyyMMddHHmmss.fff")
@" @"
Describe "Tests from $($XlFilename) in $($WorksheetName)" { Describe "Tests from $($XlFilename) in $($WorksheetName)" {
$($blocks) $($blocks)
} }
"@ | Set-Content -Encoding Ascii $testFileName "@ | Set-Content -Encoding Ascii $testFileName
#Invoke-Pester -Script (Get-ChildItem $testFileName) (Get-ChildItem $testFileName).FullName
Get-ChildItem $testFileName }
}

Binary file not shown.

View File

@@ -1,4 +1,4 @@
Import-Module ..\ImportExcel.psd1 -Force try {. $PSScriptRoot\..\..\LoadPSD1.ps1} catch {}
$file = "C:\Temp\test.xlsx" $file = "C:\Temp\test.xlsx"

View File

@@ -0,0 +1,38 @@
$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 -PassThru -AutoSize
$wb = $Excel.Workbook
$sheet = $wb.Worksheets["Sheet1"]
$wb.CreateVBAProject()
$code = @"
Public Function HelloWorld() As String
HelloWorld = "Hello World"
End Function
Public Function DoSum() As Integer
DoSum = Application.Sum(Range("C:C"))
End Function
"@
$module = $wb.VbaProject.Modules.AddModule("PSExcelModule")
$module.Code = $code
Set-Format -WorkSheet $sheet -Range "h7" -Formula "HelloWorld()" -AutoSize
Set-Format -WorkSheet $sheet -Range "h8" -Formula "DoSum()" -AutoSize
Close-ExcelPackage $Excel -Show

View File

@@ -17,7 +17,7 @@
.PARAMETER ClearSheet .PARAMETER ClearSheet
If specified Export-Excel will remove any existing worksheet with the selected name. The Default behaviour is to overwrite cells in this sheet as needed (but leaving non-overwritten ones in place). If specified Export-Excel will remove any existing worksheet with the selected name. The Default behaviour is to overwrite cells in this sheet as needed (but leaving non-overwritten ones in place).
.PARAMETER Append .PARAMETER Append
If specified dat,a will be added to the end of an existing sheet, using the same column headings. If specified data will be added to the end of an existing sheet, using the same column headings.
.PARAMETER TargetData .PARAMETER TargetData
Data to insert onto the worksheet - this is usually provided from the pipeline. Data to insert onto the worksheet - this is usually provided from the pipeline.
.PARAMETER DisplayPropertySet .PARAMETER DisplayPropertySet
@@ -76,7 +76,7 @@
.PARAMETER ConditionalText .PARAMETER ConditionalText
Applies a Conditional formatting rule defined with New-ConditionalText. When specific conditions are met the format is applied. Applies a Conditional formatting rule defined with New-ConditionalText. When specific conditions are met the format is applied.
.PARAMETER NoNumberConversion .PARAMETER NoNumberConversion
By default we convert all values to numbers if possible, but this isn't always desirable. NoNumberConversion allows you to add exceptions for the conversion. Wildcards (like '*') are allowed. By default we convert all values to numbers if possible, but this isn't always desirable. NoNumberConversion allows you to add exceptions for the conversion. The only Wildcard allowed is * for all properties
.PARAMETER BoldTopRow .PARAMETER BoldTopRow
Makes the top row boldface. Makes the top row boldface.
.PARAMETER NoHeader .PARAMETER NoHeader
@@ -84,9 +84,9 @@
.PARAMETER RangeName .PARAMETER RangeName
Makes the data in the worksheet a named range. Makes the data in the worksheet a named range.
.PARAMETER TableName .PARAMETER TableName
Makes the data in the worksheet a table with a name, and applies a style to it. Name must not contain spaces. Makes the data in the worksheet a table with a name, and applies a style to it. The name must not contain spaces. If a style is specified without a name, table1, table2 etc. will be used.
.PARAMETER TableStyle .PARAMETER TableStyle
Selects the style for the named table - defaults to 'Medium6'. Selects the style for the named table - if a name is specified without a style, 'Medium6' is used as a default.
.PARAMETER BarChart .PARAMETER BarChart
Creates a "quick" bar chart using the first text column as labels and the first numeric column as values Creates a "quick" bar chart using the first text column as labels and the first numeric column as values
.PARAMETER ColumnChart .PARAMETER ColumnChart
@@ -133,10 +133,12 @@
Enables the Excel filter on the complete header row, so users can easily sort, filter and/or search the data in the selected column. Enables the Excel filter on the complete header row, so users can easily sort, filter and/or search the data in the selected column.
.PARAMETER AutoSize .PARAMETER AutoSize
Sizes the width of the Excel column to the maximum width needed to display all the containing data in that cell. Sizes the width of the Excel column to the maximum width needed to display all the containing data in that cell.
.PARAMETER MaxAutoSizeRows
Autosizing can be time consuming, so this sets a maximum number of rows to look at for the Autosize operation. Default is 1000; If 0 is specified ALL rows will be checked
.PARAMETER Activate .PARAMETER Activate
If there is already content in the workbook, a new sheet will not be active UNLESS Activate is specified; if a PivotTable is included it will be the active sheet If there is already content in the workbook, a new sheet will not be active UNLESS Activate is specified; if a PivotTable is included it will be the active sheet
.PARAMETER Now .PARAMETER Now
The -Now switch is a shortcut that automatically creates a temporary file, enables "AutoSize", "AutoFiler" and "Show", and opens the file immediately. The -Now switch is a shortcut that automatically creates a temporary file, enables "AutoSize", "TableName" and "Show", and opens the file immediately.
.PARAMETER NumberFormat .PARAMETER NumberFormat
Formats all values that can be converted to a number to the format specified. Formats all values that can be converted to a number to the format specified.
@@ -420,14 +422,15 @@
[OutputType([OfficeOpenXml.ExcelPackage])] [OutputType([OfficeOpenXml.ExcelPackage])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
Param( Param(
[Parameter(ParameterSetName = "Default", Position = 0)]
[Parameter(ParameterSetName = "Table" , Position = 0)] [Parameter(ParameterSetName = 'Default', Position = 0)]
[String]$Path, [String]$Path,
[Parameter(Mandatory = $true, ParameterSetName = "PackageDefault")] [Parameter(Mandatory = $true, ParameterSetName = "Package")]
[Parameter(Mandatory = $true, ParameterSetName = "PackageTable")]
[OfficeOpenXml.ExcelPackage]$ExcelPackage, [OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Parameter(ValueFromPipeline = $true)] [Parameter(ValueFromPipeline = $true)]
$TargetData, [Alias('TargetData')]
$InputObject,
[Switch]$Calculate, [Switch]$Calculate,
[Switch]$Show, [Switch]$Show,
[String]$WorksheetName = 'Sheet1', [String]$WorksheetName = 'Sheet1',
@@ -453,13 +456,14 @@
[Switch]$ShowCategory, [Switch]$ShowCategory,
[Switch]$ShowPercent, [Switch]$ShowPercent,
[Switch]$AutoSize, [Switch]$AutoSize,
$MaxAutoSizeRows = 1000,
[Switch]$NoClobber, [Switch]$NoClobber,
[Switch]$FreezeTopRow, [Switch]$FreezeTopRow,
[Switch]$FreezeFirstColumn, [Switch]$FreezeFirstColumn,
[Switch]$FreezeTopRowFirstColumn, [Switch]$FreezeTopRowFirstColumn,
[Int[]]$FreezePane, [Int[]]$FreezePane,
[Parameter(ParameterSetName = 'Default')]
[Parameter(ParameterSetName = 'PackageDefault')]
[Switch]$AutoFilter, [Switch]$AutoFilter,
[Switch]$BoldTopRow, [Switch]$BoldTopRow,
[Switch]$NoHeader, [Switch]$NoHeader,
@@ -469,17 +473,12 @@
else { $true } else { $true }
})] })]
[String]$RangeName, [String]$RangeName,
[ValidateScript( {
if (-not $_) { throw 'Tablename is null or empty.' }
elseif ($_[0] -notmatch '[a-z]') { throw 'Tablename starts with an invalid character.' } $TableName,
else { $true }
})]
[Parameter(ParameterSetName = 'Table' , Mandatory = $true, ValueFromPipelineByPropertyName)] [OfficeOpenXml.Table.TableStyles]$TableStyle,
[Parameter(ParameterSetName = 'PackageTable' , Mandatory = $true, ValueFromPipelineByPropertyName)]
[String]$TableName,
[Parameter(ParameterSetName = 'Table')]
[Parameter(ParameterSetName = 'PackageTable')]
[OfficeOpenXml.Table.TableStyles]$TableStyle = 'Medium6',
[Switch]$Barchart, [Switch]$Barchart,
[Switch]$PieChart, [Switch]$PieChart,
[Switch]$LineChart , [Switch]$LineChart ,
@@ -495,6 +494,7 @@
[Switch]$AutoNameRange, [Switch]$AutoNameRange,
[Int]$StartRow = 1, [Int]$StartRow = 1,
[Int]$StartColumn = 1, [Int]$StartColumn = 1,
[alias('PT')]
[Switch]$PassThru, [Switch]$PassThru,
[String]$Numberformat = 'General', [String]$Numberformat = 'General',
[string[]]$ExcludeProperty, [string[]]$ExcludeProperty,
@@ -503,10 +503,11 @@
[String[]]$NoNumberConversion, [String[]]$NoNumberConversion,
[Object[]]$ConditionalFormat, [Object[]]$ConditionalFormat,
[Object[]]$ConditionalText, [Object[]]$ConditionalText,
[Object[]]$Style,
[ScriptBlock]$CellStyleSB, [ScriptBlock]$CellStyleSB,
#If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified #If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified
[switch]$Activate, [switch]$Activate,
[Parameter(ParameterSetName = 'Now')] [Parameter(ParameterSetName = 'Default')]
[Switch]$Now, [Switch]$Now,
[Switch]$ReturnRange, [Switch]$ReturnRange,
#By default PivotTables have Totals for each Row (on the right) and for each column at the bottom. This allows just one or neither to be selected. #By default PivotTables have Totals for each Row (on the right) and for each column at the bottom. This allows just one or neither to be selected.
@@ -517,109 +518,25 @@
[Switch]$ReZip [Switch]$ReZip
) )
Begin { begin {
$numberRegex = [Regex]'\d' $numberRegex = [Regex]'\d'
function Add-CellValue { $isDataTypeValueType = $false
<# if ($NoClobber) {Write-Warning -Message "-NoClobber parameter is no longer used" }
.SYNOPSIS #Open the file, get the worksheet, and decide where in the sheet we are writing, and if there is a number format to apply.
Save a value in an Excel cell. try {
.DESCRIPTION
DateTime objects are always converted to a short DateTime format in Excel. When Excel loads the file,
it applies the local format for dates. And formulas are always saved as formulas. URIs are set as hyperlinks in the file.
Numerical values will be converted to numbers as defined in the regional settings of the local
system. In case the parameter 'NoNumberConversion' is used, we don't convert to number and leave
the value 'as is'. In case of conversion failure, we also leave the value 'as is'.
#>
Param (
$TargetCell,
$CellValue
)
#The write-verbose commands have been commented out below - even if verbose is silenced they cause a significiant performance impact and if it's on they will cause a flood of messages.
Switch ($CellValue) {
{ $_ -is [DateTime]} {
# Save a date with one of Excel's built in formats format
$TargetCell.Value = $_
$TargetCell.Style.Numberformat.Format = 'm/d/yy h:mm' # This is not a custom format, but a preset recognized as date and localized.
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$_' as date"
break
}
{ $_ -is [TimeSpan]} {
#Save a timespans with a built in format for elapsed hours, minutes and seconds
$TargetCell.Value = $_
$TargetCell.Style.Numberformat.Format = '[h]:mm:ss'
break
}
{ $_ -is [System.ValueType]} {
# Save numerics, setting format if need be.
$TargetCell.Value = $_
if ($setNumformat) {$targetCell.Style.Numberformat.Format = $Numberformat }
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$_' as value"
break
}
{($_ -is [String]) -and ($_[0] -eq '=')} {
#region Save an Excel formula - we need = to spot the formula but the EPPLUS won't like it if we include it (Excel doesn't care if is there or not)
$TargetCell.Formula = ($_ -replace '^=','')
if ($setNumformat) {$targetCell.Style.Numberformat.Format = $Numberformat }
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$_' as formula"
break
}
{ [System.Uri]::IsWellFormedUriString($_ , [System.UriKind]::Absolute) } {
# Save a hyperlink : internal links can be in the form xl://sheet!E419 (use A1 as goto sheet), or xl://RangeName
if ($_ -is [uri]) {$targetCell.HyperLink = $_ }
elseif ($_ -match "^xl://internal/") {
$referenceAddress = $_ -replace "^xl://internal/" , ""
$display = $referenceAddress -replace "!A1$" , ""
$h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
$TargetCell.HyperLink = $h
}
else {$TargetCell.HyperLink = $_ } #$TargetCell.Value = $_.AbsoluteUri
$TargetCell.Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
$TargetCell.Style.Font.UnderLine = $true
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$($_.AbsoluteUri)' as Hyperlink"
break
}
{( $NoNumberConversion -and (
($NoNumberConversion -contains $Name) -or ($NoNumberConversion -eq '*'))) } {
#Save text without it to converting to number
$TargetCell.Value = $_
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$($TargetCell.Value)' unconverted"
break
}
Default {
#Save a value as a number if possible
$number = $null
if ($numberRegex.IsMatch($_) -and [Double]::TryParse($_, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number)) {
# as simpler version using [Double]::TryParse( $_ , [ref]$number)) was found to cause problems reverted back to the longer version
$TargetCell.Value = $number
if ($setNumformat) {$targetCell.Style.Numberformat.Format = $Numberformat }
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$($TargetCell.Value)' as number converted from '$_' with format '$Numberformat'"
}
else {
$TargetCell.Value = $_
#Write-Verbose "Cell '$Row`:$ColumnIndex' header '$Name' add value '$($TargetCell.Value)' as string"
}
break
}
}
}
try {
$script:Header = $null $script:Header = $null
if ($Append -and $ClearSheet) {throw "You can't use -Append AND -ClearSheet."} if ($Append -and $ClearSheet) {throw "You can't use -Append AND -ClearSheet."}
$TableName = if ($null -eq $TableName -or ($TableName -is [bool] -and $false -eq $TableName)) { $null } else {[String]$TableName}
if ($PSBoundParameters.Keys.Count -eq 0 -Or $Now) { if ($PSBoundParameters.Keys.Count -eq 0 -Or $Now -or (-not $Path -and -not $ExcelPackage) ) {
$Path = [System.IO.Path]::GetTempFileName() -replace '\.tmp', '.xlsx' if (-not $PSBoundParameters.ContainsKey("Path")) { $Path = [System.IO.Path]::GetTempFileName() -replace '\.tmp', '.xlsx' }
$Show = $true if (-not $PSBoundParameters.ContainsKey("Show")) { $Show = $true }
$AutoSize = $true if (-not $PSBoundParameters.ContainsKey("AutoSize")) { $AutoSize = $true }
if (!$TableName) { if (-not $PSBoundParameters.ContainsKey("TableName") -and
$AutoFilter = $true -not $PSBoundParameters.ContainsKey("TableStyle") -and
-not $AutoFilter) {
$TableName = ''
} }
} }
if ($ExcelPackage) { if ($ExcelPackage) {
$pkg = $ExcelPackage $pkg = $ExcelPackage
$Path = $pkg.File $Path = $pkg.File
@@ -627,8 +544,7 @@
Else { $pkg = Open-ExcelPackage -Path $Path -Create -KillExcel:$KillExcel -Password:$Password} Else { $pkg = Open-ExcelPackage -Path $Path -Create -KillExcel:$KillExcel -Password:$Password}
} }
catch {throw "Could not open Excel Package $path"} catch {throw "Could not open Excel Package $path"}
if ($NoClobber) {Write-Warning -Message "-NoClobber parameter is no longer used" } try {
try {
$params = @{WorksheetName=$WorksheetName} $params = @{WorksheetName=$WorksheetName}
foreach ($p in @("ClearSheet", "MoveToStart", "MoveToEnd", "MoveBefore", "MoveAfter", "Activate")) {if ($PSBoundParameters[$p]) {$params[$p] = $PSBoundParameters[$p]}} foreach ($p in @("ClearSheet", "MoveToStart", "MoveToEnd", "MoveBefore", "MoveAfter", "Activate")) {if ($PSBoundParameters[$p]) {$params[$p] = $PSBoundParameters[$p]}}
$ws = $pkg | Add-WorkSheet @params $ws = $pkg | Add-WorkSheet @params
@@ -638,7 +554,7 @@
} }
} }
catch {throw "Could not get worksheet $worksheetname"} catch {throw "Could not get worksheet $worksheetname"}
try { try {
if ($Append -and $ws.Dimension) { if ($Append -and $ws.Dimension) {
#if there is a title or anything else above the header row, append needs to be combined wih a suitable startrow parameter #if there is a title or anything else above the header row, append needs to be combined wih a suitable startrow parameter
$headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow $headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
@@ -660,7 +576,7 @@
} }
#if we did not get a table name but there is a table which covers the active part of the sheet, set table name to that, and don't do anything with autofilter #if we did not get a table name but there is a table which covers the active part of the sheet, set table name to that, and don't do anything with autofilter
if (-not $TableName -and $ws.Tables.Where({$_.address.address -eq $ws.dimension.address})) { if ($null -eq $TableName -and $ws.Tables.Where({$_.address.address -eq $ws.dimension.address})) {
$TableName = $ws.Tables.Where({$_.address.address -eq $ws.dimension.address},'First', 1).Name $TableName = $ws.Tables.Where({$_.address.address -eq $ws.dimension.address},'First', 1).Name
$AutoFilter = $false $AutoFilter = $false
} }
@@ -674,6 +590,7 @@
$row = $ws.Dimension.End.Row $row = $ws.Dimension.End.Row
Write-Debug -Message ("Appending: headers are " + ($script:Header -join ", ") + " Start row is $row") Write-Debug -Message ("Appending: headers are " + ($script:Header -join ", ") + " Start row is $row")
if ($Title) {Write-Warning -Message "-Title Parameter is ignored when appending."}
} }
elseif ($Title) { elseif ($Title) {
#Can only add a title if not appending! #Can only add a title if not appending!
@@ -701,81 +618,144 @@
$setNumformat = $false $setNumformat = $false
} }
else { $setNumformat = ($Numberformat -ne $ws.Cells.Style.Numberformat.Format) } else { $setNumformat = ($Numberformat -ne $ws.Cells.Style.Numberformat.Format) }
}
$firstTimeThru = $true catch {throw "Failed preparing to export to worksheet '$WorksheetName' to '$Path': $_"}
$isDataTypeValueType = $false #region Special case -inputobject passed a dataTable object
} <# If inputObject was passed via the pipeline it won't be visible until the process block, we will only see it here if it was passed as a parameter
catch { if it was passed it is a data table don't do foreach on it (slow) put the whole table in and set dates on date columns,
if ($AlreadyExists) { set things up for the end block, and skip the process block #>
#Is this set anywhere ? if ($InputObject -is [System.Data.DataTable]) {
throw "Failed exporting worksheet '$WorksheetName' to '$Path': The worksheet '$WorksheetName' already exists." $null = $ws.Cells[$row,$StartColumn].LoadFromDataTable($InputObject, (-not $noHeader) )
foreach ($c in $InputObject.Columns.where({$_.datatype -eq [datetime]})) {
Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat 'Date-Time'
} }
else { foreach ($c in $InputObject.Columns.where({$_.datatype -eq [timespan]})) {
throw "Failed preparing to export to worksheet '$WorksheetName' to '$Path': $_" Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat '[h]:mm:ss'
} }
} $ColumnIndex += $InputObject.Columns.Count - 1
if ($noHeader) {$row += $InputObject.Rows.Count -1 }
else {$row += $InputObject.Rows.Count }
$null = $PSBoundParameters.Remove('InputObject')
$firstTimeThru = $false
}
#endregion
else {$firstTimeThru = $true}
} }
Process { process { if ($PSBoundParameters.ContainsKey("InputObject")) {
if ($PSBoundParameters.ContainsKey("TargetData")) { try {
try { if ($null -eq $InputObject) {$row += 1}
foreach ($TargetData in $InputObject) {
if ($firstTimeThru) { if ($firstTimeThru) {
$firstTimeThru = $false $firstTimeThru = $false
$isDataTypeValueType = ($null -eq $TargetData) -or ($TargetData.GetType().name -match 'string|timespan|datetime|bool|byte|char|decimal|double|float|int|long|sbyte|short|uint|ulong|ushort|URI|ExcelHyperLink') $isDataTypeValueType = ($null -eq $TargetData) -or ($TargetData.GetType().name -match 'string|timespan|datetime|bool|byte|char|decimal|double|float|int|long|sbyte|short|uint|ulong|ushort|URI|ExcelHyperLink')
if ($isDataTypeValueType -and -not $Append) {$row -= 1} #row incremented before adding values, so it is set to the number of rows inserted at the end if ($isDataTypeValueType ) {
if ($null -ne $TargetData) {Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" } $script:Header = @(".") # dummy value to make sure we go through the "for each name in $header"
if (-not $Append) {$row -= 1} # By default row will be 1, it is incremented before inserting values (so it ends pointing at final row.); si first data row is 2 - move back up 1 if there is no header .
}
if ($null -ne $TargetData) {Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" }
} }
if ($isDataTypeValueType) { #region Add headers - if we are appending, or we have been through here once already we will have the headers
$ColumnIndex = $StartColumn if (-not $script:Header) {
$Row += 1 if ($DisplayPropertySet -and $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
try {Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData} $script:Header = $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( {$_ -notin $ExcludeProperty})
catch {Write-Warning "Could not insert value at Row $Row. "} }
} else {
else { if ($NoAliasOrScriptPropeties) {$propType = "Property"} else {$propType = "*"}
#region Add headers - if we are appending, or we have been through here once already we will have the headers $script:Header = $TargetData.PSObject.Properties.where( {$_.MemberType -like $propType}).Name
if (-not $script:Header) { }
foreach ($exclusion in $ExcludeProperty) {$script:Header = $script:Header -notlike $exclusion}
if ($NoHeader) {
# Don't push the headers to the spreadsheet
$Row -= 1
}
else {
$ColumnIndex = $StartColumn $ColumnIndex = $StartColumn
if ($DisplayPropertySet -and $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) { foreach ($Name in $script:Header) {
$script:Header = $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( {$_ -notin $ExcludeProperty}) $ws.Cells[$Row, $ColumnIndex].Value = $Name
} Write-Verbose "Cell '$Row`:$ColumnIndex' add header '$Name'"
else { $ColumnIndex += 1
if ($NoAliasOrScriptPropeties) {$propType = "Property"} else {$propType = "*"}
$script:Header = $TargetData.PSObject.Properties.where( {$_.MemberType -like $propType}).Name
}
foreach ($exclusion in $ExcludeProperty) {$script:Header = $script:Header -notlike $exclusion}
if ($NoHeader) {
# Don't push the headers to the spreadsheet
$Row -= 1
}
else {
foreach ($Name in $script:Header) {
$ws.Cells[$Row, $ColumnIndex].Value = $Name
Write-Verbose "Cell '$Row`:$ColumnIndex' add header '$Name'"
$ColumnIndex += 1
}
} }
} }
#endregion
#region Add non header values
$Row += 1
$ColumnIndex = $StartColumn
foreach ($Name in $script:Header) {
try {Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData.$Name}
catch {Write-Warning -Message "Could not insert the '$Name' property at Row $Row, Column $ColumnIndex"}
$ColumnIndex += 1
}
$ColumnIndex -= 1 # column index will be the last column whether isDataTypeValueType was true or false
#endregion
} }
} #endregion
catch { #region Add non header values
throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" $Row += 1
$ColumnIndex = $StartColumn
<#
For each item in the header OR for the Data item if this is a simple Type or data table :
If it is a date insert with one of Excel's built in formats - recognized as "Date and time to be localized"
if it is a timespan insert with a built in format for elapsed hours, minutes and seconds
if its any other numeric insert as is , setting format if need be.
Preserve URI, Insert a data table, convert non string objects to string.
For strings, check for fomula, URI or Number, before inserting as a string (ignore nulls) #>
foreach ($Name in $script:Header) {
if ($isDataTypeValueType) {$v = $TargetData}
else {$v = $TargetData.$Name}
try {
if ($v -is [DateTime]) {
$ws.Cells[$Row, $ColumnIndex].Value = $v
$ws.Cells[$Row, $ColumnIndex].Style.Numberformat.Format = 'm/d/yy h:mm' # This is not a custom format, but a preset recognized as date and localized.
}
elseif ($v -is [TimeSpan]) {
$ws.Cells[$Row, $ColumnIndex].Value = $v
$ws.Cells[$Row, $ColumnIndex].Style.Numberformat.Format = '[h]:mm:ss'
}
elseif ($v -is [System.ValueType]) {
$ws.Cells[$Row, $ColumnIndex].Value = $v
if ($setNumformat) {$ws.Cells[$Row, $ColumnIndex].Style.Numberformat.Format = $Numberformat }
}
elseif ($v -is [uri] ) {
$ws.Cells[$Row, $ColumnIndex].HyperLink = $v
$ws.Cells[$Row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
$ws.Cells[$Row, $ColumnIndex].Style.Font.UnderLine = $true
}
elseif ($v -isnot [String] ) { #Other objects or null.
if ($null -ne $v) { $ws.Cells[$Row, $ColumnIndex].Value = $v.toString()}
}
elseif ($v[0] -eq '=') {
$ws.Cells[$Row, $ColumnIndex].Formula = ($v -replace '^=','')
if ($setNumformat) {$ws.Cells[$Row, $ColumnIndex].Style.Numberformat.Format = $Numberformat }
}
elseif ( [System.Uri]::IsWellFormedUriString($v , [System.UriKind]::Absolute) ) {
if ($v -match "^xl://internal/") {
$referenceAddress = $v -replace "^xl://internal/" , ""
$display = $referenceAddress -replace "!A1$" , ""
$h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
$ws.Cells[$Row, $ColumnIndex].HyperLink = $h
}
else {$ws.Cells[$Row, $ColumnIndex].HyperLink = $v } #$ws.Cells[$Row, $ColumnIndex].Value = $v.AbsoluteUri
$ws.Cells[$Row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
$ws.Cells[$Row, $ColumnIndex].Style.Font.UnderLine = $true
}
else {
$number = $null
if ( $numberRegex.IsMatch($v) -and # if it contains digit(s) - this syntax is quicker than -match for many items and cuts out slow checks for non numbers
$NoNumberConversion -ne '*' -and # and NoNumberConversion isn't specified
$NoNumberConversion -notcontains $Name -and
[Double]::TryParse($v, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number)
) {
$ws.Cells[$Row, $ColumnIndex].Value = $number
if ($setNumformat) {$ws.Cells[$Row, $ColumnIndex].Style.Numberformat.Format = $Numberformat }
}
else {
$ws.Cells[$Row, $ColumnIndex].Value = $v
}
}
}
catch {Write-Warning -Message "Could not insert the '$Name' property at Row $Row, Column $ColumnIndex"}
$ColumnIndex += 1
}
$ColumnIndex -= 1 # column index will be the last column whether isDataTypeValueType was true or false
#endregion
} }
} }
} catch {throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" }
End { }}
end {
if ($firstTimeThru -and $ws.Dimension) { if ($firstTimeThru -and $ws.Dimension) {
$LastRow = $ws.Dimension.End.Row $LastRow = $ws.Dimension.End.Row
$LastCol = $ws.Dimension.End.Column $LastCol = $ws.Dimension.End.Column
@@ -809,13 +789,16 @@
# if we have 5 columns from 3 to 8, headers are numbered 0..4, so that is in the for loop and used for getting the name... # if we have 5 columns from 3 to 8, headers are numbered 0..4, so that is in the for loop and used for getting the name...
# but we have to add the start column on when referencing positions # but we have to add the start column on when referencing positions
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 "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property name." Write-Warning -Message "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property."
} }
} Catch {} }
Catch {
Write-Warning -Message "AutoNameRange: Testing '$targetRangeName' caused an error. This should be harmless, but a change of property name may be needed.."
}
} }
} }
catch {Write-Warning -Message "Failed adding named ranges to worksheet '$WorksheetName': $_" } catch {Write-Warning -Message "Failed adding named ranges to worksheet '$WorksheetName': $_" }
@@ -823,14 +806,17 @@
#Empty string is not allowed as a name for ranges or tables. #Empty string is not allowed as a name for ranges or tables.
if ($RangeName) { Add-ExcelName -Range $ws.Cells[$dataRange] -RangeName $RangeName} if ($RangeName) { Add-ExcelName -Range $ws.Cells[$dataRange] -RangeName $RangeName}
if ($TableName) { #Allow table to be inserted by specifying Name, or Style or both; only process autoFilter if there is no table (they clash).
if ($null -ne $TableName) {
if ($PSBoundParameters.ContainsKey('TableStyle')) { if ($PSBoundParameters.ContainsKey('TableStyle')) {
Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $TableName -TableStyle $TableStyle Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $TableName -TableStyle $TableStyle
} }
else {Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $TableName} else {Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $TableName}
} }
elseif ($PSBoundParameters.ContainsKey('TableStyle')) {
if ($AutoFilter) { Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName "" -TableStyle $TableStyle
}
elseif ($AutoFilter) {
try { try {
$ws.Cells[$dataRange].AutoFilter = $true $ws.Cells[$dataRange].AutoFilter = $true
Write-Verbose -Message "Enabled autofilter. " Write-Verbose -Message "Enabled autofilter. "
@@ -923,13 +909,19 @@
} }
catch {Write-Warning -Message "Failed setting the top row to bold in worksheet '$WorksheetName': $_"} catch {Write-Warning -Message "Failed setting the top row to bold in worksheet '$WorksheetName': $_"}
} }
if ($AutoSize) { if ($AutoSize -and -not $env:NoAutoSize) {
try { try {
$ws.Cells.AutoFitColumns() #Don't fit the all the columns in the sheet; if we are adding cells beside things with hidden columns, that unhides them
if ($MaxAutoSizeRows -and $MaxAutoSizeRows -lt $LastRow ) {
$AutosizeRange = [OfficeOpenXml.ExcelAddress]::GetAddress($startRow,$StartColumn, $MaxAutoSizeRows , $LastCol)
$ws.Cells[$AutosizeRange].AutoFitColumns()
}
else {$ws.Cells[$dataRange].AutoFitColumns() }
Write-Verbose -Message "Auto-sized columns" Write-Verbose -Message "Auto-sized columns"
} }
catch { Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_"} catch { Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_"}
} }
elseif ($AutoSize) {Write-Warning -Message "Auto-fitting columns is not available with this OS configuration." }
foreach ($Sheet in $HideSheet) { foreach ($Sheet in $HideSheet) {
try { try {
@@ -1031,7 +1023,10 @@
} }
catch {throw "Error applying conditional formatting to worksheet $_"} catch {throw "Error applying conditional formatting to worksheet $_"}
} }
foreach ($s in $Style) {
if (-not $s.Range) {$s["Range"] = $ws.Dimension.Address }
Set-ExcelRange -WorkSheet $ws @s
}
if ($CellStyleSB) { if ($CellStyleSB) {
try { try {
$TotalRows = $ws.Dimension.Rows $TotalRows = $ws.Dimension.Rows
@@ -1069,9 +1064,9 @@
} }
try { try {
$TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName()) $TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
[io.compression.zipfile]::ExtractToDirectory($pkg.File, $TempZipPath) | Out-Null $null = [io.compression.zipfile]::ExtractToDirectory($pkg.File, $TempZipPath)
Remove-Item $pkg.File -Force Remove-Item $pkg.File -Force
[io.compression.zipfile]::CreateFromDirectory($TempZipPath, $pkg.File) | Out-Null $null = [io.compression.zipfile]::CreateFromDirectory($TempZipPath, $pkg.File)
} }
catch {throw "Error resizipping $path : $_"} catch {throw "Error resizipping $path : $_"}
} }
@@ -1087,7 +1082,7 @@
function Add-WorkSheet { function Add-WorkSheet {
<# <#
.Synopsis .Synopsis
Adds a workshet to an existing workbook. Adds a worksheet to an existing workbook.
.Description .Description
If the named worksheet already exists, the -Clearsheet parameter decides whether it should be deleted and a new one returned, If the named worksheet already exists, the -Clearsheet parameter decides whether it should be deleted and a new one returned,
or if not specified the existing sheet will be returned. By default the sheet is created at the end of the work book, the or if not specified the existing sheet will be returned. By default the sheet is created at the end of the work book, the
@@ -1250,7 +1245,7 @@ function Select-Worksheet {
} }
} }
Function Add-ExcelName { function Add-ExcelName {
<# <#
.SYNOPSIS .SYNOPSIS
Adds a named-range to an existing Excel worksheet. Adds a named-range to an existing Excel worksheet.
@@ -1285,7 +1280,7 @@ Function Add-ExcelName {
} }
else { else {
Write-verbose -Message "Creating Named range '$RangeName' as $($Range.FullAddressAbsolute)." Write-verbose -Message "Creating Named range '$RangeName' as $($Range.FullAddressAbsolute)."
$ws.Names.Add($RangeName, $Range) | Out-Null $null = $ws.Names.Add($RangeName, $Range)
} }
} }
catch {Write-Warning -Message "Failed adding named range '$RangeName' to worksheet '$($ws.Name)': $_" } catch {Write-Warning -Message "Failed adding named range '$RangeName' to worksheet '$($ws.Name)': $_" }
@@ -1314,9 +1309,8 @@ function Add-ExcelTable {
#The range of cells to assign to a table. #The range of cells to assign to a table.
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]
[OfficeOpenXml.ExcelRange]$Range, [OfficeOpenXml.ExcelRange]$Range,
#The name for the Table - this should be unqiue in the Workbook. #The name for the Table - this should be unqiue in the Workbook - auto generated names will be used if this is left empty.
[Parameter(Mandatory=$true)] [String]$TableName = "",
[String]$TableName,
#The Style for the table, by default "Medium6" is used #The Style for the table, by default "Medium6" is used
[OfficeOpenXml.Table.TableStyles]$TableStyle = 'Medium6', [OfficeOpenXml.Table.TableStyles]$TableStyle = 'Medium6',
#By default the header row is shown - it can be turned off with -ShowHeader:$false. #By default the header row is shown - it can be turned off with -ShowHeader:$false.
@@ -1339,24 +1333,37 @@ function Add-ExcelTable {
[Switch]$PassThru [Switch]$PassThru
) )
try { try {
if ($TableName -match "\W") { if ($TableName -eq "" -or $null -eq $TableName) {
Write-Warning -Message "At least one character in $TableName is illegal in a table name and will be replaced with '_' . " $tbl = $Range.Worksheet.Tables.Add($Range, "")
$TableName = $TableName -replace '\W', '_'
}
$ws = $Range.Worksheet
#if the table exists in this worksheet, update it.
if ($ws.Tables[$TableName]) {
$tbl =$ws.Tables[$TableName]
$tbl.TableXml.table.ref = $Range.Address
Write-Verbose -Message "Re-defined table '$TableName', now at $($Range.Address)."
}
elseif ($ws.Workbook.Worksheets.Tables.Name -contains $TableName) {
Write-Warning -Message "The Table name '$TableName' is already used on a different worksheet."
return
} }
else { else {
$tbl = $ws.Tables.Add($Range, $TableName) if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress($TableName)) {
Write-Verbose -Message "Defined table '$TableName' at $($Range.Address)" Write-Warning -Message "$TableName reads as an Excel address, and so is not allowed as a table name."
return
}
if ($TableName -notMatch '^[A-Z]') {
Write-Warning -Message "$TableName is not allowed as a table name because it does not begin with a letter."
return
}
if ($TableName -match "\W") {
Write-Warning -Message "At least one character in $TableName is illegal in a table name and will be replaced with '_' . "
$TableName = $TableName -replace '\W', '_'
}
$ws = $Range.Worksheet
#if the table exists in this worksheet, update it.
if ($ws.Tables[$TableName]) {
$tbl =$ws.Tables[$TableName]
$tbl.TableXml.table.ref = $Range.Address
Write-Verbose -Message "Re-defined table '$TableName', now at $($Range.Address)."
}
elseif ($ws.Workbook.Worksheets.Tables.Name -contains $TableName) {
Write-Warning -Message "The Table name '$TableName' is already used on a different worksheet."
return
}
else {
$tbl = $ws.Tables.Add($Range, $TableName)
Write-Verbose -Message "Defined table '$($tbl.Name)' at $($Range.Address)"
}
} }
#it seems that show total changes some of the others, so the sequence matters. #it seems that show total changes some of the others, so the sequence matters.
if ($PSBoundParameters.ContainsKey('ShowHeader')) {$tbl.ShowHeader = [bool]$ShowHeader} if ($PSBoundParameters.ContainsKey('ShowHeader')) {$tbl.ShowHeader = [bool]$ShowHeader}
@@ -1365,7 +1372,7 @@ function Add-ExcelTable {
foreach ($k in $TotalSettings.keys) { foreach ($k in $TotalSettings.keys) {
if (-not $tbl.Columns[$k]) {Write-Warning -Message "Table does not have a Column '$k'."} if (-not $tbl.Columns[$k]) {Write-Warning -Message "Table does not have a Column '$k'."}
elseif ($TotalSettings[$k] -notin @("Average", "Count", "CountNums", "Max", "Min", "None", "StdDev", "Sum", "Var") ) { elseif ($TotalSettings[$k] -notin @("Average", "Count", "CountNums", "Max", "Min", "None", "StdDev", "Sum", "Var") ) {
Write-wanring "'$($TotalSettings[$k])' is not a valid total function." Write-Warning -Message "'$($TotalSettings[$k])' is not a valid total function."
} }
else {$tbl.Columns[$k].TotalsRowFunction = $TotalSettings[$k]} else {$tbl.Columns[$k].TotalsRowFunction = $TotalSettings[$k]}
} }
@@ -1376,9 +1383,9 @@ function Add-ExcelTable {
if ($PSBoundParameters.ContainsKey('ShowLastColumn')) {$tbl.ShowLastColumn = [bool]$ShowLastColumn} if ($PSBoundParameters.ContainsKey('ShowLastColumn')) {$tbl.ShowLastColumn = [bool]$ShowLastColumn}
if ($PSBoundParameters.ContainsKey('ShowRowStripes')) {$tbl.ShowRowStripes = [bool]$ShowRowStripes} if ($PSBoundParameters.ContainsKey('ShowRowStripes')) {$tbl.ShowRowStripes = [bool]$ShowRowStripes}
if ($PSBoundParameters.ContainsKey('ShowColumnStripes')) {$tbl.ShowColumnStripes = [bool]$ShowColumnStripes} if ($PSBoundParameters.ContainsKey('ShowColumnStripes')) {$tbl.ShowColumnStripes = [bool]$ShowColumnStripes}
if ($PSBoundParameters.ContainsKey('TableStyle')) {$tbl.TableStyle = $TableStyle} $tbl.TableStyle = $TableStyle
if ($PassThru) {return $tbl} if ($PassThru) {return $tbl}
} }
catch {Write-Warning -Message "Failed adding table '$TableName' to worksheet '$WorksheetName': $_"} catch {Write-Warning -Message "Failed adding table '$TableName' to worksheet '$WorksheetName': $_"}
} }

28
Export-StocksToExcel.ps1 Normal file
View File

@@ -0,0 +1,28 @@
function Export-StocksToExcel {
param(
[string]$symbols,
[ValidateSet("Open", "High", "Low", "Close", "Volume")]
$measure = "Open"
)
$xl = Join-Path ([IO.Path]::GetTempPath()) 'Stocks.xlsx'
Remove-Item $xl -ErrorAction SilentlyContinue
$r = Invoke-RestMethod "https://azfnstockdata-fn83fffd32.azurewebsites.net/api/GetQuoteChart?symbol=$($symbols)"
$chartColumn = $symbols.Split(',').count + 2
$ptd = New-PivotTableDefinition `
-SourceWorkSheet Sheet1 `
-PivotTableName result `
-PivotData @{$measure = 'sum'} `
-PivotRows date `
-PivotColumns symbol `
-ChartType Line `
-ChartTitle "Stock - $measure " `
-IncludePivotChart -NoTotalsInPivot -ChartColumn $chartColumn -ChartRow 3 -Activate
$r | Sort-Object Date, symbol | Export-Excel $xl -PivotTableDefinition $ptd -AutoSize -AutoFilter -Show
}
# Export-StocksToExcel -symbols 'ibm,aapl,msft' -measure High

View File

@@ -1,49 +1,49 @@
<# <#
.Synopsis .Synopsis
Exports the charts in an Excel spreadSheet Exports the charts in an Excel spreadSheet
.Example .Example
Export-Charts .\test.xlsx Export-Charts .\test.xlsx
Exports the charts in test.xlsx to JPEG files in the current directory. Exports the charts in test.xlsx to JPEG files in the current directory.
.Example .Example
Export-Charts -path .\test,xlsx -destination [System.Environment+SpecialFolder]::MyDocuments -outputType PNG -passthrough Export-Charts -path .\test,xlsx -destination [System.Environment+SpecialFolder]::MyDocuments -outputType PNG -passthrough
Exports the charts to PNG files in MyDocuments , and returns file objects representing the newly created files Exports the charts to PNG files in MyDocuments , and returns file objects representing the newly created files
#> #>
Param ( Param (
#Path to the Excel file whose chars we will export. #Path to the Excel file whose chars we will export.
$Path = "C:\Users\public\Documents\stats.xlsx", $Path = "C:\Users\public\Documents\stats.xlsx",
#If specified, output file objects representing the image files #If specified, output file objects representing the image files
[switch]$Passthru, [switch]$Passthru,
#Format to write - JPG by default #Format to write - JPG by default
[ValidateSet("JPG","PNG","GIF")] [ValidateSet("JPG","PNG","GIF")]
$OutputType = "JPG", $OutputType = "JPG",
#Folder to write image files to (defaults to same one as the Excel file is in) #Folder to write image files to (defaults to same one as the Excel file is in)
$Destination $Destination
) )
#if no output folder was specified, set destination to the folder where the Excel file came from #if no output folder was specified, set destination to the folder where the Excel file came from
if (-not $Destination) {$Destination = Split-Path -Path $Path -Parent } if (-not $Destination) {$Destination = Split-Path -Path $Path -Parent }
#Call up Excel and tell it to open the file. #Call up Excel and tell it to open the file.
try { $excelApp = New-Object -ComObject "Excel.Application" } try { $excelApp = New-Object -ComObject "Excel.Application" }
catch { Write-Warning "Could not start Excel application - which usually means it is not installed." ; return } catch { Write-Warning "Could not start Excel application - which usually means it is not installed." ; return }
try { $excelWorkBook = $excelApp.Workbooks.Open($Path) } try { $excelWorkBook = $excelApp.Workbooks.Open($Path) }
catch { Write-Warning -Message "Could not Open $Path." ; return } catch { Write-Warning -Message "Could not Open $Path." ; return }
#For each worksheet, for each chart, jump to the chart, create a filename of "WorksheetName_ChartTitle.jpg", and export the file. #For each worksheet, for each chart, jump to the chart, create a filename of "WorksheetName_ChartTitle.jpg", and export the file.
foreach ($excelWorkSheet in $excelWorkBook.Worksheets) { foreach ($excelWorkSheet in $excelWorkBook.Worksheets) {
#note somewhat unusual way of telling excel we want all the charts. #note somewhat unusual way of telling excel we want all the charts.
foreach ($excelchart in $excelWorkSheet.ChartObjects([System.Type]::Missing)) { foreach ($excelchart in $excelWorkSheet.ChartObjects([System.Type]::Missing)) {
#if you don't go to the chart the image will be zero size ! #if you don't go to the chart the image will be zero size !
$excelApp.Goto($excelchart.TopLeftCell,$true) $excelApp.Goto($excelchart.TopLeftCell,$true)
$imagePath = Join-Path -Path $Destination -ChildPath ($excelWorkSheet.Name + "_" + ($excelchart.Chart.ChartTitle.Text -split "\s\d\d:\d\d,")[0] + ".$OutputType") $imagePath = Join-Path -Path $Destination -ChildPath ($excelWorkSheet.Name + "_" + ($excelchart.Chart.ChartTitle.Text -split "\s\d\d:\d\d,")[0] + ".$OutputType")
if ( $excelchart.Chart.Export($imagePath, $OutputType, $false) ) { # Export returs true/false for success/failure if ( $excelchart.Chart.Export($imagePath, $OutputType, $false) ) { # Export returs true/false for success/failure
if ($Passthru) {Get-Item -Path $imagePath } # when succesful return a file object (-Passthru) or print a verbose message, write warning for any failures if ($Passthru) {Get-Item -Path $imagePath } # when succesful return a file object (-Passthru) or print a verbose message, write warning for any failures
else {Write-Verbose -Message "Exported $imagePath"} else {Write-Verbose -Message "Exported $imagePath"}
} }
else {Write-Warning -Message "Failure exporting $imagePath" } else {Write-Warning -Message "Failure exporting $imagePath" }
} }
} }
$excelApp.DisplayAlerts = $false $excelApp.DisplayAlerts = $false

View File

@@ -6,10 +6,15 @@ function Get-ExcelColumnName {
Process { Process {
$dividend = $columnNumber $dividend = $columnNumber
$columnName = @() $columnName = New-Object System.Collections.ArrayList($null)
while($dividend -gt 0) { while($dividend -gt 0) {
$modulo = ($dividend - 1) % 26 $modulo = ($dividend - 1) % 26
$columnName += [char](65 + $modulo) if ($columnName.length -eq 0) {
[char](65 + $modulo)
} else {
$columnName.insert(0,[char](65 + $modulo))
}
$dividend = [int](($dividend -$modulo)/26) $dividend = [int](($dividend -$modulo)/26)
} }
@@ -19,4 +24,4 @@ function Get-ExcelColumnName {
} }
} }
} }

View File

@@ -29,7 +29,7 @@ Function Get-ExcelSheetInfo {
$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path,'Open','Read','ReadWrite' $stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path,'Open','Read','ReadWrite'
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream $xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream
$workbook = $xl.Workbook $workbook = $xl.Workbook
if ($workbook -and $workbook.Worksheets) { if ($workbook -and $workbook.Worksheets) {
$workbook.Worksheets | $workbook.Worksheets |
Select-Object -Property name,index,hidden,@{ Select-Object -Property name,index,hidden,@{

View File

@@ -1,8 +1,8 @@
Function Get-ExcelWorkbookInfo { Function Get-ExcelWorkbookInfo {
<# <#
.SYNOPSIS .SYNOPSIS
Retrieve information of an Excel workbook. Retrieve information of an Excel workbook.
.DESCRIPTION .DESCRIPTION
The Get-ExcelWorkbookInfo cmdlet retrieves information (LastModifiedBy, LastPrinted, Created, Modified, ...) fron an Excel workbook. These are the same details that are visible in Windows Explorer when right clicking the Excel file, selecting Properties and check the Details tabpage. The Get-ExcelWorkbookInfo cmdlet retrieves information (LastModifiedBy, LastPrinted, Created, Modified, ...) fron an Excel workbook. These are the same details that are visible in Windows Explorer when right clicking the Excel file, selecting Properties and check the Details tabpage.
.PARAMETER Path .PARAMETER Path
Specifies the path to the Excel file. This parameter is required. Specifies the path to the Excel file. This parameter is required.
@@ -10,22 +10,22 @@
Get-ExcelWorkbookInfo .\Test.xlsx Get-ExcelWorkbookInfo .\Test.xlsx
CorePropertiesXml : #document CorePropertiesXml : #document
Title : Title :
Subject : Subject :
Author : Konica Minolta User Author : Konica Minolta User
Comments : Comments :
Keywords : Keywords :
LastModifiedBy : Bond, James (London) GBR LastModifiedBy : Bond, James (London) GBR
LastPrinted : 2017-01-21T12:36:11Z LastPrinted : 2017-01-21T12:36:11Z
Created : 17/01/2017 13:51:32 Created : 17/01/2017 13:51:32
Category : Category :
Status : Status :
ExtendedPropertiesXml : #document ExtendedPropertiesXml : #document
Application : Microsoft Excel Application : Microsoft Excel
HyperlinkBase : HyperlinkBase :
AppVersion : 14.0300 AppVersion : 14.0300
Company : Secret Service Company : Secret Service
Manager : Manager :
Modified : 10/02/2017 12:45:37 Modified : 10/02/2017 12:45:37
CustomPropertiesXml : #document CustomPropertiesXml : #document
@@ -35,8 +35,8 @@
.LINK .LINK
https://github.com/dfinke/ImportExcel https://github.com/dfinke/ImportExcel
#> #>
[CmdletBinding()] [CmdletBinding()]
Param ( Param (
[Alias('FullName')] [Alias('FullName')]
@@ -52,12 +52,12 @@
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream $xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream
$workbook = $xl.Workbook $workbook = $xl.Workbook
$workbook.Properties $workbook.Properties
$stream.Close() $stream.Close()
$stream.Dispose() $stream.Dispose()
$xl.Dispose() $xl.Dispose()
$xl = $null $xl = $null
} }
Catch { Catch {
throw "Failed retrieving Excel workbook information for '$Path': $_" throw "Failed retrieving Excel workbook information for '$Path': $_"
} }

View File

@@ -1,3 +1,5 @@
# https://www.leeholmes.com/blog/2015/01/05/extracting-tables-from-powershells-invoke-webrequest/
# tweaked from the above code
function Get-HtmlTable { function Get-HtmlTable {
param( param(
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]
@@ -9,7 +11,7 @@ function Get-HtmlTable {
) )
$r = Invoke-WebRequest $url -UseDefaultCredentials: $UseDefaultCredentials $r = Invoke-WebRequest $url -UseDefaultCredentials: $UseDefaultCredentials
$table = $r.ParsedHtml.getElementsByTagName("table")[$tableIndex] $table = $r.ParsedHtml.getElementsByTagName("table")[$tableIndex]
$propertyNames=$Header $propertyNames=$Header
$totalRows=@($table.rows).count $totalRows=@($table.rows).count
@@ -17,7 +19,7 @@ function Get-HtmlTable {
for ($idx = $FirstDataRow; $idx -lt $totalRows; $idx++) { for ($idx = $FirstDataRow; $idx -lt $totalRows; $idx++) {
$row = $table.rows[$idx] $row = $table.rows[$idx]
$cells = @($row.cells) $cells = @($row.cells)
if(!$propertyNames) { if(!$propertyNames) {
if($cells[0].tagName -eq 'th') { if($cells[0].tagName -eq 'th') {
@@ -26,7 +28,7 @@ function Get-HtmlTable {
$propertyNames = @(1..($cells.Count + 2) | Foreach-Object { "P$_" }) $propertyNames = @(1..($cells.Count + 2) | Foreach-Object { "P$_" })
} }
continue continue
} }
$result = [ordered]@{} $result = [ordered]@{}
@@ -39,4 +41,4 @@ function Get-HtmlTable {
[PSCustomObject]$result [PSCustomObject]$result
} }
} }

View File

@@ -96,7 +96,7 @@ function ConvertFrom-ExcelColumnName {
$sum $sum
} }
ipmo .\ImportExcel.psd1 -Force Import-Module .\ImportExcel.psd1 -Force
#Get-ExcelTableName .\testTable.xlsx | Get-ExcelTable .\testTable.xlsx #Get-ExcelTableName .\testTable.xlsx | Get-ExcelTable .\testTable.xlsx
Get-ExcelTable .\testTable.xlsx Table3 Get-ExcelTable .\testTable.xlsx Table3

View File

@@ -2,19 +2,19 @@
function Import-Html { function Import-Html {
[CmdletBinding()] [CmdletBinding()]
param( param(
$url, $url,
$index, $index,
$Header, $Header,
[int]$FirstDataRow=0, [int]$FirstDataRow=0,
[Switch]$UseDefaultCredentials [Switch]$UseDefaultCredentials
) )
$xlFile = [System.IO.Path]::GetTempFileName() -replace "tmp","xlsx" $xlFile = [System.IO.Path]::GetTempFileName() -replace "tmp","xlsx"
rm $xlFile -ErrorAction Ignore Remove-Item $xlFile -ErrorAction Ignore
Write-Verbose "Exporting to Excel file $($xlFile)" Write-Verbose "Exporting to Excel file $($xlFile)"
$data = Get-HtmlTable -url $url -tableIndex $index -Header $Header -FirstDataRow $FirstDataRow -UseDefaultCredentials: $UseDefaultCredentials $data = Get-HtmlTable -url $url -tableIndex $index -Header $Header -FirstDataRow $FirstDataRow -UseDefaultCredentials: $UseDefaultCredentials
$data | Export-Excel $xlFile -Show -AutoSize $data | Export-Excel $xlFile -Show -AutoSize
} }

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
RootModule = 'ImportExcel.psm1' RootModule = 'ImportExcel.psm1'
# Version number of this module. # Version number of this module.
ModuleVersion = '5.4.0' ModuleVersion = '6.5.3'
# 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'
@@ -16,7 +16,7 @@
CompanyName = 'Doug Finke' CompanyName = 'Doug Finke'
# Copyright statement for this module # Copyright statement for this module
Copyright = 'c 2015 All rights reserved.' Copyright = 'c 2019 All rights reserved.'
# Description of the functionality provided by this module # Description of the functionality provided by this module
Description = @' Description = @'
@@ -61,16 +61,86 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
# NestedModules = @() # NestedModules = @()
# Functions to export from this module # Functions to export from this module
FunctionsToExport = '*' FunctionsToExport = @(
'Add-ConditionalFormatting',
'Add-ExcelChart',
'Add-ExcelDataValidationRule',
'Add-ExcelName',
'Add-ExcelTable',
'Add-PivotTable',
'Add-WorkSheet',
'BarChart',
'Close-ExcelPackage',
'ColumnChart',
'Compare-WorkSheet',
'Convert-XlRangeToImage',
'ConvertFrom-ExcelData',
'ConvertFrom-ExcelSheet',
'ConvertFrom-ExcelToSQLInsert',
'ConvertTo-ExcelXlsx',
'Copy-ExcelWorkSheet',
'DoChart',
'Expand-NumberFormat',
'Export-Excel',
'Export-ExcelSheet',
'Export-MultipleExcelSheets',
'Get-ExcelColumnName',
'Get-ExcelSheetInfo',
'Get-ExcelWorkbookInfo',
'Get-HtmlTable',
'Get-Range',
'Get-XYRange',
'Import-Excel',
'Import-Html',
'Import-UPS',
'Import-USPS',
'Invoke-AllTests',
'Invoke-Sum',
'Join-Worksheet',
'LineChart',
'Merge-MultipleSheets',
'Merge-Worksheet',
'New-ConditionalFormattingIconSet',
'New-ConditionalText',
'New-ExcelChartDefinition',
'New-ExcelStyle',
'New-PivotTableDefinition',
'New-Plot',
'New-PSItem',
'NumberFormatCompletion',
'Open-ExcelPackage',
'PieChart',
'Pivot',
'Remove-WorkSheet'
'Select-Worksheet',
'Send-SQLDataToExcel',
'Set-CellStyle',
'Set-ExcelColumn',
'Set-ExcelRange',
'Set-ExcelRow',
'Set-WorkSheetProtection',
'Test-Boolean',
'Test-Date',
'Test-Integer',
'Test-Number',
'Test-String',
'Update-FirstObjectProperties'
)
# Cmdlets to export from this module # Cmdlets to export from this module
CmdletsToExport = '*' #CmdletsToExport = '*'
# Variables to export from this module # Variables to export from this module
VariablesToExport = '*' #VariablesToExport = '*'
# Aliases to export from this module # Aliases to export from this module
AliasesToExport = '*' AliasesToExport = @(
'New-ExcelChart',
'Set-Column',
'Set-Format',
'Set-Row',
'Use-ExcelData'
)
# List of all modules packaged with this module # List of all modules packaged with this module
# ModuleList = @() # ModuleList = @()

View File

@@ -1,62 +1,91 @@
#region import everything we need #region import everything we need
Add-Type -Path "$($PSScriptRoot)\EPPlus.dll" Add-Type -Path "$($PSScriptRoot)\EPPlus.dll"
. $PSScriptRoot\AddConditionalFormatting.ps1 . $PSScriptRoot\AddConditionalFormatting.ps1
. $PSScriptRoot\Charting.ps1 . $PSScriptRoot\AddDataValidation.ps1
. $PSScriptRoot\ColorCompletion.ps1 . $PSScriptRoot\Charting.ps1
. $PSScriptRoot\ConvertExcelToImageFile.ps1 . $PSScriptRoot\ColorCompletion.ps1
. $PSScriptRoot\Compare-WorkSheet.ps1 . $PSScriptRoot\Compare-WorkSheet.ps1
. $PSScriptRoot\ConvertFromExcelData.ps1 . $PSScriptRoot\ConvertExcelToImageFile.ps1
. $PSScriptRoot\ConvertFromExcelToSQLInsert.ps1 . $PSScriptRoot\ConvertFromExcelData.ps1
. $PSScriptRoot\ConvertToExcelXlsx.ps1 . $PSScriptRoot\ConvertFromExcelToSQLInsert.ps1
. $PSScriptRoot\Copy-ExcelWorkSheet.ps1 . $PSScriptRoot\ConvertToExcelXlsx.ps1
. $PSScriptRoot\Export-Excel.ps1 . $PSScriptRoot\Copy-ExcelWorkSheet.ps1
. $PSScriptRoot\Export-ExcelSheet.ps1 . $PSScriptRoot\Export-Excel.ps1
. $PSScriptRoot\Get-ExcelColumnName.ps1 . $PSScriptRoot\Export-ExcelSheet.ps1
. $PSScriptRoot\Get-ExcelSheetInfo.ps1 . $PSScriptRoot\Export-StocksToExcel.ps1
. $PSScriptRoot\Get-ExcelWorkbookInfo.ps1 . $PSScriptRoot\Get-ExcelColumnName.ps1
. $PSScriptRoot\Get-HtmlTable.ps1 . $PSScriptRoot\Get-ExcelSheetInfo.ps1
. $PSScriptRoot\Get-Range.ps1 . $PSScriptRoot\Get-ExcelWorkbookInfo.ps1
. $PSScriptRoot\Get-XYRange.ps1 . $PSScriptRoot\Get-HtmlTable.ps1
. $PSScriptRoot\Import-Html.ps1 . $PSScriptRoot\Get-Range.ps1
. $PSScriptRoot\InferData.ps1 . $PSScriptRoot\Get-XYRange.ps1
. $PSScriptRoot\Invoke-Sum.ps1 . $PSScriptRoot\Import-Html.ps1
. $PSScriptRoot\Join-WorkSheet.ps1 . $PSScriptRoot\InferData.ps1
. $PSScriptRoot\Merge-Worksheet.ps1 . $PSScriptRoot\Invoke-Sum.ps1
. $PSScriptRoot\New-ConditionalFormattingIconSet.ps1 . $PSScriptRoot\Join-Worksheet.ps1
. $PSScriptRoot\New-ConditionalText.ps1 . $PSScriptRoot\Merge-Worksheet.ps1
. $PSScriptRoot\New-ExcelChart.ps1 . $PSScriptRoot\New-ConditionalFormattingIconSet.ps1
. $PSScriptRoot\New-PSItem.ps1 . $PSScriptRoot\New-ConditionalText.ps1
. $PSScriptRoot\Open-ExcelPackage.ps1 . $PSScriptRoot\New-ExcelChart.ps1
. $PSScriptRoot\Pivot.ps1 . $PSScriptRoot\New-PSItem.ps1
. $PSScriptRoot\PivotTable.ps1 . $PSScriptRoot\Open-ExcelPackage.ps1
. $PSScriptRoot\Send-SQLDataToExcel.ps1 . $PSScriptRoot\Pivot.ps1
. $PSScriptRoot\Set-CellStyle.ps1 . $PSScriptRoot\PivotTable.ps1
. $PSScriptRoot\Set-Column.ps1 #. $PSScriptRoot\Plot.ps1
. $PSScriptRoot\Set-Row.ps1 . $PSScriptRoot\RemoveWorksheet.ps1
. $PSScriptRoot\SetFormat.ps1 . $PSScriptRoot\Send-SQLDataToExcel.ps1
. $PSScriptRoot\TrackingUtils.ps1 . $PSScriptRoot\Set-CellStyle.ps1
. $PSScriptRoot\Update-FirstObjectProperties.ps1 . $PSScriptRoot\Set-Column.ps1
. $PSScriptRoot\Set-Row.ps1
. $PSScriptRoot\Set-WorkSheetProtection.ps1
. $PSScriptRoot\SetFormat.ps1
. $PSScriptRoot\TrackingUtils.ps1
. $PSScriptRoot\Update-FirstObjectProperties.ps1
New-Alias -Name Use-ExcelData -Value "ConvertFrom-ExcelData" -Force New-Alias -Name Use-ExcelData -Value "ConvertFrom-ExcelData" -Force
if ($PSVersionTable.PSVersion.Major -ge 5) { if ($PSVersionTable.PSVersion.Major -ge 5) {
. $PSScriptRoot\Plot.ps1 . $PSScriptRoot\Plot.ps1
Function New-Plot { Function New-Plot {
Param() [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'New-Plot does not change system state')]
Param()
[PSPlot]::new() [PSPlot]::new()
}
}
else {
Write-Warning 'PowerShell 5 is required for plot.ps1'
Write-Warning 'PowerShell Excel is ready, except for that functionality'
}
if (($IsLinux -or $IsMacOS) -or $env:NoAutoSize) {
$ExcelPackage = [OfficeOpenXml.ExcelPackage]::new()
$Cells = ($ExcelPackage | Add-WorkSheet).Cells['A1']
$Cells.Value = 'Test'
try {
$Cells.AutoFitColumns()
if ($env:NoAutoSize) {Remove-Item Env:\NoAutoSize}
}
catch {
$env:NoAutoSize = $true
if ($IsLinux) {
Write-Warning -Message ('ImportExcel Module Cannot Autosize. Please run the following command to install dependencies:' + [environment]::newline +
'"sudo apt-get install -y --no-install-recommends libgdiplus libc6-dev"')
}
if ($IsMacOS) {
Write-Warning -Message ('ImportExcel Module Cannot Autosize. Please run the following command to install dependencies:' + [environment]::newline +
'"brew install mono-libgdiplus"')
} }
} }
else { finally {
Write-Warning 'PowerShell 5 is required for plot.ps1' $ExcelPackage | Close-ExcelPackage -NoSave
Write-Warning 'PowerShell Excel is ready, except for that functionality'
} }
}
#endregion #endregion
function Import-Excel { function Import-Excel {
<# <#
.SYNOPSIS .SYNOPSIS
Create custom objects from the rows in an Excel worksheet. Create custom objects from the rows in an Excel worksheet.
@@ -69,7 +98,11 @@ function Import-Excel {
.PARAMETER Path .PARAMETER Path
Specifies the path to the Excel file. Specifies the path to the Excel file.
.PARAMETER ExcelPackage
Instead of specifying a path provides an Excel Package object (from Open-ExcelPackage)
Using this avoids re-reading the whole file when importing multiple parts of it.
To allow multiple read operations Import-Excel does NOT close the package, and you should use
Close-ExcelPackage -noSave to close it.
.PARAMETER WorksheetName .PARAMETER WorksheetName
Specifies the name of the worksheet in the Excel workbook to import. By default, if no name is provided, the first worksheet will be imported. Specifies the name of the worksheet in the Excel workbook to import. By default, if no name is provided, the first worksheet will be imported.
@@ -78,19 +111,15 @@ function Import-Excel {
.PARAMETER HeaderName .PARAMETER HeaderName
Specifies custom property names to use, instead of the values defined in the column headers of the TopRow. Specifies custom property names to use, instead of the values defined in the column headers of the TopRow.
If you provide fewer header names than there are columns of data in the worksheet, then data will only be imported from that number of columns - the others will be ignored.
In case you provide less header names than there is data in the worksheet, then only the data with a corresponding header name will be imported and the data without header name will be disregarded. If you provide more header names than there are columns of data in the worksheet, it will result in blank properties being added to the objects returned.
In case you provide more header names than there is data in the worksheet, then all data will be imported and all objects will have all the property names you defined in the header names. As such, the last properties will be blanc as there is no data for them.
.PARAMETER NoHeader .PARAMETER NoHeader
Automatically generate property names (P1, P2, P3, ..) instead of the ones defined in the column headers of the TopRow. Automatically generate property names (P1, P2, P3, ..) instead of the ones defined in the column headers of the TopRow.
This switch is best used when you want to import the complete worksheet as is and are not concerned with the property names. This switch is best used when you want to import the complete worksheet as is and are not concerned with the property names.
.PARAMETER StartRow .PARAMETER StartRow
The row from where we start to import data, all rows above the StartRow are disregarded. By default this is the first row. The row from where we start to import data, all rows above the StartRow are disregarded. By default this is the first row.
When the parameters -NoHeader and -HeaderName are not provided, this row will contain the column headers that will be used as property names. When one of both parameters are provided, the property names are automatically created and this row will be treated as a regular row containing data. When the parameters -NoHeader and -HeaderName are not provided, this row will contain the column headers that will be used as property names. When one of both parameters are provided, the property names are automatically created and this row will be treated as a regular row containing data.
.PARAMETER EndRow .PARAMETER EndRow
@@ -102,6 +131,9 @@ function Import-Excel {
.PARAMETER EndColumn .PARAMETER EndColumn
By default the import reads up to the last populated column, -EndColumn tells the import to stop at an earlier number. By default the import reads up to the last populated column, -EndColumn tells the import to stop at an earlier number.
.PARAMETER AsText
Normally Import-Excel returns the Cell values. AsText allows selected columns to be returned as the text displayed in their cells. * is supported as a wildcard.
.PARAMETER Password .PARAMETER Password
Accepts a string that will be used to open a password protected Excel file. Accepts a string that will be used to open a password protected Excel file.
@@ -247,7 +279,7 @@ function Import-Excel {
Write-SqlTableData -ServerInstance localhost\DEFAULT -Database BlankDB -SchemaName dbo -TableName MyNewTable_fromExcel -Force Write-SqlTableData -ServerInstance localhost\DEFAULT -Database BlankDB -SchemaName dbo -TableName MyNewTable_fromExcel -Force
Imports data from an Excel file and pipe the data to the Write-SqlTableData to be INSERTed into a table in a SQL Server database. Imports data from an Excel file and pipe the data to the Write-SqlTableData to be INSERTed into a table in a SQL Server database.
The ",( ... )" around the Import-Excel command allows all rows to be imported from the Excel file, prior to pipelining to the Write-SqlTableData cmdlet. This helps prevent a RBAR scenario and is important when trying to import thousands of rows. The ",( ... )" around the Import-Excel command allows all rows to be imported from the Excel file, prior to pipelining to the Write-SqlTableData cmdlet. This helps prevent a RBAR scenario and is important when trying to import thousands of rows.
The -Force parameter will be ignored if the table already exists. However, if a table is not found that matches the values provided by -SchemaName and -TableName parameters, it will create a new table in SQL Server database. The Write-SqlTableData cmdlet will inherit the column names & datatypes for the new table from the object being piped in. The -Force parameter will be ignored if the table already exists. However, if a table is not found that matches the values provided by -SchemaName and -TableName parameters, it will create a new table in SQL Server database. The Write-SqlTableData cmdlet will inherit the column names & datatypes for the new table from the object being piped in.
NOTE: You need to install the SqlServer module from the PowerShell Gallery in oder to get the Write-SqlTableData cmdlet. NOTE: You need to install the SqlServer module from the PowerShell Gallery in oder to get the Write-SqlTableData cmdlet.
@@ -257,42 +289,51 @@ function Import-Excel {
.NOTES .NOTES
#> #>
[CmdLetBinding(DefaultParameterSetName)] [CmdLetBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
Param ( Param (
[Alias('FullName')] [Alias('FullName')]
[Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Position=0, Mandatory)] [Parameter(ParameterSetName = "PathA", Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0 )]
[ValidateScript( {(Test-Path -Path $_ -PathType Leaf) -and ($_ -match '.xls$|.xlsx$|.xlsm$')})] [Parameter(ParameterSetName = "PathB", Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0 )]
[Parameter(ParameterSetName = "PathC", Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0 )]
[String]$Path, [String]$Path,
[Parameter(ParameterSetName = "PackageA", Mandatory)]
[Parameter(ParameterSetName = "PackageB", Mandatory)]
[Parameter(ParameterSetName = "PackageC", Mandatory)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Alias('Sheet')] [Alias('Sheet')]
[Parameter(Position=1)] [Parameter(Position = 1)]
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[String]$WorksheetName, [String]$WorksheetName,
[Parameter(ParameterSetName='B', Mandatory)] [Parameter(ParameterSetName = 'PathB' , Mandatory)]
[Parameter(ParameterSetName = 'PackageB', Mandatory)]
[String[]]$HeaderName , [String[]]$HeaderName ,
[Parameter(ParameterSetName='C', Mandatory)] [Parameter(ParameterSetName = 'PathC' , Mandatory)]
[Parameter(ParameterSetName = 'PackageC', Mandatory)]
[Switch]$NoHeader , [Switch]$NoHeader ,
[Alias('HeaderRow','TopRow')] [Alias('HeaderRow', 'TopRow')]
[ValidateRange(1, 9999)] [ValidateRange(1, 9999)]
[Int]$StartRow = 1, [Int]$StartRow = 1,
[Alias('StopRow','BottomRow')] [Alias('StopRow', 'BottomRow')]
[Int]$EndRow , [Int]$EndRow ,
[Alias('LeftColumn')] [Alias('LeftColumn')]
[Int]$StartColumn = 1, [Int]$StartColumn = 1,
[Alias('RightColumn')] [Alias('RightColumn')]
[Int]$EndColumn , [Int]$EndColumn ,
[Switch]$DataOnly, [Switch]$DataOnly,
[string[]]$AsText,
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[String]$Password [String]$Password
) )
Begin { begin {
$sw = [System.Diagnostics.Stopwatch]::StartNew() $sw = [System.Diagnostics.Stopwatch]::StartNew()
Function Get-PropertyNames { Function Get-PropertyNames {
<# <#
.SYNOPSIS .SYNOPSIS
Create objects containing the column number and the column name for each of the different header types. Create objects containing the column number and the column name for each of the different header types.
#> #>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = "Name would be incorrect, and command is not exported")]
Param ( Param (
[Parameter(Mandatory)] [Parameter(Mandatory)]
[Int[]]$Columns, [Int[]]$Columns,
@@ -305,96 +346,93 @@ function Import-Excel {
$i = 0 $i = 0
foreach ($C in $Columns) { foreach ($C in $Columns) {
$i++ $i++
$C | Select-Object @{N='Column'; E={$_}}, @{N='Value'; E={'P' + $i}} $C | Select-Object @{N = 'Column'; E = { $_ } }, @{N = 'Value'; E = { 'P' + $i } }
} }
} }
elseif ($HeaderName) { elseif ($HeaderName) {
$i = 0 $i = 0
foreach ($H in $HeaderName) { foreach ($H in $HeaderName) {
$H | Select-Object @{N='Column'; E={$Columns[$i]}}, @{N='Value'; E={$H}} $H | Select-Object @{N = 'Column'; E = { $Columns[$i] } }, @{N = 'Value'; E = { $H } }
$i++ $i++
} }
} }
else { else {
if ($StartRow -eq 0) { if ($StartRow -lt 1) {
throw 'The top row can never be equal to 0 when we need to retrieve headers from the worksheet.' throw 'The top row can never be less than 1 when we need to retrieve headers from the worksheet.' ; return
} }
foreach ($C in $Columns) { foreach ($C in $Columns) {
$Worksheet.Cells[$StartRow,$C] | Where-Object {$_.Value} | Select-Object @{N='Column'; E={$C}}, Value $Worksheet.Cells[$StartRow, $C] | Where-Object { $_.Value } | Select-Object @{N = 'Column'; E = { $C } }, Value
} }
} }
} }
Catch { Catch {
throw "Failed creating property names: $_" throw "Failed creating property names: $_" ; return
} }
} }
} }
Process { process {
#region Open file if ($path) {
try { $extension = [System.IO.Path]::GetExtension($Path)
$Path = (Resolve-Path $Path).ProviderPath if ($extension -notmatch '.xlsx$|.xlsm$') {
Write-Verbose "Import Excel workbook '$Path' with worksheet '$Worksheetname'" throw "Import-Excel does not support reading this extension type $($extension)"
$Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite' }
}
Catch {throw "Could not open $Path ; $_ "}
if ($Password) { $resolvedPath = (Resolve-Path $Path -ErrorAction SilentlyContinue)
Try {$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage if ($resolvedPath) {
$excel.Load( $Stream,$Password)} $Path = $resolvedPath.ProviderPath
Catch { throw "Could not read $Path with the provided password." }
}
else {
try {$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream}
Catch {throw "Failed to read $Path"}
}
#endregion
Try {
#region Select worksheet
if ($WorksheetName) {
if (-not ($Worksheet = $Excel.Workbook.Worksheets[$WorkSheetName])) {
throw "Worksheet '$WorksheetName' not found, the workbook only contains the worksheets '$($Excel.Workbook.Worksheets)'. If you only wish to select the first worksheet, please remove the '-WorksheetName' parameter."
}
} }
else { else {
$Worksheet = $Excel.Workbook.Worksheets | Select-Object -First 1 throw "'$($Path)' file not found"
} }
#endregion
$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite'
$ExcelPackage = New-Object -TypeName OfficeOpenXml.ExcelPackage
if ($Password) { $ExcelPackage.Load($stream,$Password)}
else { $ExcelPackage.Load($stream) }
}
try {
#Select worksheet
if (-not $WorksheetName) { $Worksheet = $ExcelPackage.Workbook.Worksheets[1] }
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
}
Write-Debug $sw.Elapsed.TotalMilliseconds Write-Debug $sw.Elapsed.TotalMilliseconds
#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 = $Worksheet.Dimension.End.Row }
if (-not $EndColumn) {$EndColumn = $Worksheet.Dimension.End.Column } if (-not $EndColumn) { $EndColumn = $Worksheet.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 headerrow so examine data from startRow + 1, #If we are using headers startrow will be the header-row so examine data from startRow + 1,
if ($NoHeader) {$range = "A" + ($StartRow ) + ":" + $endAddress } if ($NoHeader) { $range = "A" + ($StartRow ) + ":" + $endAddress }
else {$range = "A" + ($StartRow + 1 ) + ":" + $endAddress } else { $range = "A" + ($StartRow + 1 ) + ":" + $endAddress }
#We're going to look at every cell and build 2 hash tables holding rows & columns which contain data. #We're going to look at every cell and build 2 hash tables holding rows & columns which contain data.
#Want to Avoid 'select unique' operations & large Sorts, becuse time time taken increases with square #Want to Avoid 'select unique' operations & large Sorts, becuse time time taken increases with square
#of number of items (PS uses heapsort at large size). Instead keep a list of what we have seen, #of number of items (PS uses heapsort at large size). Instead keep a list of what we have seen,
#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 $Worksheet.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[$_] })
$columns = ($StartColumn..$EndColumn).Where({$colHash[$_]}) $columns = ($StartColumn..$EndColumn).Where( { $colHash[$_] })
} }
else { else {
$Columns = $StartColumn..$EndColumn ; if ($StartColumn -gt $EndColumn) {Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results."} $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." }
if ($NoHeader) {$Rows = ( $StartRow)..$EndRow ; if ($StartRow -gt $EndRow) {Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results."} } if ($NoHeader) { $Rows = $StartRow..$EndRow ; if ($StartRow -gt $EndRow) { Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results." } }
else {$Rows = (1 + $StartRow)..$EndRow ; if ($StartRow -ge $EndRow) {Write-Warning -Message "Selecting $StartRow as the header with data in $(1+$StartRow) to $EndRow might give odd results."}} else { $Rows = (1 + $StartRow)..$EndRow } # ; if ($StartRow -ge $EndRow) { Write-Warning -Message "Selecting $StartRow as the header with data in $(1+$StartRow) to $EndRow might give odd results." } }
} }
#endregion #endregion
#region Create property names #region Create property names
if ((-not $Columns) -or (-not ($PropertyNames = Get-PropertyNames -Columns $Columns -StartRow $StartRow))) { if ((-not $Columns) -or (-not ($PropertyNames = Get-PropertyNames -Columns $Columns -StartRow $StartRow))) {
throw "No column headers found on top row '$StartRow'. If column headers in the worksheet are not a requirement then please use the '-NoHeader' or '-HeaderName' parameter." throw "No column headers found on top row '$StartRow'. If column headers in the worksheet are not a requirement then please use the '-NoHeader' or '-HeaderName' parameter."; return
} }
if ($Duplicates = $PropertyNames | Group-Object Value | Where-Object Count -GE 2) { if ($Duplicates = $PropertyNames | Group-Object Value | Where-Object Count -GE 2) {
throw "Duplicate column headers found on row '$StartRow' in columns '$($Duplicates.Group.Column)'. Column headers must be unique, if this is not a requirement please use the '-NoHeader' or '-HeaderName' parameter." throw "Duplicate column headers found on row '$StartRow' in columns '$($Duplicates.Group.Column)'. Column headers must be unique, if this is not a requirement please use the '-NoHeader' or '-HeaderName' parameter."; return
} }
#endregion #endregion
Write-Debug $sw.Elapsed.TotalMilliseconds Write-Debug $sw.Elapsed.TotalMilliseconds
@@ -403,30 +441,42 @@ function Import-Excel {
} }
else { else {
#region Create one object per row #region Create one object per row
if ($AsText) {
<#join items in AsText together with ~~~ . Escape any regex special characters...
# which turns * into \* make it .*. Convert ~~~ to $|^ and top and tail with ^%;
So if we get "Week", "[Time]" and "*date*" ; make the expression ^week$|^\[Time\]$|^.*Date.*$
$make a regex for this which is case insensitive (option 1) and compiled (option 8)
#>
$TextColExpression = "^" + [regex]::Escape($AsText -join "~~~").replace("\*",".*").replace("~~~","$|^") +"$"
$TextColRegEx = New-Object -TypeName regex -ArgumentList $TextColExpression , 9
}
foreach ($R in $Rows) { foreach ($R in $Rows) {
#Disabled write-verbose for speed #Disabled write-verbose for speed
# Write-Verbose "Import row '$R'" # Write-Verbose "Import row '$R'"
$NewRow = [Ordered]@{} $NewRow = [Ordered]@{ }
if ($TextColRegEx) {
foreach ($P in $PropertyNames) { foreach ($P in $PropertyNames) {
$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value if ($TextColRegEx.IsMatch($P.Value)) {
# Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$($p.Value)' and value '$($Worksheet.Cells[$R, $P.Column].Value)'." $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text
}
else {$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value}
}
}
else {
foreach ($P in $PropertyNames) {
$NewRow[$P.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 [PSCustomObject]$NewRow
} }
#endregion #endregion
} }
Write-Debug $sw.Elapsed.TotalMilliseconds Write-Debug $sw.Elapsed.TotalMilliseconds
} }
Catch { catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$Worksheetname': $_"; return }
throw "Failed importing the Excel workbook '$Path' with worksheet '$Worksheetname': $_" finally {
} if ($Path) { $stream.close(); $ExcelPackage.Dispose() }
Finally {
$Stream.Close()
$Stream.Dispose()
$Excel.Dispose()
$Excel = $null
} }
} }
} }
@@ -455,11 +505,11 @@ function ConvertFrom-ExcelSheet {
[String] [String]
$OutputPath = '.\', $OutputPath = '.\',
[String] [String]
$SheetName="*", $SheetName = "*",
[ValidateSet('ASCII', 'BigEndianUniCode','Default','OEM','UniCode','UTF32','UTF7','UTF8')] [ValidateSet('ASCII', 'BigEndianUniCode', 'Default', 'OEM', 'UniCode', 'UTF32', 'UTF7', 'UTF8')]
[string] [string]
$Encoding = 'UTF8', $Encoding = 'UTF8',
[ValidateSet('.txt', '.log','.csv')] [ValidateSet('.txt', '.log', '.csv')]
[string] [string]
$Extension = '.csv', $Extension = '.csv',
[ValidateSet(';', ',')] [ValidateSet(';', ',')]
@@ -468,20 +518,19 @@ function ConvertFrom-ExcelSheet {
) )
$Path = (Resolve-Path $Path).Path $Path = (Resolve-Path $Path).Path
$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path,"Open","Read","ReadWrite" $Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, "Open", "Read", "ReadWrite"
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream $xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream
$workbook = $xl.Workbook $workbook = $xl.Workbook
$targetSheets = $workbook.Worksheets | Where-Object {$_.Name -like $SheetName} $targetSheets = $workbook.Worksheets | Where-Object { $_.Name -like $SheetName }
$params = @{} + $PSBoundParameters $params = @{ } + $PSBoundParameters
$params.Remove("OutputPath") $params.Remove("OutputPath")
$params.Remove("SheetName") $params.Remove("SheetName")
$params.Remove('Extension') $params.Remove('Extension')
$params.NoTypeInformation = $true $params.NoTypeInformation = $true
Foreach ($sheet in $targetSheets) Foreach ($sheet in $targetSheets) {
{
Write-Verbose "Exporting sheet: $($sheet.Name)" Write-Verbose "Exporting sheet: $($sheet.Name)"
$params.Path = "$OutputPath\$($Sheet.Name)$Extension" $params.Path = "$OutputPath\$($Sheet.Name)$Extension"
@@ -489,24 +538,24 @@ function ConvertFrom-ExcelSheet {
Import-Excel $Path -Sheet $($sheet.Name) | Export-Csv @params Import-Excel $Path -Sheet $($sheet.Name) | Export-Csv @params
} }
$stream.Close() $Stream.Close()
$stream.Dispose() $Stream.Dispose()
$xl.Dispose() $xl.Dispose()
} }
function Export-MultipleExcelSheets { function Export-MultipleExcelSheets {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
param( param(
[Parameter(Mandatory=$true)] [Parameter(Mandatory = $true)]
$Path, $Path,
[Parameter(Mandatory=$true)] [Parameter(Mandatory = $true)]
[hashtable]$InfoMap, [hashtable]$InfoMap,
[string]$Password, [string]$Password,
[Switch]$Show, [Switch]$Show,
[Switch]$AutoSize [Switch]$AutoSize
) )
$parameters = @{}+$PSBoundParameters $parameters = @{ } + $PSBoundParameters
$parameters.Remove("InfoMap") $parameters.Remove("InfoMap")
$parameters.Remove("Show") $parameters.Remove("Show")
@@ -514,24 +563,24 @@ function Export-MultipleExcelSheets {
foreach ($entry in $InfoMap.GetEnumerator()) { foreach ($entry in $InfoMap.GetEnumerator()) {
Write-Progress -Activity "Exporting" -Status "$($entry.Key)" Write-Progress -Activity "Exporting" -Status "$($entry.Key)"
$parameters.WorkSheetname=$entry.Key $parameters.WorkSheetname = $entry.Key
& $entry.Value | Export-Excel @parameters & $entry.Value | Export-Excel @parameters
} }
if($Show) {Invoke-Item $Path} if ($Show) { Invoke-Item $Path }
} }
Function WorksheetArgumentCompleter { Function WorksheetArgumentCompleter {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
$xlPath = $fakeBoundParameter['Path'] $xlPath = $fakeBoundParameter['Path']
if (Test-Path -Path $xlPath) { if (Test-Path -Path $xlPath) {
$xlpkg = Open-ExcelPackage -Path $xlPath $xlpkg = Open-ExcelPackage -ReadOnly -Path $xlPath
$WorksheetNames = $xlPkg.Workbook.Worksheets.Name $WorksheetNames = $xlPkg.Workbook.Worksheets.Name
Close-ExcelPackage -nosave -ExcelPackage $xlpkg Close-ExcelPackage -nosave -ExcelPackage $xlpkg
$WorksheetNames.where({$_ -like "*$wordToComplete*"}) | foreach-object { $WorksheetNames.where( { $_ -like "*$wordToComplete*" }) | foreach-object {
New-Object -TypeName System.Management.Automation.CompletionResult -ArgumentList "'$_'", New-Object -TypeName System.Management.Automation.CompletionResult -ArgumentList "'$_'",
$_ , ([System.Management.Automation.CompletionResultType]::ParameterValue) ,$_ $_ , ([System.Management.Automation.CompletionResultType]::ParameterValue) , $_
} }
} }
} }

View File

@@ -1,104 +1,213 @@
<# <#
.SYNOPSIS .SYNOPSIS
Download the module files from GitHub. Installs module from Git clone or directly from GitHub.
File must not have BOM for GitHub deploy to work.
.DESCRIPTION
Download the module files from GitHub to the local client in the module folder.
#> #>
[CmdletBinding(DefaultParameterSetName = 'Default')]
[CmdLetBinding()]
Param ( Param (
# Path to install the module to, if not provided -Scope used.
[Parameter(Mandatory, ParameterSetName = 'ModulePath')]
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[String]$ModuleName = 'ImportExcel', [String]$ModulePath,
[String]$InstallDirectory,
# Path to install the module to, PSModulePath "CurrentUser" or "AllUsers", if not provided "CurrentUser" used.
[Parameter(Mandatory, ParameterSetName = 'Scope')]
[ValidateSet('CurrentUser', 'AllUsers')]
[string]
$Scope = 'CurrentUser',
# Get module from GitHub instead of local Git clone, for example "https://raw.githubusercontent.com/ili101/Module.Template/master/Install.ps1"
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[String]$GitPath = 'https://raw.github.com/dfinke/ImportExcel/master' [Uri]$FromGitHub
)
# Set Files and Folders patterns to Include/Exclude.
$IncludeFiles = @(
'*.dll',
'*.psd1',
'*.psm1',
'AddConditionalFormatting.ps1',
'AddDataValidation.ps1',
'Charting.ps1',
'ColorCompletion.ps1',
'Compare-WorkSheet.ps1',
'ConvertExcelToImageFile.ps1',
'ConvertFromExcelData.ps1',
'ConvertFromExcelToSQLInsert.ps1',
'ConvertToExcelXlsx.ps1',
'Copy-ExcelWorkSheet.ps1',
'Export-Excel.ps1',
'Export-ExcelSheet.ps1',
'Export-StocksToExcel.ps1',
'Get-ExcelColumnName.ps1',
'Get-ExcelSheetInfo.ps1',
'Get-ExcelWorkbookInfo.ps1',
'Get-HtmlTable.ps1',
'Get-Range.ps1',
'Get-XYRange.ps1',
'Import-Html.ps1',
'InferData.ps1',
'Invoke-Sum.ps1',
'Join-Worksheet.ps1',
'Merge-Worksheet.ps1',
'New-ConditionalFormattingIconSet.ps1',
'New-ConditionalText.ps1',
'New-ExcelChart.ps1',
'New-PSItem.ps1',
'Open-ExcelPackage.ps1',
'Pivot.ps1',
'PivotTable.ps1',
'Plot.ps1',
'RemoveWorksheet.ps1',
'Send-SQLDataToExcel.ps1',
'Set-CellStyle.ps1',
'Set-Column.ps1',
'Set-Row.ps1',
'Set-WorkSheetProtection.ps1',
'SetFormat.ps1',
'TrackingUtils.ps1',
'Update-FirstObjectProperties.ps1'
)
$ExcludeFiles = @(
'Install.ps1'
) )
Begin {
Try {
Write-Verbose "$ModuleName module installation started"
$Files = @( function Invoke-MultiLike {
'AddConditionalFormatting.ps1', [alias("LikeAny")]
'Charting.ps1', [CmdletBinding()]
'ColorCompletion.ps1', param
'ConvertFromExcelData.ps1', (
'ConvertFromExcelToSQLInsert.ps1', $InputObject,
'ConvertExcelToImageFile.ps1', [Parameter(Mandatory)]
'ConvertToExcelXlsx.ps1', [String[]]$Filters,
'Copy-ExcelWorkSheet.ps1', [Switch]$Not
'EPPlus.dll', )
'Export-charts.ps1', $FiltersRegex = foreach ($Filter In $Filters) {
'Export-Excel.ps1', $Filter = [regex]::Escape($Filter)
'Export-ExcelSheet.ps1', if ($Filter -match "^\\\*") {
'formatting.ps1', $Filter = $Filter.Remove(0, 2)
'Get-ExcelColumnName.ps1', }
'Get-ExcelSheetInfo.ps1', else {
'Get-ExcelWorkbookInfo.ps1', $Filter = '^' + $Filter
'Get-HtmlTable.ps1', }
'Get-Range.ps1', if ($Filter -match "\\\*$") {
'Get-XYRange.ps1', $Filter = $Filter.Substring(0, $Filter.Length - 2)
'Import-Html.ps1', }
'ImportExcel.psd1', else {
'ImportExcel.psm1', $Filter = $Filter + '$'
'InferData.ps1', }
'Invoke-Sum.ps1', $Filter
'New-ConditionalFormattingIconSet.ps1',
'New-ConditionalText.ps1',
'New-ExcelChart.ps1',
'New-PSItem.ps1',
'Open-ExcelPackage.ps1',
'Pivot.ps1',
'plot.ps1',
'Send-SqlDataToExcel.ps1',
'Set-CellStyle.ps1',
'Set-Column.ps1',
'Set-Row.ps1',
'SetFormat.ps1',
'TrackingUtils.ps1',
'Update-FirstObjectProperties.ps1'
)
} }
Catch { if ($Not) {
throw "Failed installing the module in the install directory '$InstallDirectory': $_" $InputObject -notmatch ($FiltersRegex -join '|').replace('\*', '.*').replace('\?', '.')
}
else {
$InputObject -match ($FiltersRegex -join '|').replace('\*', '.*').replace('\?', '.')
} }
} }
Process { Try {
Try { Write-Verbose -Message 'Module installation started'
if (-not $InstallDirectory) {
Write-Verbose "$ModuleName no installation directory provided"
$PersonalModules = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath WindowsPowerShell\Modules if (!$ModulePath) {
if ($Scope -eq 'CurrentUser') {
if (($env:PSModulePath -split ';') -notcontains $PersonalModules) { $ModulePathIndex = 0
Write-Warning "$ModuleName personal module path '$PersonalModules' not found in '`$env:PSModulePath'"
}
if (-not (Test-Path $PersonalModules)) {
Write-Error "$ModuleName path '$PersonalModules' does not exist"
}
$InstallDirectory = Join-Path -Path $PersonalModules -ChildPath $ModuleName
Write-Verbose "$ModuleName default installation directory is '$InstallDirectory'"
} }
else {
if (-not (Test-Path $InstallDirectory)) { $ModulePathIndex = 1
New-Item -Path $InstallDirectory -ItemType Directory -EA Stop | Out-Null
Write-Verbose "$ModuleName created module folder '$InstallDirectory'"
} }
if ($IsLinux -or $IsMacOS) {
$WebClient = New-Object System.Net.WebClient $ModulePathSeparator = ':'
$Files | ForEach-Object {
$WebClient.DownloadFile("$GitPath/$_","$installDirectory\$_")
Write-Verbose "$ModuleName installed module file '$_'"
} }
else {
Write-Verbose "$ModuleName module installation successful" $ModulePathSeparator = ';'
}
$ModulePath = ($env:PSModulePath -split $ModulePathSeparator)[$ModulePathIndex]
} }
Catch {
throw "Failed installing the module in the install directory '$InstallDirectory': $_" # Get $ModuleName, $TargetPath, [$Links]
if ($FromGitHub) {
# Fix Could not create SSL/TLS secure channel
#$SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol
#[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$WebClient = [System.Net.WebClient]::new()
$GitUri = $FromGitHub.AbsolutePath.Split('/')[1, 2] -join '/'
$GitBranch = $FromGitHub.AbsolutePath.Split('/')[3]
$Links = (Invoke-RestMethod -Uri "https://api.github.com/repos/$GitUri/contents" -Body @{ref = $GitBranch }) | Where-Object { (LikeAny $_.name $IncludeFiles) -and (LikeAny $_.name $ExcludeFiles -Not) }
$ModuleName = [System.IO.Path]::GetFileNameWithoutExtension(($Links | Where-Object { $_.name -like '*.psm1' }).name)
$ModuleVersion = (. ([Scriptblock]::Create((Invoke-WebRequest -Uri ($Links | Where-Object { $_.name -eq "$ModuleName.psd1" }).download_url)))).ModuleVersion
} }
else {
$ModuleName = [System.IO.Path]::GetFileNameWithoutExtension((Get-ChildItem -File -Filter *.psm1 -Name -Path $PSScriptRoot))
$ModuleVersion = (. ([Scriptblock]::Create((Get-Content -Path (Join-Path $PSScriptRoot "$ModuleName.psd1") | Out-String)))).ModuleVersion
}
$TargetPath = Join-Path -Path $ModulePath -ChildPath $ModuleName
$TargetPath = Join-Path -Path $TargetPath -ChildPath $ModuleVersion
# Create Directory
if (-not (Test-Path -Path $TargetPath)) {
$null = New-Item -Path $TargetPath -ItemType Directory -ErrorAction Stop
Write-Verbose -Message ('Created module folder: "{0}"' -f $TargetPath)
}
# Copy Files
if ($FromGitHub) {
foreach ($Link in $Links) {
$TargetPathItem = Join-Path -Path $TargetPath -ChildPath $Link.name
if ($Link.type -ne 'dir') {
$WebClient.DownloadFile($Link.download_url, $TargetPathItem)
Write-Verbose -Message ('Installed module file: "{0}"' -f $Link.name)
}
else {
if (-not (Test-Path -Path $TargetPathItem)) {
$null = New-Item -Path $TargetPathItem -ItemType Directory -ErrorAction Stop
Write-Verbose -Message 'Created module folder: "{0}"' -f $TargetPathItem
}
$SubLinks = (Invoke-RestMethod -Uri $Link.git_url -Body @{recursive = '1' }).tree
foreach ($SubLink in $SubLinks) {
$TargetPathSub = Join-Path -Path $TargetPathItem -ChildPath $SubLink.path
if ($SubLink.'type' -EQ 'tree') {
if (-not (Test-Path -Path $TargetPathSub)) {
$null = New-Item -Path $TargetPathSub -ItemType Directory -ErrorAction Stop
Write-Verbose -Message 'Created module folder: "{0}"' -f $TargetPathSub
}
}
else {
$WebClient.DownloadFile(
('https://raw.githubusercontent.com/{0}/{1}/{2}/{3}' -f $GitUri, $GitBranch, $Link.name, $SubLink.path),
$TargetPathSub
)
}
}
}
}
}
else {
Get-ChildItem -Path $PSScriptRoot -Exclude $ExcludeFiles | Where-Object { LikeAny $_.Name $IncludeFiles } | ForEach-Object {
if ($_.Attributes -ne 'Directory') {
Copy-Item -Path $_ -Destination $TargetPath
Write-Verbose -Message ('Installed module file "{0}"' -f $_)
}
else {
Copy-Item -Path $_ -Destination $TargetPath -Recurse -Force
Write-Verbose -Message ('Installed module folder "{0}"' -f $_)
}
}
}
# Import Module
Write-Verbose -Message "$ModuleName module installation successful to $TargetPath"
Import-Module -Name $ModuleName -Force
Write-Verbose -Message "Module installed"
}
Catch {
throw ('Failed installing module "{0}". Error: "{1}" in Line {2}' -f $ModuleName, $_, $_.InvocationInfo.ScriptLineNumber)
}
finally {
#if ($FromGitHub) {
# [Net.ServicePointManager]::SecurityProtocol = $SecurityProtocol
#}
Write-Verbose -Message 'Module installation end'
} }

View File

@@ -1,3 +0,0 @@
$fullPath = 'C:\Program Files\WindowsPowerShell\Modules\ImportExcel'
Robocopy . $fullPath /mir /XD .vscode .git examples testimonials images spikes /XF appveyor.yml .gitattributes .gitignore

View File

@@ -18,7 +18,7 @@ function Invoke-Sum {
$h.$key=[ordered]@{} $h.$key=[ordered]@{}
} }
foreach($m in $measure) { foreach($m in $measure) {
$value = $item.$m $value = $item.$m
if($value -is [string] -or $value -is [System.Enum]) { if($value -is [string] -or $value -is [System.Enum]) {
$value = 1 $value = 1
@@ -27,15 +27,15 @@ function Invoke-Sum {
$h.$key.$m+=$value $h.$key.$m+=$value
} }
} }
foreach ($entry in $h.GetEnumerator()){ foreach ($entry in $h.GetEnumerator()){
$nh=[ordered]@{Name=$entry.key} $nh=[ordered]@{Name=$entry.key}
foreach ($item in $entry.value.getenumerator()) { foreach ($item in $entry.value.getenumerator()) {
$nh.($item.key)=$item.value $nh.($item.key)=$item.value
} }
[pscustomobject]$nh [pscustomobject]$nh
} }
} }

View File

@@ -198,7 +198,7 @@
#We accept a bunch of parameters work to pass on to Export-excel ( Autosize, Autofilter, boldtopRow Freeze ); if we have any of those call export-excel otherwise close the package here. #We accept a bunch of parameters work to pass on to Export-excel ( Autosize, Autofilter, boldtopRow Freeze ); if we have any of those call export-excel otherwise close the package here.
$params = @{} + $PSBoundParameters $params = @{} + $PSBoundParameters
'Path', 'Clearsheet', 'NoHeader', 'FromLabel', 'LabelBlocks', 'HideSource', 'Path', 'Clearsheet', 'NoHeader', 'FromLabel', 'LabelBlocks', 'HideSource',
'Title', 'TitleFillPattern', 'TitleBackgroundColor', 'TitleBold', 'TitleSize' | ForEach-Object {[void]$params.Remove($_)} 'Title', 'TitleFillPattern', 'TitleBackgroundColor', 'TitleBold', 'TitleSize' | ForEach-Object {$null = $params.Remove($_)}
if ($params.Keys.Count) { if ($params.Keys.Count) {
if ($Title) { $params.StartRow = 2} if ($Title) { $params.StartRow = 2}
$params.WorkSheetName = $WorkSheetName $params.WorkSheetName = $WorkSheetName

View File

@@ -1,3 +1,3 @@
if((Get-Module -list ImportExcel) -eq $null) { if($null -eq (Get-Module -ListAvailable ImportExcel) ) {
Import-Module $PSScriptRoot\ImportExcel.psd1 -force Import-Module $PSScriptRoot\ImportExcel.psd1 -force
} }

View File

@@ -316,10 +316,10 @@
} }
Function Merge-MultipleSheets { Function Merge-MultipleSheets {
<# <#
.Synopsis .Synopsis
Merges Worksheets into a single Worksheet with differences marked up. Merges Worksheets into a single Worksheet with differences marked up.
.Description .Description
The Merge Worksheet command combines two sheets. Merge-MultipleSheets is The Merge Worksheet command combines two sheets. Merge-MultipleSheets is
designed to merge more than two. So if asked to merge sheets A,B,C which designed to merge more than two. So if asked to merge sheets A,B,C which
contain Services, with a Name, Displayname and Start mode, where "Name" is contain Services, with a Name, Displayname and Start mode, where "Name" is
@@ -353,30 +353,32 @@ Function Merge-MultipleSheets {
sheet. However if Sheet B is the reference sheet, A and C will be seen to sheet. However if Sheet B is the reference sheet, A and C will be seen to
have an item removed; and if B is processed before C, the extra item is have an item removed; and if B is processed before C, the extra item is
known when C is processed and so C is considered to be missing that item. known when C is processed and so C is considered to be missing that item.
.Example .Example
dir Server*.xlsx | Merge-MulipleSheets -WorksheetName Services -OutputFile Test2.xlsx -OutputSheetName Services -Show dir Server*.xlsx | Merge-MulipleSheets -WorksheetName Services -OutputFile Test2.xlsx -OutputSheetName Services -Show
Here we are auditing servers and each one has a workbook in the current Here we are auditing servers and each one has a workbook in the current
directory which contains a "Services" Worksheet (the result of directory which contains a "Services" Worksheet (the result of
Get-WmiObject -Class win32_service | Select-Object -Property Name, Displayname, Startmode) Get-WmiObject -Class win32_service | Select-Object -Property Name, Displayname, Startmode)
No key is specified so the key is assumed to be the "Name" column. No key is specified so the key is assumed to be the "Name" column.
The files are merged and the result is opened on completion. The files are merged and the result is opened on completion.
.Example .Example
dir Serv*.xlsx | Merge-MulipleSheets -WorksheetName Software -Key "*" -ExcludeProperty Install* -OutputFile Test2.xlsx -OutputSheetName Software -Show dir Serv*.xlsx | Merge-MulipleSheets -WorksheetName Software -Key "*" -ExcludeProperty Install* -OutputFile Test2.xlsx -OutputSheetName Software -Show
The server audit files in the previous example also have "Software" worksheet, The server audit files in the previous example also have "Software" worksheet,
but no single field on that sheet works as a key. Specifying "*" for the key but no single field on that sheet works as a key. Specifying "*" for the key
produces a compound key using all non-excluded fields (and the installation produces a compound key using all non-excluded fields (and the installation
date and file location are excluded). date and file location are excluded).
.Example .Example
Merge-MulipleSheets -Path hotfixes.xlsx -WorksheetName Serv* -Key hotfixid -OutputFile test2.xlsx -OutputSheetName hotfixes -HideRowNumbers -Show Merge-MulipleSheets -Path hotfixes.xlsx -WorksheetName Serv* -Key hotfixid -OutputFile test2.xlsx -OutputSheetName hotfixes -HideRowNumbers -Show
This time all the servers have written their hotfix information to their own This time all the servers have written their hotfix information to their own
worksheets in a shared Excel workbook named "Hotfixes.xlsx" (the information was worksheets in a shared Excel workbook named "Hotfixes.xlsx" (the information was
obtained by running Get-Hotfix | Sort-Object -Property description,hotfixid | Select-Object -Property Description,HotfixID) obtained by running Get-Hotfix | Sort-Object -Property description,hotfixid | Select-Object -Property Description,HotfixID)
This ignores any sheets which are not named "Serv*", and uses the HotfixID as This ignores any sheets which are not named "Serv*", and uses the HotfixID as
the key; in this version the row numbers are hidden. the key; in this version the row numbers are hidden.
#> #>
[cmdletbinding()] [cmdletbinding()]
#[Alias("Merge-MulipleSheets")] #There was a spelling error in the first release. This was there to ensure things didn't break but intelisense gave the alias first. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification="False positives when initializing variable in begin block")]
param ( [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification="MultipleSheet would be incorrect")]
#[Alias("Merge-MulipleSheets")] #There was a spelling error in the first release. This was there to ensure things didn't break but intelisense gave the alias first.
param (
#Paths to the files to be merged. Files are also accepted #Paths to the files to be merged. Files are also accepted
[Parameter(Mandatory=$true,ValueFromPipeline=$true)] [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
$Path , $Path ,
@@ -418,9 +420,9 @@ Function Merge-MultipleSheets {
#If specified, opens the output workbook. #If specified, opens the output workbook.
[Switch]$Show [Switch]$Show
) )
begin { $filestoProcess = @() } begin { $filestoProcess = @() }
process { $filestoProcess += $Path} process { $filestoProcess += $Path}
end { end {
if ($filestoProcess.Count -eq 1 -and $WorksheetName -match '\*') { if ($filestoProcess.Count -eq 1 -and $WorksheetName -match '\*') {
Write-Progress -Activity "Merging sheets" -CurrentOperation "Expanding * to names of sheets in $($filestoProcess[0]). " Write-Progress -Activity "Merging sheets" -CurrentOperation "Expanding * to names of sheets in $($filestoProcess[0]). "
$excel = Open-ExcelPackage -Path $filestoProcess $excel = Open-ExcelPackage -Path $filestoProcess
@@ -510,7 +512,8 @@ Function Merge-MultipleSheets {
Add-ConditionalFormatting @condFormattingParams -ConditionValue ("AND(" +(($sameChecks -join ",") -replace '<>"Same"','="Changed"') +")" ) -BackgroundColor $ChangeBackgroundColor Add-ConditionalFormatting @condFormattingParams -ConditionValue ("AND(" +(($sameChecks -join ",") -replace '<>"Same"','="Changed"') +")" ) -BackgroundColor $ChangeBackgroundColor
} }
#We've made a bunch of things wider so now is the time to autofit columns. Any hiding has to come AFTER this, because it unhides things #We've made a bunch of things wider so now is the time to autofit columns. Any hiding has to come AFTER this, because it unhides things
$sheet.Cells.AutoFitColumns() if ($env:NoAutoSize) {Write-Warning "Autofit is not available with this OS configuration."}
else {$sheet.Cells.AutoFitColumns()}
#if we have a key field (we didn't concatenate all fields) use what we built up in $sameChecks to apply conditional formatting to it (Row no will be in column A, Key in Column B) #if we have a key field (we didn't concatenate all fields) use what we built up in $sameChecks to apply conditional formatting to it (Row no will be in column A, Key in Column B)
if ($Key -ne '*') { if ($Key -ne '*') {
@@ -532,5 +535,5 @@ Function Merge-MultipleSheets {
if ($Passthru) {$excel} if ($Passthru) {$excel}
else {Close-ExcelPackage -ExcelPackage $excel -Show:$Show} else {Close-ExcelPackage -ExcelPackage $excel -Show:$Show}
Write-Progress -Activity "Merging sheets" -Completed Write-Progress -Activity "Merging sheets" -Completed
} }
} }

View File

@@ -27,6 +27,7 @@ function New-ConditionalFormattingIconSet {
Add-Add-ConditionalFormatting Add-Add-ConditionalFormatting
New-ConditionalText New-ConditionalText
#> #>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system State')]
param( param(
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]
$Range, $Range,

View File

@@ -36,14 +36,14 @@ function New-ConditionalText {
This builds on the previous example, and specifies a condition of <=3 with This builds on the previous example, and specifies a condition of <=3 with
a format of red text on a white background; this applies to a named range a format of red text on a white background; this applies to a named range
"Finish Position". The range could be written "C:C" to specify a named "Finish Position". The range could be written -Range "C:C" to specify a
column, or "C2:C102" to specify certain cells in the column. named column, or -Range "C2:C102" to specify certain cells in the column.
.Link .Link
Add-Add-ConditionalFormatting Add-ConditionalFormatting
New-ConditionalFormattingIconSet New-ConditionalFormattingIconSet
#> #>
[cmdletbinding()] [cmdletbinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system State')]
param( param(
#[Parameter(Mandatory=$true)] #[Parameter(Mandatory=$true)]
[Alias("ConditionValue")] [Alias("ConditionValue")]

View File

@@ -97,10 +97,12 @@
#> #>
[Alias("New-ExcelChart")] #This was the former name. The new name reflects that we are defining a chart, not making one in the workbook. [Alias("New-ExcelChart")] #This was the former name. The new name reflects that we are defining a chart, not making one in the workbook.
[cmdletbinding()] [cmdletbinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Does not change system State')]
param( param(
$Title = "Chart Title", $Title = "Chart Title",
$Header, $Header,
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = "ColumnStacked", [OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = "ColumnStacked",
[OfficeOpenXml.Drawing.Chart.eTrendLine[]]$ChartTrendLine,
$XRange, $XRange,
$YRange, $YRange,
$Width = 500, $Width = 500,
@@ -137,11 +139,12 @@
$YMinValue, $YMinValue,
[OfficeOpenXml.Drawing.Chart.eAxisPosition]$YAxisPosition [OfficeOpenXml.Drawing.Chart.eAxisPosition]$YAxisPosition
) )
if ( $Header ) {Write-Warning "The header parameter is ignored."} #Nothing was done with it when creating a chart. if ( $Header ) { Write-Warning "The header parameter is ignored." } #Nothing was done with it when creating a chart.
#might be able to do [PSCustomObject]$PsboundParameters, the defaults here match those in Add-Excel Chart #might be able to do [PSCustomObject]$PsboundParameters, the defaults here match those in Add-Excel Chart
[PSCustomObject]@{ [PSCustomObject]@{
Title = $Title Title = $Title
ChartType = $ChartType ChartType = $ChartType
ChartTrendLine = $ChartTrendLine
XRange = $XRange XRange = $XRange
YRange = $YRange YRange = $YRange
Width = $Width Width = $Width
@@ -150,14 +153,14 @@
RowOffSetPixels = $RowOffSetPixels RowOffSetPixels = $RowOffSetPixels
Column = $Column Column = $Column
ColumnOffSetPixels = $ColumnOffSetPixels ColumnOffSetPixels = $ColumnOffSetPixels
LegendPosition = $LegendPosition LegendPosition = $LegendPosition
LegendSize = $LegendSize LegendSize = $LegendSize
Legendbold = $LegendBold Legendbold = $LegendBold
NoLegend = $NoLegend -as [Boolean] NoLegend = $NoLegend -as [Boolean]
ShowCategory = $ShowCategory -as [Boolean] ShowCategory = $ShowCategory -as [Boolean]
ShowPercent = $ShowPercent -as [Boolean] ShowPercent = $ShowPercent -as [Boolean]
SeriesHeader = $SeriesHeader SeriesHeader = $SeriesHeader
TitleBold = $TitleBold -as [Boolean] TitleBold = $TitleBold -as [Boolean]
TitleSize = $TitleSize TitleSize = $TitleSize
XAxisTitleText = $XAxisTitleText XAxisTitleText = $XAxisTitleText
XAxisTitleBold = $XAxisTitleBold -as [Boolean] XAxisTitleBold = $XAxisTitleBold -as [Boolean]
@@ -169,7 +172,7 @@
XMinValue = $XMinValue XMinValue = $XMinValue
XAxisPosition = $XAxisPosition XAxisPosition = $XAxisPosition
YAxisTitleText = $YAxisTitleText YAxisTitleText = $YAxisTitleText
YAxisTitleBold = $YAxisTitleBold -as [Boolean] YAxisTitleBold = $YAxisTitleBold -as [Boolean]
YAxisTitleSize = $YAxisTitleSize YAxisTitleSize = $YAxisTitleSize
YAxisNumberformat = $YAxisNumberformat YAxisNumberformat = $YAxisNumberformat
YMajorUnit = $YMajorUnit YMajorUnit = $YMajorUnit
@@ -325,24 +328,25 @@ function Add-ExcelChart {
and is marked off in units of 0.25 shown to two decimal places. and is marked off in units of 0.25 shown to two decimal places.
The key will for the chart will be at the bottom in 8 point bold type and the line will be named "Sin(x)". The key will for the chart will be at the bottom in 8 point bold type and the line will be named "Sin(x)".
#> #>
[cmdletbinding(DefaultParameterSetName='Worksheet')] [cmdletbinding(DefaultParameterSetName = 'Worksheet')]
[OutputType([OfficeOpenXml.Drawing.Chart.ExcelChart])] [OutputType([OfficeOpenXml.Drawing.Chart.ExcelChart])]
param( param(
[Parameter(ParameterSetName='Workshet',Mandatory=$true)] [Parameter(ParameterSetName = 'Workshet', Mandatory = $true)]
[OfficeOpenXml.ExcelWorksheet]$Worksheet, [OfficeOpenXml.ExcelWorksheet]$Worksheet,
[Parameter(ParameterSetName='PivotTable',Mandatory=$true)] [Parameter(ParameterSetName = 'PivotTable', Mandatory = $true)]
[OfficeOpenXml.Table.PivotTable.ExcelPivotTable]$PivotTable , [OfficeOpenXml.Table.PivotTable.ExcelPivotTable]$PivotTable ,
[String]$Title, [String]$Title,
#$Header, Not used but referenced previously #$Header, Not used but referenced previously
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = "ColumnStacked", [OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = "ColumnStacked",
[OfficeOpenXml.Drawing.Chart.eTrendLine[]]$ChartTrendLine,
$XRange, $XRange,
$YRange, $YRange,
[int]$Width = 500, [int]$Width = 500,
[int]$Height = 350, [int]$Height = 350,
[int]$Row = 0, [int]$Row = 0,
[int]$RowOffSetPixels = 10, [int]$RowOffSetPixels = 10,
[int]$Column = 6, [int]$Column = 6,
[int]$ColumnOffSetPixels = 5, [int]$ColumnOffSetPixels = 5,
[OfficeOpenXml.Drawing.Chart.eLegendPosition]$LegendPosition, [OfficeOpenXml.Drawing.Chart.eLegendPosition]$LegendPosition,
$LegendSize, $LegendSize,
[Switch]$LegendBold, [Switch]$LegendBold,
@@ -371,11 +375,11 @@ function Add-ExcelChart {
$YMinValue, $YMinValue,
[OfficeOpenXml.Drawing.Chart.eAxisPosition]$YAxisPosition, [OfficeOpenXml.Drawing.Chart.eAxisPosition]$YAxisPosition,
[Switch]$PassThru [Switch]$PassThru
) )
try { try {
if ($PivotTable) { if ($PivotTable) {
$Worksheet = $PivotTable.WorkSheet $Worksheet = $PivotTable.WorkSheet
$chart = $Worksheet.Drawings.AddChart(("Chart" + $PivotTable.Name ),$ChartType,$PivotTable) $chart = $Worksheet.Drawings.AddChart(("Chart" + $PivotTable.Name ), $ChartType, $PivotTable)
} }
else { else {
$ChartName = 'Chart' + (Split-Path -Leaf ([System.IO.path]::GetTempFileName())) -replace 'tmp|\.', '' $ChartName = 'Chart' + (Split-Path -Leaf ([System.IO.path]::GetTempFileName())) -replace 'tmp|\.', ''
@@ -383,75 +387,85 @@ function Add-ExcelChart {
$chartDefCount = @($YRange).Count $chartDefCount = @($YRange).Count
if ($chartDefCount -eq 1) { if ($chartDefCount -eq 1) {
$Series = $chart.Series.Add($YRange, $XRange) $Series = $chart.Series.Add($YRange, $XRange)
if ($SeriesHeader) { $Series.Header = $SeriesHeader} if ($ChartTrendLine) {
else { $Series.Header = 'Series 1'} if ($ChartType -notmatch "stacked|3D$|pie|Doughnut|Cone|Cylinder|Pyramid") {
foreach ($trendLine in $ChartTrendLine) {
$null = $Series.TrendLines.Add($trendLine)
}
}
else {
Write-Warning "Chart trend line is not supported for chart type: $ChartType"
}
}
if ($SeriesHeader) { $Series.Header = $SeriesHeader }
else { $Series.Header = 'Series 1' }
} }
else { else {
for ($idx = 0; $idx -lt $chartDefCount; $idx += 1) { for ($idx = 0; $idx -lt $chartDefCount; $idx += 1) {
if ($Yrange.count -eq $xrange.count) { if ($Yrange.count -eq $xrange.count) {
$Series = $chart.Series.Add($YRange[$idx], $XRange[$idx]) $Series = $chart.Series.Add($YRange[$idx], $XRange[$idx])
} }
else { else {
$Series = $chart.Series.Add($YRange[$idx], $XRange) $Series = $chart.Series.Add($YRange[$idx], $XRange)
} }
if ($SeriesHeader.Count -gt 0) { if ($SeriesHeader.Count -gt 0) {
if ($SeriesHeader[$idx] -match '^=') {$Series.HeaderAddress = $SeriesHeader[$idx] -replace '^=',''} if ($SeriesHeader[$idx] -match '^=') { $Series.HeaderAddress = $SeriesHeader[$idx] -replace '^=', '' }
else {$Series.Header = $SeriesHeader[$idx] } else { $Series.Header = $SeriesHeader[$idx] }
} }
else { $Series.Header = "Series $($idx)"} else { $Series.Header = "Series $($idx)" }
} }
} }
} }
if ($Title) { if ($Title) {
$chart.Title.Text = $Title $chart.Title.Text = $Title
if ($TitleBold) {$chart.Title.Font.Bold = $true} if ($TitleBold) { $chart.Title.Font.Bold = $true }
if ($TitleSize) {$chart.Title.Font.Size = $TitleSize} if ($TitleSize) { $chart.Title.Font.Size = $TitleSize }
} }
if ($NoLegend) { $chart.Legend.Remove() } if ($NoLegend) { $chart.Legend.Remove() }
else { else {
if ($PSBoundParameters.ContainsKey('LegendPosition')) {$chart.Legend.Position = $LegendPosition} if ($PSBoundParameters.ContainsKey('LegendPosition')) { $chart.Legend.Position = $LegendPosition }
if ($PSBoundParameters.ContainsKey('LegendBold')) {$chart.Legend.Font.Bold = [boolean]$LegendBold} if ($PSBoundParameters.ContainsKey('LegendBold')) { $chart.Legend.Font.Bold = [boolean]$LegendBold }
if ($LegendSize) {$chart.Legend.Font.Size = $LegendSize} if ($LegendSize) { $chart.Legend.Font.Size = $LegendSize }
} }
if ($XAxisTitleText) { if ($XAxisTitleText) {
$chart.XAxis.Title.Text = $XAxisTitleText $chart.XAxis.Title.Text = $XAxisTitleText
if ($PSBoundParameters.ContainsKey('XAxisTitleBold')) { if ($PSBoundParameters.ContainsKey('XAxisTitleBold')) {
$chart.XAxis.Title.Font.Bold = [boolean]$XAxisTitleBold $chart.XAxis.Title.Font.Bold = [boolean]$XAxisTitleBold
} }
if ($XAxisTitleSize) {$chart.XAxis.Title.Font.Size = $XAxisTitleSize} if ($XAxisTitleSize) { $chart.XAxis.Title.Font.Size = $XAxisTitleSize }
} }
if ($XAxisPosition) {Write-Warning "X-axis position is not being set propertly at the moment, parameter ignored" } if ($XAxisPosition) { Write-Warning "X-axis position is not being set propertly at the moment, parameter ignored" }
#$chart.ChartXml.chartSpace.chart.plotArea.catAx.axPos.val = $XAxisPosition.ToString().substring(0,1)} #$chart.ChartXml.chartSpace.chart.plotArea.catAx.axPos.val = $XAxisPosition.ToString().substring(0,1)}
if ($XMajorUnit) {$chart.XAxis.MajorUnit = $XMajorUnit} if ($XMajorUnit) { $chart.XAxis.MajorUnit = $XMajorUnit }
if ($XMinorUnit) {$chart.XAxis.MinorUnit = $XMinorUnit} if ($XMinorUnit) { $chart.XAxis.MinorUnit = $XMinorUnit }
if ($null -ne $XMinValue) {$chart.XAxis.MinValue = $XMinValue} if ($null -ne $XMinValue) { $chart.XAxis.MinValue = $XMinValue }
if ($null -ne $XMaxValue) {$chart.XAxis.MaxValue = $XMaxValue} if ($null -ne $XMaxValue) { $chart.XAxis.MaxValue = $XMaxValue }
if ($XAxisNumberformat) {$chart.XAxis.Format = (Expand-NumberFormat $XAxisNumberformat)} if ($XAxisNumberformat) { $chart.XAxis.Format = (Expand-NumberFormat $XAxisNumberformat) }
if ($YAxisTitleText) { if ($YAxisTitleText) {
$chart.YAxis.Title.Text = $YAxisTitleText $chart.YAxis.Title.Text = $YAxisTitleText
if ($PSBoundParameters.ContainsKey('YAxisTitleBold')) { if ($PSBoundParameters.ContainsKey('YAxisTitleBold')) {
$chart.YAxis.Title.Font.Bold = [boolean]$YAxisTitleBold $chart.YAxis.Title.Font.Bold = [boolean]$YAxisTitleBold
} }
if ($YAxisTitleSize) {$chart.YAxis.Title.Font.Size = $YAxisTitleSize} if ($YAxisTitleSize) { $chart.YAxis.Title.Font.Size = $YAxisTitleSize }
} }
if ($YAxisPosition) {Write-Warning "Y-axis position is not being set propertly at the moment, parameter ignored" } if ($YAxisPosition) { Write-Warning "Y-axis position is not being set propertly at the moment, parameter ignored" }
#$chart.ChartXml.chartSpace.chart.plotArea.valAx.axPos.val= $YAxisPosition.ToString().substring(0,1)} #$chart.ChartXml.chartSpace.chart.plotArea.valAx.axPos.val= $YAxisPosition.ToString().substring(0,1)}
if ($YMajorUnit) {$chart.YAxis.MajorUnit = $YMajorUnit} if ($YMajorUnit) { $chart.YAxis.MajorUnit = $YMajorUnit }
if ($YMinorUnit) {$chart.YAxis.MinorUnit = $YMinorUnit} if ($YMinorUnit) { $chart.YAxis.MinorUnit = $YMinorUnit }
if ($null -ne $YMinValue){$chart.YAxis.MinValue = $YMinValue} if ($null -ne $YMinValue) { $chart.YAxis.MinValue = $YMinValue }
if ($null -ne $YMaxValue){$chart.YAxis.MaxValue = $YMaxValue} if ($null -ne $YMaxValue) { $chart.YAxis.MaxValue = $YMaxValue }
if ($YAxisNumberformat) {$chart.YAxis.Format = (Expand-NumberFormat $YAxisNumberformat)} if ($YAxisNumberformat) { $chart.YAxis.Format = (Expand-NumberFormat $YAxisNumberformat) }
if ($null -ne $chart.Datalabel) { if ($null -ne $chart.Datalabel) {
$chart.Datalabel.ShowCategory = [boolean]$ShowCategory $chart.Datalabel.ShowCategory = [boolean]$ShowCategory
$chart.Datalabel.ShowPercent = [boolean]$ShowPercent $chart.Datalabel.ShowPercent = [boolean]$ShowPercent
} }
$chart.SetPosition($Row, $RowOffsetPixels, $Column, $ColumnOffsetPixels) $chart.SetPosition($Row, $RowOffsetPixels, $Column, $ColumnOffsetPixels)
$chart.SetSize($Width, $Height) $chart.SetSize($Width, $Height)
if ($PassThru) {return $chart} if ($PassThru) { return $chart }
} }
catch {Write-Warning -Message "Failed adding Chart to worksheet '$($WorkSheet).name': $_"} catch { Write-Warning -Message "Failed adding Chart to worksheet '$($WorkSheet).name': $_" }
} }

View File

@@ -1,3 +1,5 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function', Target='New*', Justification='Does not change system State')]
param()
function New-PSItem { function New-PSItem {
$totalArgs = $args.Count $totalArgs = $args.Count

View File

@@ -1,94 +0,0 @@
#Requires -Modules Pester
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
Import-Module $here -Force
$WarningPreference = 'SilentlyContinue'
$ProgressPreference = 'SilentlyContinue'
Function Test-isNumeric {
Param (
[Parameter(ValueFromPipeline)]$x
)
Return $x -is [byte] -or $x -is [int16] -or $x -is [int32] -or $x -is [int64] `
-or $x -is [sbyte] -or $x -is [uint16] -or $x -is [uint32] -or $x -is [uint64] `
-or $x -is [float] -or $x -is [double] -or $x -is [decimal]
}
$fakeData = [PSCustOmobject]@{
Property_1_Date = (Get-Date).ToString('d') # US '10/16/2017' BE '16/10/2107'
Property_2_Formula = '=SUM(G2:H2)'
Property_3_String = 'My String'
Property_4_String = 'a'
Property_5_IPAddress = '10.10.25.5'
Property_6_Number = '0'
Property_7_Number = '5'
Property_8_Number = '007'
Property_9_Number = (33).ToString('F2') # US '33.00' BE '33,00'
Property_10_Number = (5/3).ToString('F2') # US '1.67' BE '1,67'
Property_11_Number = (15999998/3).ToString('N2') # US '5,333,332.67' BE '5.333.332,67'
Property_12_Number = '1.555,83'
Property_13_PhoneNr = '+32 44'
Property_14_PhoneNr = '+32 4 4444 444'
Property_15_PhoneNr = '+3244444444'
}
$Path = 'Test.xlsx'
Describe 'Export-Excel' {
in $TestDrive {
Describe 'Number conversion' {
Context 'numerical values expected' {
#region Create test file
$fakeData | Export-Excel -Path $Path
$Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
$Excel = New-Object OfficeOpenXml.ExcelPackage $Path
$Worksheet = $Excel.Workbook.WorkSheets[1]
#endregion
it 'zero' {
$fakeData.Property_6_Number | Should -BeExactly '0'
$Worksheet.Cells[2, 6].Text | Should -BeExactly $fakeData.Property_6_Number
$Worksheet.Cells[2, 6].Value | Test-isNumeric | Should -Be $true
}
It 'regular number' {
$fakeData.Property_7_Number | Should -BeExactly '5'
$Worksheet.Cells[2, 7].Text | Should -BeExactly $fakeData.Property_7_Number
$Worksheet.Cells[2, 7].Value | Test-isNumeric | Should -Be $true
}
It 'number starting with zero' {
$fakeData.Property_8_Number | Should -BeExactly '007'
$Worksheet.Cells[2, 8].Text | Should -BeExactly '7'
$Worksheet.Cells[2, 8].Value | Test-isNumeric | Should -Be $true
}
It 'decimal number' {
# US '33.00' BE '33,00'
$fakeData.Property_9_Number | Should -BeExactly (33).ToString('F2')
$Worksheet.Cells[2, 9].Text | Should -BeExactly '33'
$Worksheet.Cells[2, 9].Value | Test-isNumeric | Should -Be $true
# US '1.67' BE '1,67'
$fakeData.Property_10_Number | Should -BeExactly (5/3).ToString('F2')
$Worksheet.Cells[2, 10].Text | Should -BeExactly $fakeData.Property_10_Number
$Worksheet.Cells[2, 10].Value | Test-isNumeric | Should -Be $true
}
It 'thousand seperator and decimal number' {
# US '5,333,332.67' BE '5.333.332,67'
# Excel BE '5333332,67'
$fakeData.Property_11_Number | Should -BeExactly (15999998/3).ToString('N2')
$Worksheet.Cells[2, 11].Text | Should -BeExactly $fakeData.Property_11_Number
$Worksheet.Cells[2, 11].Value | Test-isNumeric | Should -Be $true
}
}
}
}
}

View File

@@ -38,9 +38,53 @@
but here -Address is specified to place it beside the data. The Add-Pivot table is given the chart definition and told to create a tale but here -Address is specified to place it beside the data. The Add-Pivot table is given the chart definition and told to create a tale
using the City field to create rows, the Product field to create columns and the data should be the sum of the gross field and the sum of the net field; using the City field to create rows, the Product field to create columns and the data should be the sum of the gross field and the sum of the net field;
grand totals for both gross and net are included for rows (Cities) and columns (product) and the data is explicitly formatted as a currency. grand totals for both gross and net are included for rows (Cities) and columns (product) and the data is explicitly formatted as a currency.
Not that in the chart definition the number format for the axis does not include any fraction part. Note that in the chart definition the number format for the axis does not include any fraction part.
.Example
>
$excel = Convertfrom-csv @"
Location,OrderDate,quantity
Boston,1/1/2017,100
New York,1/21/2017,200
Boston,1/11/2017,300
New York,1/9/2017,400
Boston,1/18/2017,500
Boston,2/1/2017,600
New York,2/21/2017,700
New York,2/11/2017,800
Boston,2/9/2017,900
Boston,2/18/2017,1000
New York,1/1/2018,100
Boston,1/21/2018,200
New York,1/11/2018,300
Boston,1/9/2018,400
New York,1/18/2018,500
Boston,2/1/2018,600
Boston,2/21/2018,700
New York,2/11/2018,800
New York,2/9/2018,900
Boston,2/18/2018,1000
"@ | Select-Object -Property @{n="OrderDate";e={[datetime]::ParseExact($_.OrderDate,"M/d/yyyy",(Get-Culture))}},
Location, Quantity | Export-Excel "test2.xlsx" -PassThru -AutoSize
Set-ExcelColumn -Worksheet $excel.sheet1 -Column 1 -NumberFormat 'Short Date'
$pt = Add-PivotTable -PassThru -PivotTableName "ByDate" -Address $excel.Sheet1.cells["F1"] -SourceWorkSheet $excel.Sheet1 -PivotRows location,orderdate -PivotData @{'quantity'='sum'} -GroupDateRow orderdate -GroupDatePart 'Months,Years' -PivotTotals None
$pt.RowFields[0].SubtotalTop=$false
$pt.RowFields[0].Compact=$false
Close-ExcelPackage $excel -Show
Here the data contains dates formatted as strings using US format. These
are converted to DateTime objects before being exported to Excel; the
"OrderDate" column is formatted with the local short-date style. Then
the PivotTable is added; it groups information by date and location, the
date is split into years and then months. No grand totals are displayed.
The Pivot table object is caught in a variable, and the "Location"
column has its subtotal moved from the top to the bottom of each location
section, and the "Compact" option is disabled to prevent "Year" moving
into the same column as location.
Finally the workbook is saved and shown in Excel.
#> #>
[cmdletbinding(defaultParameterSetName='ChartbyParams')] [cmdletbinding(defaultParameterSetName = 'ChartbyParams')]
[OutputType([OfficeOpenXml.Table.PivotTable.ExcelPivotTable])] [OutputType([OfficeOpenXml.Table.PivotTable.ExcelPivotTable])]
param ( param (
#Name for the new PivotTable - this will be the name of a sheet in the Workbook. #Name for the new PivotTable - this will be the name of a sheet in the Workbook.
@@ -67,52 +111,64 @@
#If there are multiple data items in a PivotTable, by default they are shown on separate rows; this switch makes them separate columns. #If there are multiple data items in a PivotTable, by default they are shown on separate rows; this switch makes them separate columns.
[Switch]$PivotDataToColumn, [Switch]$PivotDataToColumn,
#Define whether totals should be added to rows, columns neither, or both (the default is both). #Define whether totals should be added to rows, columns neither, or both (the default is both).
[ValidateSet("Both","Columns","Rows","None")] [ValidateSet("Both", "Columns", "Rows", "None")]
[String]$PivotTotals = "Both", [String]$PivotTotals = "Both",
#Included for compatibility - equivalent to -PivotTotals "None". #Included for compatibility - equivalent to -PivotTotals "None".
[Switch]$NoTotalsInPivot, [Switch]$NoTotalsInPivot,
#The name of a row field which should be grouped by parts of the date/time (ignored if GroupDateRow is not specified)
[String]$GroupDateRow,
#The Part(s) of the date to use in the grouping (ignored if GroupDateRow is not specified)
[OfficeOpenXml.Table.PivotTable.eDateGroupBy[]]$GroupDatePart,
#The name of a row field which should be grouped by Number (e.g 0-99, 100-199, 200-299 )
[String]$GroupNumericRow,
#The starting point for grouping
[double]$GroupNumericMin = 0 ,
#The endpoint for grouping
[double]$GroupNumericMax = [Double]::MaxValue ,
#The interval for grouping
[double]$GroupNumericInterval = 100 ,
#Number format to apply to the data cells in the PivotTable. #Number format to apply to the data cells in the PivotTable.
[string]$PivotNumberFormat, [string]$PivotNumberFormat,
#Apply a table style to the PivotTable. #Apply a table style to the PivotTable.
[OfficeOpenXml.Table.TableStyles]$PivotTableStyle, [OfficeOpenXml.Table.TableStyles]$PivotTableStyle,
#Use a chart definition instead of specifying chart settings one by one. #Use a chart definition instead of specifying chart settings one by one.
[Parameter(ParameterSetName='ChartbyDef', Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [Parameter(ParameterSetName = 'ChartbyDef', Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
$PivotChartDefinition, $PivotChartDefinition,
#If specified, a chart will be included. #If specified, a chart will be included.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$IncludePivotChart, [Switch]$IncludePivotChart,
#Optional title for the pivot chart, by default the title omitted. #Optional title for the pivot chart, by default the title omitted.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[String]$ChartTitle = "", [String]$ChartTitle = "",
#Height of the chart in Pixels (400 by default). #Height of the chart in Pixels (400 by default).
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartHeight = 400 , [int]$ChartHeight = 400 ,
#Width of the chart in Pixels (600 by default). #Width of the chart in Pixels (600 by default).
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartWidth = 600, [int]$ChartWidth = 600,
#Cell position of the top left corner of the chart, there will be this number of rows above the top edge of the chart (default is 0, chart starts at top edge of row 1). #Cell position of the top left corner of the chart, there will be this number of rows above the top edge of the chart (default is 0, chart starts at top edge of row 1).
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRow = 0 , [Int]$ChartRow = 0 ,
#Cell position of the top left corner of the chart, there will be this number of cells to the left of the chart (default is 4, chart starts at left edge of column E). #Cell position of the top left corner of the chart, there will be this number of cells to the left of the chart (default is 4, chart starts at left edge of column E).
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumn = 4, [Int]$ChartColumn = 4,
#Vertical offset of the chart from the cell corner. #Vertical offset of the chart from the cell corner.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRowOffSetPixels = 0 , [Int]$ChartRowOffSetPixels = 0 ,
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
#Horizontal offset of the chart from the cell corner. #Horizontal offset of the chart from the cell corner.
[Int]$ChartColumnOffSetPixels = 0, [Int]$ChartColumnOffSetPixels = 0,
#Type of chart; defaults to "Pie". #Type of chart; defaults to "Pie".
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie', [OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie',
#If specified hides the chart legend. #If specified hides the chart legend.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$NoLegend, [Switch]$NoLegend,
#If specified attaches the category to slices in a pie chart : not supported on all chart types, this may give errors if applied to an unsupported type. #If specified attaches the category to slices in a pie chart : not supported on all chart types, this may give errors if applied to an unsupported type.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowCategory, [Switch]$ShowCategory,
#If specified attaches percentages to slices in a pie chart. #If specified attaches percentages to slices in a pie chart.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowPercent, [Switch]$ShowPercent,
#If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified. #If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified.
[switch]$Activate, [switch]$Activate,
@@ -121,7 +177,7 @@
) )
if ($PivotTableName.length -gt 250) { if ($PivotTableName.length -gt 250) {
Write-warning -Message "PivotTable name will be truncated" Write-warning -Message "PivotTable name will be truncated"
$PivotTableName = $PivotTableName.Substring(0,250) $PivotTableName = $PivotTableName.Substring(0, 250)
} }
if ($Address) { if ($Address) {
[OfficeOpenXml.ExcelWorksheet]$wsPivot = $address.Worksheet [OfficeOpenXml.ExcelWorksheet]$wsPivot = $address.Worksheet
@@ -131,7 +187,7 @@
if (-not $ExcelPackage) {Write-Warning -message "This combination of Parameters needs to include the ExcelPackage." ; return } if (-not $ExcelPackage) {Write-Warning -message "This combination of Parameters needs to include the ExcelPackage." ; return }
[OfficeOpenXml.ExcelWorksheet]$wsPivot = Add-WorkSheet -ExcelPackage $ExcelPackage -WorksheetName $pivotTableName -Activate:$Activate [OfficeOpenXml.ExcelWorksheet]$wsPivot = Add-WorkSheet -ExcelPackage $ExcelPackage -WorksheetName $pivotTableName -Activate:$Activate
if ($wsPivot.Name -ne $PivotTableName) {Write-Warning -Message "The Worksheet name for the PivotTable does not match the table name '$PivotTableName'; probably because excess or illegal characters were removed." } if ($wsPivot.Name -ne $PivotTableName) {Write-Warning -Message "The Worksheet name for the PivotTable does not match the table name '$PivotTableName'; probably because excess or illegal characters were removed." }
if ($PivotFilter) {$Address = $wsPivot.Cells["A3"]} else { $Address = $wsPivot.Cells["A1"]} if ($PivotFilter) {$Address = $wsPivot.Cells["A3"]} else { $Address = $wsPivot.Cells["A1"]}
} }
catch {throw "Could not create the sheet for the PivotTable. $_" } catch {throw "Could not create the sheet for the PivotTable. $_" }
} }
@@ -140,25 +196,25 @@
if (-not $wsPivot.PivotTables[$pivotTableName] ) { if (-not $wsPivot.PivotTables[$pivotTableName] ) {
try { try {
#Accept a string or a worksheet object as $SourceWorksheet - we don't need a worksheet if we have a Rangebase . #Accept a string or a worksheet object as $SourceWorksheet - we don't need a worksheet if we have a Rangebase .
if ( $SourceWorkSheet -is [string]) { if ( $SourceWorkSheet -is [string]) {
$SourceWorkSheet = $ExcelPackage.Workbook.Worksheets.where( {$_.name -Like $SourceWorkSheet})[0] $SourceWorkSheet = $ExcelPackage.Workbook.Worksheets.where( {$_.name -Like $SourceWorkSheet})[0]
} }
elseif ( $SourceWorkSheet -is [int] ) { elseif ( $SourceWorkSheet -is [int] ) {
$SourceWorkSheet = $ExcelPackage.Workbook.Worksheets[$SourceWorkSheet] $SourceWorkSheet = $ExcelPackage.Workbook.Worksheets[$SourceWorkSheet]
} }
if ( $SourceRange -is [OfficeOpenXml.Table.ExcelTable]) {$SourceRange = $SourceRange.Address } if ( $SourceRange -is [OfficeOpenXml.Table.ExcelTable]) {$SourceRange = $SourceRange.Address }
if ( $sourceRange -is [OfficeOpenXml.ExcelRange] -or if ( $sourceRange -is [OfficeOpenXml.ExcelRange] -or
$SourceRange -is [OfficeOpenXml.ExcelAddress]) { $SourceRange -is [OfficeOpenXml.ExcelAddress]) {
$pivotTable = $wsPivot.PivotTables.Add($Address, $SourceRange, $pivotTableName) $pivotTable = $wsPivot.PivotTables.Add($Address, $SourceRange, $pivotTableName)
} }
elseif (-not $SourceRange) { elseif (-not $SourceRange) {
$pivotTable = $wsPivot.PivotTables.Add($Address, $SourceWorkSheet.cells[$SourceWorkSheet.Dimension.Address], $pivotTableName) $pivotTable = $wsPivot.PivotTables.Add($Address, $SourceWorkSheet.cells[$SourceWorkSheet.Dimension.Address], $pivotTableName)
} }
elseif ($SourceWorkSheet -isnot [OfficeOpenXml.ExcelWorksheet] ) { elseif ($SourceWorkSheet -isnot [OfficeOpenXml.ExcelWorksheet] ) {
Write-Warning -Message "Could not find source Worksheet for pivot-table '$pivotTableName'." ; return Write-Warning -Message "Could not find source Worksheet for pivot-table '$pivotTableName'." ; return
} }
elseif ( $SourceRange -is [String] -or $SourceRange -is [OfficeOpenXml.ExcelAddress]) { elseif ( $SourceRange -is [String] -or $SourceRange -is [OfficeOpenXml.ExcelAddress]) {
$pivotTable = $wsPivot.PivotTables.Add($Address,$SourceWorkSheet.Cells[$SourceRange], $pivotTableName) $pivotTable = $wsPivot.PivotTables.Add($Address, $SourceWorkSheet.Cells[$SourceRange], $pivotTableName)
} }
else {Write-warning "Could not create a PivotTable with the Source Range provided."; return} else {Write-warning "Could not create a PivotTable with the Source Range provided."; return}
foreach ($Row in $PivotRows) { foreach ($Row in $PivotRows) {
@@ -192,13 +248,23 @@
try { $null = $pivotTable.PageFields.Add($pivotTable.Fields[$pFilter])} try { $null = $pivotTable.PageFields.Add($pivotTable.Fields[$pFilter])}
catch {Write-Warning -message "Could not add '$pFilter' to Filter/Page fields in PivotTable $pivotTableName." } catch {Write-Warning -message "Could not add '$pFilter' to Filter/Page fields in PivotTable $pivotTableName." }
} }
if ($NoTotalsInPivot) {$PivotTotals = "None" } if ($NoTotalsInPivot) {$PivotTotals = "None" }
if ($PivotTotals -eq "None" -or $PivotTotals -eq "Columns") { $pivotTable.RowGrandTotals = $false } if ($PivotTotals -eq "None" -or $PivotTotals -eq "Columns") { $pivotTable.RowGrandTotals = $false }
elseif ($PivotTotals -eq "Both" -or $PivotTotals -eq "Rows") { $pivotTable.RowGrandTotals = $true } elseif ($PivotTotals -eq "Both" -or $PivotTotals -eq "Rows") { $pivotTable.RowGrandTotals = $true }
if ($PivotTotals -eq "None" -or $PivotTotals -eq "Rows") { $pivotTable.ColumGrandTotals = $false } # Epplus spelling mistake, not mine! if ($PivotTotals -eq "None" -or $PivotTotals -eq "Rows") { $pivotTable.ColumGrandTotals = $false } # Epplus spelling mistake, not mine!
elseif ($PivotTotals -eq "Both" -or $PivotTotals -eq "Columns") { $pivotTable.ColumGrandTotals = $true } elseif ($PivotTotals -eq "Both" -or $PivotTotals -eq "Columns") { $pivotTable.ColumGrandTotals = $true }
if ($PivotDataToColumn ) { $pivotTable.DataOnRows = $false } if ($PivotDataToColumn ) { $pivotTable.DataOnRows = $false }
if ($PivotTableStyle) { $pivotTable.TableStyle = $PivotTableStyle} if ($PivotTableStyle) { $pivotTable.TableStyle = $PivotTableStyle}
if ($GroupNumericRow) {
$r = $pivotTable.RowFields.Where( {$_.name -eq $GroupNumericRow })
if (-not $r ) {Write-Warning -Message "Could not find a Row field named '$GroupNumericRow'; no numeric grouping will be done."}
else {$r.AddNumericGrouping($GroupNumericMin, $GroupNumericMax, $GroupNumericInterval)}
}
if ($GroupDateRow -and $PSBoundParameters.ContainsKey("GroupDatePart")) {
$r = $pivotTable.RowFields.Where( {$_.name -eq $GroupDateRow })
if (-not $r ) {Write-Warning -Message "Could not find a Row field named '$GroupDateRow'; no date grouping will be done."}
else {$r.AddDateGrouping($GroupDatePart)}
}
} }
catch {Write-Warning -Message "Failed adding PivotTable '$pivotTableName': $_"} catch {Write-Warning -Message "Failed adding PivotTable '$pivotTableName': $_"}
} }
@@ -206,21 +272,24 @@
Write-Warning -Message "PivotTable defined in $($pivotTableName) already exists, only the data range will be changed." Write-Warning -Message "PivotTable defined in $($pivotTableName) already exists, only the data range will be changed."
$pivotTable = $wsPivot.PivotTables[$pivotTableName] $pivotTable = $wsPivot.PivotTables[$pivotTableName]
if (-not $SourceRange) { $SourceRange = $SourceWorkSheet.Dimension.Address} if (-not $SourceRange) { $SourceRange = $SourceWorkSheet.Dimension.Address}
$pivotTable.CacheDefinition.CacheDefinitionXml.pivotCacheDefinition.cacheSource.worksheetSource.ref = $SourceRange $pivotTable.CacheDefinition.SourceRange = $SourceWorkSheet.cells[$SourceRange]
} #change for epPlus 4.5 - Previously needed to hack the xml
# $pivotTable.CacheDefinition.CacheDefinitionXml.pivotCacheDefinition.cacheSource.worksheetSource.ref = $SourceRange
}
#Create the chart if it doesn't exist, leave alone if it does. #Create the chart if it doesn't exist, leave alone if it does.
if ($IncludePivotChart -and -not $wsPivot.Drawings["Chart$pivotTableName"] ) { if ($IncludePivotChart -and -not $wsPivot.Drawings["Chart$pivotTableName"] ) {
try {Add-ExcelChart -PivotTable $pivotTable -ChartType $ChartType -Width $ChartWidth -Height $ChartHeight -Row $ChartRow -Column $ChartColumn -RowOffSetPixels $ChartRowOffSetPixels -ColumnOffSetPixels $ChartColumnOffSetPixels -Title $ChartTitle -NoLegend:$NoLegend -ShowCategory:$ShowCategory -ShowPercent:$ShowPercent } try {Add-ExcelChart -PivotTable $pivotTable -ChartType $ChartType -Width $ChartWidth -Height $ChartHeight -Row $ChartRow -Column $ChartColumn -RowOffSetPixels $ChartRowOffSetPixels -ColumnOffSetPixels $ChartColumnOffSetPixels -Title $ChartTitle -NoLegend:$NoLegend -ShowCategory:$ShowCategory -ShowPercent:$ShowPercent }
catch {Write-Warning -Message "Failed adding chart for pivotable '$pivotTableName': $_"} catch {Write-Warning -Message "Failed adding chart for pivotable '$pivotTableName': $_"}
} }
elseif ($PivotChartDefinition -and -not $wsPivot.Drawings["Chart$pivotTableName"]) { elseif ($PivotChartDefinition -and -not $wsPivot.Drawings["Chart$pivotTableName"]) {
if ($PivotChartDefinition -is [System.Management.Automation.PSCustomObject]) { if ($PivotChartDefinition -is [System.Management.Automation.PSCustomObject]) {
$params = @{PivotTable= $pivotTable } $params = @{PivotTable = $pivotTable }
$PivotChartDefinition.PSObject.Properties | ForEach-Object {if ( $null -ne $_.value) {$params[$_.name] = $_.value}} $PivotChartDefinition.PSObject.Properties | ForEach-Object {if ( $null -ne $_.value) {$params[$_.name] = $_.value}}
Add-ExcelChart @params Add-ExcelChart @params
} }
elseif ($PivotChartDefinition -is [hashtable] -or $PivotChartDefinition -is[System.Collections.Specialized.OrderedDictionary]) { elseif ($PivotChartDefinition -is [hashtable] -or $PivotChartDefinition -is [System.Collections.Specialized.OrderedDictionary]) {
Add-ExcelChart -PivotTable $pivotTable @PivotChartDefinition Add-ExcelChart -PivotTable $pivotTable @PivotChartDefinition
} }
} }
@@ -246,6 +315,7 @@ function New-PivotTableDefinition {
This is a re-work of one of the examples in Export-Excel - instead of writing out the pivot definition hash table it is built by calling New-PivotTableDefinition. This is a re-work of one of the examples in Export-Excel - instead of writing out the pivot definition hash table it is built by calling New-PivotTableDefinition.
#> #>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system State')]
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
[Alias("PivtoTableName")]#Previous typo - use alias to avoid breaking scripts [Alias("PivtoTableName")]#Previous typo - use alias to avoid breaking scripts
@@ -267,59 +337,71 @@ function New-PivotTableDefinition {
[Switch]$PivotDataToColumn, [Switch]$PivotDataToColumn,
#By default PivotTables have Totals for each Row (on the right) and for each column at the bottom. This allows just one or neither to be selected. #By default PivotTables have Totals for each Row (on the right) and for each column at the bottom. This allows just one or neither to be selected.
#Define whther totals should be added to rows, columns neither, or both (the default is both) #Define whther totals should be added to rows, columns neither, or both (the default is both)
[ValidateSet("Both","Columns","Rows","None")] [ValidateSet("Both", "Columns", "Rows", "None")]
[String]$PivotTotals = "Both", [String]$PivotTotals = "Both",
#Included for compatibility - equivalent to -PivotTotals "None" #Included for compatibility - equivalent to -PivotTotals "None"
[Switch]$NoTotalsInPivot, [Switch]$NoTotalsInPivot,
#The name of a row field which should be grouped by parts of the date/time (ignored if GroupDateRow is not specified)
[String]$GroupDateRow,
#The Part(s) of the date to use in the grouping (ignored if GroupDateRow is not specified)
[OfficeOpenXml.Table.PivotTable.eDateGroupBy[]]$GroupDatePart,
#The name of a row field which should be grouped by Number (e.g 0-99, 100-199, 200-299 )
[String]$GroupNumericRow,
#The starting point for grouping
[double]$GroupNumericMin = 0 ,
#The endpoint for grouping
[double]$GroupNumericMax = [Double]::MaxValue ,
#The interval for grouping
[double]$GroupNumericInterval = 100 ,
#Number format to apply to the data cells in the PivotTable #Number format to apply to the data cells in the PivotTable
[string]$PivotNumberFormat, [string]$PivotNumberFormat,
#Apply a table style to the PivotTable #Apply a table style to the PivotTable
[OfficeOpenXml.Table.TableStyles]$PivotTableStyle, [OfficeOpenXml.Table.TableStyles]$PivotTableStyle,
#Use a chart definition instead of specifying chart settings one by one #Use a chart definition instead of specifying chart settings one by one
[Parameter(ParameterSetName='ChartbyDef', Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [Parameter(ParameterSetName = 'ChartbyDef', Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
$PivotChartDefinition, $PivotChartDefinition,
#If specified a chart Will be included. #If specified a chart Will be included.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$IncludePivotChart, [Switch]$IncludePivotChart,
#Optional title for the pivot chart, by default the title omitted. #Optional title for the pivot chart, by default the title omitted.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[String]$ChartTitle, [String]$ChartTitle,
#Height of the chart in Pixels (400 by default) #Height of the chart in Pixels (400 by default)
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartHeight = 400 , [int]$ChartHeight = 400 ,
#Width of the chart in Pixels (600 by default) #Width of the chart in Pixels (600 by default)
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartWidth = 600, [int]$ChartWidth = 600,
#Cell position of the top left corner of the chart, there will be this number of rows above the top edge of the chart (default is 0, chart starts at top edge of row 1). #Cell position of the top left corner of the chart, there will be this number of rows above the top edge of the chart (default is 0, chart starts at top edge of row 1).
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRow = 0 , [Int]$ChartRow = 0 ,
#Cell position of the top left corner of the chart, there will be this number of cells to the left of the chart (default is 4, chart starts at left edge of column E) #Cell position of the top left corner of the chart, there will be this number of cells to the left of the chart (default is 4, chart starts at left edge of column E)
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumn = 4, [Int]$ChartColumn = 4,
#Vertical offset of the chart from the cell corner. #Vertical offset of the chart from the cell corner.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRowOffSetPixels = 0 , [Int]$ChartRowOffSetPixels = 0 ,
#Horizontal offset of the chart from the cell corner. #Horizontal offset of the chart from the cell corner.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumnOffSetPixels = 0, [Int]$ChartColumnOffSetPixels = 0,
#Type of chart #Type of chart
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie', [OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie',
#If specified hides the chart legend #If specified hides the chart legend
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$NoLegend, [Switch]$NoLegend,
#if specified attaches the category to slices in a pie chart : not supported on all chart types, this may give errors if applied to an unsupported type. #if specified attaches the category to slices in a pie chart : not supported on all chart types, this may give errors if applied to an unsupported type.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowCategory, [Switch]$ShowCategory,
#If specified attaches percentages to slices in a pie chart. #If specified attaches percentages to slices in a pie chart.
[Parameter(ParameterSetName='ChartbyParams')] [Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowPercent, [Switch]$ShowPercent,
#If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified #If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified
[switch]$Activate [switch]$Activate
) )
$validDataFuntions = [system.enum]::GetNames([OfficeOpenXml.Table.PivotTable.DataFieldFunctions]) $validDataFuntions = [system.enum]::GetNames([OfficeOpenXml.Table.PivotTable.DataFieldFunctions])
if ($PivotData.values.Where({$_ -notin $validDataFuntions}) ) { if ($PivotData.values.Where( {$_ -notin $validDataFuntions}) ) {
Write-Warning -Message ("Pivot data functions might not be valid, they should be one of " + ($validDataFuntions -join ", ") + ".") Write-Warning -Message ("Pivot data functions might not be valid, they should be one of " + ($validDataFuntions -join ", ") + ".")
} }
@@ -330,8 +412,8 @@ function New-PivotTableDefinition {
} }
$parameters.Remove('PivotTableName') $parameters.Remove('PivotTableName')
if ($PivotChartDefinition) { if ($PivotChartDefinition) {
$parameters.PivotChartDefinition.XRange = $null $parameters.PivotChartDefinition.XRange = $null
$parameters.PivotChartDefinition.YRange = $null $parameters.PivotChartDefinition.YRange = $null
$parameters.PivotChartDefinition.SeriesHeader = $null $parameters.PivotChartDefinition.SeriesHeader = $null
} }
@{$PivotTableName = $parameters} @{$PivotTableName = $parameters}

View File

@@ -1,6 +1,8 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification="False positives")]
param()
class PSPlot { class PSPlot {
hidden $path hidden $path
hidden $pkg hidden $pkg
hidden $ws hidden $ws
hidden $chart hidden $chart
@@ -11,62 +13,62 @@ class PSPlot {
} }
[PSPlot] Plot($yValues) { [PSPlot] Plot($yValues) {
$this.NewChart() $this.NewChart()
$xValues = 0..$yValues.Count $xValues = 0..$yValues.Count
$xCol = 'A' $xCol = 'A'
$yCol = 'B' $yCol = 'B'
$this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues) $this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues)
$this.AddSeries($xCol,$yCol,$yValues) $this.AddSeries($xCol,$yCol,$yValues)
$this.SetChartPosition($yCol) $this.SetChartPosition($yCol)
return $this return $this
} }
[PSPlot] Plot($yValues,[string]$options) { [PSPlot] Plot($yValues,[string]$options) {
$this.NewChart() $this.NewChart()
$xValues = 0..$yValues.Count $xValues = 0..$yValues.Count
$xCol = 'A' $xCol = 'A'
$yCol = 'B' $yCol = 'B'
$this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues) $this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues)
$this.AddSeries($xCol,$yCol,$yValues) $this.AddSeries($xCol,$yCol,$yValues)
$this.SetMarkerInfo($options) $this.SetMarkerInfo($options)
$this.SetChartPosition($yCol) $this.SetChartPosition($yCol)
return $this return $this
} }
[PSPlot] Plot($xValues,$yValues) { [PSPlot] Plot($xValues,$yValues) {
$this.NewChart() $this.NewChart()
$xCol = 'A' $xCol = 'A'
$yCol = 'B' $yCol = 'B'
$this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues) $this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues)
$this.AddSeries($xCol,$yCol,$yValues) $this.AddSeries($xCol,$yCol,$yValues)
$this.SetChartPosition($yCol) $this.SetChartPosition($yCol)
return $this return $this
} }
[PSPlot] Plot($xValues,$yValues,[string]$options) { [PSPlot] Plot($xValues,$yValues,[string]$options) {
$this.NewChart() $this.NewChart()
$xCol = 'A' $xCol = 'A'
$yCol = 'B' $yCol = 'B'
$this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues) $this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues)
$this.AddSeries($xCol,$yCol,$yValues) $this.AddSeries($xCol,$yCol,$yValues)
$this.SetMarkerInfo($options) $this.SetMarkerInfo($options)
$this.SetChartPosition($yCol) $this.SetChartPosition($yCol)
@@ -75,19 +77,19 @@ class PSPlot {
} }
[PSPlot] Plot($xValues,$yValues,$x1Values,$y1Values) { [PSPlot] Plot($xValues,$yValues,$x1Values,$y1Values) {
$this.NewChart() $this.NewChart()
$xCol = 'A' $xCol = 'A'
$yCol = 'B' $yCol = 'B'
$this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues) $this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues)
$this.AddSeries($xCol,$yCol,$yValues) $this.AddSeries($xCol,$yCol,$yValues)
$xCol=$this.GetNextColumnName($yCol) $xCol=$this.GetNextColumnName($yCol)
$yCol=$this.GetNextColumnName($xCol) $yCol=$this.GetNextColumnName($xCol)
$this.AddDataToSheet($xCol,$yCol,'x1','y1',$x1Values,$y1Values) $this.AddDataToSheet($xCol,$yCol,'x1','y1',$x1Values,$y1Values)
$this.AddSeries($xCol,$yCol,$y1Values) $this.AddSeries($xCol,$yCol,$y1Values)
$this.SetChartPosition($yCol) $this.SetChartPosition($yCol)
@@ -96,32 +98,32 @@ class PSPlot {
} }
[PSPlot] Plot($xValues,$yValues,$x1Values,$y1Values,$x2Values,$y2Values) { [PSPlot] Plot($xValues,$yValues,$x1Values,$y1Values,$x2Values,$y2Values) {
$this.NewChart() $this.NewChart()
$xCol = 'A' $xCol = 'A'
$yCol = 'B' $yCol = 'B'
$this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues) $this.AddDataToSheet($xCol,$yCol,'x','y',$xValues,$yValues)
$this.AddSeries($xCol,$yCol,$yValues) $this.AddSeries($xCol,$yCol,$yValues)
$xCol=$this.GetNextColumnName($yCol) $xCol=$this.GetNextColumnName($yCol)
$yCol=$this.GetNextColumnName($xCol) $yCol=$this.GetNextColumnName($xCol)
$this.AddDataToSheet($xCol,$yCol,'x1','y1',$x1Values,$y1Values) $this.AddDataToSheet($xCol,$yCol,'x1','y1',$x1Values,$y1Values)
$this.AddSeries($xCol,$yCol,$y1Values) $this.AddSeries($xCol,$yCol,$y1Values)
$xCol=$this.GetNextColumnName($yCol) $xCol=$this.GetNextColumnName($yCol)
$yCol=$this.GetNextColumnName($xCol) $yCol=$this.GetNextColumnName($xCol)
$this.AddDataToSheet($xCol,$yCol,'x2','y2',$x2Values,$y2Values) $this.AddDataToSheet($xCol,$yCol,'x2','y2',$x2Values,$y2Values)
$this.AddSeries($xCol,$yCol,$y2Values) $this.AddSeries($xCol,$yCol,$y2Values)
$this.SetChartPosition($yCol) $this.SetChartPosition($yCol)
return $this return $this
} }
[PSPLot] SetChartPosition($yCol) { [PSPLot] SetChartPosition($yCol) {
$columnNumber = $this.GetColumnNumber($yCol)+1 $columnNumber = $this.GetColumnNumber($yCol)+1
$this.chart.SetPosition(1,0,$columnNumber,0) $this.chart.SetPosition(1,0,$columnNumber,0)
@@ -131,29 +133,29 @@ class PSPlot {
AddSeries($xCol,$yCol,$yValues) { AddSeries($xCol,$yCol,$yValues) {
$yRange = "{0}2:{0}{1}" -f $yCol,($yValues.Count+1) $yRange = "{0}2:{0}{1}" -f $yCol,($yValues.Count+1)
$xRange = "{0}2:{0}{1}" -f $xCol,($yValues.Count+1) $xRange = "{0}2:{0}{1}" -f $xCol,($yValues.Count+1)
$Series=$this.chart.Series.Add($yRange,$xRange) $Series=$this.chart.Series.Add($yRange,$xRange)
} }
hidden SetMarkerInfo([string]$options) { hidden SetMarkerInfo([string]$options) {
$c=$options.Substring(0,1) $c=$options.Substring(0,1)
$m=$options.Substring(1) $m=$options.Substring(1)
$cmap=@{r='red';g='green';b='blue';i='indigo';v='violet';c='cyan'} $cmap=@{r='red';g='green';b='blue';i='indigo';v='violet';c='cyan'}
$mmap=@{Ci='Circle';Da='Dash';di='diamond';do='dot';pl='plus';sq='square';tr='triangle'} $mmap=@{Ci='Circle';Da='Dash';di='diamond';do='dot';pl='plus';sq='square';tr='triangle'}
$this.chart.Series[0].Marker = $mmap.$m $this.chart.Series[0].Marker = $mmap.$m
$this.chart.Series[0].MarkerColor = $cmap.$c $this.chart.Series[0].MarkerColor = $cmap.$c
$this.chart.Series[0].MarkerLineColor = $cmap.$c $this.chart.Series[0].MarkerLineColor = $cmap.$c
} }
hidden [string]GetNextColumnName($columnName) { hidden [string]GetNextColumnName($columnName) {
return $this.GetColumnName($this.GetColumnNumber($columnName)+1) return $this.GetColumnName($this.GetColumnNumber($columnName)+1)
} }
hidden [int]GetColumnNumber($columnName) { hidden [int]GetColumnNumber($columnName) {
$sum=0 $sum=0
$columnName.ToCharArray() | $columnName.ToCharArray() |
ForEach-Object { ForEach-Object {
$sum*=26 $sum*=26
@@ -179,20 +181,20 @@ class PSPlot {
$count=$yValues.Count $count=$yValues.Count
$this.ws.Cells["$($xColumn)1"].Value=$xHeader $this.ws.Cells["$($xColumn)1"].Value=$xHeader
$this.ws.Cells["$($yColumn)1"].Value=$yHeader $this.ws.Cells["$($yColumn)1"].Value=$yHeader
for ($idx= 0; $idx-lt $count; $idx++) { for ($idx= 0; $idx-lt $count; $idx++) {
$row=$idx+2 $row=$idx+2
$this.ws.Cells["$($xColumn)$($row)"].Value=$xValues[$idx] $this.ws.Cells["$($xColumn)$($row)"].Value=$xValues[$idx]
$this.ws.Cells["$($yColumn)$($row)"].Value=$yValues[$idx] $this.ws.Cells["$($yColumn)$($row)"].Value=$yValues[$idx]
} }
} }
hidden NewChart() { hidden NewChart() {
$chartType="XYScatter" $chartType="XYScatter"
#$chartType="line" #$chartType="line"
$this.chart=$this.ws.Drawings.AddChart("plot", $chartType) $this.chart=$this.ws.Drawings.AddChart("plot", $chartType)
$this.chart.Title.Text = 'Plot' $this.chart.Title.Text = 'Plot'
$this.chart.Legend.Remove() $this.chart.Legend.Remove()
$this.SetChartSize(300,300) $this.SetChartSize(300,300)
} }

View File

@@ -1,7 +0,0 @@
$p = @{
Name = "ImportExcel"
NuGetApiKey = $NuGetApiKey
ReleaseNote = "Add NumberFormat parameter"
}
Publish-Module @p

164
README.md
View File

@@ -7,23 +7,21 @@ If this project helped you reduce the time to get your job done, let me know.
![](https://media.giphy.com/media/hpXxJ78YtpT0s/giphy.gif) ![](https://media.giphy.com/media/hpXxJ78YtpT0s/giphy.gif)
<br/>
<br/> <p>
<br/> <a href="https://www.powershellgallery.com/packages/ImportExcel"><img src="https://img.shields.io/powershellgallery/v/ImportExcel.svg"></a>
<br/> <a href="https://www.powershellgallery.com/packages/ImportExcel"><img src="https://img.shields.io/powershellgallery/dt/ImportExcel.svg"></a>
<p align="center"> <a href="./LICENSE.txt"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a>
<a href="https://ci.appveyor.com/project/dfinke/importexcel/branch/master"><img src="https://ci.appveyor.com/api/projects/status/21hko6eqtpccrkba/branch/master?svg=true"></a>
<a href="https://dougfinke.visualstudio.com/ImportExcel/_build?definitionId=10"><img src="https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/ImportExcel-CI?branchName=master"></a>
</p> </p>
<p align="center"> | CI System | Environment | Status |
<a href="./LICENSE.txt"><img |--------------|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a> | AppVeyor | Windows, Core preview, Ubuntu | [![Build status](https://ci.appveyor.com/api/projects/status/21hko6eqtpccrkba/branch/master?svg=true)](https://ci.appveyor.com/project/dfinke/importexcel/branch/master) |
<a href="https://www.powershellgallery.com/packages/ImportExcel"><img | Azure DevOps | Windows | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Windows)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
src="https://img.shields.io/powershellgallery/dt/ImportExcel.svg"></a> | Azure DevOps | Windows (Core) | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=WindowsPSCore)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
<a href="https://www.powershellgallery.com/packages/ImportExcel"><img | Azure DevOps | Ubuntu | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Ubuntu)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
src="https://img.shields.io/powershellgallery/v/ImportExcel.svg"></a> | Azure DevOps | macOS | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=macOS)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) |
</p>
<!-- /BADGES --> <!-- /BADGES -->
@@ -37,7 +35,8 @@ This PowerShell Module allows you to read and write Excel files without installi
![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/testimonial.png) ![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/testimonial.png)
# How to Videos # How to Videos
* [PowerShell Excel Module - ImportExcel](https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq)
* [PowerShell Excel Module - ImportExcel](https://www.youtube.com/watch?v=fvKKdIzJCws&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq)
Installation Installation
- -
@@ -53,7 +52,136 @@ Install-Module ImportExcel -scope CurrentUser
Install-Module ImportExcel Install-Module ImportExcel
``` ```
# What's new 5.4 # What's new 6.5.3
Thank you [uSlackr](https://github.com/uSlackr)
- Fixes Column order issue (plus tests) for `Get-ExcelColumnName`
Thank you [jhoneill](https://github.com/jhoneill)
- Linux. Now set an environment variable if the support needed for Autosize is present, and use that Environment variable to decide to skip autosize operations.
- Fixed tests which needed autosize to work so they skip of the environment variable is set.
- Fixed another break where on azure the module never loaded.
- Added -Force to Send-SQLDataToExcel so it sends something even if no rows are returned. (see [#703](https://github.com/dfinke/ImportExcel/issues/703))
- Added -asText to import-Excel see (#164)[https://github.com/dfinke/ImportExcel/issues/164] and multiple others
- Add a comment to ci.ps1 re better .NET version detection and left some commented out code.
# What's new 6.5.2
- Added the example ReadAllSheets.ps1 based on the thread https://github.com/dfinke/ImportExcel/issues/678
# What's new 6.5.0
This is now using the latest version of EPPlus. Unit tests are updated and passing, if you hit problems, please open an issue.
You can rollback to an older version from the PowerShell Gallery if you are blocked.
- Unit tests were updated and fixed
- "Set-WorksheetProtection" is now switched on
- Made a change to make Set-Excel range more friendly when Auto Sizing on non-windows platforms
- Fixed - Windows only tests don't attempt to run on non-windows systems
- Tests based on Get-Process don't attempt to run if <20 processes are returned
- If $env:TEMP is not set (as will be the case on Linux)
- Join-Path if used so paths are built with / or with \ as suits the OS where the test is running.
- Excel Sparklines now supported, check out the examples [SalesByQuarter](https://github.com/dfinke/ImportExcel/blob/master/Examples/Sparklines/SalesByQuarter.ps1) and [Sparklines](https://github.com/dfinke/ImportExcel/blob/master/Examples/Sparklines/Sparklines.ps1).
![](./images/Sparklines.png)
# What's new 6.2.4
Sensible parameter defaults, make your life easier and gets things done faster.
- Thank you to [DomRRuggeri](https://github.com/DomRRuggeri) for the initial Out-Excel PR and kicking off the conversation on the improvements.
- Thank you to [ili101](https://github.com/ili101) for refactoring and improving the defaults, and adding the tests for parameters.
- Creates a table, with filtering
- Chooses a `TableStyle`
- Displays the Excel spreadsheet automatically
```powershell
Get-Process | select Company, Name, Handles | Export-Excel
```
![image](./images/ImproveNowDefaults.png)
# What's new 6.2.3
Thank you [jhoneill](https://github.com/jhoneill).
- Refactored copy sheet and added pipe support
- Add `ClearAll` to `Set-ExcelRange`
- Fix broken test & regression for `passwords`
- **Note**: Passwords do not work on `pwsh`. The EPPlus library does not support these dotnet core APIs at this time.
# What's new 6.2.2
- Added requested feature, chart trendlines.
- [Example PowerShell script](https://github.com/dfinke/ImportExcel/blob/master/Examples/Charts/NumberOfVisitors.ps1)
![](/images/ChartTrendlines.png)
- Fixed Import-Excel and relative path issue, added unit tests.
# What's new 6.2.0
Thank you to [James O'Neill](https://github.com/jhoneill)
- Fixed, Import-Excel can read xlsx files even if already open in Excel
- Added `New-ExcelStyle`, plus `-Style` to `Export-Excel` and `-Merge` to `Set-ExcelRange`
- Added [Style Examples](https://github.com/dfinke/ImportExcel/tree/master/Examples/Styles)
![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/NewExcelStyle.png)
# What's new 6.1.0
Thank you to [James O'Neill](https://github.com/jhoneill)
- Instead of specifying a path provides an Excel Package object (from `Open-ExcelPackage`), using this avoids re-reading the whole file when importing multiple parts of it. To allow multiple read operations `Import-Excel` does NOT close the package, and you should use `Close-ExcelPackage -noSave` to close it.
# What's new 6.0.0
Thank you to [James O'Neill](https://github.com/jhoneill) for the optimizations, and refactoring leading to a ***~10x*** speed increase. Thanks to [ili101](https://github.com/ili101) for earlier PRs that provided the ground work for this.
* Performance improvement to `Export-Excel` see [#506](https://github.com/dfinke/ImportExcel/issues/506) and [#555](https://github.com/dfinke/ImportExcel/issues/555). This has meant taking code in Add-CellValue back into process block of `Export-Excel`, as the overhead of calling the function was a lot greater than time executing the code inside it. [Blog post to follow](https://jamesone111.wordpress.com/). Some tests are showing a ***~10x*** speed increase. [#572](https://github.com/dfinke/ImportExcel/issues/572) was about a broken #region tag in this part of the code and that has been cleaned up in the process.
* `Export-Excel` now has an -InputObject parameter (this was previously -TargetData , which is now an alias for InputObject).
If the `inputobject` is an array, each item will be inserted, so you can run `export-excel -inputobject $x` rather than `$x | Export-Excel`, and if it is a `system.data.datatable` object it will be inserted directly rather than cell-by-cell. `Send-SQLDataToExcel` takes advantage of this new functionality. There are simple tests for these new items
* `Export-Excel` previously assumed `-Now` if there were no other parameters, it will now assume `-Now` if there is no `-Path` or `-ExcelPackage`.
The .PSD1 file now itemizes the items exported by the module [#557](https://github.com/dfinke/ImportExcel/issues/557)
# What's new 5.4.5
Thank you to [James O'Neill](https://github.com/jhoneill) for the great additions.
- Modified Send-SQLDataToExcel so it creates tables and ranges itself; previously it relied on export-excel to do this which cause problems when adding data to an existing sheet (#555)
- Added new command Add-ExcelDataValidation which will apply different data-validation rules to ranges of cells
- Changed the export behavior so that (1) attempts to convert to a number only apply if the the value was a string; (2) Nulls are no longer converted to an empty string (3) there is a specific check for URIs and not just text which is a valid URI. Using UNC names in hyperlinks remains problematic.
- Changed the behavior of AutoSize in export excel so it only applies to the exported columns. Previously if something was exported next to pre-existing data, AutoSize would resize the whole sheet, potentially undoing things which had been set on the earlier data. If anyone relied on this behavior they will need to explicitly tell the sheet to auto size with $sheet.cells.autofitColumns. (where $sheet points to the sheet, it might be $ExcelPackage.Workbook.Worksheets['Name'])
- In Compare-Worksheet,the Key for comparing the sheets can now be written as a hash table with an expression - it is used with a Group-Object command so if it is valid in Group-Object it should be accepted; this allows the creation of composite keys when data being compared doesn't have a column which uniquely identifies rows.
- In Set-ExcelRange , added a 'Locked' option equivalent to the checkbox on the Protection Tab of the format cells dialog box in Excel.
- Created a Set-WorksheetProtection function. This gives the same options the protection dialog in Excel but is 0.9 release at the moment.
## New Example
- Added [MutipleValidations.ps1](https://github.com/dfinke/ImportExcel/blob/master/Examples/ExcelDataValidation/MutipleValidations.ps1). Culled from the `tests`.
# What's new 5.4.4
- Fix issue when only a single property is piped into Export-Excel
- Fix issue in `Copy-ExcelWorksheet`, close the `$Stream`
# What's new 5.4.3
- Added Remove-Worksheet: Removes one or more worksheets from one or more workbooks
# What's new 5.4.2
- Added parameters -GroupDateRow and -GroupDatePart & -GroupNumericRow, -GroupNumericMin, -GroupNumericMax and -GroupNumericInterval
to Add-PivotTable and New-PivotTableDefinition. The date ones gather dates of the same year and/or quarter and/or month and/or day etc.
the number ones group numbers into bands, starting at Min, and going up steps specified by Interval. Added tests and help for these.
- Set-ExcelRow and Set-ExcelColumn now check that the worksheet name they passed exists in the workbook.
![](https://raw.githubusercontent.com/dfinke/ImportExcel/cf964e3e4f761ca4058c4a4b809e2206b16709da/images/GroupingNumeric.png)
# What's new 5.4.0
- Thank you to Conrad Agramont, Twitter: [@AGramont](https://twitter.com/@AGramont) for the `AddMultiWorkSheet.ps1` example. Much appreciated! - Thank you to Conrad Agramont, Twitter: [@AGramont](https://twitter.com/@AGramont) for the `AddMultiWorkSheet.ps1` example. Much appreciated!
- Fixed several more bugs where parameters were ignored if passed a zero value - Fixed several more bugs where parameters were ignored if passed a zero value
@@ -65,7 +193,7 @@ Install-Module ImportExcel
# What's new 5.3.4 # What's new 5.3.4
- HotFix for parameter PivotTableSyle should be PivotTableStyle https://github.com/dfinke/ImportExcel/issues/453 - HotFix for parameter PivotTableStyle should be PivotTableStyle https://github.com/dfinke/ImportExcel/issues/453
# What's new 5.3.3 # What's new 5.3.3
@@ -949,4 +1077,4 @@ You can also find EPPLus on [Nuget](https://www.nuget.org/packages/EPPlus/).
* Using `-IncludePivotTable`, if that pivot table name exists, you'll get an error. * Using `-IncludePivotTable`, if that pivot table name exists, you'll get an error.
* Investigating a solution * Investigating a solution
* *Workaround* delete the Excel file first, then do the export * *Workaround* delete the Excel file first, then do the export

View File

@@ -1,34 +1,45 @@
Function Remove-WorkSheet { Function Remove-WorkSheet {
Param ( <#
$Path, .SYNOPSIS
$WorksheetName Removes one or more worksheets from one or more workbooks
.EXAMPLE
C:\> Remove-WorkSheet -Path Test1.xlsx -WorksheetName Sheet1
Removes the worksheet named 'Sheet1' from 'Test1.xlsx'
C:\> Remove-WorkSheet -Path Test1.xlsx -WorksheetName Sheet1,Target1
Removes the worksheet named 'Sheet1' and 'Target1' from 'Test1.xlsx'
C:\> Remove-WorkSheet -Path Test1.xlsx -WorksheetName Sheet1,Target1 -Show
Removes the worksheets and then launches the xlsx in Excel
C:\> dir c:\reports\*.xlsx | Remove-WorkSheet
Removes 'Sheet1' from all the xlsx files in the c:\reports directory
#>
[cmdletbinding(SupportsShouldProcess=$true)]
param(
# [Parameter(ValueFromPipelineByPropertyName)]
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('Path')]
$FullName,
[String[]]$WorksheetName = "Sheet1",
[Switch]$Show
) )
$Path = (Resolve-Path $Path).ProviderPath Process {
if (!$FullName) {
$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $Path throw "Remove-WorkSheet requires the and Excel file"
$workSheet = $Excel.Workbook.Worksheets[$WorkSheetName]
if($workSheet) {
if($Excel.Workbook.Worksheets.Count -gt 1) {
$Excel.Workbook.Worksheets.Delete($workSheet)
} else {
throw "Cannot delete $WorksheetName. A workbook must contain at least one visible worksheet"
} }
} else { $pkg = Open-ExcelPackage -Path $FullName
throw "$WorksheetName not found"
if ($pkg) {
foreach ($wsn in $WorksheetName) {
if ($PSCmdlet.ShouldProcess($FullName,"Remove Sheet $wsn")) {
$pkg.Workbook.Worksheets.Delete($wsn)
}
}
Close-ExcelPackage -ExcelPackage $pkg -Show:$Show
}
} }
}
$Excel.Save()
$Excel.Dispose()
}
Import-Module .\ImportExcel.psd1 -Force
$names = Get-ExcelSheetInfo C:\Temp\testDelete.xlsx
$names | Foreach-Object { Remove-WorkSheet C:\Temp\testDelete.xlsx $_.Name}
##Remove-WorkSheet C:\Temp\testDelete.xlsx sheet6

204
Send-SQLDataToExcel.ps1 Normal file
View File

@@ -0,0 +1,204 @@
Function Send-SQLDataToExcel {
<#
.SYNOPSIS
Inserts a DataTable - returned by a SQL query - into an ExcelSheet
.DESCRIPTION
This command takes a SQL statement and run it against a database connection; for the connection it accepts either
* an object representing a session with a SQL server or ODBC database, or
* a connection string to make a session (if -MSSQLServer is specified it uses the SQL Native client,
and -Connection can be a server name instead of a detailed connection string. Without this switch it uses ODBC)
The command takes all the parameters of Export-Excel, except for -InputObject (alias TargetData); after
fetching the data it calls Export-Excel with the data as the value of InputParameter and whichever of
Export-Excel's parameters it was passed; for details of these parameters see the help for Export-Excel.
.PARAMETER Session
An active ODBC Connection or SQL connection object representing a session with a database which will be queried to get the data .
.PARAMETER Connection
A database connection string to be used to create a database session; either
* A Data source name written in the form DSN=ODBC_Data_Source_Name, or
* A full ODBC or SQL Native Client Connection string, or
* The name of a SQL server.
.PARAMETER MSSQLServer
Specifies the connection string is for SQL server, not ODBC.
.PARAMETER SQL
The SQL query to run against the session which was passed in -Session or set up from -Connection.
.PARAMETER Database
Switches to a specific database on a SQL server.
.PARAMETER QueryTimeout
Override the default query time of 30 seconds.
.PARAMETER DataTable
A System.Data.DataTable object containing the data to be inserted into the spreadsheet without running a query.
This remains supported to avoid breaking older scripts, but if you have a DataTable object you can pass the it
into Export-Excel using -InputObject.
.PARAMETER Force
If specified Export-Excel will be called with parameters specified, even if there is no data to send
.EXAMPLE
C:\> Send-SQLDataToExcel -MsSQLserver -Connection localhost -SQL "select name,type,type_desc from [master].[sys].[all_objects]" -Path .\temp.xlsx -WorkSheetname master -AutoSize -FreezeTopRow -AutoFilter -BoldTopRow
Connects to the local SQL server and selects 3 columns from [Sys].[all_objects] and exports then to a sheet named master with some basic header management
.EXAMPLE
C:\> $dbPath = 'C:\Users\James\Documents\Database1.accdb'
C:\> $Connection = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=$dbPath;"
C:\> $SQL="SELECT top 25 Name,Length From TestData ORDER BY Length DESC"
C:\> Send-SQLDataToExcel -Connection $connection -SQL $sql -path .\demo1.xlsx -WorkSheetname "Sizes" -AutoSize
This creates an ODBC connection string to read from an Access file and a SQL Statement to extracts data from it,
and sends the resulting data to a new worksheet
.EXAMPLE
C:\> $dbPath = 'C:\users\James\Documents\f1Results.xlsx'
C:\> $Connection = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};Dbq=$dbPath;"
C:\> $SQL="SELECT top 25 DriverName, Count(RaceDate) as Races, Count(Win) as Wins, Count(Pole) as Poles, Count(FastestLap) as Fastlaps " +
" FROM Results GROUP BY DriverName ORDER BY (count(win)) DESC"
C:\> Send-SQLDataToExcel -Connection $connection -SQL $sql -path .\demo2.xlsx -WorkSheetname "Winners" -AutoSize -AutoNameRange -ConditionalFormat @{DataBarColor="Blue"; Range="Wins"}
Similar to the previous example this creates a connection string, this time for an Excel file, and runs
a SQL statement to get a list of motor-racing results, outputting the resulting data to a new spreadsheet.
The spreadsheet is formatted and a data bar added to show make the drivers' wins clearer.
(the F1 results database is available from https://1drv.ms/x/s!AhfYu7-CJv4ehNdZWxJE9LMAX_N5sg )
.EXAMPLE
C:\> $dbPath = 'C:\users\James\Documents\f1Results.xlsx'
C:\> $SQL = "SELECT top 25 DriverName, Count(RaceDate) as Races, Count(Win) as Wins, Count(Pole) as Poles, Count(FastestLap) as Fastlaps " +
" FROM Results GROUP BY DriverName ORDER BY (count(win)) DESC"
C:\> $null = Get-SQL -Session F1 -excel -Connection $dbPath -sql $sql -OutputVariable Table
C:\> Send-SQLDataToExcel -DataTable $Table -Path ".\demo3.xlsx" -WorkSheetname Gpwinners -autosize -TableName winners -TableStyle Light6 -show
This uses Get-SQL (at least V1.1 - download from the PowerShell gallery with Install-Module -Name GetSQL -
note the function is Get-SQL the module is GetSQL without the "-" )
Get-SQL simplify making database connections and building /submitting SQL statements.
Here Get-SQL uses the same SQL statement as before; -OutputVariable leaves a System.Data.DataTable object in $table
and Send-SQLDataToExcel puts $table into the worksheet and sets it as an Excel table.
The command is equivalent to running
C:\> Export-Excel -inputObject $Table -Path ".\demo3.xlsx" -WorkSheetname Gpwinners -autosize -TableName winners -TableStyle Light6 -show
This is quicker than using
C:\> Get-SQL <parameters> | export-excel -ExcludeProperty rowerror,rowstate,table,itemarray,haserrors <parameters>
(the F1 results database is available from https://1drv.ms/x/s!AhfYu7-CJv4ehNdZWxJE9LMAX_N5sg )
.EXAMPLE
C:\> $SQL = "SELECT top 25 DriverName, Count(Win) as Wins FROM Results GROUP BY DriverName ORDER BY (count(win)) DESC"
C:\> Send-SQLDataToExcel -Session $DbSessions["f1"] -SQL $sql -Path ".\demo3.xlsx" -WorkSheetname Gpwinners -ClearSheet -autosize -ColumnChart
Like the previous example, this uses Get-SQL (download from the gallery with Install-Module -Name GetSQL).
It uses the database session which Get-SQL created, rather than an ODBC connection string.
The Session parameter can either be a object (as shown here), or the name used by Get-SQL ("F1" in this case).
Here the data is presented as a quick chart.
.EXAMPLE
C:\> Send-SQLDataToExcel -path .\demo4.xlsx -WorkSheetname "LR" -Connection "DSN=LR" -sql "SELECT name AS CollectionName FROM AgLibraryCollection Collection ORDER BY CollectionName"
This example uses an Existing ODBC datasource name "LR" which maps to an adobe lightroom database and gets a list of collection names into a worksheet
.Link
Export-Excel
#>
[CmdletBinding(DefaultParameterSetName="none")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification="Allowed to use DBSessions Global variable from GETSQL Module")]
param (
[Parameter(ParameterSetName="SQLConnection", Mandatory=$true)]
[Parameter(ParameterSetName="ODBCConnection", Mandatory=$true)]
$Connection,
[Parameter(ParameterSetName="ExistingSession", Mandatory=$true)]
$Session,
[Parameter(ParameterSetName="SQLConnection", Mandatory=$true)]
[switch]$MsSQLserver,
[Parameter(ParameterSetName="SQLConnection")]
[String]$DataBase,
[Parameter(ParameterSetName="SQLConnection", Mandatory=$true)]
[Parameter(ParameterSetName="ODBCConnection", Mandatory=$true)]
[Parameter(ParameterSetName="ExistingSession", Mandatory=$true)]
[string]$SQL,
[int]$QueryTimeout,
[Parameter(ParameterSetName="Pre-FetchedData", Mandatory=$true)]
[System.Data.DataTable]$DataTable,
[switch]$Force
)
#Import the parameters from Export-Excel, we will pass InputObject, and we have the common parameters so exclude those,
#and re-write the [Parmameter] attribute on each one to avoid parameterSetName here competing with the settings in Export excel.
#The down side of this that impossible parameter combinations won't be filtered out and need to be caught later.
DynamicParam {
$ParameterAttribute = "System.Management.Automation.ParameterAttribute"
$RuntimeDefinedParam = "System.Management.Automation.RuntimeDefinedParameter"
$paramDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
$attributeCollection = New-Object -TypeName System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add((New-Object -TypeName $ParameterAttribute -Property @{ ParameterSetName = "__AllParameterSets" ;Mandatory = $false}))
foreach ($P in (Get-Command -Name Export-Excel).Parameters.values.where({$_.name -notmatch 'Verbose|Debug|Action$|Variable$|Buffer$|TargetData$|InputObject$'})) {
$paramDictionary.Add($p.Name, (New-Object -TypeName $RuntimeDefinedParam -ArgumentList $p.name, $p.ParameterType, $attributeCollection ) )
}
return $paramDictionary
}
process {
#region Dynamic params mean we can get passed parameter combination Export-Excel will reject, so throw here, rather than get data and then have Export-Excel error.
if ($PSBoundParameters.Path -and $PSBoundParameters.ExcelPackage) {
throw 'Parameter error: you cannot specify both a path and an Excel Package.'
return
}
if ($PSBoundParameters.AutoFilter -and ($PSBoundParameters.TableName -or $PSBoundParameters.TableStyle)) {
Write-Warning "Tables are automatically auto-filtered, -AutoFilter will be ignored"
$null = $PSBoundParameters.Remove('AutoFilter')
}
#endregion
#region if we were either given a session object or a connection string (& optionally -MSSQLServer) make sure we can connect
try {
#If we got -MSSQLServer, create a SQL connection, if we didn't but we got -Connection create an ODBC connection
if ($MsSQLserver -and $Connection) {
if ($Connection -notmatch '=') {$Connection = "server=$Connection;trusted_connection=true;timeout=60"}
$Session = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $Connection
if ($Session.State -ne 'Open') {$Session.Open()}
if ($DataBase) {$Session.ChangeDatabase($DataBase) }
}
elseif ($Connection) {
$Session = New-Object -TypeName System.Data.Odbc.OdbcConnection -ArgumentList $Connection ; $Session.ConnectionTimeout = 30
}
}
catch {
Write-Warning "An Error occured trying to connect to $Connection, the error was $([Environment]::NewLine + $_.Exception.InnerException))"
}
if ($Session -is [String] -and $Global:DbSessions[$Session]) {$Session = $Global:DbSessions[$Session]}
#endregion
#region we may have been given a table, but if there is a db session to connect to, send the query
if ($Session) {
try {
#If the session a SQL one make a SQL DataAdapter, otherwise make an ODBC one
if ($Session.GetType().name -match "SqlConnection") {
$dataAdapter = New-Object -TypeName System.Data.SqlClient.SqlDataAdapter -ArgumentList (
New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList $SQL, $Session)
}
else {
$dataAdapter = New-Object -TypeName System.Data.Odbc.OdbcDataAdapter -ArgumentList (
New-Object -TypeName System.Data.Odbc.OdbcCommand -ArgumentList $SQL, $Session )
}
if ($QueryTimeout) {$dataAdapter.SelectCommand.CommandTimeout = $QueryTimeout}
#Both adapter types output the same kind of table, create one and fill it from the adapter
$DataTable = New-Object -TypeName System.Data.DataTable
$rowCount = $dataAdapter.fill($dataTable)
Write-Verbose -Message "Query returned $rowCount row(s)"
}
catch {
Write-Warning "An Error occured trying to run the query, the error was $([Environment]::NewLine + $_.Exception.InnerException))"
}
}
#endregion
#region send the table to Excel
#remove parameters which relate to querying SQL, leaving the ones used by Export-Excel
'Connection' , 'Database' , 'Session' , 'MsSQLserver' , 'SQL' , 'DataTable' , 'QueryTimeout' , 'Force' |
ForEach-Object {$null = $PSBoundParameters.Remove($_) }
#if force was specified export even if there are no rows. If there are no columns, the query failed and export "null" if forced
if ($DataTable.Rows.Count) {
Export-Excel @PSBoundParameters -InputObject $DataTable
}
elseif ($Force -and $DataTable.Columns.Count) {
Write-Warning -Message "Zero rows returned, and -Force was specified, sending empty table to Excel."
Export-Excel @PSBoundParameters -InputObject $DataTable
}
elseif ($Force) {
Write-Warning -Message "-Force was specified but there is no data to send."
Export-Excel @PSBoundParameters -InputObject $null
}
else {Write-Warning -Message 'There is no Data to insert, and -Force was not specified.' }
#endregion
#If we were passed a connection and opened a session, close that session.
if ($Connection) {$Session.close() }
}
}

View File

@@ -1,297 +0,0 @@
Function Send-SQLDataToExcel {
<#
.SYNOPSIS
Inserts a DataTable - returned by SQL query into an ExcelSheet, more efficiently than sending it via Export-Excel
.DESCRIPTION
This command can accept a data table object or take a SQL statement and run it against a database connection.
If running a SQL statement, the accepts either
* an object representing a session with a SQL server or ODBC database, or
* a connection String to make a session.
The command takes most of the parameters of Export-Excel, and after inserting the table into the worksheet it
calls Export-Excel to carry out other tasks on the sheet. It is more efficient to do this than to get data-rows
and pipe them into Export-Excel, stripped off the database 'housekeeping' properties.
.PARAMETER DataTable
A System.Data.DataTable object containing the data to be inserted into the spreadsheet without running a query.
.PARAMETER Session
An active ODBC Connection or SQL connection object representing a session with a database which will be queried to get the data .
.PARAMETER Connection
A database connection string to be used to create a database session; either
* A Data source name written in the form DSN=ODBC_Data_Source_Name, or
* A full odbc or SQL Connection string, or
* The name of a SQL server.
.PARAMETER MSSQLServer
Specifies the connection string is for SQL server, not ODBC.
.PARAMETER SQL
The SQL query to run against the session which was passed in -Session or set up from -Connection.
.PARAMETER Database
Switches to a specific database on a SQL server.
.PARAMETER QueryTimeout
Override the default query time of 30 seconds.
.PARAMETER Path
Path to a new or existing .XLSX file.
.PARAMETER WorkSheetName
The name of a sheet within the workbook - "Sheet1" by default.
.PARAMETER KillExcel
Closes Excel - prevents errors writing to the file because Excel has it open.
.PARAMETER Title
Text of a title to be placed in the top left cell.
.PARAMETER TitleBold
Sets the title in boldface type.
.PARAMETER TitleSize
Sets the point size for the title.
.PARAMETER TitleBackgroundColor
Sets the cell background color for the title cell.
.PARAMETER TitleFillPattern
Sets the fill pattern for the title cell.
.PARAMETER Password
Sets password protection on the workbook.
.PARAMETER IncludePivotTable
Adds a Pivot table using the data in the worksheet.
.PARAMETER PivotTableName
If a Pivot table is created from command line parameters, specificies the name of the new sheet holding the pivot. If Omitted this will be "WorksheetName-PivotTable"
.PARAMETER PivotRows
Name(s) columns from the spreadhseet which will provide the Row name(s) in a pivot table created from command line parameters.
.PARAMETER PivotColumns
Name(s) columns from the spreadhseet which will provide the Column name(s) in a pivot table created from command line parameters.
.PARAMETER PivotFilter
Name(s) columns from the spreadhseet which will provide the Filter name(s) in a pivot table created from command line parameters.
.PARAMETER PivotData
In a pivot table created from command line parameters, the fields to use in the table body is given as a Hash table in the form ColumnName = Average|Count|CountNums|Max|Min|Product|None|StdDev|StdDevP|Sum|Var|VarP .
.PARAMETER PivotDataToColumn
If there are multiple datasets in a PivotTable, by default they are shown seperatate rows under the given row heading; this switch makes them seperate columns.
.PARAMETER NoTotalsInPivot
In a pivot table created from command line parameters, prevents the addition of totals to rows and columns.
.PARAMETER IncludePivotChart
Include a chart with the Pivot table - implies -IncludePivotTable.
.PARAMETER ChartType
The type for Pivot chart (one of Excel's defined chart types)
.PARAMETER NoLegend
Exclude the legend from the pivot chart.
.PARAMETER ShowCategory
Add category labels to the pivot chart.
.PARAMETER ShowPercent
Add Percentage labels to the pivot chart.
.PARAMETER PivotTableDefinition
Instead of describing a single pivot table with mutliple commandline paramters; you can use a HashTable in the form PivotTableName = Definition;
Definition is itself a hashtable with Sheet PivotTows, PivotColumns, PivotData, IncludePivotChart and ChartType values.
.PARAMETER ConditionalFormat
One or more conditional formatting rules defined with New-ConditionalFormattingIconSet.
.PARAMETER ConditionalText
Applies a 'Conditional formatting rule' in Excel on all the cells. When specific conditions are met a rule is triggered.
.PARAMETER BoldTopRow
Makes the top Row boldface.
.PARAMETER NoHeader
Does not put field names at the top of columns.
.PARAMETER RangeName
Makes the data in the worksheet a named range.
.PARAMETER AutoNameRange
Makes each column a named range.
.PARAMETER TableName
Makes the data in the worksheet a table with a name applies a style to it. Name must not contain spaces.
.PARAMETER TableStyle
Selects the style for the named table - defaults to 'Medium6'.
.PARAMETER BarChart
Creates a "quick" bar chart using the first text column as labels and the first numeric column as values
.PARAMETER ColumnChart
Creates a "quick" column chart using the first text column as labels and the first numeric column as values
.PARAMETER LineChart
Creates a "quick" line chart using the first text column as labels and the first numeric column as values
.PARAMETER PieChart
Creates a "quick" pie chart using the first text column as labels and the first numeric column as values
.PARAMETER ExcelChartDefinition
A hash table containing ChartType, Title, NoLegend, ShowCategory, ShowPercent, Yrange, Xrange and SeriesHeader for one or more [non-pivot] charts.
.PARAMETER StartRow
Row to start adding data. 1 by default. Row 1 will contain the title if any. Then headers will appear (Unless -No header is specified) then the data appears.
.PARAMETER StartColumn
Column to start adding data - 1 by default.
.PARAMETER FreezeTopRow
Freezes headers etc. in the top row.
.PARAMETER FreezeFirstColumn
Freezes titles etc. in the left column.
.PARAMETER FreezeTopRowFirstColumn
Freezes top row and left column (equivalent to Freeze pane 2,2 ).
.PARAMETER FreezePane
Freezes panes at specified coordinates (in the form RowNumber , ColumnNumber).
.PARAMETER AutoFilter
Enables the 'Filter' in Excel on the complete header row. So users can easily sort, filter and/or search the data in the select column from within Excel.
.PARAMETER AutoSize
Sizes the width of the Excel column to the maximum width needed to display all the containing data in that cell.
.PARAMETER Show
Opens the Excel file immediately after creation. Convenient for viewing the results instantly without having to search for the file first.
.PARAMETER CellStyleSB
A script block which is run at the end of the process to apply styles to cells (although it can be used for other purposes).
The script block is given three paramaters; an object containing the current worksheet, the Total number of Rows and the number of the last column.
.PARAMETER ReturnRange
If specified, Export-Excel returns the range of added cells in the format "A1:Z100"
.PARAMETER PassThru
If specified, Export-Excel returns an object representing the Excel package without saving the package first. To save it you need to call the save or Saveas method or send it back to Export-Excel.
.EXAMPLE
C:\> Send-SQLDataToExcel -MsSQLserver -Connection localhost -SQL "select name,type,type_desc from [master].[sys].[all_objects]" -Path .\temp.xlsx -WorkSheetname master -AutoSize -FreezeTopRow -AutoFilter -BoldTopRow
Connects to the local SQL server and selects 3 columns from [Sys].[all_objects] and exports then to a sheet named master with some basic header management
.EXAMPLE
C:\> $SQL="SELECT top 25 Name,Length From TestData ORDER BY Length DESC"
C:\> $Connection = ' Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=C:\Users\James\Documents\Database1.accdb;'
C:\> Send-SQLDataToExcel -Connection $connection -SQL $sql -path .\demo1.xlsx -WorkSheetname "Sizes" -AutoSize
This declares a SQL statement and creates an ODBC connection string to read from an Access file and extracts data from it and sends it to a new worksheet
.EXAMPLE
C:\> $SQL="SELECT top 25 DriverName, Count(RaceDate) as Races, Count(Win) as Wins, Count(Pole) as Poles, Count(FastestLap) as Fastlaps FROM Results GROUP BY DriverName ORDER BY (count(win)) DESC"
C:\> $Connection = 'Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};Dbq=C:\users\James\Documents\f1Results.xlsx;'
C:\> Send-SQLDataToExcel -Connection $connection -SQL $sql -path .\demo1.xlsx -WorkSheetname "Winners" -AutoSize -AutoNameRange -ConditionalFormat @{DataBarColor="Blue"; Range="Wins"}
This declares a SQL statement and creates an ODBC connection string to read from an Excel file, it then runs the statement and outputs the resulting data to a new spreadsheet.
The spreadsheet is formatted and a data bar added to show make the drivers' wins clearer.
(the F1 results database is available from https://1drv.ms/x/s!AhfYu7-CJv4ehNdZWxJE9LMAX_N5sg )
.EXAMPLE
C:\> $SQL = "SELECT top 25 DriverName, Count(RaceDate) as Races, Count(Win) as Wins, Count(Pole) as Poles, Count(FastestLap) as Fastlaps FROM Results GROUP BY DriverName ORDER BY (count(win)) DESC"
C:\> Get-SQL -Session F1 -excel -Connection "C:\Users\mcp\OneDrive\public\f1\f1Results.xlsx" -sql $sql -OutputVariable Table | out-null
C:\> Send-SQLDataToExcel -DataTable $Table -Path ".\demo3.xlsx" -WorkSheetname Gpwinners -autosize -TableName winners -TableStyle Light6 -show
This uses Get-SQL (at least V1.1 - download from the gallery with Install-Module -Name GetSQL - note the function is Get-SQL the module is GetSQL without the "-" )
to simplify making database connections and building /submitting SQL statements.
Here it uses the same SQL statement as before; -OutputVariable leaves a System.Data.DataTable object in $table
and Send-SQLDataToExcel puts $table into the worksheet and sets it as an Excel table.
(the F1 results database is available from https://1drv.ms/x/s!AhfYu7-CJv4ehNdZWxJE9LMAX_N5sg )
.EXAMPLE
C:\> $SQL = "SELECT top 25 DriverName, Count(Win) as Wins FROM Results GROUP BY DriverName ORDER BY (count(win)) DESC"
C:\> Send-SQLDataToExcel -Session $DbSessions["f1"] -SQL $sql -Path ".\demo3.xlsx" -WorkSheetname Gpwinners -autosize -ColumnChart
Like the previous example, this uses Get-SQL (download from the gallery with Install-Module -Name GetSQL). It uses the connection which Get-SQL made rather than an ODFBC connection string
Here the data is presented as a quick chart.
.EXAMPLE
C:\> Send-SQLDataToExcel -path .\demo3.xlsx -WorkSheetname "LR" -Connection "DSN=LR" -sql "SELECT name AS CollectionName FROM AgLibraryCollection Collection ORDER BY CollectionName"
This example uses an Existing ODBC datasource name "LR" which maps to an adobe lightroom database and gets a list of collection names into a worksheet
#>
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")]
param (
[Parameter(ParameterSetName="SQLConnection", Mandatory=$true)]
[Parameter(ParameterSetName="ODBCConnection",Mandatory=$true)]
$Connection,
[Parameter(ParameterSetName="ExistingSession",Mandatory=$true)]
[System.Data.Common.DbConnection]$Session,
[Parameter(ParameterSetName="SQLConnection",Mandatory=$true)]
[switch]$MsSQLserver,
[Parameter(ParameterSetName="SQLConnection")]
[String]$DataBase,
[Parameter(ParameterSetName="SQLConnection", Mandatory=$true)]
[Parameter(ParameterSetName="ODBCConnection",Mandatory=$true)]
[Parameter(ParameterSetName="ExistingSession",Mandatory=$true)]
[string]$SQL,
[int]$QueryTimeout,
[Parameter(ParameterSetName="Pre-FetchedData",Mandatory=$true)]
[System.Data.DataTable]$DataTable,
$Path,
[String]$WorkSheetname = 'Sheet1',
[Switch]$KillExcel,
[Switch]$Show,
[String]$Title,
[OfficeOpenXml.Style.ExcelFillStyle]$TitleFillPattern = 'None',
[Switch]$TitleBold,
[Int]$TitleSize = 22,
$TitleBackgroundColor,
[String]$Password,
[Hashtable]$PivotTableDefinition,
[Switch]$IncludePivotTable,
[String[]]$PivotRows,
[String[]]$PivotColumns,
$PivotData,
[String[]]$PivotFilter,
[Switch]$PivotDataToColumn,
[Switch]$NoTotalsInPivot,
[Switch]$IncludePivotChart,
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie',
[Switch]$NoLegend,
[Switch]$ShowCategory,
[Switch]$ShowPercent,
[Switch]$AutoSize,
[Switch]$FreezeTopRow,
[Switch]$FreezeFirstColumn,
[Switch]$FreezeTopRowFirstColumn,
[Int[]]$FreezePane,
[Switch]$AutoFilter,
[Switch]$BoldTopRow,
[Switch]$NoHeader,
[String]$RangeName,
[String]$TableName,
[OfficeOpenXml.Table.TableStyles]$TableStyle = 'Medium6',
[Switch]$Barchart,
[Switch]$PieChart,
[Switch]$LineChart ,
[Switch]$ColumnChart ,
[Object[]]$ExcelChartDefinition,
[Switch]$AutoNameRange,
[Object[]]$ConditionalFormat,
[Object[]]$ConditionalText,
[ScriptBlock]$CellStyleSB,
[Int]$StartRow = 1,
[Int]$StartColumn = 1,
[Switch]$ReturnRange,
[Switch]$Passthru
)
if ($KillExcel) {
Get-Process excel -ErrorAction Ignore | Stop-Process
while (Get-Process excel -ErrorAction Ignore) {Start-Sleep -Milliseconds 250}
}
#We were either given a session object or a connection string (with, optionally a MSSQLServer parameter)
# If we got -MSSQLServer, create a SQL connection, if we didn't but we got -Connection create an ODBC connection
if ($MsSQLserver -and $Connection) {
if ($Connection -notmatch "=") {$Connection = "server=$Connection;trusted_connection=true;timeout=60"}
$Session = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $Connection
if ($Session.State -ne 'Open') {$Session.Open()}
if ($DataBase) {$Session.ChangeDatabase($DataBase) }
}
elseif ($Connection) {
$Session = New-Object -TypeName System.Data.Odbc.OdbcConnection -ArgumentList $Connection ; $Session.ConnectionTimeout = 30
}
If ($session) {
#A session was either passed in or just created. If it's a SQL one make a SQL DataAdapter, otherwise make an ODBC one
if ($Session.GetType().name -match "SqlConnection") {
$dataAdapter = New-Object -TypeName System.Data.SqlClient.SqlDataAdapter -ArgumentList (
New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList $SQL, $Session)
}
else {
$dataAdapter = New-Object -TypeName System.Data.Odbc.OdbcDataAdapter -ArgumentList (
New-Object -TypeName System.Data.Odbc.OdbcCommand -ArgumentList $SQL, $Session )
}
if ($QueryTimeout) {$dataAdapter.SelectCommand.CommandTimeout = $ServerTimeout}
#Both adapter types output the same kind of table, create one and fill it from the adapter
$DataTable = New-Object -TypeName System.Data.DataTable
$rowCount = $dataAdapter.fill($dataTable)
Write-Verbose -Message "Query returned $rowCount row(s)"
}
if ($DataTable.Rows.Count) {
#ExportExcel user a -NoHeader parameter so that's what we use here, but needs to be the other way around.
$printHeaders = -not $NoHeader
if ($Title) {$r = $StartRow +1 }
else {$r = $StartRow}
#Get our Excel sheet and fill it with the data
$excelPackage = Export-Excel -Path $Path -WorkSheetname $WorkSheetname -PassThru
$excelPackage.Workbook.Worksheets[$WorkSheetname].Cells[$r,$StartColumn].LoadFromDataTable($dataTable, $printHeaders ) | Out-Null
#Apply date format
for ($c=0 ; $c -lt $DataTable.Columns.Count ; $c++) {
if ($DataTable.Columns[$c].DataType -eq [datetime]) {
Set-ExcelColumn -Worksheet $excelPackage.Workbook.Worksheets[$WorkSheetname] -Column ($c +1) -NumberFormat 'Date-Time'
}
}
#Call export-excel with any parameters which don't relate to the SQL query
"Connection", "Database" , "Session", "MsSQLserver", "Destination" , "SQL" , "DataTable", "Path" | ForEach-Object {$null = $PSBoundParameters.Remove($_) }
Export-Excel -ExcelPackage $excelPackage @PSBoundParameters
}
else {Write-Warning -Message "No Data to insert."}
#If we were passed a connection and opened a session, close that session.
if ($Connection) {$Session.close() }
}

View File

@@ -1,4 +1,7 @@
function Set-CellStyle { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function', Target='Set*', Justification='Does not change system state')]
param()
function Set-CellStyle {
param( param(
$WorkSheet, $WorkSheet,
$Row, $Row,

View File

@@ -25,6 +25,14 @@
"WinsToFastLaps" and the data cells should contain =E2/C2 , =E3/C3 etc "WinsToFastLaps" and the data cells should contain =E2/C2 , =E3/C3 etc
the new data cells should become a named range, which will also be the new data cells should become a named range, which will also be
named "WinsToFastLaps" and the column width will be set automatically. named "WinsToFastLaps" and the column width will be set automatically.
When a value begins with "=", it is treated as a formula.
If value is a script block it will be evaluated, so here the string "=E$row/C$Row"
will have the number of the current row inserted. See the value parameter for a list of
variables which can be used. Note than when evaluating an expression in a string,
it is necessary to wrap it in $() so $row is valid but $($row+1) is needed. To prevent
Variables merging into other parts of the string, use the back tick "$columnName`4" will
be "G4" - withouth the backtick the string will look for a variable named "columnName4"
.EXAMPLE .EXAMPLE
Set-ExcelColumn -Worksheet $ws -Heading "Link" -Value {"https://en.wikipedia.org" + $worksheet.cells["B$Row"].value } -AutoSize Set-ExcelColumn -Worksheet $ws -Heading "Link" -Value {"https://en.wikipedia.org" + $worksheet.cells["B$Row"].value } -AutoSize
@@ -44,6 +52,8 @@
[cmdletbinding()] [cmdletbinding()]
[Alias("Set-Column")] [Alias("Set-Column")]
[OutputType([OfficeOpenXml.ExcelColumn],[String])] [OutputType([OfficeOpenXml.ExcelColumn],[String])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system state')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification="Variables created for script block which may be passed as a parameter, but not used in the script")]
Param ( Param (
#If specifying the worksheet by name, the ExcelPackage object which contains the worksheet also needs to be passed. #If specifying the worksheet by name, the ExcelPackage object which contains the worksheet also needs to be passed.
[Parameter(ParameterSetName="Package",Mandatory=$true)] [Parameter(ParameterSetName="Package",Mandatory=$true)]
@@ -121,7 +131,12 @@
begin { begin {
#if we were passed a package object and a worksheet name , get the worksheet. #if we were passed a package object and a worksheet name , get the worksheet.
if ($ExcelPackage) {$Worksheet = $ExcelPackage.Workbook.Worksheets[$Worksheetname] } if ($ExcelPackage) {
if ($ExcelPackage.Workbook.Worksheets.Name -notcontains $Worksheetname) {
throw "The Workbook does not contain a sheet named '$Worksheetname'"
}
else {$Worksheet = $ExcelPackage.Workbook.Worksheets[$Worksheetname] }
}
#In a script block to build a formula, we may want any of corners or the column name, #In a script block to build a formula, we may want any of corners or the column name,
#if Column and Startrow aren't specified, assume first unused column, and first row #if Column and Startrow aren't specified, assume first unused column, and first row
@@ -133,7 +148,7 @@
process { process {
if ($null -eq $workSheet.Dimension) {Write-Warning "Can't format an empty worksheet."; return} if ($null -eq $workSheet.Dimension) {Write-Warning "Can't format an empty worksheet."; return}
if ($Column -eq 0 ) {$Column = $endColumn + 1 } if ($Column -eq 0 ) {$Column = $endColumn + 1 }
$columnName = [OfficeOpenXml.ExcelCellAddress]::new(1,$column).Address -replace "1","" $columnName = (New-Object 'OfficeOpenXml.ExcelCellAddress' @(1, $column)).Address -replace "1",""
Write-Verbose -Message "Updating Column $columnName" Write-Verbose -Message "Updating Column $columnName"
#If there is a heading, insert it and use it as the name for a range (if we're creating one) #If there is a heading, insert it and use it as the name for a range (if we're creating one)
if ($PSBoundParameters.ContainsKey('Heading')) { if ($PSBoundParameters.ContainsKey('Heading')) {
@@ -151,10 +166,11 @@
if ($PSBoundParameters.ContainsKey('Value')) { foreach ($row in ($StartRow..$endRow)) { if ($PSBoundParameters.ContainsKey('Value')) { foreach ($row in ($StartRow..$endRow)) {
if ($Value -is [scriptblock]) { #re-create the script block otherwise variables from this function are out of scope. if ($Value -is [scriptblock]) { #re-create the script block otherwise variables from this function are out of scope.
$cellData = & ([scriptblock]::create( $Value )) $cellData = & ([scriptblock]::create( $Value ))
Write-Verbose -Message $cellData if ($null -eq $cellData) {Write-Verbose -Message "Script block evaluates to null."}
else {Write-Verbose -Message "Script block evaluates to '$cellData'"}
} }
else { $cellData = $Value} else { $cellData = $Value}
if ($cellData -match "^=") { $Worksheet.Cells[$Row, $Column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care if ($cellData -match "^=") { $Worksheet.Cells[$Row, $Column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care
elseif ( [System.Uri]::IsWellFormedUriString($cellData , [System.UriKind]::Absolute)) { elseif ( [System.Uri]::IsWellFormedUriString($cellData , [System.UriKind]::Absolute)) {
# Save a hyperlink : internal links can be in the form xl://sheet!E419 (use A1 as goto sheet), or xl://RangeName # Save a hyperlink : internal links can be in the form xl://sheet!E419 (use A1 as goto sheet), or xl://RangeName
if ($cellData -match "^xl://internal/") { if ($cellData -match "^xl://internal/") {
@@ -163,13 +179,13 @@
$h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display $h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
$Worksheet.Cells[$Row, $Column].HyperLink = $h $Worksheet.Cells[$Row, $Column].HyperLink = $h
} }
else {$Worksheet.Cells[$Row, $Column].HyperLink = $cellData } else {$Worksheet.Cells[$Row, $Column].HyperLink = $cellData }
$Worksheet.Cells[$Row, $Column].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
$Worksheet.Cells[$Row, $Column].Style.Font.UnderLine = $true $Worksheet.Cells[$Row, $Column].Style.Font.UnderLine = $true
$Worksheet.Cells[$Row, $Column].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
} }
else { $Worksheet.Cells[$Row, $Column].Value = $cellData } else { $Worksheet.Cells[$Row, $Column].Value = $cellData }
if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } # This is not a custom format, but a preset recognized as date and localized. if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } # This is not a custom format, but a preset recognized as date and localized.
if ($cellData -is [timespan]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = '[h]:mm:ss' } if ($cellData -is [timespan]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = '[h]:mm:ss' }
}} }}
#region Apply formatting #region Apply formatting

View File

@@ -13,7 +13,7 @@
Set-ExcelRow -Worksheet $ws -Heading Total -Value {"=sum($columnName`2:$columnName$endrow)" } Set-ExcelRow -Worksheet $ws -Heading Total -Value {"=sum($columnName`2:$columnName$endrow)" }
$Ws contains a worksheet object, and no Row number is specified so $Ws contains a worksheet object, and no Row number is specified so
Set-ExcelRow will select the next row after the endof the data in Set-ExcelRow will select the next row after the end of the data in
the sheet. The first cell in the row will contain "Total", and the sheet. The first cell in the row will contain "Total", and
each of the other cells will contain each of the other cells will contain
=Sum(xx2:xx99) =Sum(xx2:xx99)
@@ -33,6 +33,8 @@
[cmdletbinding()] [cmdletbinding()]
[Alias("Set-Row")] [Alias("Set-Row")]
[OutputType([OfficeOpenXml.ExcelRow],[String])] [OutputType([OfficeOpenXml.ExcelRow],[String])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system state')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification="Variables created for script block which may be passed as a parameter, but not used in the script")]
Param ( Param (
#An Excel package object - e.g. from Export-Excel -PassThru - requires a sheet name. #An Excel package object - e.g. from Export-Excel -PassThru - requires a sheet name.
[Parameter(ParameterSetName="Package",Mandatory=$true)] [Parameter(ParameterSetName="Package",Mandatory=$true)]
@@ -116,8 +118,12 @@
) )
begin { begin {
#if we were passed a package object and a worksheet name , get the worksheet. #if we were passed a package object and a worksheet name , get the worksheet.
if ($ExcelPackage) {$Worksheet = $ExcelPackage.Workbook.worksheets[$Worksheetname] } if ($ExcelPackage) {
if ($ExcelPackage.Workbook.Worksheets.Name -notcontains $Worksheetname) {
throw "The Workbook does not contain a sheet named '$Worksheetname'"
}
else {$Worksheet = $ExcelPackage.Workbook.Worksheets[$Worksheetname] }
}
#In a script block to build a formula, we may want any of corners or the columnname, #In a script block to build a formula, we may want any of corners or the columnname,
#if row and start column aren't specified assume first unused row, and first column #if row and start column aren't specified assume first unused row, and first column
if (-not $StartColumn) {$StartColumn = $Worksheet.Dimension.Start.Column } if (-not $StartColumn) {$StartColumn = $Worksheet.Dimension.Start.Column }
@@ -139,11 +145,12 @@
#Fill in the data #Fill in the data
if ($PSBoundParameters.ContainsKey('Value')) {foreach ($column in ($StartColumn..$endColumn)) { if ($PSBoundParameters.ContainsKey('Value')) {foreach ($column in ($StartColumn..$endColumn)) {
#We might want the column name in a script block #We might want the column name in a script block
$columnName = [OfficeOpenXml.ExcelCellAddress]::new(1,$column).Address -replace "1","" $columnName = (New-Object -TypeName OfficeOpenXml.ExcelCellAddress @(1,$column)).Address -replace "1",""
if ($Value -is [scriptblock] ) { if ($Value -is [scriptblock] ) {
#re-create the script block otherwise variables from this function are out of scope. #re-create the script block otherwise variables from this function are out of scope.
$cellData = & ([scriptblock]::create( $Value )) $cellData = & ([scriptblock]::create( $Value ))
Write-Verbose -Message $cellData if ($null -eq $cellData) {Write-Verbose -Message "Script block evaluates to null."}
else {Write-Verbose -Message "Script block evaluates to '$cellData'"}
} }
else{$cellData = $Value} else{$cellData = $Value}
if ($cellData -match "^=") { $Worksheet.Cells[$Row, $column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care if ($cellData -match "^=") { $Worksheet.Cells[$Row, $column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care
@@ -172,7 +179,7 @@
if ($PSBoundParameters.ContainsKey($p)) {$params[$p] = $PSBoundParameters[$p]} if ($PSBoundParameters.ContainsKey($p)) {$params[$p] = $PSBoundParameters[$p]}
} }
if ($params.Count) { if ($params.Count) {
$theRange = [OfficeOpenXml.ExcelAddress]::New($Row, $StartColumn, $Row, $endColumn) $theRange = New-Object -TypeName OfficeOpenXml.ExcelAddress @($Row, $StartColumn, $Row, $endColumn)
Set-ExcelRange -WorkSheet $Worksheet -Range $theRange @params Set-ExcelRange -WorkSheet $Worksheet -Range $theRange @params
} }
#endregion #endregion

View File

@@ -0,0 +1,84 @@
Function Set-WorkSheetProtection {
[Cmdletbinding()]
<#
.Synopsis
Sets protection on the worksheet
.Description
.Example
Set-WorkSheetProtection -WorkSheet $planSheet -IsProtected -AllowAll -AllowInsertColumns:$false -AllowDeleteColumns:$false -UnLockAddress "A:N"
Turns on protection for the worksheet in $planSheet, checks all the allow boxes except Insert and Delete columns and unlocks columns A-N
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system state')]
param (
#The worksheet where protection is to be applied.
[Parameter(Mandatory=$true)]
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
#Value of the "Protect Worksheet and Contents of locked cells" check box. Initially FALSE. use -IsProtected:$false to turn off it it has been switched on
[switch]$IsProtected,
#If provided sets all the ALLOW options to true or false and then allows them to be changed individually
[switch]$AllowAll,
#Opposite of the value in the 'Select locked cells' check box. Set to allow when Protect is first enabled
[switch]$BlockSelectLockedCells,
#Opposite of the value in the 'Select unlocked cells' check box. Set to allow when Protect is first enabled
[switch]$BlockSelectUnlockedCells,
#Value of the 'Format Cells' check box. Set to block when Protect is first enabled
[switch]$AllowFormatCells,
#Value of the 'Format Columns' check box. Set to block when Protect is first enabled
[switch]$AllowFormatColumns,
#Value of the 'Format Rows' check box. Set to block when Protect is first enabled
[switch]$AllowFormatRows,
#Value of the 'Insert Columns' check box. Set to block when Protect is first enabled
[switch]$AllowInsertColumns,
#Value of the 'Insert Columns' check box. Set to block when Protect is first enabled
[switch]$AllowInsertRows,
#Value of the 'Insert Hyperlinks' check box. Set to block when Protect is first enabled
[switch]$AllowInsertHyperlinks,
#Value of the 'Delete Columns' check box. Set to block when Protect is first enabled
[switch]$AllowDeleteColumns,
#Value of the 'Delete Rows' check box. Set to block when Protect is first enabled
[switch]$AllowDeleteRows,
#Value of the 'Sort' check box. Set to block when Protect is first enabled
[switch]$AllowSort,
#Value of the 'Use AutoFilter' check box. Set to block when Protect is first enabled
[switch]$AllowAutoFilter,
#Value of the 'Use PivotTable and PivotChart' check box. Set to block when Protect is first enabled
[switch]$AllowPivotTables,
##Opposite of the value in the 'Edit objects' check box. Set to allow when Protect is first enabled
[switch]$BlockEditObject,
##Opposite of the value in the 'Edit Scenarios' check box. Set to allow when Protect is first enabled
[switch]$BlockEditScenarios,
#Address range for cells to lock in the form "A:Z" or "1:10" or "A1:Z10". If No range is specified, the whole sheet is locked by default.
[string]$LockAddress,
#Address range for cells to Unlock in the form "A:Z" or "1:10" or "A1:Z10"
[string]$UnLockAddress
)
if ($PSBoundParameters.ContainsKey('isprotected') -and $IsProtected -eq $false) {$worksheet.Protection.IsProtected = $false}
elseif ($IsProtected) {
$worksheet.Protection.IsProtected = $true
foreach ($ParName in @('AllowFormatCells',
'AllowFormatColumns', 'AllowFormatRows',
'AllowInsertColumns', 'AllowInsertRows', 'AllowInsertHyperlinks',
'AllowDeleteColumns', 'AllowDeleteRows',
'AllowSort' , 'AllowAutoFilter', 'AllowPivotTables')) {
if ($AllowAll -and -not $PSBoundParameters.ContainsKey($Parname)) {$worksheet.Protection.$ParName = $true}
elseif ($PSBoundParameters[$ParName] -eq $true ) {$worksheet.Protection.$ParName = $true}
}
if ($BlockSelectLockedCells) {$worksheet.Protection.AllowSelectLockedCells = $false }
if ($BlockSelectUnlockedCells) {$worksheet.Protection.AllowSelectUnLockedCells = $false }
if ($BlockEditObject) {$worksheet.Protection.AllowEditObject = $false }
if ($BlockEditScenarios) {$worksheet.Protection.AllowEditScenarios = $false }
}
Else {Write-Warning -Message "You haven't said if you want to turn protection off, or on." }
if ($LockAddress) {
Set-ExcelRange -Range $WorkSheet.cells[$LockAddress] -Locked
}
elseif ($IsProtected) {
Set-ExcelRange -Range $WorkSheet.Cells -Locked
}
if ($UnlockAddress) {
Set-ExcelRange -Range $WorkSheet.cells[$UnlockAddress] -Locked:$false
}
}

View File

@@ -1,4 +1,4 @@
Function Set-ExcelRange { function Set-ExcelRange {
<# <#
.SYNOPSIS .SYNOPSIS
Applies number, font, alignment and/or color formatting, values or formulas to a range of Excel cells. Applies number, font, alignment and/or color formatting, values or formulas to a range of Excel cells.
@@ -32,6 +32,7 @@
#> #>
[cmdletbinding()] [cmdletbinding()]
[Alias("Set-Format")] [Alias("Set-Format")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system state')]
Param ( Param (
#One or more row(s), Column(s) and/or block(s) of cells to format. #One or more row(s), Column(s) and/or block(s) of cells to format.
[Parameter(ValueFromPipeline = $true,Position=0)] [Parameter(ValueFromPipeline = $true,Position=0)]
@@ -55,6 +56,7 @@
#Style for the right border. #Style for the right border.
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight, [OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight,
#Colour for the text - if none is specified it will be left as it is. #Colour for the text - if none is specified it will be left as it is.
[Alias('ForegroundColor')]
$FontColor, $FontColor,
#Value for the cell. #Value for the cell.
$Value, $Value,
@@ -104,11 +106,15 @@
#Set cells to a fixed height (rows or ranges only). #Set cells to a fixed height (rows or ranges only).
[float]$Height, [float]$Height,
#Hide a row or column (not a range); use -Hidden:$false to unhide. #Hide a row or column (not a range); use -Hidden:$false to unhide.
[Switch]$Hidden [Switch]$Hidden,
#Locks cells. Cells are locked by default use -locked:$false on the whole sheet and then lock specific ones, and enable protection on the sheet.
[Switch]$Locked,
#Merges cells - it is recommended that you explicitly set -HorizontalAlignment
[Switch]$Merge
) )
process { process {
if ($Range -is [Array]) { if ($Range -is [Array]) {
[void]$PSBoundParameters.Remove("Range") $null = $PSBoundParameters.Remove("Range")
$Range | Set-ExcelRange @PSBoundParameters $Range | Set-ExcelRange @PSBoundParameters
} }
else { else {
@@ -117,8 +123,11 @@
elseif ($WorkSheet -and ($Range -is [string] -or $Range -is [OfficeOpenXml.ExcelAddress])) { elseif ($WorkSheet -and ($Range -is [string] -or $Range -is [OfficeOpenXml.ExcelAddress])) {
$Range = $WorkSheet.Cells[$Range] $Range = $WorkSheet.Cells[$Range]
} }
elseif ($Range -is [string]) {Write-Warning -Message "The range pararameter you have specified also needs a worksheet parameter."} elseif ($Range -is [string]) {Write-Warning -Message "The range pararameter you have specified also needs a worksheet parameter." ;return}
#else we assume $Range is a range.
if ($ClearAll) {
$Range.Clear()
}
if ($ResetFont) { if ($ResetFont) {
$Range.Style.Font.Color.SetColor( ([System.Drawing.Color]::Black)) $Range.Style.Font.Color.SetColor( ([System.Drawing.Color]::Black))
$Range.Style.Font.Bold = $false $Range.Style.Font.Bold = $false
@@ -165,6 +174,9 @@
if ($PSBoundParameters.ContainsKey('VerticalAlignment')) { if ($PSBoundParameters.ContainsKey('VerticalAlignment')) {
$Range.Style.VerticalAlignment = $VerticalAlignment $Range.Style.VerticalAlignment = $VerticalAlignment
} }
if ($PSBoundParameters.ContainsKey('Merge')) {
$Range.Merge = [boolean]$Merge
}
if ($PSBoundParameters.ContainsKey('Value')) { if ($PSBoundParameters.ContainsKey('Value')) {
if ($Value -match '^=') {$PSBoundParameters["Formula"] = $Value -replace '^=','' } if ($Value -match '^=') {$PSBoundParameters["Formula"] = $Value -replace '^=','' }
else { else {
@@ -217,14 +229,18 @@
} }
else {Write-Warning -Message ("Can set the height of a row or a range but not a {0} object" -f ($Range.GetType().name)) } else {Write-Warning -Message ("Can set the height of a row or a range but not a {0} object" -f ($Range.GetType().name)) }
} }
if ($Autosize) { if ($Autosize -and -not $env:NoAutoSize) {
if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.AutoFit() } try {
elseif ($Range -is [OfficeOpenXml.ExcelRange] ) { if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.AutoFit() }
$Range.AutoFitColumns() elseif ($Range -is [OfficeOpenXml.ExcelRange] ) {
} $Range.AutoFitColumns()
else {Write-Warning -Message ("Can autofit a column or a range but not a {0} object" -f ($Range.GetType().name)) }
}
else {Write-Warning -Message ("Can autofit a column or a range but not a {0} object" -f ($Range.GetType().name)) }
}
catch {Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_"}
} }
elseif ($AutoSize) {Write-Warning -Message "Auto-fitting columns is not available with this OS configuration." }
elseif ($PSBoundParameters.ContainsKey('Width')) { elseif ($PSBoundParameters.ContainsKey('Width')) {
if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.Width = $Width} if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.Width = $Width}
elseif ($Range -is [OfficeOpenXml.ExcelRange] ) { elseif ($Range -is [OfficeOpenXml.ExcelRange] ) {
@@ -241,11 +257,14 @@
$Range -is [OfficeOpenXml.ExcelColumn] ) {$Range.Hidden = [boolean]$Hidden} $Range -is [OfficeOpenXml.ExcelColumn] ) {$Range.Hidden = [boolean]$Hidden}
else {Write-Warning -Message ("Can hide a row or a column but not a {0} object" -f ($Range.GetType().name)) } else {Write-Warning -Message ("Can hide a row or a column but not a {0} object" -f ($Range.GetType().name)) }
} }
if ($PSBoundParameters.ContainsKey('Locked')) {
$Range.Style.Locked=$Locked
}
} }
} }
} }
Function NumberFormatCompletion { function NumberFormatCompletion {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
$numformats = [ordered]@{ $numformats = [ordered]@{
"General" = "General" # format ID 0 "General" = "General" # format ID 0
@@ -288,6 +307,7 @@ Function NumberFormatCompletion {
if (Get-Command -ErrorAction SilentlyContinue -name Register-ArgumentCompleter) { if (Get-Command -ErrorAction SilentlyContinue -name Register-ArgumentCompleter) {
Register-ArgumentCompleter -CommandName Add-ConditionalFormatting -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion Register-ArgumentCompleter -CommandName Add-ConditionalFormatting -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion
Register-ArgumentCompleter -CommandName Export-Excel -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion Register-ArgumentCompleter -CommandName Export-Excel -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion
Register-ArgumentCompleter -CommandName New-ExcelStyle -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion
Register-ArgumentCompleter -CommandName Set-ExcelColumn -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion Register-ArgumentCompleter -CommandName Set-ExcelColumn -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion
Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName NumberFormat -ScriptBlock $Function:NumberFormatCompletion
@@ -299,7 +319,28 @@ if (Get-Command -ErrorAction SilentlyContinue -name Register-ArgumentCompleter)
Register-ArgumentCompleter -CommandName Add-ExcelChart -ParameterName YAxisNumberformat -ScriptBlock $Function:NumberFormatCompletion Register-ArgumentCompleter -CommandName Add-ExcelChart -ParameterName YAxisNumberformat -ScriptBlock $Function:NumberFormatCompletion
} }
Function Expand-NumberFormat { function ListFonts {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
if (-not $script:FontFamilies) {
$script:FontFamilies = @("","")
try {
$script:FontFamilies = (New-Object System.Drawing.Text.InstalledFontCollection).Families.Name
}
catch {}
}
$script:FontFamilies.where({$_ -Gt "" -and $_ -like "$wordToComplete*"} ) | ForEach-Object {
New-Object -TypeName System.Management.Automation.CompletionResult -ArgumentList "'$_'" , $_ ,
([System.Management.Automation.CompletionResultType]::ParameterValue) , $_
}
}
if (Get-Command -ErrorAction SilentlyContinue -name Register-ArgumentCompleter) {
Register-ArgumentCompleter -CommandName New-ExcelStyle -ParameterName FontName -ScriptBlock $Function:ListFonts
Register-ArgumentCompleter -CommandName Set-ExcelColumn -ParameterName FontName -ScriptBlock $Function:ListFonts
Register-ArgumentCompleter -CommandName Set-ExcelRange -ParameterName FontName -ScriptBlock $Function:ListFonts
Register-ArgumentCompleter -CommandName Set-ExcelRow -ParameterName FontName -ScriptBlock $Function:ListFonts
}
function Expand-NumberFormat {
<# <#
.SYNOPSIS .SYNOPSIS
Converts short names for number formats to the formatting strings used in Excel Converts short names for number formats to the formatting strings used in Excel
@@ -375,3 +416,81 @@ Function Expand-NumberFormat {
Default {return $NumberFormat} Default {return $NumberFormat}
} }
} }
function New-ExcelStyle {
param (
[Alias("Address")]
$Range ,
#Number format to apply to cells e.g. "dd/MM/yyyy HH:mm", "£#,##0.00;[Red]-£#,##0.00", "0.00%" , "##/##" , "0.0E+0" etc.
[Alias("NFormat")]
$NumberFormat,
#Style of border to draw around the range.
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround,
#Color of the border.
$BorderColor=[System.Drawing.Color]::Black,
#Style for the bottom border.
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderBottom,
#Style for the top border.
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderTop,
#Style for the left border.
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderLeft,
#Style for the right border.
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight,
#Colour for the text - if none is specified it will be left as it is.
[Alias('ForegroundColor')]
$FontColor,
#Value for the cell.
$Value,
#Formula for the cell.
$Formula,
#Specifies formula should be an array formula (a.k.a CSE [ctrl-shift-enter] formula).
[Switch]$ArrayFormula,
#Clear Bold, Italic, StrikeThrough and Underline and set color to Black.
[Switch]$ResetFont,
#Make text bold; use -Bold:$false to remove bold.
[Switch]$Bold,
#Make text italic; use -Italic:$false to remove italic.
[Switch]$Italic,
#Underline the text using the underline style in -UnderlineType; use -Underline:$false to remove underlining.
[Switch]$Underline,
#Specifies whether underlining should be single or double, normal or accounting mode. The default is "Single".
[OfficeOpenXml.Style.ExcelUnderLineType]$UnderLineType = [OfficeOpenXml.Style.ExcelUnderLineType]::Single,
#Strike through text; use -Strikethru:$false to remove Strike through
[Switch]$StrikeThru,
#Subscript or Superscript (or none).
[OfficeOpenXml.Style.ExcelVerticalAlignmentFont]$FontShift,
#Font to use - Excel defaults to Calibri.
[String]$FontName,
#Point size for the text.
[float]$FontSize,
#Change background color.
$BackgroundColor,
#Background pattern - Solid by default.
[OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid ,
#Secondary color for background pattern.
[Alias("PatternColour")]
$PatternColor,
#Turn on Text-Wrapping; use -WrapText:$false to turn off wrapping.
[Switch]$WrapText,
#Position cell contents to Left, Right, Center etc. default is 'General'.
[OfficeOpenXml.Style.ExcelHorizontalAlignment]$HorizontalAlignment,
#Position cell contents to Top, Bottom or Center.
[OfficeOpenXml.Style.ExcelVerticalAlignment]$VerticalAlignment,
#Degrees to rotate text. Up to +90 for anti-clockwise ("upwards"), or to -90 for clockwise.
[ValidateRange(-90, 90)]
[int]$TextRotation ,
#Autofit cells to width (columns or ranges only).
[Alias("AutoFit")]
[Switch]$AutoSize,
#Set cells to a fixed width (columns or ranges only), ignored if Autosize is specified.
[float]$Width,
#Set cells to a fixed height (rows or ranges only).
[float]$Height,
#Hide a row or column (not a range); use -Hidden:$false to unhide.
[Switch]$Hidden,
#Locks cells. Cells are locked by default use -locked:$false on the whole sheet and then lock specific ones, and enable protection on the sheet.
[Switch]$Locked,
[Switch]$Merge
)
$PSBoundParameters
}

View File

@@ -1,6 +1,11 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function', Target='Update*', Justification='Does not change system state')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Scope='Function', Target='Update*', Justification='Property would be incorrect')]
param()
Function Update-FirstObjectProperties { Function Update-FirstObjectProperties {
<# <#
.SYNOPSIS .SYNOPSIS
Updates the first object to contain all the properties of the object with the most properties in the array. Updates the first object to contain all the properties of the object with the most properties in the array.
.DESCRIPTION .DESCRIPTION
@@ -30,7 +35,7 @@ Function Update-FirstObjectProperties {
$Array = $Obj1, $Obj2, $Obj3 $Array = $Obj1, $Obj2, $Obj3
$Array | Out-GridView -Title 'Not showing Member3 and Member4' $Array | Out-GridView -Title 'Not showing Member3 and Member4'
$Array | Update-FirstObjectProperties | Out-GridView -Title 'All properties are visible' $Array | Update-FirstObjectProperties | Out-GridView -Title 'All properties are visible'
Updates the fist object of the array by adding Member3 and Member4. Updates the fist object of the array by adding Member3 and Member4.
.EXAMPLE .EXAMPLE
@@ -79,7 +84,7 @@ Function Update-FirstObjectProperties {
$Union = @() $Union = @()
$Input | ForEach-Object { $Input | ForEach-Object {
If ($Union.Count) { If ($Union.Count) {
$_ | Get-Member | Where {-not ($Union[0] | Get-Member $_.Name)} | ForEach-Object { $_ | Get-Member | Where-Object {-not ($Union[0] | Get-Member $_.Name)} | ForEach-Object {
$Union[0] | Add-Member -MemberType NoteProperty -Name $_.Name -Value $Null $Union[0] | Add-Member -MemberType NoteProperty -Name $_.Name -Value $Null
} }
} }

View File

@@ -0,0 +1,52 @@
if (-not (get-command Import-Excel -ErrorAction SilentlyContinue)) {
Import-Module $PSScriptRoot\..\ImportExcel.psd1
}
Describe "Test adding trendlines to charts" {
BeforeAll {
$script:data = ConvertFrom-Csv @"
Region,Item,TotalSold
West,screws,60
South,lemon,48
South,apple,71
East,screwdriver,70
East,kiwi,32
West,screwdriver,1
South,melon,21
East,apple,79
South,apple,68
South,avocado,73
"@
}
BeforeEach {
$xlfile = "TestDrive:\trendLine.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
}
It "Should add a linear trendline".PadRight(90) {
$cd = New-ExcelChartDefinition -XRange Region -YRange TotalSold -ChartType ColumnClustered -ChartTrendLine Linear
$data | Export-Excel $xlfile -ExcelChartDefinition $cd -AutoNameRange
$excel = Open-ExcelPackage -Path $xlfile
$ws = $excel.Workbook.Worksheets["Sheet1"]
$ws.Drawings[0].Series.TrendLines.Type | Should Be 'Linear'
Close-ExcelPackage $excel
}
It "Should add a MovingAvgerage trendline".PadRight(90) {
$cd = New-ExcelChartDefinition -XRange Region -YRange TotalSold -ChartType ColumnClustered -ChartTrendLine MovingAvgerage
$data | Export-Excel $xlfile -ExcelChartDefinition $cd -AutoNameRange
$excel = Open-ExcelPackage -Path $xlfile
$ws = $excel.Workbook.Worksheets["Sheet1"]
$ws.Drawings[0].Series.TrendLines.Type | Should Be 'MovingAvgerage'
Close-ExcelPackage $excel
}
}

142
__tests__/CI.ps1 Normal file
View File

@@ -0,0 +1,142 @@
<#
.SYNOPSIS
Handel Continuous Integration Testing in AppVeyor and Azure DevOps Pipelines.
#>
param
(
# AppVeyor Only - Update AppVeyor build name.
[Switch]$Initialize,
# Installs the module and invoke the Pester tests with the current version of PowerShell.
[Switch]$Test,
# AppVeyor Only - Upload results to AppVeyor "Tests" tab.
[Switch]$Finalize,
# AppVeyor and Azure - Upload module as AppVeyor Artifact.
[Switch]$Artifact
)
$ErrorActionPreference = 'Stop'
if ($Initialize) {
$Psd1 = (Get-ChildItem -File -Filter *.psd1 -Name -Path (Split-Path $PSScriptRoot)).PSPath
$ModuleVersion = (. ([Scriptblock]::Create((Get-Content -Path $Psd1 | Out-String)))).ModuleVersion
Update-AppveyorBuild -Version "$ModuleVersion ($env:APPVEYOR_BUILD_NUMBER) $env:APPVEYOR_REPO_BRANCH"
}
if ($Test) {
function Get-EnvironmentInfo {
if ([environment]::OSVersion.Platform -like "win*") {
# Get Windows Version
try {
$WinRelease, $WinVer = Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" ReleaseId, CurrentMajorVersionNumber, CurrentMinorVersionNumber, CurrentBuildNumber, UBR
$WindowsVersion = "$($WinVer -join '.') ($WinRelease)"
}
catch {
$WindowsVersion = [System.Environment]::OSVersion.Version
}
#TODO FIXME BUG this gets the latest version of the .NET Framework on the machine (ok for powershell.exe), not the version of .NET CORE in use by PWSH.EXE
<#
$VersionFilePath = (Get-Process -Id $PID | Select-Object -ExpandProperty Modules |
Where-Object -Property modulename -eq "clrjit.dll").FileName
if (-not $VersionFilePath) {
$VersionFilePath = [System.Reflection.Assembly]::LoadWithPartialName("System.Core").location
}
(Get-ItemProperty -Path $VersionFilePath).VersionInfo |
Select-Object -Property @{n="Version"; e={$_.ProductName + " " + $_.FileVersion}}, ProductName, FileVersionRaw, FileName
#>
# Get .Net Version
# https://stackoverflow.com/questions/3487265/powershell-script-to-return-versions-of-net-framework-on-a-machine
$Lookup = @{
378389 = [version]'4.5'
378675 = [version]'4.5.1'
378758 = [version]'4.5.1'
379893 = [version]'4.5.2'
393295 = [version]'4.6'
393297 = [version]'4.6'
394254 = [version]'4.6.1'
394271 = [version]'4.6.1'
394802 = [version]'4.6.2'
394806 = [version]'4.6.2'
460798 = [version]'4.7'
460805 = [version]'4.7'
461308 = [version]'4.7.1'
461310 = [version]'4.7.1'
461808 = [version]'4.7.2'
461814 = [version]'4.7.2'
528040 = [version]'4.8'
528049 = [version]'4.8'
}
# For One True framework (latest .NET 4x), change the Where-Object match
# to PSChildName -eq "Full":
$DotNetVersion = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
Get-ItemProperty -name Version, Release -EA 0 |
Where-Object { $_.PSChildName -eq "Full" } |
Select-Object @{name = ".NET Framework"; expression = { $_.PSChildName } },
@{name = "Product"; expression = { $Lookup[$_.Release] } },
Version, Release
# Output
[PSCustomObject]($PSVersionTable + @{
ComputerName = $env:Computername
WindowsVersion = $WindowsVersion
'.Net Version' = '{0} (Version: {1}, Release: {2})' -f $DotNetVersion.Product, $DotNetVersion.Version, $DotNetVersion.Release
#EnvironmentPath = $env:Path
})
}
else {
# Output
[PSCustomObject]($PSVersionTable + @{
ComputerName = $env:Computername
#EnvironmentPath = $env:Path
})
}
}
'[Info] Testing On:'
Get-EnvironmentInfo
'[Progress] Installing Module.'
. .\Install.ps1
'[Progress] Invoking Pester.'
Invoke-Pester -OutputFile ('TestResultsPS{0}.xml' -f $PSVersionTable.PSVersion)
}
if ($Finalize) {
'[Progress] Finalizing.'
$Failure = $false
$AppVeyorResultsUri = 'https://ci.appveyor.com/api/testresults/nunit/{0}' -f $env:APPVEYOR_JOB_ID
foreach ($TestResultsFile in Get-ChildItem -Path 'TestResultsPS*.xml') {
$TestResultsFilePath = $TestResultsFile.FullName
"[Info] Uploading Files: $AppVeyorResultsUri, $TestResultsFilePath."
# Add PowerShell version to test results
$PSVersion = $TestResultsFile.Name.Replace('TestResults', '').Replace('.xml', '')
[Xml]$Xml = Get-Content -Path $TestResultsFilePath
Select-Xml -Xml $Xml -XPath '//test-case' | ForEach-Object { $_.Node.name = "$PSVersion " + $_.Node.name }
$Xml.OuterXml | Out-File -FilePath $TestResultsFilePath
#Invoke-RestMethod -Method Post -Uri $AppVeyorResultsUri -Body $Xml
[Net.WebClient]::new().UploadFile($AppVeyorResultsUri, $TestResultsFilePath)
if ($Xml.'test-results'.failures -ne '0') {
$Failure = $true
}
}
if ($Failure) {
throw 'Tests failed.'
}
}
if ($Artifact) {
# Get Module Info
$ModuleName = [System.IO.Path]::GetFileNameWithoutExtension((Get-ChildItem -File -Filter *.psm1 -Name -Path (Split-Path $PSScriptRoot)))
$ModulePath = (Get-Module -Name $ModuleName -ListAvailable).ModuleBase | Split-Path
$VersionLocal = ((Get-Module -Name $ModuleName -ListAvailable).Version | Measure-Object -Maximum).Maximum
"[Progress] Artifact Start for Module: $ModuleName, Version: $VersionLocal."
if ($env:APPVEYOR) {
$ZipFileName = "{0} {1} {2} {3:yyyy-MM-dd HH-mm-ss}.zip" -f $ModuleName, $VersionLocal, $env:APPVEYOR_REPO_BRANCH, (Get-Date)
$ZipFileFullPath = Join-Path -Path $PSScriptRoot -ChildPath $ZipFileName
"[Info] Artifact. $ModuleName, ZipFileName: $ZipFileName."
#Compress-Archive -Path $ModulePath -DestinationPath $ZipFileFullPath
[System.IO.Compression.ZipFile]::CreateFromDirectory($ModulePath, $ZipFileFullPath, [System.IO.Compression.CompressionLevel]::Optimal, $true)
Push-AppveyorArtifact $ZipFileFullPath -DeploymentName $ModuleName
}
elseif ($env:AGENT_NAME) {
#Write-Host "##vso[task.setvariable variable=ModuleName]$ModuleName"
Copy-Item -Path $ModulePath -Destination $env:Build_ArtifactStagingDirectory -Recurse
}
}

View File

@@ -1,26 +1,33 @@
#Requires -Modules Pester #Requires -Modules Pester
Import-Module $PSScriptRoot\..\ImportExcel.psd1 -Force if (-not (get-command Import-Excel -ErrorAction SilentlyContinue)) {
if ($PSVersionTable.PSVersion.Major -gt 5) { Write-Warning "Can't test grid view on V6" } Import-Module $PSScriptRoot\..\ImportExcel.psd1
else {Add-Type -AssemblyName System.Windows.Forms } }
Describe "Compare Worksheet" { Describe "Compare Worksheet" {
Context "Simple comparison output" { BeforeAll {
BeforeAll { if ($PSVersionTable.PSVersion.Major -gt 5) {
Remove-Item -Path "$env:temp\server*.xlsx" It "GridView Support" {
[System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property Name, RequiredServices, CanPauseAndContinue, CanShutdown, CanStop, DisplayName, DependentServices, MachineName Set-ItResult -Pending -Because "Can't test grid view on V6 and later"
$s | Export-Excel -Path $env:temp\server1.xlsx }
#$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s
$row4Displayname = $s[2].DisplayName
$s[2].DisplayName = "Changed from the orginal"
$d = $s[-1] | Select-Object -Property *
$d.DisplayName = "Dummy Service"
$d.Name = "Dummy"
$s.Insert(3,$d)
$row6Name = $s[5].name
$s.RemoveAt(5)
$s | Export-Excel -Path $env:temp\server2.xlsx
#Assume default worksheet name, (sheet1) and column header for key ("name")
$comp = compare-WorkSheet "$env:temp\Server1.xlsx" "$env:temp\Server2.xlsx" | Sort-Object -Property _row, _file
} }
else { Add-Type -AssemblyName System.Windows.Forms }
. "$PSScriptRoot\Samples\Samples.ps1"
Remove-Item -Path "TestDrive:\server*.xlsx"
[System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property Name, RequiredServices, CanPauseAndContinue, CanShutdown, CanStop, DisplayName, DependentServices, MachineName
$s | Export-Excel -Path TestDrive:\server1.xlsx
#$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s
$row4Displayname = $s[2].DisplayName
$s[2].DisplayName = "Changed from the orginal"
$d = $s[-1] | Select-Object -Property *
$d.DisplayName = "Dummy Service"
$d.Name = "Dummy"
$s.Insert(3,$d)
$row6Name = $s[5].name
$s.RemoveAt(5)
$s | Export-Excel -Path TestDrive:\server2.xlsx
#Assume default worksheet name, (sheet1) and column header for key ("name")
$comp = compare-WorkSheet "TestDrive:\server1.xlsx" "TestDrive:\server2.xlsx" | Sort-Object -Property _row, _file
}
Context "Simple comparison output" {
it "Found the right number of differences " { it "Found the right number of differences " {
$comp | should not beNullOrEmpty $comp | should not beNullOrEmpty
$comp.Count | should be 4 $comp.Count | should be 4
@@ -48,13 +55,11 @@ Describe "Compare Worksheet" {
} }
} }
Context "Setting the background to highlight different rows, use of grid view." { Context "Setting the background to highlight different rows" {
BeforeAll { BeforeAll {
$useGrid = ($PSVersionTable.PSVersion.Major -LE 5) $null = Compare-WorkSheet "TestDrive:\server1.xlsx" "TestDrive:\server2.xlsx" -BackgroundColor ([System.Drawing.Color]::LightGreen)
$null = Compare-WorkSheet "$env:temp\Server1.xlsx" "$env:temp\Server2.xlsx" -BackgroundColor ([System.Drawing.Color]::LightGreen) -GridView:$useGrid $xl1 = Open-ExcelPackage -Path "TestDrive:\server1.xlsx"
if ($useGrid) {Start-Sleep -sec 5; [System.Windows.Forms.SendKeys]::Sendwait("%{F4}") } $xl2 = Open-ExcelPackage -Path "TestDrive:\server2.xlsx"
$xl1 = Open-ExcelPackage -Path "$env:temp\Server1.xlsx"
$xl2 = Open-ExcelPackage -Path "$env:temp\Server2.xlsx"
$s1Sheet = $xl1.Workbook.Worksheets[1] $s1Sheet = $xl1.Workbook.Worksheets[1]
$s2Sheet = $xl2.Workbook.Worksheets[1] $s2Sheet = $xl2.Workbook.Worksheets[1]
} }
@@ -78,9 +83,9 @@ Describe "Compare Worksheet" {
Context "Setting the forgound to highlight changed properties" { Context "Setting the forgound to highlight changed properties" {
BeforeAll { BeforeAll {
$null = compare-WorkSheet "$env:temp\Server1.xlsx" "$env:temp\Server2.xlsx" -AllDataBackgroundColor([System.Drawing.Color]::white) -BackgroundColor ([System.Drawing.Color]::LightGreen) -FontColor ([System.Drawing.Color]::DarkRed) $null = compare-WorkSheet "TestDrive:\server1.xlsx" "TestDrive:\server2.xlsx" -AllDataBackgroundColor([System.Drawing.Color]::white) -BackgroundColor ([System.Drawing.Color]::LightGreen) -FontColor ([System.Drawing.Color]::DarkRed)
$xl1 = Open-ExcelPackage -Path "$env:temp\Server1.xlsx" $xl1 = Open-ExcelPackage -Path "TestDrive:\server1.xlsx"
$xl2 = Open-ExcelPackage -Path "$env:temp\Server2.xlsx" $xl2 = Open-ExcelPackage -Path "TestDrive:\server2.xlsx"
$s1Sheet = $xl1.Workbook.Worksheets[1] $s1Sheet = $xl1.Workbook.Worksheets[1]
$s2Sheet = $xl2.Workbook.Worksheets[1] $s2Sheet = $xl2.Workbook.Worksheets[1]
} }
@@ -107,9 +112,9 @@ Describe "Compare Worksheet" {
Context "More complex comparison: output check and different worksheet names " { Context "More complex comparison: output check and different worksheet names " {
BeforeAll { BeforeAll {
[System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property RequiredServices, CanPauseAndContinue, CanShutdown, CanStop, [System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property RequiredServices, CanPauseAndContinue, CanShutdown, CanStop,
DisplayName, DependentServices, MachineName, ServiceName, ServicesDependedOn, ServiceHandle, Status, ServiceType, StartType -ExcludeProperty Name DisplayName, DependentServices, MachineName, ServiceName, ServicesDependedOn, ServiceHandle, Status, ServiceType, StartType -ExcludeProperty Name
$s | Export-Excel -Path $env:temp\server1.xlsx -WorkSheetname Server1 $s | Export-Excel -Path TestDrive:\server1.xlsx -WorkSheetname server1
#$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s #$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s
$row4Displayname = $s[2].DisplayName $row4Displayname = $s[2].DisplayName
$s[2].DisplayName = "Changed from the orginal" $s[2].DisplayName = "Changed from the orginal"
@@ -121,11 +126,11 @@ Describe "Compare Worksheet" {
$s.RemoveAt(5) $s.RemoveAt(5)
$s[10].ServiceType = "Changed should not matter" $s[10].ServiceType = "Changed should not matter"
$s | Select-Object -Property ServiceName, DisplayName, StartType, ServiceType | Export-Excel -Path $env:temp\server2.xlsx -WorkSheetname server2 $s | Select-Object -Property ServiceName, DisplayName, StartType, ServiceType | Export-Excel -Path TestDrive:\server2.xlsx -WorkSheetname server2
#Assume default worksheet name, (sheet1) and column header for key ("name") #Assume default worksheet name, (sheet1) and column header for key ("name")
$comp = compare-WorkSheet "$env:temp\Server1.xlsx" "$env:temp\Server2.xlsx" -WorkSheetName Server1,Server2 -Key ServiceName -Property DisplayName,StartType -AllDataBackgroundColor ([System.Drawing.Color]::AliceBlue) -BackgroundColor ([System.Drawing.Color]::White) -FontColor ([System.Drawing.Color]::Red) | Sort-Object _row,_file $comp = compare-WorkSheet "TestDrive:\server1.xlsx" "TestDrive:\server2.xlsx" -WorkSheetName server1,server2 -Key ServiceName -Property DisplayName,StartType -AllDataBackgroundColor ([System.Drawing.Color]::AliceBlue) -BackgroundColor ([System.Drawing.Color]::White) -FontColor ([System.Drawing.Color]::Red) | Sort-Object _row,_file
$xl1 = Open-ExcelPackage -Path "$env:temp\Server1.xlsx" $xl1 = Open-ExcelPackage -Path "TestDrive:\server1.xlsx"
$xl2 = Open-ExcelPackage -Path "$env:temp\Server2.xlsx" $xl2 = Open-ExcelPackage -Path "TestDrive:\server2.xlsx"
$s1Sheet = $xl1.Workbook.Worksheets["server1"] $s1Sheet = $xl1.Workbook.Worksheets["server1"]
$s2Sheet = $xl2.Workbook.Worksheets["server2"] $s2Sheet = $xl2.Workbook.Worksheets["server2"]
} }
@@ -179,36 +184,36 @@ Describe "Compare Worksheet" {
} }
Describe "Merge Worksheet" { Describe "Merge Worksheet" {
BeforeAll {
Remove-Item -Path "TestDrive:\server*.xlsx" , "TestDrive:\combined*.xlsx" -ErrorAction SilentlyContinue
[System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property *
$s | Export-Excel -Path TestDrive:\server1.xlsx
#$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s
$s[2].DisplayName = "Changed from the orginal"
$d = $s[-1] | Select-Object -Property *
$d.DisplayName = "Dummy Service"
$d.Name = "Dummy"
$s.Insert(3,$d)
$s.RemoveAt(5)
$s | Export-Excel -Path TestDrive:\server2.xlsx
#Assume default worksheet name, (sheet1) and column header for key ("name")
Merge-Worksheet -Referencefile "TestDrive:\server1.xlsx" -Differencefile "TestDrive:\server2.xlsx" -OutputFile "TestDrive:\combined1.xlsx" -Property name,displayname,startType -Key name
$excel = Open-ExcelPackage -Path "TestDrive:\combined1.xlsx"
$ws = $excel.Workbook.Worksheets["sheet1"]
}
Context "Merge with 3 properties" { Context "Merge with 3 properties" {
BeforeAll {
Remove-Item -Path "$env:temp\server*.xlsx" , "$env:temp\Combined*.xlsx" -ErrorAction SilentlyContinue
[System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property *
$s | Export-Excel -Path $env:temp\server1.xlsx
#$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s
$s[2].DisplayName = "Changed from the orginal"
$d = $s[-1] | Select-Object -Property *
$d.DisplayName = "Dummy Service"
$d.Name = "Dummy"
$s.Insert(3,$d)
$s.RemoveAt(5)
$s | Export-Excel -Path $env:temp\server2.xlsx
#Assume default worksheet name, (sheet1) and column header for key ("name")
Merge-Worksheet -Referencefile "$env:temp\server1.xlsx" -Differencefile "$env:temp\Server2.xlsx" -OutputFile "$env:temp\combined1.xlsx" -Property name,displayname,startType -Key name
$excel = Open-ExcelPackage -Path "$env:temp\combined1.xlsx"
$ws = $excel.Workbook.Worksheets["sheet1"]
}
it "Created a worksheet with the correct headings " { it "Created a worksheet with the correct headings " {
$ws | should not beNullOrEmpty $ws | should not beNullOrEmpty
$ws.Cells[ 1,1].Value | Should be "name" $ws.Cells[ 1,1].Value | Should be "name"
$ws.Cells[ 1,2].Value | Should be "DisplayName" $ws.Cells[ 1,2].Value | Should be "DisplayName"
$ws.Cells[ 1,3].Value | Should be "StartType" $ws.Cells[ 1,3].Value | Should be "StartType"
$ws.Cells[ 1,4].Value | Should be "Server2 DisplayName" $ws.Cells[ 1,4].Value | Should be "server2 DisplayName"
$ws.Cells[ 1,5].Value | Should be "Server2 StartType" $ws.Cells[ 1,5].Value | Should be "server2 StartType"
} }
it "Joined the two sheets correctly " { it "Joined the two sheets correctly " {
$ws.Cells[ 2,2].Value | Should be $ws.Cells[ 2,4].Value $ws.Cells[ 2,2].Value | Should be $ws.Cells[ 2,4].Value
@@ -240,16 +245,16 @@ Describe "Merge Worksheet" {
} }
Context "Wider data set" { Context "Wider data set" {
it "Coped with columns beyond Z in the Output sheet " { it "Coped with columns beyond Z in the Output sheet " {
{ Merge-Worksheet -Referencefile "$env:temp\server1.xlsx" -Differencefile "$env:temp\Server2.xlsx" -OutputFile "$env:temp\combined2.xlsx" } | Should not throw { Merge-Worksheet -Referencefile "TestDrive:\server1.xlsx" -Differencefile "TestDrive:\server2.xlsx" -OutputFile "TestDrive:\combined2.xlsx" } | Should not throw
} }
} }
} }
Describe "Merge Multiple sheets" { Describe "Merge Multiple sheets" {
Context "Merge 3 sheets with 3 properties" { Context "Merge 3 sheets with 3 properties" {
BeforeAll { BeforeAll {
Remove-Item -Path "$env:temp\server*.xlsx" , "$env:temp\Combined*.xlsx" -ErrorAction SilentlyContinue Remove-Item -Path "TestDrive:\server*.xlsx" , "TestDrive:\combined*.xlsx" -ErrorAction SilentlyContinue
[System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property Name,DisplayName,StartType [System.Collections.ArrayList]$s = get-service | Select-Object -first 25 -Property Name,DisplayName,StartType
$s | Export-Excel -Path $env:temp\server1.xlsx $s | Export-Excel -Path TestDrive:\server1.xlsx
#$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s #$s is a zero based array, excel rows are 1 based and excel has a header row so Excel rows will be 2 + index in $s
$row4Displayname = $s[2].DisplayName $row4Displayname = $s[2].DisplayName
@@ -262,7 +267,7 @@ Describe "Merge Multiple sheets" {
$s.RemoveAt(5) $s.RemoveAt(5)
$s | Export-Excel -Path $env:temp\server2.xlsx $s | Export-Excel -Path TestDrive:\server2.xlsx
$s[2].displayname = $row4Displayname $s[2].displayname = $row4Displayname
@@ -272,26 +277,26 @@ Describe "Merge Multiple sheets" {
$s.Insert(6,$d) $s.Insert(6,$d)
$s.RemoveAt(8) $s.RemoveAt(8)
$s | Export-Excel -Path $env:temp\server3.xlsx $s | Export-Excel -Path TestDrive:\server3.xlsx
Merge-MultipleSheets -Path "$env:temp\server1.xlsx", "$env:temp\Server2.xlsx","$env:temp\Server3.xlsx" -OutputFile "$env:temp\combined3.xlsx" -Property name,displayname,startType -Key name Merge-MultipleSheets -Path "TestDrive:\server1.xlsx", "TestDrive:\server2.xlsx","TestDrive:\server3.xlsx" -OutputFile "TestDrive:\combined3.xlsx" -Property name,displayname,startType -Key name
$excel = Open-ExcelPackage -Path "$env:temp\combined3.xlsx" $excel = Open-ExcelPackage -Path "TestDrive:\combined3.xlsx"
$ws = $excel.Workbook.Worksheets["sheet1"] $ws = $excel.Workbook.Worksheets["sheet1"]
} }
it "Created a worksheet with the correct headings " { it "Created a worksheet with the correct headings " {
$ws | Should not beNullOrEmpty $ws | Should not beNullOrEmpty
$ws.Cells[ 1,2 ].Value | Should be "name" $ws.Cells[ 1,2 ].Value | Should be "name"
$ws.Cells[ 1,3 ].Value | Should be "Server1 DisplayName" $ws.Cells[ 1,3 ].Value | Should be "server1 DisplayName"
$ws.Cells[ 1,4 ].Value | Should be "Server1 StartType" $ws.Cells[ 1,4 ].Value | Should be "server1 StartType"
$ws.Cells[ 1,5 ].Value | Should be "Server2 DisplayName" $ws.Cells[ 1,5 ].Value | Should be "server2 DisplayName"
$ws.Cells[ 1,6 ].Value | Should be "Server2 StartType" $ws.Cells[ 1,6 ].Value | Should be "server2 StartType"
$ws.Column(7).hidden | Should be $true $ws.Column(7).hidden | Should be $true
$ws.Cells[ 1,8].Value | Should be "Server2 Row" $ws.Cells[ 1,8].Value | Should be "server2 Row"
$ws.Cells[ 1,9 ].Value | Should be "Server3 DisplayName" $ws.Cells[ 1,9 ].Value | Should be "server3 DisplayName"
$ws.Cells[ 1,10].Value | Should be "Server3 StartType" $ws.Cells[ 1,10].Value | Should be "server3 StartType"
$ws.Column(11).hidden | Should be $true $ws.Column(11).hidden | Should be $true
$ws.Cells[ 1,12].Value | Should be "Server3 Row" $ws.Cells[ 1,12].Value | Should be "server3 Row"
} }
it "Joined the three sheets correctly " { it "Joined the three sheets correctly " {
$ws.Cells[ 2,3 ].Value | Should be $ws.Cells[ 2,5 ].Value $ws.Cells[ 2,3 ].Value | Should be $ws.Cells[ 2,5 ].Value
@@ -321,7 +326,7 @@ Describe "Merge Multiple sheets" {
$ws.Cells[12,9 ].Value | Should be $ws.Cells[12,5].Value $ws.Cells[12,9 ].Value | Should be $ws.Cells[12,5].Value
$ws.Cells[12,10].Value | Should be $ws.Cells[12,6].Value $ws.Cells[12,10].Value | Should be $ws.Cells[12,6].Value
} }
it "Creared Conditional formatting rules " { it "Created Conditional formatting rules " {
$cf=$ws.ConditionalFormatting $cf=$ws.ConditionalFormatting
$cf.Count | Should be 17 $cf.Count | Should be 17
$cf[16].Address.Address | Should be 'B2:B1048576' $cf[16].Address.Address | Should be 'B2:B1048576'

View File

@@ -1,6 +1,7 @@
Import-Module $PSScriptRoot\..\ImportExcel.psd1 -Force if (-not (get-command Import-Excel -ErrorAction SilentlyContinue)) {
Import-Module $PSScriptRoot\..\ImportExcel.psd1
$xlFile = ".\testSQL.xlsx" }
$xlFile = "TestDrive:\testSQL.xlsx"
Describe "ConvertFrom-ExcelToSQLInsert" { Describe "ConvertFrom-ExcelToSQLInsert" {
@@ -16,7 +17,7 @@ Describe "ConvertFrom-ExcelToSQLInsert" {
Remove-Item $xlFile -Recurse -Force -ErrorAction Ignore Remove-Item $xlFile -Recurse -Force -ErrorAction Ignore
} }
It "Should be empty double single quotes" { It "Should be empty double single quotes".PadRight(90) {
$expected="INSERT INTO Sheet1 ('Name', 'Age') Values('John', '');" $expected="INSERT INTO Sheet1 ('Name', 'Age') Values('John', '');"
$actual = ConvertFrom-ExcelToSQLInsert -Path $xlFile Sheet1 $actual = ConvertFrom-ExcelToSQLInsert -Path $xlFile Sheet1
@@ -24,7 +25,7 @@ Describe "ConvertFrom-ExcelToSQLInsert" {
$actual | should be $expected $actual | should be $expected
} }
It "Should have NULL" { It "Should have NULL".PadRight(90) {
$expected="INSERT INTO Sheet1 ('Name', 'Age') Values('John', NULL);" $expected="INSERT INTO Sheet1 ('Name', 'Age') Values('John', NULL);"
$actual = ConvertFrom-ExcelToSQLInsert -Path $xlFile Sheet1 -ConvertEmptyStringsToNull $actual = ConvertFrom-ExcelToSQLInsert -Path $xlFile Sheet1 -ConvertEmptyStringsToNull

View File

@@ -1,37 +1,37 @@
$path1 = "$env:TEMP\Test1.xlsx"
$path2 = "$env:TEMP\Test2.xlsx"
Remove-item -Path $path1, $path2 -ErrorAction SilentlyContinue
$ProcRange = Get-Process | Export-Excel $path1 -DisplayPropertySet -WorkSheetname Processes -ReturnRange
if ((Get-Culture).NumberFormat.CurrencySymbol -eq "<EFBFBD>") {$OtherCurrencySymbol = "$"}
else {$OtherCurrencySymbol = "<EFBFBD>"}
[PSCustOmobject][Ordered]@{
Date = Get-Date
Formula1 = '=SUM(F2:G2)'
String1 = 'My String'
Float = [math]::pi
IPAddress = '10.10.25.5'
StrLeadZero = '07670'
StrComma = '0,26'
StrEngThousand = '1,234.56'
StrEuroThousand = '1.555,83'
StrDot = '1.2'
StrNegInt = '-31'
StrTrailingNeg = '31-'
StrParens = '(123)'
strLocalCurrency = ('{0}123.45' -f (Get-Culture).NumberFormat.CurrencySymbol )
strOtherCurrency = ('{0}123.45' -f $OtherCurrencySymbol )
StrE164Phone = '+32 (444) 444 4444'
StrAltPhone1 = '+32 4 4444 444'
StrAltPhone2 = '+3244444444'
StrLeadSpace = ' 123'
StrTrailSpace = '123 '
Link1 = [uri]"https://github.com/dfinke/ImportExcel"
Link2 = "https://github.com/dfinke/ImportExcel" # Links are not copied correctly, hopefully this will be fixed at some future date
} | Export-Excel -NoNumberConversion IPAddress, StrLeadZero, StrAltPhone2 -WorkSheetname MixedTypes -Path $path2
Describe "Copy-Worksheet" { Describe "Copy-Worksheet" {
Context "Simplest copy"{ $path1 = "TestDrive:\Test1.xlsx"
$path2 = "TestDrive:\Test2.xlsx"
Remove-Item -Path $path1, $path2 -ErrorAction SilentlyContinue
$ProcRange = Get-Process | Export-Excel $path1 -DisplayPropertySet -WorkSheetname Processes -ReturnRange
if ((Get-Culture).NumberFormat.CurrencySymbol -eq "£") { $OtherCurrencySymbol = "$" }
else { $OtherCurrencySymbol = "£" }
[PSCustOmobject][Ordered]@{
Date = Get-Date
Formula1 = '=SUM(F2:G2)'
String1 = 'My String'
Float = [math]::pi
IPAddress = '10.10.25.5'
StrLeadZero = '07670'
StrComma = '0,26'
StrEngThousand = '1,234.56'
StrEuroThousand = '1.555,83'
StrDot = '1.2'
StrNegInt = '-31'
StrTrailingNeg = '31-'
StrParens = '(123)'
strLocalCurrency = ('{0}123.45' -f (Get-Culture).NumberFormat.CurrencySymbol )
strOtherCurrency = ('{0}123.45' -f $OtherCurrencySymbol )
StrE164Phone = '+32 (444) 444 4444'
StrAltPhone1 = '+32 4 4444 444'
StrAltPhone2 = '+3244444444'
StrLeadSpace = ' 123'
StrTrailSpace = '123 '
Link1 = [uri]"https://github.com/dfinke/ImportExcel"
Link2 = "https://github.com/dfinke/ImportExcel" # Links are not copied correctly, hopefully this will be fixed at some future date
} | Export-Excel -NoNumberConversion IPAddress, StrLeadZero, StrAltPhone2 -WorkSheetname MixedTypes -Path $path2
Context "Simplest copy" {
BeforeAll { BeforeAll {
Copy-ExcelWorkSheet -SourceWorkbook $path1 -DestinationWorkbook $path2 Copy-ExcelWorkSheet -SourceWorkbook $path1 -DestinationWorkbook $path2
$excel = Open-ExcelPackage -Path $path2 $excel = Open-ExcelPackage -Path $path2
@@ -43,12 +43,12 @@ Describe "Copy-Worksheet" {
$ws.Dimension.Address | should be $ProcRange $ws.Dimension.Address | should be $ProcRange
} }
} }
Context "Mixed types using a package object"{ Context "Mixed types using a package object" {
BeforeAll { BeforeAll {
Copy-ExcelWorkSheet -SourceWorkbook $excel -DestinationWorkbook $excel -DestinationWorkSheet "CopyOfMixedTypes" Copy-ExcelWorkSheet -SourceWorkbook $excel -DestinationWorkbook $excel -DestinationWorkSheet "CopyOfMixedTypes"
Close-ExcelPackage -ExcelPackage $excel Close-ExcelPackage -ExcelPackage $excel
$excel = Open-ExcelPackage -Path $path2 $excel = Open-ExcelPackage -Path $path2
$ws = $Excel.Workbook.Worksheets[3] $ws = $Excel.Workbook.Worksheets[3]
} }
it "Copied a worksheet, giving the expected name, number of rows and number of columns " { it "Copied a worksheet, giving the expected name, number of rows and number of columns " {
$Excel.Workbook.Worksheets.count | Should be 3 $Excel.Workbook.Worksheets.count | Should be 3
@@ -60,29 +60,81 @@ Describe "Copy-Worksheet" {
it "Copied the expected data into the worksheet " { it "Copied the expected data into the worksheet " {
$ws.Cells[2, 1].Value.Gettype().name | Should be 'DateTime' $ws.Cells[2, 1].Value.Gettype().name | Should be 'DateTime'
$ws.Cells[2, 2].Formula | Should be 'SUM(F2:G2)' $ws.Cells[2, 2].Formula | Should be 'SUM(F2:G2)'
$ws.Cells[2, 5].Value.GetType().name | Should be 'String' $ws.Cells[2, 5].Value.GetType().name | Should be 'String'
$ws.Cells[2, 6].Value.GetType().name | Should be 'String' $ws.Cells[2, 6].Value.GetType().name | Should be 'String'
$ws.Cells[2, 18].Value.GetType().name | Should be 'String' $ws.Cells[2, 18].Value.GetType().name | Should be 'String'
($ws.Cells[2, 11].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 11].Value -is [valuetype] ) | Should be $true
($ws.Cells[2, 12].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 12].Value -is [valuetype] ) | Should be $true
($ws.Cells[2, 13].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 13].Value -is [valuetype] ) | Should be $true
$ws.Cells[2, 11].Value | Should beLessThan 0 $ws.Cells[2, 11].Value | Should beLessThan 0
$ws.Cells[2, 12].Value | Should beLessThan 0 $ws.Cells[2, 12].Value | Should beLessThan 0
$ws.Cells[2, 13].Value | Should beLessThan 0 $ws.Cells[2, 13].Value | Should beLessThan 0
if ((Get-Culture).NumberFormat.NumberGroupSeparator -EQ ",") { if ((Get-Culture).NumberFormat.NumberGroupSeparator -EQ ",") {
($ws.Cells[2, 8].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 8].Value -is [valuetype] ) | Should be $true
$ws.Cells[2, 9].Value.GetType().name | Should be 'String' $ws.Cells[2, 9].Value.GetType().name | Should be 'String'
} }
elseif ((Get-Culture).NumberFormat.NumberGroupSeparator -EQ ".") { elseif ((Get-Culture).NumberFormat.NumberGroupSeparator -EQ ".") {
($ws.Cells[2, 9].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 9].Value -is [valuetype] ) | Should be $true
$ws.Cells[2, 8].Value.GetType().name | Should be 'String' $ws.Cells[2, 8].Value.GetType().name | Should be 'String'
} }
($ws.Cells[2, 14].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 14].Value -is [valuetype] ) | Should be $true
$ws.Cells[2, 15].Value.GetType().name | Should be 'String' $ws.Cells[2, 15].Value.GetType().name | Should be 'String'
$ws.Cells[2, 16].Value.GetType().name | Should be 'String' $ws.Cells[2, 16].Value.GetType().name | Should be 'String'
$ws.Cells[2, 17].Value.GetType().name | Should be 'String' $ws.Cells[2, 17].Value.GetType().name | Should be 'String'
($ws.Cells[2, 19].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 19].Value -is [valuetype] ) | Should be $true
($ws.Cells[2, 20].Value -is [valuetype] ) | Should be $true ($ws.Cells[2, 20].Value -is [valuetype] ) | Should be $true
}
}
Context "Copy worksheet should close all files" {
BeforeAll {
$xlfile = "TestDrive:\reports.xlsx"
$xlfileArchive = "TestDrive:\reportsArchive.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
Remove-Item $xlfileArchive -ErrorAction SilentlyContinue
$sheets = echo 1.1.2019 1.2.2019 1.3.2019 1.4.2019 1.5.2019
$sheets | ForEach-Object {
"Hello World" | Export-Excel $xlfile -WorksheetName $_
}
}
it "Should copy and remove sheets " {
$targetSheets = echo 1.1.2019 1.4.2019
$targetSheets | ForEach-Object {
Copy-ExcelWorkSheet -SourceWorkbook $xlfile -DestinationWorkbook $xlfileArchive -SourceWorkSheet $_ -DestinationWorkSheet $_
}
$targetSheets | ForEach-Object { Remove-WorkSheet -FullName $xlfile -WorksheetName $_ }
(Get-ExcelSheetInfo -Path $xlfile ).Count | Should Be 3
}
}
Context "Copy worksheet should support piped input" {
BeforeAll {
$xlfile = "TestDrive:\reports.xlsx"
$xlfileArchive = "TestDrive:\reportsArchive.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue
Remove-Item $xlfileArchive -ErrorAction SilentlyContinue
$sheets = echo 1.1.2019 1.2.2019 1.3.2019 1.4.2019 1.5.2019
$sheets | ForEach-Object {
"Hello World" | Export-Excel $xlfile -WorksheetName $_
}
$e = Open-ExcelPackage $xlfile
$e.Workbook.Worksheets | Copy-ExcelWorkSheet -DestinationWorkbook $xlfileArchive
Close-ExcelPackage -NoSave $e
}
it "Should copy sheets piped into the command " {
$excel = Open-ExcelPackage $xlfileArchive
$excel.Workbook.Worksheets.Count | should be 5
$excel.Workbook.Worksheets['1.3.2019'].Cells['A1'].Value | should be 'Hello World'
} }
} }
} }

View File

@@ -1,15 +1,26 @@
#Requires -Modules Pester #Requires -Modules Pester
#Import-Module $PSScriptRoot\..\ImportExcel.psd1 -Force if (-not (get-command Import-Excel -ErrorAction SilentlyContinue)) {
Import-Module $PSScriptRoot\..\ImportExcel.psd1
if (Get-process -Name Excel,xlim -ErrorAction SilentlyContinue) { Write-Warning -Message "You need to close Excel before running the tests." ; return} }
if ($null -eq $IsWindows) {$IsWindows = [environment]::OSVersion.Platform -like "win*"}
$WarningAction = "SilentlyContinue"
Describe ExportExcel { Describe ExportExcel {
. "$PSScriptRoot\Samples\Samples.ps1"
if (Get-process -Name Excel,xlim -ErrorAction SilentlyContinue) {
It "Excel is open" {
$Warning = "You need to close Excel before running the tests."
Write-Warning -Message $Warning
Set-ItResult -Inconclusive -Because $Warning
}
return
}
Context "#Example 1 # Creates and opens a file with the right number of rows and columns" { Context "#Example 1 # Creates and opens a file with the right number of rows and columns" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
#Test with a maximum of 100 processes for speed; export all properties, then export smaller subsets. #Test with a maximum of 100 processes for speed; export all properties, then export smaller subsets.
$processes = Get-Process | select-object -first 100 -Property * -excludeProperty Parent $processes = Get-Process | where {$_.StartTime} | Select-Object -first 100 -Property * -excludeProperty Parent
$propertyNames = $Processes[0].psobject.properties.name $propertyNames = $Processes[0].psobject.properties.name
$rowcount = $Processes.Count $rowcount = $Processes.Count
$Processes | Export-Excel $path #-show $Processes | Export-Excel $path #-show
@@ -68,7 +79,7 @@ Describe ExportExcel {
} }
Context " # NoAliasOrScriptPropeties -ExcludeProperty and -DisplayPropertySet work" { Context " # NoAliasOrScriptPropeties -ExcludeProperty and -DisplayPropertySet work" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
$processes = Get-Process | Select-Object -First 100 $processes = Get-Process | Select-Object -First 100
$propertyNames = $Processes[0].psobject.properties.where( {$_.MemberType -eq 'Property'}).name $propertyNames = $Processes[0].psobject.properties.where( {$_.MemberType -eq 'Property'}).name
@@ -117,7 +128,7 @@ Describe ExportExcel {
Context "#Example 2 # Exports a list of numbers and applies number format " { Context "#Example 2 # Exports a list of numbers and applies number format " {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
#testing -ReturnRange switch and applying number format to Formulas as well as values. #testing -ReturnRange switch and applying number format to Formulas as well as values.
$returnedRange = @($null, -1, 0, 34, 777, "", -0.5, 119, -0.1, 234, 788,"=A9+A10") | Export-Excel -NumberFormat '[Blue]$#,##0.00;[Red]-$#,##0.00' -Path $path -ReturnRange $returnedRange = @($null, -1, 0, 34, 777, "", -0.5, 119, -0.1, 234, 788,"=A9+A10") | Export-Excel -NumberFormat '[Blue]$#,##0.00;[Red]-$#,##0.00' -Path $path -ReturnRange
@@ -135,7 +146,7 @@ Describe ExportExcel {
it "Created the worksheet with the expected name, number of rows and number of columns " { it "Created the worksheet with the expected name, number of rows and number of columns " {
$ws.Name | Should be "sheet1" $ws.Name | Should be "sheet1"
$ws.Dimension.Columns | Should be 1 $ws.Dimension.Columns | Should be 1
$ws.Dimension.Rows | Should be 12 $ws.Dimension.End.Row | Should be 12
} }
it "Set the default style for the sheet as expected " { it "Set the default style for the sheet as expected " {
@@ -156,7 +167,7 @@ Describe ExportExcel {
Context " # Number format parameter" { Context " # Number format parameter" {
BeforeAll { BeforeAll {
$path = "$env:temp\test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue Remove-Item -Path $path -ErrorAction SilentlyContinue
1..10 | Export-Excel -Path $path -Numberformat 'Number' 1..10 | Export-Excel -Path $path -Numberformat 'Number'
1..10 | Export-Excel -Path $path -Numberformat 'Percentage' -Append 1..10 | Export-Excel -Path $path -Numberformat 'Percentage' -Append
@@ -179,7 +190,7 @@ Describe ExportExcel {
if ((Get-Culture).NumberFormat.CurrencySymbol -eq "£") {$OtherCurrencySymbol = "$"} if ((Get-Culture).NumberFormat.CurrencySymbol -eq "£") {$OtherCurrencySymbol = "$"}
else {$OtherCurrencySymbol = "£"} else {$OtherCurrencySymbol = "£"}
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
$warnVar = $null $warnVar = $null
#Test correct export of different data types and number formats; test hyperlinks, test -NoNumberConversion test object is converted to a string with no warnings, test calcuation of formula #Test correct export of different data types and number formats; test hyperlinks, test -NoNumberConversion test object is converted to a string with no warnings, test calcuation of formula
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
@@ -296,7 +307,7 @@ Describe ExportExcel {
Context "# # Setting cells for different data types with -noHeader" { Context "# # Setting cells for different data types with -noHeader" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
#Test -NoHeader & -NoNumberConversion #Test -NoHeader & -NoNumberConversion
[PSCustOmobject][Ordered]@{ [PSCustOmobject][Ordered]@{
@@ -357,7 +368,7 @@ Describe ExportExcel {
#Test New-ConditionalText builds correctly #Test New-ConditionalText builds correctly
$ct = New-ConditionalText -ConditionalType GreaterThan 525 -ConditionalTextColor ([System.Drawing.Color]::DarkRed) -BackgroundColor ([System.Drawing.Color]::LightPink) $ct = New-ConditionalText -ConditionalType GreaterThan 525 -ConditionalTextColor ([System.Drawing.Color]::DarkRed) -BackgroundColor ([System.Drawing.Color]::LightPink)
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
#Test -ConditionalText with a single conditional spec. #Test -ConditionalText with a single conditional spec.
Write-Output 489 668 299 777 860 151 119 497 234 788 | Export-Excel -Path $path -ConditionalText $ct Write-Output 489 668 299 777 860 151 119 497 234 788 | Export-Excel -Path $path -ConditionalText $ct
@@ -384,18 +395,19 @@ Describe ExportExcel {
} }
} }
Context "#Example 6 # Adding multiple conditional formats using short form syntax. " { #Test adding mutliple conditional blocks and using the minimal syntax for new-ConditionalText
#Test adding mutliple conditional blocks and using the minimal syntax for new-ConditionalText $path = "TestDrive:\test.xlsx"
$path = "$env:TEMP\Test.xlsx" Remove-item -Path $path -ErrorAction SilentlyContinue
Remove-item -Path $path -ErrorAction SilentlyContinue
#Testing -Passthrough #Testing -Passthrough
$Excel = Get-Service | Select-Object Name, Status, DisplayName, ServiceName | $Excel = Get-Service | Select-Object Name, Status, DisplayName, ServiceName |
Export-Excel $path -PassThru -ConditionalText $( Export-Excel $path -PassThru -ConditionalText $(
New-ConditionalText Stop ([System.Drawing.Color]::DarkRed) ([System.Drawing.Color]::LightPink) New-ConditionalText Stop ([System.Drawing.Color]::DarkRed) ([System.Drawing.Color]::LightPink)
New-ConditionalText Running ([System.Drawing.Color]::Blue) ([System.Drawing.Color]::Cyan) New-ConditionalText Running ([System.Drawing.Color]::Blue) ([System.Drawing.Color]::Cyan)
) )
$ws = $Excel.Workbook.Worksheets[1] $ws = $Excel.Workbook.Worksheets[1]
Context "#Example 6 # Adding multiple conditional formats using short form syntax. " {
it "Added two blocks of conditional formating for the data range " { it "Added two blocks of conditional formating for the data range " {
$ws.ConditionalFormatting.Count | Should be 2 $ws.ConditionalFormatting.Count | Should be 2
$ws.ConditionalFormatting[0].Address | Should be ($ws.Dimension.Address) $ws.ConditionalFormatting[0].Address | Should be ($ws.Dimension.Address)
@@ -408,8 +420,8 @@ Describe ExportExcel {
$ws.ConditionalFormatting[1].Type | Should be "ContainsText" $ws.ConditionalFormatting[1].Type | Should be "ContainsText"
#Add RGB Comparison #Add RGB Comparison
} }
Close-ExcelPackage -ExcelPackage $Excel
} }
Close-ExcelPackage -ExcelPackage $Excel
Context "#Example 7 # Update-FirstObjectProperties works " { Context "#Example 7 # Update-FirstObjectProperties works " {
$Array = @() $Array = @()
@@ -448,7 +460,7 @@ Describe ExportExcel {
} }
Context "#Examples 8 & 9 # Adding Pivot tables and charts from parameters" { Context "#Examples 8 & 9 # Adding Pivot tables and charts from parameters" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
#Test -passthru and -worksheetName creating a new, named, sheet in an existing file. #Test -passthru and -worksheetName creating a new, named, sheet in an existing file.
$Excel = Get-Process | Select-Object -first 20 -Property Name, cpu, pm, handles, company | Export-Excel $path -WorkSheetname Processes -PassThru $Excel = Get-Process | Select-Object -first 20 -Property Name, cpu, pm, handles, company | Export-Excel $path -WorkSheetname Processes -PassThru
#Testing -Excel Pacakage and adding a Pivot-table as a second step. Want to save and re-open it ... #Testing -Excel Pacakage and adding a Pivot-table as a second step. Want to save and re-open it ...
@@ -461,11 +473,14 @@ Describe ExportExcel {
$excel.ProcessesPivotTable | Should not beNullOrEmpty $excel.ProcessesPivotTable | Should not beNullOrEmpty
$PTws | Should not beNullOrEmpty $PTws | Should not beNullOrEmpty
$PTws.PivotTables.Count | Should be 1 $PTws.PivotTables.Count | Should be 1
$PTws.View.TabSelected | Should be $true
$Excel.Workbook.Worksheets["Processes"] | Should not beNullOrEmpty $Excel.Workbook.Worksheets["Processes"] | Should not beNullOrEmpty
$Excel.Workbook.Worksheets.Count | Should beGreaterThan 2 $Excel.Workbook.Worksheets.Count | Should beGreaterThan 2
$excel.Workbook.Worksheets["Processes"].Dimension.rows | Should be 21 #20 data + 1 header $excel.Workbook.Worksheets["Processes"].Dimension.rows | Should be 21 #20 data + 1 header
} }
it "Selected the Pivottable page " {
Set-ItResult -Pending -Because "Bug in EPPLus 4.5"
$PTws.View.TabSelected | Should be $true
}
$pt = $PTws.PivotTables[0] $pt = $PTws.PivotTables[0]
it "Built the expected Pivot table " { it "Built the expected Pivot table " {
$pt.RowFields.Count | Should be 1 $pt.RowFields.Count | Should be 1
@@ -505,7 +520,7 @@ Describe ExportExcel {
} }
Context " # Add-Worksheet inserted sheets, moved them correctly, and copied a sheet" { Context " # Add-Worksheet inserted sheets, moved them correctly, and copied a sheet" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
#Test the -CopySource and -Movexxxx parameters for Add-WorkSheet #Test the -CopySource and -Movexxxx parameters for Add-WorkSheet
$Excel = Open-ExcelPackage $path $Excel = Open-ExcelPackage $path
#At this point Sheets Should be in the order Sheet1, Processes, ProcessesPivotTable #At this point Sheets Should be in the order Sheet1, Processes, ProcessesPivotTable
@@ -540,7 +555,7 @@ Describe ExportExcel {
} }
Context " # Create and append with Start row and Start Column, inc ranges and Pivot table. " { Context " # Create and append with Start row and Start Column, inc ranges and Pivot table. " {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
remove-item -Path $path -ErrorAction SilentlyContinue remove-item -Path $path -ErrorAction SilentlyContinue
#Catch warning #Catch warning
$warnVar = $null $warnVar = $null
@@ -590,7 +605,7 @@ Describe ExportExcel {
} }
Context " # Create and append explicit and auto table and range extension" { Context " # Create and append explicit and auto table and range extension" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
#Test -Append automatically extends a table, even when it is not specified in the append command; #Test -Append automatically extends a table, even when it is not specified in the append command;
Get-Process | Select-Object -first 10 -Property Name, cpu, pm, handles, company | Export-Excel -Path $path -TableName ProcTab -AutoNameRange -WorkSheetname NoOffset -ClearSheet Get-Process | Select-Object -first 10 -Property Name, cpu, pm, handles, company | Export-Excel -Path $path -TableName ProcTab -AutoNameRange -WorkSheetname NoOffset -ClearSheet
#Test number format applying to new data #Test number format applying to new data
@@ -623,7 +638,7 @@ Describe ExportExcel {
} }
Context "#Example 11 # Create and append with title, inc ranges and Pivot table" { Context "#Example 11 # Create and append with title, inc ranges and Pivot table" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
#Test New-PivotTableDefinition builds definition using -Pivotfilter and -PivotTotals options. #Test New-PivotTableDefinition builds definition using -Pivotfilter and -PivotTotals options.
$ptDef = [ordered]@{} $ptDef = [ordered]@{}
$ptDef += New-PivotTableDefinition -PivotTableName "PT1" -SourceWorkSheet 'Sheet1' -PivotRows "Status" -PivotData @{'Status' = 'Count'} -PivotTotals Columns -PivotFilter "StartType" -IncludePivotChart -ChartType BarClustered3D -ChartTitle "Services by status" -ChartHeight 512 -ChartWidth 768 -ChartRow 10 -ChartColumn 0 -NoLegend -PivotColumns CanPauseAndContinue $ptDef += New-PivotTableDefinition -PivotTableName "PT1" -SourceWorkSheet 'Sheet1' -PivotRows "Status" -PivotData @{'Status' = 'Count'} -PivotTotals Columns -PivotFilter "StartType" -IncludePivotChart -ChartType BarClustered3D -ChartTitle "Services by status" -ChartHeight 512 -ChartWidth 768 -ChartRow 10 -ChartColumn 0 -NoLegend -PivotColumns CanPauseAndContinue
@@ -642,20 +657,21 @@ Describe ExportExcel {
#Catch warning #Catch warning
$warnvar = $null $warnvar = $null
#Test create two data pages; as part of adding the second give both their own pivot table, test -autosize switch #Test create two data pages; as part of adding the second give both their own pivot table, test -autosize switch
Get-Service | Select-Object -Property Status, Name, DisplayName, StartType, CanPauseAndContinue | Export-Excel -Path $path -AutoSize -TableName "All Services" -TableStyle Medium1 -WarningAction SilentlyContinue -WarningVariable warnvar Get-Service | Select-Object -Property Status, Name, DisplayName, StartType, CanPauseAndContinue | Export-Excel -Path $path -AutoSize -TableName "All Services" -TableStyle Medium1 -WarningVariable warnvar
Get-Process | Select-Object -Property Name, Company, Handles, CPU, VM | Export-Excel -Path $path -AutoSize -WorkSheetname 'sheet2' -TableName "Processes" -TableStyle Light1 -Title "Processes" -TitleFillPattern Solid -TitleBackgroundColor ([System.Drawing.Color]::AliceBlue) -TitleBold -TitleSize 22 -PivotTableDefinition $ptDef Get-Process | Select-Object -Property Name, Company, Handles, CPU, VM | Export-Excel -Path $path -AutoSize -WorkSheetname 'sheet2' -TableName "Processes" -TableStyle Light1 -Title "Processes" -TitleFillPattern Solid -TitleBackgroundColor ([System.Drawing.Color]::AliceBlue) -TitleBold -TitleSize 22 -PivotTableDefinition $ptDef
$Excel = Open-ExcelPackage $path $Excel = Open-ExcelPackage $path
$ws1 = $Excel.Workbook.Worksheets["Sheet1"] $ws1 = $Excel.Workbook.Worksheets["Sheet1"]
$ws2 = $Excel.Workbook.Worksheets["Sheet2"] $ws2 = $Excel.Workbook.Worksheets["Sheet2"]
if ($isWindows) {
it "Set Column widths (with autosize) " { it "Set Column widths (with autosize) " {
$ws1.Column(2).Width | Should not be $ws1.DefaultColWidth $ws1.Column(2).Width | Should not be $ws1.DefaultColWidth
$ws2.Column(1).width | Should not be $ws2.DefaultColWidth $ws2.Column(1).width | Should not be $ws2.DefaultColWidth
}
} }
it "Added tables to both sheets (handling illegal chars) and a title in sheet 2 " { it "Added tables to both sheets (handling illegal chars) and a title in sheet 2 " {
$warnvar.count | Should be 1 $warnvar.count | Should beGreaterThan 0
$ws1.tables.Count | Should be 1 $ws1.tables.Count | Should be 1
$ws2.tables.Count | Should be 1 $ws2.tables.Count | Should be 1
$ws1.Tables[0].Address.Start.Row | Should be 1 $ws1.Tables[0].Address.Start.Row | Should be 1
@@ -678,10 +694,10 @@ Describe ExportExcel {
$PC1 = $ptsheet1.Drawings[0] $PC1 = $ptsheet1.Drawings[0]
$PC2 = $ptsheet2.Drawings[0] $PC2 = $ptsheet2.Drawings[0]
it "Created the pivot tables linked to the right data. " { it "Created the pivot tables linked to the right data. " {
$PT1.CacheDefinition.CacheDefinitionXml.pivotCacheDefinition.cacheSource.worksheetSource.ref | $PT1.CacheDefinition.CacheDefinitionXml.pivotCacheDefinition.cacheSource.worksheetSource.name|
Should be ("A1:" + $ws1.Dimension.End.Address) Should be "All_services"
$PT2.CacheDefinition.CacheDefinitionXml.pivotCacheDefinition.cacheSource.worksheetSource.ref | $PT2.CacheDefinition.CacheDefinitionXml.pivotCacheDefinition.cacheSource.worksheetSource.name |
Should be ("A2:" + $ws2.Dimension.End.Address) #Title in row 1 Should be "Processes"
} }
it "Set the other pivot tables and chart options from the definitions. " { it "Set the other pivot tables and chart options from the definitions. " {
$pt1.PageFields[0].Name | Should be 'StartType' $pt1.PageFields[0].Name | Should be 'StartType'
@@ -705,12 +721,13 @@ Describe ExportExcel {
} }
Context "#Example 13 # Formatting and another way to do a pivot. " { Context "#Example 13 # Formatting and another way to do a pivot. " {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-Item $path Remove-Item $path
#Test freezing top row/first column, adding formats and a pivot table - from Add-Pivot table not a specification variable - after the export #Test freezing top row/first column, adding formats and a pivot table - from Add-Pivot table not a specification variable - after the export
$excel = Get-Process | Select-Object -Property Name, Company, Handles, CPU, PM, NPM, WS | Export-Excel -Path $path -ClearSheet -WorkSheetname "Processes" -FreezeTopRowFirstColumn -PassThru $excel = Get-Process | Select-Object -Property Name, Company, Handles, CPU, PM, NPM, WS | Export-Excel -Path $path -ClearSheet -WorkSheetname "Processes" -FreezeTopRowFirstColumn -PassThru
$sheet = $excel.Workbook.Worksheets["Processes"] $sheet = $excel.Workbook.Worksheets["Processes"]
$sheet.Column(1) | Set-ExcelRange -Bold -AutoFit if ($isWindows) {$sheet.Column(1) | Set-ExcelRange -Bold -AutoFit }
else {$sheet.Column(1) | Set-ExcelRange -Bold }
$sheet.Column(2) | Set-ExcelRange -Width 29 -WrapText $sheet.Column(2) | Set-ExcelRange -Width 29 -WrapText
$sheet.Column(3) | Set-ExcelRange -HorizontalAlignment Right -NFormat "#,###" $sheet.Column(3) | Set-ExcelRange -HorizontalAlignment Right -NFormat "#,###"
Set-ExcelRange -Address $sheet.Cells["E1:H1048576"] -HorizontalAlignment Right -NFormat "#,###" Set-ExcelRange -Address $sheet.Cells["E1:H1048576"] -HorizontalAlignment Right -NFormat "#,###"
@@ -721,7 +738,7 @@ Describe ExportExcel {
$rule = Add-ConditionalFormatting -passthru -Address $sheet.cells["C:C"] -RuleType TopPercent -ConditionValue 20 -Bold -StrikeThru $rule = Add-ConditionalFormatting -passthru -Address $sheet.cells["C:C"] -RuleType TopPercent -ConditionValue 20 -Bold -StrikeThru
Add-ConditionalFormatting -WorkSheet $sheet -Range "G2:G1048576" -RuleType GreaterThan -ConditionValue "104857600" -ForeGroundColor ([System.Drawing.Color]::Red) -Bold -Italic -Underline -BackgroundColor ([System.Drawing.Color]::Beige) -BackgroundPattern LightUp -PatternColor ([System.Drawing.Color]::Gray) Add-ConditionalFormatting -WorkSheet $sheet -Range "G2:G1048576" -RuleType GreaterThan -ConditionValue "104857600" -ForeGroundColor ([System.Drawing.Color]::Red) -Bold -Italic -Underline -BackgroundColor ([System.Drawing.Color]::Beige) -BackgroundPattern LightUp -PatternColor ([System.Drawing.Color]::Gray)
#Test Set-ExcelRange with a column #Test Set-ExcelRange with a column
foreach ($c in 5..9) {Set-ExcelRange $sheet.Column($c) -AutoFit } if ($isWindows) { foreach ($c in 5..9) {Set-ExcelRange $sheet.Column($c) -AutoFit } }
Add-PivotTable -PivotTableName "PT_Procs" -ExcelPackage $excel -SourceWorkSheet 1 -PivotRows Company -PivotData @{'Name' = 'Count'} -IncludePivotChart -ChartType ColumnClustered -NoLegend Add-PivotTable -PivotTableName "PT_Procs" -ExcelPackage $excel -SourceWorkSheet 1 -PivotRows Company -PivotData @{'Name' = 'Count'} -IncludePivotChart -ChartType ColumnClustered -NoLegend
Export-Excel -ExcelPackage $excel -WorksheetName "Processes" -AutoNameRange #Test adding named ranges seperately from adding data. Export-Excel -ExcelPackage $excel -WorksheetName "Processes" -AutoNameRange #Test adding named ranges seperately from adding data.
@@ -734,8 +751,10 @@ Describe ExportExcel {
} }
it "Applied the formating " { it "Applied the formating " {
$sheet | Should not beNullOrEmpty $sheet | Should not beNullOrEmpty
$sheet.Column(1).wdith | Should not be $sheet.DefaultColWidth if ($isWindows) {
$sheet.Column(7).wdith | Should not be $sheet.DefaultColWidth $sheet.Column(1).width | Should not be $sheet.DefaultColWidth
$sheet.Column(7).width | Should not be $sheet.DefaultColWidth
}
$sheet.Column(1).style.font.bold | Should be $true $sheet.Column(1).style.font.bold | Should be $true
$sheet.Column(2).style.wraptext | Should be $true $sheet.Column(2).style.wraptext | Should be $true
$sheet.Column(2).width | Should be 29 $sheet.Column(2).width | Should be 29
@@ -785,7 +804,7 @@ Describe ExportExcel {
} }
Context " # Chart from MultiSeries.ps1 in the Examples\charts Directory" { Context " # Chart from MultiSeries.ps1 in the Examples\charts Directory" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue Remove-Item -Path $path -ErrorAction SilentlyContinue
#Test we haven't missed any parameters on New-ChartDefinition which are on add chart or vice versa. #Test we haven't missed any parameters on New-ChartDefinition which are on add chart or vice versa.
@@ -843,7 +862,7 @@ Describe ExportExcel {
} }
Context " # variation of plot.ps1 from Examples Directory using Add chart outside ExportExcel" { Context " # variation of plot.ps1 from Examples Directory using Add chart outside ExportExcel" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
#Test inserting a fomual #Test inserting a fomual
$excel = 0..360 | ForEach-Object {[pscustomobject][ordered]@{x = $_; Sinx = "=Sin(Radians(x)) "}} | Export-Excel -AutoNameRange -Path $path -WorkSheetname SinX -ClearSheet -FreezeFirstColumn -PassThru $excel = 0..360 | ForEach-Object {[pscustomobject][ordered]@{x = $_; Sinx = "=Sin(Radians(x)) "}} | Export-Excel -AutoNameRange -Path $path -WorkSheetname SinX -ClearSheet -FreezeFirstColumn -PassThru
#Test-Add Excel Chart to existing data. Test add Conditional formatting with a formula #Test-Add Excel Chart to existing data. Test add Conditional formatting with a formula
@@ -883,8 +902,9 @@ Describe ExportExcel {
} }
Close-ExcelPackage -ExcelPackage $excel -nosave Close-ExcelPackage -ExcelPackage $excel -nosave
} }
Context " # Quick line chart" { Context " # Quick line chart" {
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\test.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue Remove-Item -Path $path -ErrorAction SilentlyContinue
#test drawing a chart when data doesn't have a string #test drawing a chart when data doesn't have a string
0..360 | ForEach-Object {[pscustomobject][ordered]@{x = $_; Sinx = "=Sin(Radians(x)) "}} | Export-Excel -AutoNameRange -Path $path -LineChart 0..360 | ForEach-Object {[pscustomobject][ordered]@{x = $_; Sinx = "=Sin(Radians(x)) "}} | Export-Excel -AutoNameRange -Path $path -LineChart
@@ -901,11 +921,9 @@ Describe ExportExcel {
} }
Context " # Quick Pie chart and three icon conditional formating" { Context " # Quick Pie chart and three icon conditional formating" {
$path = "$Env:TEMP\Pie.xlsx" $path = "TestDrive:\Pie.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue Remove-Item -Path $path -ErrorAction SilentlyContinue
$range = Get-Process| Group-Object -Property company | Where-Object -Property name | $range = Get-Process| Group-Object -Property company | Where-Object -Property name |
Select-Object -Property Name, @{n="TotalPm";e={($_.group | Measure-Object -sum -Property pm).sum }} | Select-Object -Property Name, @{n="TotalPm";e={($_.group | Measure-Object -sum -Property pm).sum }} |
Export-Excel -NoHeader -AutoNameRange -path $path -ReturnRange -PieChart -ShowPercent Export-Excel -NoHeader -AutoNameRange -path $path -ReturnRange -PieChart -ShowPercent
@@ -941,10 +959,16 @@ Describe ExportExcel {
} }
Context " # Awkward multiple tables" { Context " # Awkward multiple tables" {
$path = "$Env:TEMP\test.xlsx" $path = "TestDrive:\test.xlsx"
#Test creating 3 on overlapping tables on the same page. Create rightmost the left most then middle. #Test creating 3 on overlapping tables on the same page. Create rightmost the left most then middle.
remove-item -Path $path -ErrorAction SilentlyContinue remove-item -Path $path -ErrorAction SilentlyContinue
$r = Get-ChildItem -path C:\WINDOWS\system32 -File if ($IsLinux -or $IsMacOS) {
$SystemFolder = '/etc'
}
else {
$SystemFolder = 'C:\WINDOWS\system32'
}
$r = Get-ChildItem -path $SystemFolder -File
"Biggest files" | Export-Excel -Path $path -StartRow 1 -StartColumn 7 "Biggest files" | Export-Excel -Path $path -StartRow 1 -StartColumn 7
$r | Sort-Object length -Descending | Select-Object -First 14 Name, @{n="Size";e={$_.Length}} | $r | Sort-Object length -Descending | Select-Object -First 14 Name, @{n="Size";e={$_.Length}} |
@@ -966,12 +990,101 @@ Describe ExportExcel {
$ws.Tables["FileSize"].Address.Address | Should be "G2:H16" #Insert at row 2, Column 7, 14 rows x 2 columns of data $ws.Tables["FileSize"].Address.Address | Should be "G2:H16" #Insert at row 2, Column 7, 14 rows x 2 columns of data
$ws.Tables["FileSize"].StyleName | Should be "TableStyleMedium2" $ws.Tables["FileSize"].StyleName | Should be "TableStyleMedium2"
} }
it "Created the ExtSize table in the right place with the right size " { it "Created the ExtSize table in the right place with the right size and style " {
$ws.Tables["ExtSize"].Address.Address | Should be "A2:B14" #tile, then 12 rows x 2 columns of data $ws.Tables["ExtSize"].Address.Address | Should be "A2:B14" #tile, then 12 rows x 2 columns of data
$ws.Tables["ExtSize"].StyleName | Should be "TableStyleMedium6"
} }
it "Created the ExtCount table in the right place with the right size " { it "Created the ExtCount table in the right place with the right size " {
$ws.Tables["ExtCount"].Address.Address | Should be "D2:E12" #title, then 10 rows x 2 columns of data $ws.Tables["ExtCount"].Address.Address | Should be "D2:E12" #title, then 10 rows x 2 columns of data
} }
} }
Context " # Parameters and ParameterSets" {
$Path = Join-Path (Resolve-Path 'TestDrive:').ProviderPath "test.xlsx"
Remove-Item -Path $Path -ErrorAction SilentlyContinue
$Processes = Get-Process | Select-Object -first 10 -Property Name, cpu, pm, handles, company
it "Default Set with Path".PadRight(87) {
$ExcelPackage = $Processes | Export-Excel -Path $Path -PassThru
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$ExcelPackage.File | Should Be $Path
$Worksheet.Cells['A1'].Value | Should Be 'Name'
$Worksheet.Tables | Should BeNullOrEmpty
$Worksheet.AutoFilterAddress | Should BeNullOrEmpty
}
it "ExcelPackage Set. Path and (ExcelPackage or Now) should throw".PadRight(87) {
$ExcelPackage = Export-Excel -Path $Path -PassThru
{Export-Excel -ExcelPackage $ExcelPackage -Path $Path} | Should Throw 'Parameter set cannot be resolved using the specified named parameters'
{Export-Excel -ExcelPackage $ExcelPackage -Now} | Should Throw 'Parameter set cannot be resolved using the specified named parameters'
$Processes | Export-Excel -ExcelPackage $ExcelPackage
Remove-Item -Path $Path
}
it "If TableName and AutoFilter provided AutoFilter will be ignored".PadRight(87) {
$ExcelPackage = Export-Excel -Path $Path -PassThru -TableName 'Data' -AutoFilter
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$Worksheet.Tables[0].Name | Should Be 'Data'
$Worksheet.AutoFilterAddress | Should BeNullOrEmpty
}
it "Default Set with Path and TableName with generated name".PadRight(87) {
$ExcelPackage = $Processes | Export-Excel -Path $Path -PassThru -TableName ''
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$ExcelPackage.File | Should Be $Path
$Worksheet.Tables[0].Name | Should Be 'Table1'
}
it "Now will use temp Path, set TableName with generated name and AutoSize".PadRight(87) {
$ExcelPackage = $Processes | Export-Excel -Now -PassThru
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$ExcelPackage.File | Should BeLike ([IO.Path]::GetTempPath() + '*')
$Worksheet.Tables[0].Name | Should Be 'Table1'
$Worksheet.AutoFilterAddress | Should BeNullOrEmpty
if ($isWindows) {
$Worksheet.Column(5).Width | Should BeGreaterThan 9.5
}
}
it "Now allows override of Path and TableName".PadRight(87) {
$ExcelPackage = $Processes | Export-Excel -Now -PassThru -Path $Path -TableName:$false
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$ExcelPackage.File | Should Be $Path
$Worksheet.Tables | Should BeNullOrEmpty
$Worksheet.AutoFilterAddress | Should BeNullOrEmpty
if ($isWindows) {
$Worksheet.Column(5).Width | Should BeGreaterThan 9.5
}
}
<# Mock looks unreliable need to check
Mock -CommandName 'Invoke-Item'
it "Now will Show".PadRight(87) {
$Processes | Export-Excel
Assert-MockCalled -CommandName 'Invoke-Item' -Times 1 -Exactly -Scope 'It'
}
it "Now allows override of Show".PadRight(87) {
$Processes | Export-Excel -Show:$false
Assert-MockCalled -CommandName 'Invoke-Item' -Times 0 -Exactly -Scope 'It'
}
#>
it "Now allows override of AutoSize and TableName to AutoFilter".PadRight(87) {
$ExcelPackage = $Processes | Export-Excel -Now -PassThru -AutoSize:$false -AutoFilter
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$Worksheet.Tables | Should BeNullOrEmpty
$Worksheet.AutoFilterAddress | Should Not BeNullOrEmpty
[math]::Round($Worksheet.Column(5).Width, 2) | Should Be 9.14
}
it "Now allows to set TableName".PadRight(87) {
$ExcelPackage = $Processes | Export-Excel -Now -PassThru -TableName 'Data'
$Worksheet = $ExcelPackage.Workbook.Worksheets[1]
$Worksheet.Tables[0].Name | Should Be 'Data'
$Worksheet.AutoFilterAddress | Should BeNullOrEmpty
if ($isWindows) {
$Worksheet.Column(5).Width | Should BeGreaterThan 9.5
}
}
}
} }

View File

@@ -1,8 +1,9 @@
$path = "$Env:TEMP\test.xlsx" Describe "Creating workbook with a single line" {
remove-item -path $path -ErrorAction SilentlyContinue $path = "TestDrive:\test.xlsx"
ConvertFrom-Csv @" remove-item -path $path -ErrorAction SilentlyContinue
ConvertFrom-Csv @"
Product, City, Gross, Net Product, City, Gross, Net
Apple, London , 300, 250 Apple, London , 300, 250
Orange, London , 400, 350 Orange, London , 400, 350
@@ -10,16 +11,15 @@ Banana, London , 300, 200
Orange, Paris, 600, 500 Orange, Paris, 600, 500
Banana, Paris, 300, 200 Banana, Paris, 300, 200
Apple, New York, 1200,700 Apple, New York, 1200,700
"@ | Export-Excel -Path $path -TableStyle Medium13 -tablename "RawData" -ConditionalFormat @{Range="C2:C7"; DataBarColor="Green"} -ExcelChartDefinition @{ChartType="Doughnut";XRange="A2:B7"; YRange="C2:C7"; width=800; } -PivotTableDefinition @{Sales=@{ "@ | Export-Excel -Path $path -TableStyle Medium13 -tablename "RawData" -ConditionalFormat @{Range="C2:C7"; DataBarColor="Green"} -ExcelChartDefinition @{ChartType="Doughnut";XRange="A2:B7"; YRange="C2:C7"; width=800; } -PivotTableDefinition @{Sales=@{
PivotRows="City"; PivotColumns="Product"; PivotData=@{Gross="Sum";Net="Sum"}; PivotNumberFormat="$#,##0.00"; PivotTotals="Both"; PivotTableStyle="Medium12"; Activate=$true PivotRows="City"; PivotColumns="Product"; PivotData=@{Gross="Sum";Net="Sum"}; PivotNumberFormat="$#,##0.00"; PivotTotals="Both"; PivotTableStyle="Medium12"; Activate=$true
PivotChartDefinition=@{Title="Gross and net by city and product"; ChartType="ColumnClustered"; Column=6; Width=600; Height=360; YMajorUnit=500; YMinorUnit=100; YAxisNumberformat="$#,##0"; LegendPosition="Bottom"}}} PivotChartDefinition=@{Title="Gross and net by city and product"; ChartType="ColumnClustered"; Column=6; Width=600; Height=360; YMajorUnit=500; YMinorUnit=100; YAxisNumberformat="$#,##0"; LegendPosition="Bottom"}}}
$excel = Open-ExcelPackage $path $excel = Open-ExcelPackage $path
$ws1 = $excel.Workbook.Worksheets[1] $ws1 = $excel.Workbook.Worksheets[1]
$ws2 = $excel.Workbook.Worksheets[2] $ws2 = $excel.Workbook.Worksheets[2]
Describe "Creating workbook with a single line" {
Context "Data Page" { Context "Data Page" {
It "Inserted the data and created the table " { It "Inserted the data and created the table " {
$ws1.Tables[0] | Should not beNullOrEmpty $ws1.Tables[0] | Should not beNullOrEmpty
@@ -40,7 +40,7 @@ Describe "Creating workbook with a single line" {
} }
} }
Context "PivotTable" { Context "PivotTable" {
it "Created the PivotTable on a new page and made it active " { it "Created the PivotTable on a new page " {
$ws2 | Should not beNullOrEmpty $ws2 | Should not beNullOrEmpty
$ws2.PivotTables[0] | Should not beNullOrEmpty $ws2.PivotTables[0] | Should not beNullOrEmpty
$ws2.PivotTables[0].Fields.Count | Should be 4 $ws2.PivotTables[0].Fields.Count | Should be 4
@@ -49,6 +49,9 @@ Describe "Creating workbook with a single line" {
$ws2.PivotTables[0].ColumnFields[0].Name | Should be "Product" $ws2.PivotTables[0].ColumnFields[0].Name | Should be "Product"
$ws2.PivotTables[0].RowGrandTotals | Should be $true $ws2.PivotTables[0].RowGrandTotals | Should be $true
$ws2.PivotTables[0].ColumGrandTotals | Should be $true #Epplus's mis-spelling of column not mine $ws2.PivotTables[0].ColumGrandTotals | Should be $true #Epplus's mis-spelling of column not mine
}
it "Made the PivotTable page active " {
Set-ItResult -Pending -Because "Bug in EPPLus 4.5"
$ws2.View.TabSelected | Should be $true $ws2.View.TabSelected | Should be $true
} }
it "Created the Pivot Chart " { it "Created the Pivot Chart " {

View File

@@ -1,50 +1,61 @@
$scriptPath = Split-Path -Path $MyInvocation.MyCommand.path -Parent $scriptPath = Split-Path -Path $MyInvocation.MyCommand.path -Parent
$dataPath = Join-Path -Path $scriptPath -ChildPath "First10Races.csv" $dataPath = Join-Path -Path $scriptPath -ChildPath "First10Races.csv"
$WarningAction = "SilentlyContinue"
Describe "Creating small named ranges with hyperlinks" { Describe "Creating small named ranges with hyperlinks" {
BeforeAll { BeforeAll {
$path = "$env:TEMP\Results.xlsx" $path = "TestDrive:\Results.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue Remove-Item -Path $path -ErrorAction SilentlyContinue
#Read race results, and group by race name : export 1 row to get headers, leaving enough rows aboce to put in a link for each race #Read race results, and group by race name : export 1 row to get headers, leaving enough rows aboce to put in a link for each race
$results = Import-Csv -Path $dataPath | Group-Object -Property RACE $results = Import-Csv -Path $dataPath |
$topRow = $lastDataRow = 1 + $results.Count Select-Object Race, @{n = "Date"; e = {[datetime]::ParseExact($_.date, "dd/MM/yyyy", (Get-Culture))}}, FinishPosition, Driver, GridPosition, Team, Points |
$excel = $results[0].Group[0] | Export-Excel -Path $path -StartRow $TopRow -BoldTopRow -PassThru Group-Object -Property RACE
$topRow = $lastDataRow = 1 + $results.Count
$excel = $results[0].Group[0] | Export-Excel -Path $path -StartRow $TopRow -BoldTopRow -PassThru
#export each group (race) below the last one, without headers, and create a range for each using the group name (Race) #export each group (race) below the last one, without headers, and create a range for each using the group name (Race)
foreach ($r in $results) { foreach ($r in $results) {
$excel = $R.Group | Export-Excel -ExcelPackage $excel -NoHeader -StartRow ($lastDataRow +1) -RangeName $R.Name -PassThru -AutoSize $excel = $R.Group | Export-Excel -ExcelPackage $excel -NoHeader -StartRow ($lastDataRow + 1) -RangeName $R.Name -PassThru -AutoSize
$lastDataRow += $R.Group.Count $lastDataRow += $R.Group.Count
} }
$worksheet = $excel.Workbook.Worksheets[1] $worksheet = $excel.Workbook.Worksheets[1]
$columns = $worksheet.Dimension.Columns $columns = $worksheet.Dimension.Columns
1..$columns | ForEach-Object {Add-ExcelName -Range $worksheet.cells[$topRow,$_,$lastDataRow,$_]} #Test Add-Excel Name on its own (outside Export-Excel) 1..$columns | ForEach-Object {Add-ExcelName -Range $worksheet.cells[$topRow, $_, $lastDataRow, $_]} #Test Add-Excel Name on its own (outside Export-Excel)
$scwarnVar = $null $scwarnVar = $null
Set-ExcelColumn -Worksheet $worksheet -StartRow $topRow -Heading "PlacesGained/Lost" ` Set-ExcelColumn -Worksheet $worksheet -StartRow $topRow -Heading "PlacesGained/Lost" `
-Value "=GridPosition-FinishPosition" -AutoNameRange -WarningVariable scWarnVar -WarningAction SilentlyContinue #Test as many set column options as possible. -Value "=GridPosition-FinishPosition" -AutoNameRange -WarningVariable scWarnVar -WarningAction SilentlyContinue #Test as many set column options as possible.
$columns ++ $columns ++
#create a table which covers all the data. And define a pivot table which uses the same address range. #create a table which covers all the data. And define a pivot table which uses the same address range.
$table = Add-ExcelTable -PassThru -Range $worksheet.cells[$topRow,1,$lastDataRow,$columns] -TableName "AllResults" -TableStyle Light4 ` $table = Add-ExcelTable -PassThru -Range $worksheet.cells[$topRow, 1, $lastDataRow, $columns] -TableName "AllResults" -TableStyle Light4 `
-ShowHeader -ShowFilter -ShowColumnStripes -ShowRowStripes:$false -ShowFirstColumn:$false -ShowLastColumn:$false -ShowTotal:$false #Test Add-ExcelTable outside export-Excel with as many options as possible. -ShowHeader -ShowFilter -ShowColumnStripes -ShowRowStripes:$false -ShowFirstColumn:$false -ShowLastColumn:$false -ShowTotal:$false #Test Add-ExcelTable outside export-Excel with as many options as possible.
$pt = New-PivotTableDefinition -PivotTableName Analysis -SourceWorkSheet $worksheet -SourceRange $table.address.address -PivotRows Driver -PivotData @{Points="SUM"} -PivotTotals None $pt = New-PivotTableDefinition -PivotTableName Analysis -SourceWorkSheet $worksheet -SourceRange $table.address.address -PivotRows Driver -PivotData @{Points = "SUM"} -PivotTotals None
$cf = Add-ConditionalFormatting -Address $worksheet.cells[$topRow,$columns,$lastDataRow,$columns] -ThreeIconsSet Arrows -Passthru #Test using cells[r1,c1,r2,c2] $cf = Add-ConditionalFormatting -Address $worksheet.cells[$topRow, $columns, $lastDataRow, $columns] -ThreeIconsSet Arrows -Passthru #Test using cells[r1,c1,r2,c2]
$cf.Icon2.Type = $cf.Icon3.Type = "Num" $cf.Icon2.Type = $cf.Icon3.Type = "Num"
$cf.Icon2.Value = 0 $cf.Icon2.Value = 0
$cf.Icon3.Value = 1 $cf.Icon3.Value = 1
Add-ConditionalFormatting -Address $worksheet.cells["FinishPosition"] -RuleType Equal -ConditionValue 1 -ForeGroundColor ([System.Drawing.Color]::Purple) -Bold -Priority 1 -StopIfTrue #Test Priority and stopIfTrue and using range name Add-ConditionalFormatting -Address $worksheet.cells["FinishPosition"] -RuleType Equal -ConditionValue 1 -ForeGroundColor ([System.Drawing.Color]::Purple) -Bold -Priority 1 -StopIfTrue #Test Priority and stopIfTrue and using range name
Add-ConditionalFormatting -Address $worksheet.Cells["GridPosition"] -RuleType ThreeColorScale -Reverse #Test Reverse Add-ConditionalFormatting -Address $worksheet.Cells["GridPosition"] -RuleType ThreeColorScale -Reverse #Test Reverse
$ct = New-ConditionalText -Text "Ferrari" $ct = New-ConditionalText -Text "Ferrari"
$ct2 = New-ConditionalText -Range $worksheet.Names["FinishPosition"].Address -ConditionalType LessThanOrEqual -Text 3 -ConditionalText ([System.Drawing.Color]::Red) -Background ([System.Drawing.Color]::White) #Test new-conditionalText in shortest and longest forms. $ct2 = New-ConditionalText -Range $worksheet.Names["FinishPosition"].Address -ConditionalType LessThanOrEqual -Text 3 -ConditionalText ([System.Drawing.Color]::Red) -Background ([System.Drawing.Color]::White) #Test new-conditionalText in shortest and longest forms.
#Create links for each group name (race) and Export them so they start at Cell A1; create a pivot table with definition just created, save the file and open in Excel #Create links for each group name (race) and Export them so they start at Cell A1; create a pivot table with definition just created, save the file and open in Excel
$results | ForEach-Object {(New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList "Sheet1!$($_.Name)" , "$($_.name) GP")} | #Test Exporting Hyperlinks with display property. $excel = $results | ForEach-Object {(New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList "Sheet1!$($_.Name)" , "$($_.name) GP")} | #Test Exporting Hyperlinks with display property.
Export-Excel -ExcelPackage $excel -AutoSize -PivotTableDefinition $pt -Calculate -ConditionalFormat $ct,$ct2 #Test conditional text rules in conditional format (orignally icon sets only ) Export-Excel -ExcelPackage $excel -AutoSize -PivotTableDefinition $pt -Calculate -ConditionalFormat $ct, $ct2 -PassThru #Test conditional text rules in conditional format (orignally icon sets only )
$null = Add-WorkSheet -ExcelPackage $excel -WorksheetName "Points1"
Add-PivotTable -PivotTableName "Points1" -Address $excel.Points1.Cells["A1"] -ExcelPackage $excel -SourceWorkSheet sheet1 -SourceRange $excel.Sheet1.Tables[0].Address.Address -PivotRows Driver, Date -PivotData @{Points = "SUM"} -GroupDateRow Date -GroupDatePart Years, Months
$null = Add-WorkSheet -ExcelPackage $excel -WorksheetName "Places1"
$newpt = Add-PivotTable -PivotTableName "Places1" -Address $excel.Places1.Cells["A1"] -ExcelPackage $excel -SourceWorkSheet sheet1 -SourceRange $excel.Sheet1.Tables[0].Address.Address -PivotRows Driver, FinishPosition -PivotData @{Date = "Count"} -GroupNumericRow FinishPosition -GroupNumericMin 1 -GroupNumericMax 25 -GroupNumericInterval 3 -PassThru
$newpt.RowFields[0].SubTotalFunctions = [OfficeOpenXml.Table.PivotTable.eSubTotalFunctions]::None
Close-ExcelPackage -ExcelPackage $excel
$excel = Open-ExcelPackage $path $excel = Open-ExcelPackage $path
$sheet = $excel.Workbook.Worksheets[1] $sheet = $excel.Workbook.Worksheets[1]
$m = $results | measure -sum -Property count $m = $results | Measure-Object -sum -Property count
$expectedRows = 1 + $m.count + $m.sum $expectedRows = 1 + $m.count + $m.sum
} }
Context "Creating hyperlinks" { Context "Creating hyperlinks" {
@@ -62,16 +73,16 @@ Describe "Creating small named ranges with hyperlinks" {
} }
Context "Adding calculated column" { Context "Adding calculated column" {
It "Populated the cells with the right heading and formulas " { It "Populated the cells with the right heading and formulas " {
$sheet.Cells[( $results.Count),$columns] | Should benullorEmpty $sheet.Cells[( $results.Count), $columns] | Should benullorEmpty
$sheet.Cells[(1+$results.Count),$columns].Value | Should be "PlacesGained/Lost" $sheet.Cells[(1 + $results.Count), $columns].Value | Should be "PlacesGained/Lost"
$sheet.Cells[(2+$results.Count),$columns].Formula | should be "GridPosition-FinishPosition" $sheet.Cells[(2 + $results.Count), $columns].Formula | should be "GridPosition-FinishPosition"
$sheet.Names["PlacesGained_Lost"] | should not benullorEmpty $sheet.Names["PlacesGained_Lost"] | should not benullorEmpty
} }
It "Performed the calculation " { It "Performed the calculation " {
$placesMade = $Sheet.Cells[(2+$results.Count),5].value - $Sheet.Cells[(2+$results.Count),3].value $placesMade = $Sheet.Cells[(2 + $results.Count), 5].value - $Sheet.Cells[(2 + $results.Count), 3].value
$sheet.Cells[(2+$results.Count),$columns].value | Should be $placesmade $sheet.Cells[(2 + $results.Count), $columns].value | Should be $placesmade
} }
It "Applied ConditionalFormatting, including StopIfTrue, Priority and Reverse " { It "Applied ConditionalFormatting, including StopIfTrue, Priority " {
$sheet.ConditionalFormatting[0].Address.Start.Column | should be $columns $sheet.ConditionalFormatting[0].Address.Start.Column | should be $columns
$sheet.ConditionalFormatting[0].Address.End.Column | should be $columns $sheet.ConditionalFormatting[0].Address.End.Column | should be $columns
$sheet.ConditionalFormatting[0].Address.End.Row | should be $expectedRows $sheet.ConditionalFormatting[0].Address.End.Row | should be $expectedRows
@@ -80,6 +91,9 @@ Describe "Creating small named ranges with hyperlinks" {
$sheet.ConditionalFormatting[0].Icon3.Value | Should be 1 $sheet.ConditionalFormatting[0].Icon3.Value | Should be 1
$sheet.ConditionalFormatting[1].Priority | Should be 1 $sheet.ConditionalFormatting[1].Priority | Should be 1
$sheet.ConditionalFormatting[1].StopIfTrue | Should be $true $sheet.ConditionalFormatting[1].StopIfTrue | Should be $true
}
It "Applied ConditionalFormatting, including Reverse " {
Set-ItResult -Pending -Because "Bug in EPPLus 4.5"
$sheet.ConditionalFormatting[3].LowValue.Color.R | Should begreaterThan 180 $sheet.ConditionalFormatting[3].LowValue.Color.R | Should begreaterThan 180
$sheet.ConditionalFormatting[3].LowValue.Color.G | Should beLessThan 128 $sheet.ConditionalFormatting[3].LowValue.Color.G | Should beLessThan 128
$sheet.ConditionalFormatting[3].HighValue.Color.R | Should beLessThan 128 $sheet.ConditionalFormatting[3].HighValue.Color.R | Should beLessThan 128
@@ -98,4 +112,32 @@ Describe "Creating small named ranges with hyperlinks" {
$sheet.Tables[0].ShowRowStripes | should not be $true $sheet.Tables[0].ShowRowStripes | should not be $true
} }
} }
Context "Adding Pivot tables" {
it "Added a worksheet with a pivot table grouped by date " {
$excel.Points1 | should not beNullOrEmpty
$excel.Points1.PivotTables.Count | should be 1
$pt = $excel.Points1.PivotTables[0]
$pt.RowFields.Count | should be 3
$pt.RowFields[0].name | should be "Driver"
$pt.RowFields[0].Grouping | should benullorEmpty
$pt.RowFields[1].name | should be "years"
$pt.RowFields[1].Grouping | should not benullorEmpty
$pt.RowFields[2].name | should be "date"
$pt.RowFields[2].Grouping | should not benullorEmpty
}
it "Added a worksheet with a pivot table grouped by Number " {
$excel.Places1 | should not beNullOrEmpty
$excel.Places1.PivotTables.Count | should be 1
$pt = $excel.Places1.PivotTables[0]
$pt.RowFields.Count | should be 2
$pt.RowFields[0].name | should be "Driver"
$pt.RowFields[0].Grouping | should benullorEmpty
$pt.RowFields[0].SubTotalFunctions.ToString() | should be "None"
$pt.RowFields[1].name | should be "FinishPosition"
$pt.RowFields[1].Grouping | should not benullorEmpty
$pt.RowFields[1].Grouping.Start | should be 1
$pt.RowFields[1].Grouping.End | should be 25
$pt.RowFields[1].Grouping.Interval | should be 3
}
}
} }

View File

@@ -1,19 +1,19 @@
#Requires -Modules Pester #Requires -Modules Pester
remove-module importExcel -erroraction silentlyContinue if (-not (get-command Import-Excel -ErrorAction SilentlyContinue)) {
Import-Module $PSScriptRoot\..\ImportExcel.psd1 -Force Import-Module $PSScriptRoot\..\ImportExcel.psd1
}
Describe "Check if Function aliases exist" { Describe "Check if Function aliases exist" {
It "Set-Column should exist" { It "Set-Column should exist".PadRight(90) {
${Alias:Set-Column} | Should Not BeNullOrEmpty ${Alias:Set-Column} | Should Not BeNullOrEmpty
} }
It "Set-Row should exist" { It "Set-Row should exist".PadRight(90) {
${Alias:Set-Row} | Should Not BeNullOrEmpty ${Alias:Set-Row} | Should Not BeNullOrEmpty
} }
It "Set-Format should exist" { It "Set-Format should exist".PadRight(90) {
${Alias:Set-Format} | Should Not BeNullOrEmpty ${Alias:Set-Format} | Should Not BeNullOrEmpty
} }
@@ -21,7 +21,7 @@ Describe "Check if Function aliases exist" {
Get-Command Merge-MulipleSheets | Should Not Be $null Get-Command Merge-MulipleSheets | Should Not Be $null
} }
#> #>
It "New-ExcelChart should exist" { It "New-ExcelChart should exist".PadRight(90) {
${Alias:New-ExcelChart} | Should Not BeNullOrEmpty ${Alias:New-ExcelChart} | Should Not BeNullOrEmpty
} }

View File

@@ -0,0 +1,29 @@
$map = @{
1024 = 'AMJ'
2048 = 'BZT'
3072 = 'DND'
4096 = 'FAN'
5120 = 'GNX'
6144 = 'IBH'
7168 = 'JOR'
8192 = 'LCB'
9216 = 'MPL'
10240 = 'OCV'
11264 = 'PQF'
12288 = 'RDP'
13312 = 'SQZ'
14336 = 'UEJ'
15360 = 'VRT'
16384 = 'XFD'
}
(Get-ExcelColumnName 26).columnName | Should be 'Z'
(Get-ExcelColumnName 27).columnName | Should be 'AA'
(Get-ExcelColumnName 28).columnNamee | Should be 'AB'
(Get-ExcelColumnName 30).columnName | Should be 'AD'
(Get-ExcelColumnName 48).columnName | Should be 'AV'
1..16 | ForEach-Object {
$number = $_ * 1024
(Get-ExcelColumnName $number).columnName | Should be $map.$number
}

View File

@@ -1,5 +1,5 @@
Describe "ImportExcel File List" { Describe "ImportExcel File List" {
It "All files should exist" { It "All files should exist".PadRight(90) {
$fileList = Get-Content "$PSScriptRoot\..\filelist.txt" $fileList = Get-Content "$PSScriptRoot\..\filelist.txt"
foreach ($file in $fileList) { foreach ($file in $fileList) {

View File

@@ -1,5 +1,6 @@
Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 if (-not (get-command Import-Excel -ErrorAction SilentlyContinue)) {
Import-Module $PSScriptRoot\..\..\ImportExcel.psd1
}
Describe "Tests" { Describe "Tests" {
BeforeAll { BeforeAll {
$data = $null $data = $null
@@ -8,20 +9,20 @@ Describe "Tests" {
} }
} }
It "Should have two items" { It "Should have two items".PadRight(90) {
$data.count | Should be 2 $data.count | Should be 2
} }
It "Should have items a and b" { It "Should have items a and b".PadRight(90) {
$data[0].p1 | Should be "a" $data[0].p1 | Should be "a"
$data[1].p1 | Should be "b" $data[1].p1 | Should be "b"
} }
It "Should read fast < 2000 milliseconds" { It "Should read fast < 2100 milliseconds".PadRight(90) {
$timer.TotalMilliseconds | should BeLessThan 2000 $timer.TotalMilliseconds | should BeLessThan 2100
} }
It "Should read larger xlsx, 4k rows 1 col < 3000 milliseconds" { It "Should read larger xlsx, 4k rows 1 col < 3000 milliseconds".PadRight(90) {
$timer = Measure-Command { $timer = Measure-Command {
$null = Import-Excel $PSScriptRoot\LargerFile.xlsx $null = Import-Excel $PSScriptRoot\LargerFile.xlsx
} }
@@ -29,4 +30,14 @@ Describe "Tests" {
$timer.TotalMilliseconds | should BeLessThan 3000 $timer.TotalMilliseconds | should BeLessThan 3000
} }
It "Should be able to open, read and close as seperate actions".PadRight(90) {
$timer = Measure-Command {
$excel = Open-ExcelPackage $PSScriptRoot\Simple.xlsx
$data = Import-Excel -ExcelPackage $excel
Close-ExcelPackage -ExcelPackage $excel -NoSave}
$timer.TotalMilliseconds | should BeLessThan 2100
$data.count | Should be 2
$data[0].p1 | Should be "a"
$data[1].p1 | Should be "b"
}
} }

View File

@@ -0,0 +1,111 @@
Describe "Exporting with -Inputobject; table handling, Send SQL Data and import as " {
BeforeAll {
$path = "TestDrive:\Results.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue
. "$PSScriptRoot\Samples\Samples.ps1"
$results = ((Get-Process) + (Get-Process -id $PID)) | Select-Object -last 10 -Property Name, cpu, pm, handles, StartTime
$DataTable = [System.Data.DataTable]::new('Test')
$null = $DataTable.Columns.Add('Name')
$null = $DataTable.Columns.Add('CPU', [double])
$null = $DataTable.Columns.Add('PM', [Long])
$null = $DataTable.Columns.Add('Handles', [Int])
$null = $DataTable.Columns.Add('StartTime', [DateTime])
foreach ($r in $results) {
$null = $DataTable.Rows.Add($r.name, $r.CPU, $R.PM, $r.Handles, $r.StartTime)
}
export-excel -Path $path -InputObject $results -WorksheetName Sheet1 -RangeName "Whole"
export-excel -Path $path -InputObject $DataTable -WorksheetName Sheet2 -AutoNameRange
Send-SQLDataToExcel -path $path -DataTable $DataTable -WorkSheetname Sheet3 -TableName "Data"
$DataTable.Rows.Clear()
Send-SQLDataToExcel -path $path -DataTable $DataTable -WorkSheetname Sheet4 -force -WarningVariable WVOne -WarningAction SilentlyContinue
Send-SQLDataToExcel -path $path -DataTable ([System.Data.DataTable]::new('Test2')) -WorkSheetname Sheet5 -force -WarningVariable wvTwo -WarningAction SilentlyContinue
$excel = Open-ExcelPackage $path
$sheet = $excel.Sheet1
}
Context "Array of processes" {
it "Put the correct rows and columns into the sheet " {
$sheet.Dimension.Rows | should be ($results.Count + 1)
$sheet.Dimension.Columns | should be 5
$sheet.cells["A1"].Value | should be "Name"
$sheet.cells["E1"].Value | should be "StartTime"
$sheet.cells["A3"].Value | should be $results[1].Name
}
it "Created a range for the whole sheet " {
$sheet.Names[0].Name | should be "Whole"
$sheet.Names[0].Start.Address | should be "A1"
$sheet.Names[0].End.row | should be ($results.Count + 1)
$sheet.Names[0].End.Column | should be 5
}
it "Formatted date fields with date type " {
$sheet.Cells["E11"].Style.Numberformat.NumFmtID | should be 22
}
}
$sheet = $excel.Sheet2
Context "Table of processes" {
it "Put the correct rows and columns into the sheet " {
$sheet.Dimension.Rows | should be ($results.Count + 1)
$sheet.Dimension.Columns | should be 5
$sheet.cells["A1"].Value | should be "Name"
$sheet.cells["E1"].Value | should be "StartTime"
$sheet.cells["A3"].Value | should be $results[1].Name
}
it "Created named ranges for each column " {
$sheet.Names.count | should be 5
$sheet.Names[0].Name | should be "Name"
$sheet.Names[1].Start.Address | should be "B2"
$sheet.Names[2].End.row | should be ($results.Count + 1)
$sheet.Names[3].End.Column | should be 4
$sheet.Names[4].Start.Column | should be 5
}
it "Formatted date fields with date type " {
$sheet.Cells["E11"].Style.Numberformat.NumFmtID | should be 22
}
}
$sheet = $excel.Sheet3
Context "Table of processes via Send-SQLDataToExcel" {
it "Put the correct data rows and columns into the sheet " {
$sheet.Dimension.Rows | should be ($results.Count + 1)
$sheet.Dimension.Columns | should be 5
$sheet.cells["A1"].Value | should be "Name"
$sheet.cells["E1"].Value | should be "StartTime"
$sheet.cells["A3"].Value | should be $results[1].Name
}
it "Created a table " {
$sheet.Tables.count | should be 1
$sheet.Tables[0].Name | should be "Data"
$sheet.Tables[0].Columns[4].name | should be "StartTime"
}
it "Formatted date fields with date type " {
$sheet.Cells["E11"].Style.Numberformat.NumFmtID | should be 22
}
}
$Sheet = $excel.Sheet4
Context "Zero-row Data Table sent with Send-SQLDataToExcel -Force" {
it "Raised a warning and put the correct data headers into the sheet " {
$sheet.Dimension.Rows | should be 1
$sheet.Dimension.Columns | should be 5
$sheet.cells["A1"].Value | should be "Name"
$sheet.cells["E1"].Value | should be "StartTime"
$sheet.cells["A3"].Value | should beNullOrEmpty
$wvone | should not beNullOrEmpty
}
}
$Sheet = $excel.Sheet5
Context "Zero-column Data Table handled by Send-SQLDataToExcel -Force" {
it "Put Created a blank Sheet and raised a warning " {
$sheet.Dimension | should beNullOrEmpty
$wvTwo | should not beNullOrEmpty
}
}
Close-ExcelPackage $excel
Context "Import As Text returns text values" {
$x = import-excel $path -WorksheetName sheet3 -AsText StartTime,hand* | Select-Object -last 1
it "Had fields of type string, not date or int, where specified as ASText " {
$x.Handles.GetType().Name | should be "String"
$x.StartTime.GetType().Name | should be "String"
$x.CPU.GetType().Name | should not be "String"
}
}
}

View File

@@ -0,0 +1,26 @@
<#
.SYNOPSIS
Installs PowerShell Core on Windows.
#>
[CmdLetBinding()]
Param
(
# Version to install in the format from the .msi, for example "7.0.0-preview.1"
[Parameter(Mandatory)]
[String]$Version
)
$ErrorActionPreference = 'Stop'
'[Progress] Downloading PowerShell Core.'
$MsiPath = Join-Path $env:TEMP "PowerShell-$Version-win-x64.msi"
[System.Net.WebClient]::new().DownloadFile("https://github.com/PowerShell/PowerShell/releases/download/v$Version/PowerShell-$Version-win-x64.msi", $MsiPath)
'[Progress] Installing PowerShell Core.'
Start-Process 'msiexec.exe' -Wait -ArgumentList "/i $MsiPath /quiet"
Remove-Item -Path $MsiPath
$PowerShellFolder = $Version[0]
if ($Version -like "*preview*") {
$PowerShellFolder += '-preview'
}
$env:Path = "$env:ProgramFiles\PowerShell\$PowerShellFolder;$env:Path"
'[Progress] PowerShell Core Installed.'

View File

@@ -24,7 +24,8 @@ ID,Product,Quantity,Price,Total
Describe "Join Worksheet part 1" { Describe "Join Worksheet part 1" {
BeforeAll { BeforeAll {
$path = "$Env:TEMP\test.xlsx" . "$PSScriptRoot\Samples\Samples.ps1"
$path = "TestDrive:\test.xlsx"
Remove-Item -Path $path -ErrorAction SilentlyContinue Remove-Item -Path $path -ErrorAction SilentlyContinue
$data1 | Export-Excel -Path $path -WorkSheetname Oxford $data1 | Export-Excel -Path $path -WorkSheetname Oxford
$data2 | Export-Excel -Path $path -WorkSheetname Abingdon $data2 | Export-Excel -Path $path -WorkSheetname Abingdon
@@ -50,6 +51,7 @@ Describe "Join Worksheet part 1" {
$excel.Workbook.Worksheets["SummaryPivot"].Hidden | Should be 'Visible' $excel.Workbook.Worksheets["SummaryPivot"].Hidden | Should be 'Visible'
} }
it "Activated the correct worksheet " { it "Activated the correct worksheet " {
Set-ItResult -Pending -Because "Bug in EPPLus 4.5"
$excel.Workbook.worksheets["SummaryPivot"].View.TabSelected | Should be $true $excel.Workbook.worksheets["SummaryPivot"].View.TabSelected | Should be $true
$excel.Workbook.worksheets["Total"].View.TabSelected | Should be $false $excel.Workbook.worksheets["Total"].View.TabSelected | Should be $false
} }
@@ -89,14 +91,14 @@ Describe "Join Worksheet part 1" {
} }
} }
} }
$path = "$env:TEMP\Test.xlsx" $path = "TestDrive:\Test.xlsx"
Remove-item -Path $path -ErrorAction SilentlyContinue Remove-item -Path $path -ErrorAction SilentlyContinue
IF ($PSVersionTable.PSVersion.Major -gt 5) {Write-warning -message "Part 2 Does not run on V6"; return} #switched to CIM objects so test runs on V6
Describe "Join Worksheet part 2" { Describe "Join Worksheet part 2" {
Get-WmiObject -Class win32_logicaldisk | Get-CimInstance -ClassName win32_logicaldisk |
Select-Object -Property DeviceId,VolumeName, Size,Freespace | Select-Object -Property DeviceId,VolumeName, Size,Freespace |
Export-Excel -Path $path -WorkSheetname Volumes -NumberFormat "0,000" Export-Excel -Path $path -WorkSheetname Volumes -NumberFormat "0,000"
Get-NetAdapter | Get-CimInstance -Namespace root/StandardCimv2 -class MSFT_NetAdapter |
Select-Object -Property Name,InterfaceDescription,MacAddress,LinkSpeed | Select-Object -Property Name,InterfaceDescription,MacAddress,LinkSpeed |
Export-Excel -Path $path -WorkSheetname NetAdapters Export-Excel -Path $path -WorkSheetname NetAdapters
@@ -122,6 +124,6 @@ Describe "Join Worksheet part 2" {
$ws.Cells["A$NextRow"].Value | Should be $excel.Workbook.Worksheets[2].Cells["A2"].value $ws.Cells["A$NextRow"].Value | Should be $excel.Workbook.Worksheets[2].Cells["A2"].value
$ws.Cells["B$NextRow"].Value | Should be $excel.Workbook.Worksheets[2].Cells["B2"].value $ws.Cells["B$NextRow"].Value | Should be $excel.Workbook.Worksheets[2].Cells["B2"].value
} }
} }
} }

View File

@@ -1,24 +1,31 @@
Describe "Password Support" { 
Context "Password protected sheet" {
BeforeAll { Describe "Password Support" {
$password = "YouMustRememberThis" if ($PSVersionTable.PSVersion.Major -GT 5) {
$path = "$env:TEMP\Test.xlsx" It "Password Supported" {
Set-ItResult -Pending -Because "Can't test passwords on V6 and later"
}
return
}
Context "Password protected sheet" {
BeforeAll {
$password = "YouMustRememberThis"
$path = "TestDrive:\Test.xlsx"
Remove-Item $path -ErrorAction SilentlyContinue Remove-Item $path -ErrorAction SilentlyContinue
Get-Service | Select-Object -First 10 | Export-excel -password $password -Path $Path -DisplayPropertySet Get-Service | Select-Object -First 10 | Export-excel -password $password -Path $Path -DisplayPropertySet
} }
it "Threw an error when the password was omitted " { it "Threw an error when the password was omitted " {
{Open-ExcelPackage -Path $path } | should throw {Open-ExcelPackage -Path $path } | should throw
} }
it "Was able to append when the password was included " { it "Was able to append when the password was included " {
{Get-Service | Select-Object -First 10 | {Get-Service | Select-Object -First 10 |
Export-excel -password $password -Path $Path -Append } | should not throw Export-excel -password $password -Path $Path -Append } | should not throw
} }
it "Kept the password on the file when it was saved " { it "Kept the password on the file when it was saved " {
{Import-Excel $Path } | should throw {Import-Excel $Path } | should throw
} }
it "Could read the file when the password was included " { it "Could read the file when the password was included " {
(import-excel $path -Password $password).count | should be 20 (import-excel $path -Password $password).count | should be 20
} }
} }
} }

38
__tests__/Path.tests.ps1 Normal file
View File

@@ -0,0 +1,38 @@
Describe "Test reading relative paths" {
BeforeAll {
$script:xlfileName = "TestR.xlsx"
@{data = 1 } | Export-Excel (Join-Path $PWD "TestR.xlsx")
}
AfterAll {
Remove-Item (Join-Path $PWD "$($script:xlfileName)")
}
It "Should read local file".PadRight(90) {
$actual = Import-Excel -Path ".\$($script:xlfileName)"
$actual | Should Not Be $null
$actual.Count | Should Be 1
}
It "Should read with pwd".PadRight(90){
$actual = Import-Excel -Path (Join-Path $PWD "$($script:xlfileName)")
$actual | Should Not Be $null
}
It "Should read with just a file name and resolve to cwd".PadRight(90){
$actual = Import-Excel -Path "$($script:xlfileName)"
$actual | Should Not Be $null
}
It "Should fail for not found".PadRight(90){
{ Import-Excel -Path "ExcelFileDoesNotExist.xlsx" } | Should Throw "'ExcelFileDoesNotExist.xlsx' file not found"
}
It "Should fail for xls extension".PadRight(90){
{ Import-Excel -Path "ExcelFileDoesNotExist.xls" } | Should Throw "Import-Excel does not support reading this extension type .xls"
}
It "Should fail for xlsxs extension".PadRight(90){
{ Import-Excel -Path "ExcelFileDoesNotExist.xlsxs" } | Should Throw "Import-Excel does not support reading this extension type .xlsxs"
}
}

View File

@@ -0,0 +1,36 @@
Describe "Setting worksheet protection " {
BeforeAll {
$path = "TestDrive:\test.xlsx"
Remove-Item -path $path -ErrorAction SilentlyContinue
$excel = ConvertFrom-Csv @"
Product, City, Gross, Net
Apple, London , 300, 250
Orange, London , 400, 350
Banana, London , 300, 200
Orange, Paris, 600, 500
Banana, Paris, 300, 200
Apple, New York, 1200,700
"@ | Export-Excel -Path $path -WorksheetName Sheet1 -PassThru
$ws = $excel.sheet1
Set-WorkSheetProtection -WorkSheet $ws -IsProtected -BlockEditObject -AllowFormatRows -UnLockAddress "1:1"
Close-ExcelPackage -ExcelPackage $excel
$excel = Open-ExcelPackage -Path $path
$ws = $ws = $excel.sheet1
}
it "Turned on protection for the sheet " {
$ws.Protection.IsProtected | should be $true
}
it "Set sheet-wide protection options " {
$ws.Protection.AllowEditObject | should be $false
$ws.Protection.AllowFormatRows | should be $true
$ws.cells["a2"].Style.Locked | should be $true
}
it "Unprotected some cells " {
$ws.cells["a1"].Style.Locked | should be $false
}
}

Some files were not shown because too many files have changed in this diff Show More