mirror of
https://github.com/dfinke/ImportExcel.git
synced 2025-12-23 19:53:58 +00:00
Added Merge-Workshet. Made perf improvements to Import-Excel
This commit is contained in:
@@ -14,6 +14,10 @@ if (Get-Command -Name register-argumentCompleter -ErrorAction SilentlyContinue)
|
|||||||
Register-ArgumentCompleter -CommandName Compare-Worksheet -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
|
Register-ArgumentCompleter -CommandName Compare-Worksheet -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
|
||||||
Register-ArgumentCompleter -CommandName Compare-Worksheet -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
|
Register-ArgumentCompleter -CommandName Compare-Worksheet -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
|
||||||
Register-ArgumentCompleter -CommandName Compare-Worksheet -ParameterName TabColor -ScriptBlock $Function:ColorCompletion
|
Register-ArgumentCompleter -CommandName Compare-Worksheet -ParameterName TabColor -ScriptBlock $Function:ColorCompletion
|
||||||
|
Register-ArgumentCompleter -CommandName Merge-Worksheet -ParameterName AddBackgroundColor -ScriptBlock $Function:ColorCompletion
|
||||||
|
Register-ArgumentCompleter -CommandName Merge-Worksheet -ParameterName ChangeBackgroundColor -ScriptBlock $Function:ColorCompletion
|
||||||
|
Register-ArgumentCompleter -CommandName Merge-Worksheet ` -ParameterName DeleteBackgroundColor -ScriptBlock $Function:ColorCompletion
|
||||||
|
Register-ArgumentCompleter -CommandName Merge-Worksheet -ParameterName KeyFontColor -ScriptBlock $Function:ColorCompletion
|
||||||
Register-ArgumentCompleter -CommandName Set-Format -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
|
Register-ArgumentCompleter -CommandName Set-Format -ParameterName BackgroundColor -ScriptBlock $Function:ColorCompletion
|
||||||
Register-ArgumentCompleter -CommandName Set-Format -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
|
Register-ArgumentCompleter -CommandName Set-Format -ParameterName FontColor -ScriptBlock $Function:ColorCompletion
|
||||||
Register-ArgumentCompleter -CommandName Set-Format -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion
|
Register-ArgumentCompleter -CommandName Set-Format -ParameterName PatternColor -ScriptBlock $Function:ColorCompletion
|
||||||
|
|||||||
555
ImportExcel.psm1
555
ImportExcel.psm1
@@ -1,241 +1,243 @@
|
|||||||
Add-Type -Path "$($PSScriptRoot)\EPPlus.dll"
|
#region import everything we need
|
||||||
|
Add-Type -Path "$($PSScriptRoot)\EPPlus.dll"
|
||||||
. $PSScriptRoot\AddConditionalFormatting.ps1
|
. $PSScriptRoot\AddConditionalFormatting.ps1
|
||||||
. $PSScriptRoot\Charting.ps1
|
. $PSScriptRoot\Charting.ps1
|
||||||
. $PSScriptRoot\ColorCompletion.ps1
|
. $PSScriptRoot\ColorCompletion.ps1
|
||||||
. $PSScriptRoot\ConvertExcelToImageFile.ps1
|
. $PSScriptRoot\ConvertExcelToImageFile.ps1
|
||||||
. $PSScriptRoot\Compare-WorkSheet.ps1
|
. $PSScriptRoot\Compare-WorkSheet.ps1
|
||||||
. $PSScriptRoot\ConvertFromExcelData.ps1
|
. $PSScriptRoot\ConvertFromExcelData.ps1
|
||||||
. $PSScriptRoot\ConvertFromExcelToSQLInsert.ps1
|
. $PSScriptRoot\ConvertFromExcelToSQLInsert.ps1
|
||||||
. $PSScriptRoot\ConvertToExcelXlsx.ps1
|
. $PSScriptRoot\ConvertToExcelXlsx.ps1
|
||||||
. $PSScriptRoot\Copy-ExcelWorkSheet.ps1
|
. $PSScriptRoot\Copy-ExcelWorkSheet.ps1
|
||||||
. $PSScriptRoot\Export-Excel.ps1
|
. $PSScriptRoot\Export-Excel.ps1
|
||||||
. $PSScriptRoot\Export-ExcelSheet.ps1
|
. $PSScriptRoot\Export-ExcelSheet.ps1
|
||||||
. $PSScriptRoot\Get-ExcelColumnName.ps1
|
. $PSScriptRoot\Get-ExcelColumnName.ps1
|
||||||
. $PSScriptRoot\Get-ExcelSheetInfo.ps1
|
. $PSScriptRoot\Get-ExcelSheetInfo.ps1
|
||||||
. $PSScriptRoot\Get-ExcelWorkbookInfo.ps1
|
. $PSScriptRoot\Get-ExcelWorkbookInfo.ps1
|
||||||
. $PSScriptRoot\Get-HtmlTable.ps1
|
. $PSScriptRoot\Get-HtmlTable.ps1
|
||||||
. $PSScriptRoot\Get-Range.ps1
|
. $PSScriptRoot\Get-Range.ps1
|
||||||
. $PSScriptRoot\Get-XYRange.ps1
|
. $PSScriptRoot\Get-XYRange.ps1
|
||||||
. $PSScriptRoot\Import-Html.ps1
|
. $PSScriptRoot\Import-Html.ps1
|
||||||
. $PSScriptRoot\InferData.ps1
|
. $PSScriptRoot\InferData.ps1
|
||||||
. $PSScriptRoot\Invoke-Sum.ps1
|
. $PSScriptRoot\Invoke-Sum.ps1
|
||||||
. $PSScriptRoot\New-ConditionalFormattingIconSet.ps1
|
. $PSScriptRoot\Merge-Worksheet.ps1
|
||||||
. $PSScriptRoot\New-ConditionalText.ps1
|
. $PSScriptRoot\New-ConditionalFormattingIconSet.ps1
|
||||||
. $PSScriptRoot\New-ExcelChart.ps1
|
. $PSScriptRoot\New-ConditionalText.ps1
|
||||||
. $PSScriptRoot\New-PSItem.ps1
|
. $PSScriptRoot\New-ExcelChart.ps1
|
||||||
. $PSScriptRoot\Open-ExcelPackage.ps1
|
. $PSScriptRoot\New-PSItem.ps1
|
||||||
. $PSScriptRoot\Pivot.ps1
|
. $PSScriptRoot\Open-ExcelPackage.ps1
|
||||||
. $PSScriptRoot\Send-SQLDataToExcel.ps1
|
. $PSScriptRoot\Pivot.ps1
|
||||||
. $PSScriptRoot\Set-CellStyle.ps1
|
. $PSScriptRoot\Send-SQLDataToExcel.ps1
|
||||||
. $PSScriptRoot\Set-Column.ps1
|
. $PSScriptRoot\Set-CellStyle.ps1
|
||||||
. $PSScriptRoot\Set-Row.ps1
|
. $PSScriptRoot\Set-Column.ps1
|
||||||
. $PSScriptRoot\SetFormat.ps1
|
. $PSScriptRoot\Set-Row.ps1
|
||||||
. $PSScriptRoot\TrackingUtils.ps1
|
. $PSScriptRoot\SetFormat.ps1
|
||||||
. $PSScriptRoot\Update-FirstObjectProperties.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()
|
Param()
|
||||||
|
|
||||||
|
[PSPlot]::new()
|
||||||
|
}
|
||||||
|
|
||||||
[PSPlot]::new()
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
}
|
Write-Warning 'PowerShell 5 is required for plot.ps1'
|
||||||
else {
|
Write-Warning 'PowerShell Excel is ready, except for that functionality'
|
||||||
Write-Warning 'PowerShell 5 is required for plot.ps1'
|
}
|
||||||
Write-Warning 'PowerShell Excel is ready, except for that functionality'
|
#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.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
The Import-Excel cmdlet creates custom objects from the rows in an Excel worksheet. Each row represents one object. All of this is possible without installing Microsoft Excel and by using the .NET library ‘EPPLus.dll’.
|
The Import-Excel cmdlet creates custom objects from the rows in an Excel worksheet. Each row represents one object. All of this is possible without installing Microsoft Excel and by using the .NET library ‘EPPLus.dll’.
|
||||||
|
|
||||||
By default, the property names of the objects are retrieved from the column headers. Because an object cannot have a blanc property name, only columns with column headers will be imported.
|
By default, the property names of the objects are retrieved from the column headers. Because an object cannot have a blanc property name, only columns with column headers will be imported.
|
||||||
|
|
||||||
If the default behavior is not desired and you want to import the complete worksheet ‘as is’, the parameter ‘-NoHeader’ can be used. In case you want to provide your own property names, you can use the parameter ‘-HeaderName’.
|
If the default behavior is not desired and you want to import the complete worksheet ‘as is’, the parameter ‘-NoHeader’ can be used. In case you want to provide your own property names, you can use the parameter ‘-HeaderName’.
|
||||||
|
|
||||||
.PARAMETER Path
|
.PARAMETER Path
|
||||||
Specifies the path to the Excel file.
|
Specifies the path to the Excel file.
|
||||||
|
|
||||||
.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.
|
||||||
|
|
||||||
.PARAMETER DataOnly
|
.PARAMETER DataOnly
|
||||||
Import only rows and columns that contain data, empty rows and empty columns are not imported.
|
Import only rows and columns that contain data, empty rows and empty columns are not imported.
|
||||||
|
|
||||||
.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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
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 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.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Import data from an Excel worksheet. One object is created for each row. The property names of the objects consist of the column names defined in the first row. In case a column doesn’t have a column header (usually in row 1 when ‘-StartRow’ is not used), then the unnamed columns will be skipped and the data in those columns will not be imported.
|
||||||
|
|
||||||
|
----------------------------------------------
|
||||||
|
| File: Movies.xlsx - Sheet: Actors |
|
||||||
|
----------------------------------------------
|
||||||
|
| A B C |
|
||||||
|
|1 First Name Address |
|
||||||
|
|2 Chuck Norris California |
|
||||||
|
|3 Jean-Claude Vandamme Brussels |
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Actors
|
||||||
|
|
||||||
|
First Name: Chuck
|
||||||
|
Address : California
|
||||||
|
|
||||||
|
First Name: Jean-Claude
|
||||||
|
Address : Brussels
|
||||||
|
|
||||||
|
Notice that column 'B' is not imported because there's no value in cell 'B1' that can be used as property name for the objects.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Import the complete Excel worksheet ‘as is’ by using the ‘-NoHeader’ switch. One object is created for each row. The property names of the objects will be automatically generated (P1, P2, P3, ..).
|
||||||
|
|
||||||
|
----------------------------------------------
|
||||||
|
| File: Movies.xlsx - Sheet: Actors |
|
||||||
|
----------------------------------------------
|
||||||
|
| A B C |
|
||||||
|
|1 First Name Address |
|
||||||
|
|2 Chuck Norris California |
|
||||||
|
|3 Jean-Claude Vandamme Brussels |
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Actors -NoHeader
|
||||||
|
|
||||||
|
P1: First Name
|
||||||
|
P2:
|
||||||
|
P3: Address
|
||||||
|
|
||||||
|
P1: Chuck
|
||||||
|
P2: Norris
|
||||||
|
P3: California
|
||||||
|
|
||||||
|
P1: Jean-Claude
|
||||||
|
P2: Vandamme
|
||||||
|
P3: Brussels
|
||||||
|
|
||||||
|
Notice that the column header (row 1) is imported as an object too.
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Import data from an Excel worksheet. One object is created for each row. The property names of the objects consist of the column names defined in the first row. In case a column doesn’t have a column header (usually in row 1 when ‘-StartRow’ is not used), then the unnamed columns will be skipped and the data in those columns will not be imported.
|
Import data from an Excel worksheet. One object is created for each row. The property names of the objects consist of the names defined in the parameter ‘-HeaderName’. The properties are named starting from the most left column (A) to the right. In case no value is present in one of the columns, that property will have an empty value.
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------------------
|
||||||
| File: Movies.xlsx - Sheet: Actors |
|
| File: Movies.xlsx - Sheet: Movies |
|
||||||
----------------------------------------------
|
----------------------------------------------------------
|
||||||
| A B C |
|
| A B C D |
|
||||||
|1 First Name Address |
|
|1 The Bodyguard 1992 9 |
|
||||||
|2 Chuck Norris California |
|
|2 The Matrix 1999 8 |
|
||||||
|3 Jean-Claude Vandamme Brussels |
|
|3 |
|
||||||
----------------------------------------------
|
|4 Skyfall 2012 9 |
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Actors
|
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Movies -HeaderName 'Movie name', 'Year', 'Rating', 'Genre'
|
||||||
|
|
||||||
First Name: Chuck
|
Movie name: The Bodyguard
|
||||||
Address : California
|
Year : 1992
|
||||||
|
Rating : 9
|
||||||
|
Genre :
|
||||||
|
|
||||||
First Name: Jean-Claude
|
Movie name: The Matrix
|
||||||
Address : Brussels
|
Year : 1999
|
||||||
|
Rating : 8
|
||||||
|
Genre :
|
||||||
|
|
||||||
Notice that column 'B' is not imported because there's no value in cell 'B1' that can be used as property name for the objects.
|
Movie name:
|
||||||
|
Year :
|
||||||
|
Rating :
|
||||||
|
Genre :
|
||||||
|
|
||||||
|
Movie name: Skyfall
|
||||||
|
Year : 2012
|
||||||
|
Rating : 9
|
||||||
|
Genre :
|
||||||
|
|
||||||
|
Notice that empty rows are imported and that data for the property 'Genre' is not present in the worksheet. As such, the 'Genre' property will be blanc for all objects.
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Import the complete Excel worksheet ‘as is’ by using the ‘-NoHeader’ switch. One object is created for each row. The property names of the objects will be automatically generated (P1, P2, P3, ..).
|
Import data from an Excel worksheet. One object is created for each row. The property names of the objects are automatically generated by using the switch ‘-NoHeader’ (P1, P@, P#, ..). The switch ‘-DataOnly’ will speed up the import because empty rows and empty columns are not imported.
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------------------
|
||||||
| File: Movies.xlsx - Sheet: Actors |
|
| File: Movies.xlsx - Sheet: Movies |
|
||||||
----------------------------------------------
|
----------------------------------------------------------
|
||||||
| A B C |
|
| A B C D |
|
||||||
|1 First Name Address |
|
|1 The Bodyguard 1992 9 |
|
||||||
|2 Chuck Norris California |
|
|2 The Matrix 1999 8 |
|
||||||
|3 Jean-Claude Vandamme Brussels |
|
|3 |
|
||||||
----------------------------------------------
|
|4 Skyfall 2012 9 |
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Actors -NoHeader
|
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Movies –NoHeader -DataOnly
|
||||||
|
|
||||||
P1: First Name
|
P1: The Bodyguard
|
||||||
P2:
|
P2: 1992
|
||||||
P3: Address
|
P3: 9
|
||||||
|
|
||||||
P1: Chuck
|
P1: The Matrix
|
||||||
P2: Norris
|
P2: 1999
|
||||||
P3: California
|
P3: 8
|
||||||
|
|
||||||
P1: Jean-Claude
|
P1: Skyfall
|
||||||
P2: Vandamme
|
P2: 2012
|
||||||
P3: Brussels
|
P3: 9
|
||||||
|
|
||||||
Notice that the column header (row 1) is imported as an object too.
|
Notice that empty rows and empty columns are not imported.
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Import data from an Excel worksheet. One object is created for each row. The property names of the objects consist of the names defined in the parameter ‘-HeaderName’. The properties are named starting from the most left column (A) to the right. In case no value is present in one of the columns, that property will have an empty value.
|
Import data from an Excel worksheet. One object is created for each row. The property names are provided with the ‘-HeaderName’ parameter. The import will start from row 2 and empty columns and rows are not imported.
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
| File: Movies.xlsx - Sheet: Movies |
|
| File: Movies.xlsx - Sheet: Actors |
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
| A B C D |
|
| A B C D |
|
||||||
|1 The Bodyguard 1992 9 |
|
|1 Chuck Norris California |
|
||||||
|2 The Matrix 1999 8 |
|
|2 |
|
||||||
|3 |
|
|3 Jean-Claude Vandamme Brussels |
|
||||||
|4 Skyfall 2012 9 |
|
----------------------------------------------------------
|
||||||
----------------------------------------------------------
|
|
||||||
|
|
||||||
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Movies -HeaderName 'Movie name', 'Year', 'Rating', 'Genre'
|
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Actors -DataOnly -HeaderName 'FirstName', 'SecondName', 'City' –StartRow 2
|
||||||
|
|
||||||
Movie name: The Bodyguard
|
FirstName : Jean-Claude
|
||||||
Year : 1992
|
SecondName: Vandamme
|
||||||
Rating : 9
|
City : Brussels
|
||||||
Genre :
|
|
||||||
|
|
||||||
Movie name: The Matrix
|
Notice that only 1 object is imported with only 3 properties. Column B and row 2 are empty and have been disregarded by using the switch '-DataOnly'. The property names have been named with the values provided with the parameter '-HeaderName'. Row number 1 with ‘Chuck Norris’ has not been imported, because we started the import from row 2 with the parameter ‘-StartRow 2’.
|
||||||
Year : 1999
|
|
||||||
Rating : 8
|
|
||||||
Genre :
|
|
||||||
|
|
||||||
Movie name:
|
.LINK
|
||||||
Year :
|
https://github.com/dfinke/ImportExcel
|
||||||
Rating :
|
|
||||||
Genre :
|
|
||||||
|
|
||||||
Movie name: Skyfall
|
.NOTES
|
||||||
Year : 2012
|
#>
|
||||||
Rating : 9
|
|
||||||
Genre :
|
|
||||||
|
|
||||||
Notice that empty rows are imported and that data for the property 'Genre' is not present in the worksheet. As such, the 'Genre' property will be blanc for all objects.
|
|
||||||
|
|
||||||
.EXAMPLE
|
|
||||||
Import data from an Excel worksheet. One object is created for each row. The property names of the objects are automatically generated by using the switch ‘-NoHeader’ (P1, P@, P#, ..). The switch ‘-DataOnly’ will speed up the import because empty rows and empty columns are not imported.
|
|
||||||
|
|
||||||
----------------------------------------------------------
|
|
||||||
| File: Movies.xlsx - Sheet: Movies |
|
|
||||||
----------------------------------------------------------
|
|
||||||
| A B C D |
|
|
||||||
|1 The Bodyguard 1992 9 |
|
|
||||||
|2 The Matrix 1999 8 |
|
|
||||||
|3 |
|
|
||||||
|4 Skyfall 2012 9 |
|
|
||||||
----------------------------------------------------------
|
|
||||||
|
|
||||||
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Movies –NoHeader -DataOnly
|
|
||||||
|
|
||||||
P1: The Bodyguard
|
|
||||||
P2: 1992
|
|
||||||
P3: 9
|
|
||||||
|
|
||||||
P1: The Matrix
|
|
||||||
P2: 1999
|
|
||||||
P3: 8
|
|
||||||
|
|
||||||
P1: Skyfall
|
|
||||||
P2: 2012
|
|
||||||
P3: 9
|
|
||||||
|
|
||||||
Notice that empty rows and empty columns are not imported.
|
|
||||||
|
|
||||||
.EXAMPLE
|
|
||||||
Import data from an Excel worksheet. One object is created for each row. The property names are provided with the ‘-HeaderName’ parameter. The import will start from row 2 and empty columns and rows are not imported.
|
|
||||||
|
|
||||||
----------------------------------------------------------
|
|
||||||
| File: Movies.xlsx - Sheet: Actors |
|
|
||||||
----------------------------------------------------------
|
|
||||||
| A B C D |
|
|
||||||
|1 Chuck Norris California |
|
|
||||||
|2 |
|
|
||||||
|3 Jean-Claude Vandamme Brussels |
|
|
||||||
----------------------------------------------------------
|
|
||||||
|
|
||||||
PS C:\> Import-Excel -Path 'C:\Movies.xlsx' -WorkSheetname Actors -DataOnly -HeaderName 'FirstName', 'SecondName', 'City' –StartRow 2
|
|
||||||
|
|
||||||
FirstName : Jean-Claude
|
|
||||||
SecondName: Vandamme
|
|
||||||
City : Brussels
|
|
||||||
|
|
||||||
Notice that only 1 object is imported with only 3 properties. Column B and row 2 are empty and have been disregarded by using the switch '-DataOnly'. The property names have been named with the values provided with the parameter '-HeaderName'. Row number 1 with ‘Chuck Norris’ has not been imported, because we started the import from row 2 with the parameter ‘-StartRow 2’.
|
|
||||||
|
|
||||||
.LINK
|
|
||||||
https://github.com/dfinke/ImportExcel
|
|
||||||
|
|
||||||
.NOTES
|
|
||||||
#>
|
|
||||||
|
|
||||||
[CmdLetBinding(DefaultParameterSetName)]
|
[CmdLetBinding(DefaultParameterSetName)]
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")]
|
||||||
Param (
|
Param (
|
||||||
[Alias('FullName')]
|
[Alias('FullName')]
|
||||||
[Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Position=0, Mandatory)]
|
[Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Position=0, Mandatory)]
|
||||||
@@ -251,34 +253,13 @@ Function Import-Excel {
|
|||||||
[Switch]$NoHeader,
|
[Switch]$NoHeader,
|
||||||
[Alias('HeaderRow','TopRow')]
|
[Alias('HeaderRow','TopRow')]
|
||||||
[ValidateRange(1, 9999)]
|
[ValidateRange(1, 9999)]
|
||||||
[Int]$StartRow,
|
[Int]$StartRow = 1,
|
||||||
[Switch]$DataOnly,
|
[Switch]$DataOnly,
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[String]$Password
|
[String]$Password
|
||||||
)
|
)
|
||||||
|
|
||||||
Begin {
|
Begin {
|
||||||
Function Add-Property {
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Add the property name and value to the hashtable that will create a new object for each row.
|
|
||||||
#>
|
|
||||||
|
|
||||||
Param (
|
|
||||||
[Parameter(Mandatory)]
|
|
||||||
[String]$Name,
|
|
||||||
$Value
|
|
||||||
)
|
|
||||||
|
|
||||||
Try {
|
|
||||||
$NewRow.$Name = $Value
|
|
||||||
Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$Name' and value '$Value'"
|
|
||||||
}
|
|
||||||
Catch {
|
|
||||||
throw "Failed adding the property name '$Name' with value '$Value': $_"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Function Get-PropertyNames {
|
Function Get-PropertyNames {
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
@@ -313,7 +294,7 @@ Function Import-Excel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($C in $Columns) {
|
foreach ($C in $Columns) {
|
||||||
$Worksheet.Cells[$StartRow,$C] | where {$_.Value} | Select-Object @{N='Column'; E={$C}}, Value
|
$Worksheet.Cells[$StartRow,$C] | Where-Object {$_.Value} | Select-Object @{N='Column'; E={$C}}, Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,24 +309,24 @@ Function Import-Excel {
|
|||||||
#region Open file
|
#region Open file
|
||||||
$Path = (Resolve-Path $Path).ProviderPath
|
$Path = (Resolve-Path $Path).ProviderPath
|
||||||
Write-Verbose "Import Excel workbook '$Path' with worksheet '$Worksheetname'"
|
Write-Verbose "Import Excel workbook '$Path' with worksheet '$Worksheetname'"
|
||||||
|
|
||||||
$Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite'
|
$Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite'
|
||||||
|
|
||||||
if ($Password) {
|
if ($Password) {
|
||||||
$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage
|
$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage
|
||||||
|
|
||||||
Try {
|
Try {
|
||||||
$Excel.Load($Stream,$Password)
|
$Excel.Load($Stream,$Password)
|
||||||
}
|
}
|
||||||
Catch {
|
Catch {
|
||||||
throw "Password '$Password' is not correct."
|
throw "Password '$Password' is not correct."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream
|
$Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Select worksheet
|
#region Select worksheet
|
||||||
if ($WorksheetName) {
|
if ($WorksheetName) {
|
||||||
if (-not ($Worksheet = $Excel.Workbook.Worksheets[$WorkSheetName])) {
|
if (-not ($Worksheet = $Excel.Workbook.Worksheets[$WorkSheetName])) {
|
||||||
@@ -356,74 +337,59 @@ Function Import-Excel {
|
|||||||
$Worksheet = $Excel.Workbook.Worksheets | Select-Object -First 1
|
$Worksheet = $Excel.Workbook.Worksheets | Select-Object -First 1
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
Write-Debug $sw.Elapsed.TotalMilliseconds
|
||||||
#region Set the top row
|
#region Get rows and columns
|
||||||
if (((-not ($NoHeader -or $HeaderName)) -and ($StartRow -eq 0))) {
|
#If we are doing dataonly it is quicker to work out which rows to ignore before processing the cells.
|
||||||
$StartRow = 1
|
if ($DataOnly) {
|
||||||
}
|
#If we are using headers startrow will be the headerrow so examine data from startRow + 1,
|
||||||
#endregion
|
if ($NoHeader) {$range = "A" + ($StartRow ) + ":" + $Worksheet.Dimension.End.Address }
|
||||||
|
else {$range = "A" + ($StartRow + 1 ) + ":" + $Worksheet.Dimension.End.Address }
|
||||||
if (-not ($AllCells = $Worksheet.Cells | where {($_.Start.Row -ge $StartRow)})) {
|
#We're going to look at every cell and build 2 hash tables holding rows & columns which contain data.
|
||||||
Write-Warning "Worksheet '$WorksheetName' in workbook '$Path' is empty after StartRow '$StartRow'"
|
#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,
|
||||||
|
#using Hash tables: "we've seen it" is all we need, no need to worry about "seen it before" / "Seen it many times"
|
||||||
|
$colHash = @{}
|
||||||
|
$rowHash = @{}
|
||||||
|
foreach ($cell in $Worksheet.Cells[$range]) {
|
||||||
|
if ($cell.Value -ne $null) {$colHash[$cell.Start.Column]=1; $rowHash[$cell.Start.row]=1 }
|
||||||
|
}
|
||||||
|
$rows = ($StartRow..($Worksheet.Dimension.End.Row)).Where({$rowHash[$_]})
|
||||||
|
$columns = (1..($Worksheet.Dimension.End.Column) ).Where({$colHash[$_]})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#region Get rows and columns
|
$Columns = ($Worksheet.Dimension.Start.Column)..($Worksheet.Dimension.End.Column)
|
||||||
if ($DataOnly) {
|
if ($NoHeader) {$Rows = ( $StartRow)..($Worksheet.Dimension.End.Row) }
|
||||||
$CellsWithValues = $AllCells | where {$_.Value}
|
else {$Rows = (1 + $StartRow)..($Worksheet.Dimension.End.Row) }
|
||||||
|
|
||||||
$Columns = $CellsWithValues.Start.Column | Sort-Object -Unique
|
|
||||||
$Rows = $CellsWithValues.Start.Row | Sort-Object -Unique
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$LastColumn = $AllCells.Start.Column | Sort-Object -Unique | Select-Object -Last 1
|
|
||||||
$Columns = 1..$LastColumn
|
|
||||||
|
|
||||||
$LastRow = $AllCells.Start.Row | Sort-Object -Unique | Select-Object -Last 1
|
|
||||||
$Rows = $StartRow..$LastRow | where {($_ -ge $StartRow) -and ($_ -gt 0)}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Create property names
|
|
||||||
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."
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Duplicates = $PropertyNames | Group-Object Value | where 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."
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Filter out rows with data in columns that don't have a column header
|
|
||||||
if ($DataOnly -and (-not $NoHeader)) {
|
|
||||||
$Rows = $CellsWithValues.Start | where {$PropertyNames.Column -contains $_.Column} |
|
|
||||||
Sort-Object Row -Unique | Select-Object -ExpandProperty Row
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Filter out the top row when it contains column headers
|
|
||||||
if (-not ($NoHeader -or $HeaderName)) {
|
|
||||||
$Rows = $Rows | where {$_ -gt $StartRow}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
if (-not $Rows) {
|
|
||||||
Write-Warning "Worksheet '$WorksheetName' in workbook '$Path' contains no data in the rows after top row '$StartRow'"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#region Create one object per row
|
|
||||||
foreach ($R in $Rows) {
|
|
||||||
Write-Verbose "Import row '$R'"
|
|
||||||
$NewRow = [Ordered]@{}
|
|
||||||
|
|
||||||
foreach ($P in $PropertyNames) {
|
|
||||||
Add-Property -Name $P.Value -Value $Worksheet.Cells[$R, $P.Column].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
[PSCustomObject]$NewRow
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
#region Create property names
|
||||||
|
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."
|
||||||
|
}
|
||||||
|
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."
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
Write-Debug $sw.Elapsed.TotalMilliseconds
|
||||||
|
if (-not $Rows) {
|
||||||
|
Write-Warning "Worksheet '$WorksheetName' in workbook '$Path' contains no data in the rows after top row '$StartRow'"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#region Create one object per row
|
||||||
|
foreach ($R in $Rows) {
|
||||||
|
Write-Verbose "Import row '$R'"
|
||||||
|
$NewRow = [Ordered]@{}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
Write-Debug $sw.Elapsed.TotalMilliseconds
|
||||||
}
|
}
|
||||||
Catch {
|
Catch {
|
||||||
throw "Failed importing the Excel workbook '$Path' with worksheet '$Worksheetname': $_"
|
throw "Failed importing the Excel workbook '$Path' with worksheet '$Worksheetname': $_"
|
||||||
@@ -499,7 +465,7 @@ function ConvertFrom-ExcelSheet {
|
|||||||
$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 {$_.Name -like $SheetName}
|
$targetSheets = $workbook.Worksheets | Where-Object {$_.Name -like $SheetName}
|
||||||
|
|
||||||
$params = @{} + $PSBoundParameters
|
$params = @{} + $PSBoundParameters
|
||||||
$params.Remove("OutputPath")
|
$params.Remove("OutputPath")
|
||||||
@@ -518,10 +484,11 @@ function ConvertFrom-ExcelSheet {
|
|||||||
|
|
||||||
$stream.Close()
|
$stream.Close()
|
||||||
$stream.Dispose()
|
$stream.Dispose()
|
||||||
$xl.Dispose()
|
$xl.Dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
function Export-MultipleExcelSheets {
|
function Export-MultipleExcelSheets {
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")]
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory=$true)]
|
[Parameter(Mandatory=$true)]
|
||||||
$Path,
|
$Path,
|
||||||
|
|||||||
213
merge-worksheet.ps1
Normal file
213
merge-worksheet.ps1
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
Function Merge-Worksheet {
|
||||||
|
<#
|
||||||
|
.Synopsis
|
||||||
|
Merges two worksheets (or other objects) into a single worksheet with differences marked up.
|
||||||
|
.Description
|
||||||
|
The Compare-Worksheet command takes two worksheets and marks differences in the source document, and optionally outputs a grid showing the changes.
|
||||||
|
By contrast the Merge-Worksheet command takes the worksheets and combines them into a single sheet showing the old and new data side by side .
|
||||||
|
Although it is designed to work with Excel data it can work with arrays of any kind of object; so it can be a merge *of* worksheets, or a merge *to* worksheet.
|
||||||
|
.Example
|
||||||
|
merge-worksheet "Server54.xlsx" "Server55.xlsx" -WorkSheetName services -OutputFile Services.xlsx -OutputSheetName 54-55 -show
|
||||||
|
The workbooks contain audit information for two servers, one page contains a list of services. This command creates a worksheet named 54-55
|
||||||
|
in a workbook named services and shows all the services and their differences, and opens it in Excel
|
||||||
|
.Example
|
||||||
|
merge-worksheet "Server54.xlsx" "Server55.xlsx" -WorkSheetName services -OutputFile Services.xlsx -OutputSheetName 54-55 -HideEqual -AddBackgroundColor LightBlue -show
|
||||||
|
This modifies the previous command to hide the equal rows in the output sheet and changes the color used to mark rows "Added" to the second file.
|
||||||
|
.Example
|
||||||
|
merge-worksheet -OutputFile .\j1.xlsx -OutputSheetName test11 -ReferenceObject (dir .\ImportExcel\4.0.7) -DifferenceObject (dir '\ImportExcel\4.0.8') -Property Length -Show
|
||||||
|
This version compares two directories, and marks what has changed.
|
||||||
|
Because no "Key" property is given, "Name" is assumed to be the key and the only other property examined is length.
|
||||||
|
Files which are added or deleted or have changedd size will be highlighed in the output sheet. Changes to dates or other attributes will be ignored
|
||||||
|
.Example
|
||||||
|
merge-worksheet -Outf .\dummy.xlsx -RefO (dir .\ImportExcel\4.0.7) -DiffO (dir .\ImportExcel\4.0.8') -Pr Length -WhatIf -Passthru | Out-GridView
|
||||||
|
This time no file is written because -WhatIf is specified, and -Passthru causes the results to go Out-Gridview. This version uses aliases to shorten the parameters,
|
||||||
|
(OutputFileName can be "outFile" and the sheet "OutSheet" : DifferenceObject & RefeenceObject can be DiffObject & RefObject)
|
||||||
|
#>
|
||||||
|
[cmdletbinding(SupportsShouldProcess=$true)]
|
||||||
|
Param(
|
||||||
|
#First Excel file to compare. You can compare two Excel files or two other objects but not one of each.
|
||||||
|
[parameter(ParameterSetName='A',Mandatory=$true,Position=0)]
|
||||||
|
[parameter(ParameterSetName='B',Mandatory=$true,Position=0)]
|
||||||
|
[parameter(ParameterSetName='C',Mandatory=$true,Position=0)]
|
||||||
|
$Referencefile ,
|
||||||
|
|
||||||
|
#Second Excel file to compare.
|
||||||
|
[parameter(ParameterSetName='A',Mandatory=$true,Position=1)]
|
||||||
|
[parameter(ParameterSetName='B',Mandatory=$true,Position=1)]
|
||||||
|
[parameter(ParameterSetName='C',Mandatory=$true,Position=1)]
|
||||||
|
$Differencefile ,
|
||||||
|
|
||||||
|
#Name(s) of worksheets to compare,
|
||||||
|
[parameter(ParameterSetName='A',Position=2)]
|
||||||
|
[parameter(ParameterSetName='B',Position=2)]
|
||||||
|
[parameter(ParameterSetName='C',Position=2)]
|
||||||
|
$WorkSheetName = "Sheet1",
|
||||||
|
|
||||||
|
#The row from where we start to import data, all rows above the StartRow are disregarded. By default this is the first row.
|
||||||
|
[parameter(ParameterSetName='A')]
|
||||||
|
[parameter(ParameterSetName='B')]
|
||||||
|
[parameter(ParameterSetName='C')]
|
||||||
|
[int]$Startrow = 1,
|
||||||
|
|
||||||
|
#Specifies custom property names to use, instead of the values defined in the column headers of the TopRow.
|
||||||
|
[Parameter(ParameterSetName='B',Mandatory=$true)]
|
||||||
|
[String[]]$Headername,
|
||||||
|
|
||||||
|
#Automatically generate property names (P1, P2, P3, ..) instead of the using the values the top row of the sheet.
|
||||||
|
[Parameter(ParameterSetName='C',Mandatory=$true)]
|
||||||
|
[switch]$NoHeader,
|
||||||
|
|
||||||
|
[parameter(ParameterSetName='D',Mandatory=$true)]
|
||||||
|
[Alias('RefObject')]
|
||||||
|
$ReferenceObject ,
|
||||||
|
[parameter(ParameterSetName='D',Mandatory=$true)]
|
||||||
|
[Alias('DiffObject')]
|
||||||
|
$DifferenceObject ,
|
||||||
|
|
||||||
|
#File to hold merged data.
|
||||||
|
[parameter(Mandatory=$true,Position=3)]
|
||||||
|
[Alias('OutFile')]
|
||||||
|
$OutputFile ,
|
||||||
|
#Name of worksheet to output - if none specified will use the reference worksheet name.
|
||||||
|
[Alias('OutSheet')]
|
||||||
|
$OutputSheetName = "Sheet1",
|
||||||
|
#Properties to include in the DIFF - supports wildcards, default is "*".
|
||||||
|
$Property = "*" ,
|
||||||
|
#Properties to exclude from the the search - supports wildcards.
|
||||||
|
$ExcludeProperty ,
|
||||||
|
#Name of a column which is unique used to pair up rows from the refence and difference side, default is "Name".
|
||||||
|
$Key = "Name" ,
|
||||||
|
#Sets the font color for the "key" field; this means you can filter by color to get only changed rows.
|
||||||
|
[System.Drawing.Color]$KeyFontColor = "DarkRed",
|
||||||
|
#Sets the background color for changed rows.
|
||||||
|
[System.Drawing.Color]$ChangeBackgroundColor = "Orange",
|
||||||
|
#Sets the background color for rows in the reference but deleted from the difference sheet.
|
||||||
|
[System.Drawing.Color]$DeleteBackgroundColor = "LightPink",
|
||||||
|
#Sets the background color for rows not in the reference but added to the difference sheet.
|
||||||
|
[System.Drawing.Color]$AddBackgroundColor = "PaleGreen",
|
||||||
|
#if Specified hides the rows in the spreadsheet that are equal and only shows changes, added or deleted rows.
|
||||||
|
[switch]$HideEqual ,
|
||||||
|
#If specified outputs the data to the pipeline (you can add -whatif so it the command only outputs to the command)
|
||||||
|
[switch]$Passthru ,
|
||||||
|
#If specified, opens the output workbook.
|
||||||
|
[Switch]$Show
|
||||||
|
)
|
||||||
|
|
||||||
|
#region Read Excel data
|
||||||
|
if ($Referencefile -and $Differencefile) {
|
||||||
|
#if the filenames don't resolve, give up now.
|
||||||
|
try { $oneFile = ((Resolve-Path -Path $Referencefile -ErrorAction Stop).path -eq (Resolve-Path -Path $Differencefile -ErrorAction Stop).path)}
|
||||||
|
Catch { Write-Warning -Message "Could not Resolve the filenames." ; return }
|
||||||
|
|
||||||
|
#If we have one file , we must have two different worksheet names. If we have two files worksheet can be a single string or two strings.
|
||||||
|
if ($onefile -and ( ($WorkSheetName.count -ne 2) -or $WorkSheetName[0] -eq $WorkSheetName[1] ) ) {
|
||||||
|
Write-Warning -Message "If both the Reference and difference file are the same then worksheet name must provide 2 different names"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($WorkSheetName.count -eq 2) {$worksheet1 = $WorkSheetName[0] ; $WorkSheet2 = $WorkSheetName[1]}
|
||||||
|
elseif ($WorkSheetName -is [string]) {$worksheet1 = $WorkSheet2 = $WorkSheetName}
|
||||||
|
else {Write-Warning -Message "You must provide either a single worksheet name or two names." ; return }
|
||||||
|
|
||||||
|
$params= @{ ErrorAction = [System.Management.Automation.ActionPreference]::Stop }
|
||||||
|
foreach ($p in @("HeaderName","NoHeader","StartRow")) {if ($PSBoundParameters[$p]) {$params[$p] = $PSBoundParameters[$p]}}
|
||||||
|
try {
|
||||||
|
$ReferenceObject = Import-Excel -Path $Referencefile -WorksheetName $WorkSheet1 @params
|
||||||
|
$DifferenceObject = Import-Excel -Path $Differencefile -WorksheetName $WorkSheet2 @Params
|
||||||
|
}
|
||||||
|
Catch {Write-Warning -Message "Could not read the worksheet from $Referencefile and/or $Differencefile." ; return }
|
||||||
|
$firstDataRow = + 1 ;
|
||||||
|
if ($NoHeader) {$firstDataRow = $Startrow } else {$firstDataRow = $Startrow + 1}
|
||||||
|
}
|
||||||
|
else {$firstDataRow = 1 }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Set lists of properties and row numbers
|
||||||
|
#Make a list of properties/headings using the Property (default "*") and ExcludeProperty parameters
|
||||||
|
$propList = @()
|
||||||
|
$headings = $ReferenceObject[-1].psobject.Properties.Name # This preserves the sequence - using get-member would sort them alphabetically!
|
||||||
|
if ($NoHeader -and "Name" -eq $Key) {$Key = "p1"}
|
||||||
|
if ($headings -notcontains $Key) {Write-Warning -Message "You need to specify one of the headings in the sheet '$worksheet1' as a key." ; return }
|
||||||
|
foreach ($p in $Property) { $propList += ($headings.where({$_ -like $p}) )}
|
||||||
|
foreach ($p in $ExcludeProperty) { $propList = $propList.where({$_ -notlike $p}) }
|
||||||
|
if ($propList -notcontains $Key) { $propList += $Key} #If $key isn't one of the headings we will have bailed by now
|
||||||
|
$propList = $propList | Select-Object -Unique #so, prolist must contain at least $key if nothing else
|
||||||
|
#Build the list of the properties to output, in order.
|
||||||
|
$diffpart = @()
|
||||||
|
$refpart = @()
|
||||||
|
foreach ($p in $proplist.Where({$key -ne $_}) ) {$refPart += "<=$p" ; $diffPart += "=>$p" }
|
||||||
|
$outputProps = @($key) + $refpart + $diffpart
|
||||||
|
#Key will go in column A, last reference column will be A if there is one property, B if there are two, C if theere are 3 etc
|
||||||
|
$lastRefCol = [char](64 + $propList.count)
|
||||||
|
#First difference column will be the next one (we'll trap the case of only having the key later)
|
||||||
|
$FirstDiffCol = [char](65 + $propList.count)
|
||||||
|
#Last difference column will be A if there is one property, C if there are two, E if there are 3
|
||||||
|
$lastDiffCol = [char](64 + 2 * $propList.count)
|
||||||
|
|
||||||
|
#Add RowNumber to every row
|
||||||
|
#If one sheet has extra rows we can get a single "==" result from compare, but with the row from the reference sheet
|
||||||
|
#but the row in the other sheet might so we will look up the row number from the key field build a hash table for that
|
||||||
|
|
||||||
|
$Rowhash = @{}
|
||||||
|
$i = $firstDataRow ; foreach ($row in $ReferenceObject) {Add-Member -InputObject $row -MemberType NoteProperty -Name "_Row" -Value ($i ++) -Force}
|
||||||
|
$i = $firstDataRow ; foreach ($row in $DifferenceObject) {Add-Member -InputObject $row -MemberType NoteProperty -Name "_Row" -Value ($i ++) -Force
|
||||||
|
$Rowhash[$row.$key] = $row._row
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
$expandedDiff = Compare-Object -ReferenceObject $ReferenceObject -DifferenceObject $DifferenceObject -Property $propList -PassThru -IncludeEqual |
|
||||||
|
Group-Object -Property $key | ForEach-Object {
|
||||||
|
#The value of the key column is the name of the group.
|
||||||
|
$keyval = $_.name
|
||||||
|
#we're going to create a custom object from a hash table. We want the fields to be ordered
|
||||||
|
$hash = [ordered]@{}
|
||||||
|
foreach ($result in $_.Group) {
|
||||||
|
if ($result.SideIndicator -ne "=>") {$hash["<Row"] = $result._Row }
|
||||||
|
elseif (-not $hash["<Row"]) {$hash["<Row"] = "" }
|
||||||
|
#if we have already set the side, this is the second record, so set side to indicate "changed"
|
||||||
|
if ($hash.Side) {$hash.Side = "<>"} else {$hash["Side"] = $result.SideIndicator}
|
||||||
|
#if result is "in reference" and we don't have a matching "in difference" (meaning a change) the lookup will be blank. Which we want.
|
||||||
|
$hash[">Row"] = $Rowhash[$keyval]
|
||||||
|
$hash[$key] = $keyval
|
||||||
|
#For all the other fields we care about, create <=FieldName and/or =>FieldName
|
||||||
|
foreach ($p in $propList.Where({$_ -ne $key})) {
|
||||||
|
if ($result.SideIndicator -eq "==") {$hash[("=>$P")] = $hash[("<=$P")] =$result.$P}
|
||||||
|
else {$hash[($result.SideIndicator+$P)] =$result.$P}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Pscustomobject]$hash
|
||||||
|
} | Sort-Object -Property "<row"
|
||||||
|
|
||||||
|
#Already sorted by reference row number, and fill in any blanks in the differene-row column
|
||||||
|
for ($i = 1; $i -lt $expandedDiff.Count; $i++) {if (-not $expandedDiff[$i].">row") {$expandedDiff[$i].">row" = $expandedDiff[$i-1].">row" } }
|
||||||
|
#Sort by difference row number, and fill in any blanks in the reference-row column
|
||||||
|
$expandedDiff = $expandedDiff | Sort-Object -Property ">row"
|
||||||
|
for ($i = 1; $i -lt $expandedDiff.Count; $i++) {if (-not $expandedDiff[$i]."<row") {$expandedDiff[$i]."<row" = $expandedDiff[$i-1]."<row" } }
|
||||||
|
if ($PSCmdlet.ShouldProcess($OutputFile,"Write Output to Excel file")) {
|
||||||
|
$xl = $expandedDiff | Select-Object -Property $outputProps |
|
||||||
|
Export-Excel -Path $OutputFile -WorkSheetname $OutputSheetName -FreezeTopRow -BoldTopRow -AutoSize -AutoFilter -PassThru
|
||||||
|
$ws = $xl.Workbook.Worksheets[$OutputSheetName]
|
||||||
|
for ($i = 0; $i -lt $expandedDiff.Count; $i++ ) {
|
||||||
|
if ( $expandedDiff[$i].side -ne "==" ) {
|
||||||
|
Set-Format -WorkSheet $ws -Range ("A" + ($i + 2 )) -FontColor $KeyFontColor
|
||||||
|
}
|
||||||
|
elseif ( $HideEqual ) {$ws.row($i+2).hidden = $true }
|
||||||
|
if ( $expandedDiff[$i].side -eq "<>" ) {
|
||||||
|
$range = $ws.Dimension -replace "\d+", ($i + 2 )
|
||||||
|
Set-Format -WorkSheet $ws -Range $range -BackgroundColor $ChangeBackgroundColor
|
||||||
|
}
|
||||||
|
elseif ( $expandedDiff[$i].side -eq "<=" ) {
|
||||||
|
$range = "A" + ($i + 2 ) + ":" + $lastRefCol + ($i + 2 )
|
||||||
|
Set-Format -WorkSheet $ws -Range $range -BackgroundColor $DeleteBackgroundColor
|
||||||
|
}
|
||||||
|
elseif ( $expandedDiff[$i].side -eq "=>" ) {
|
||||||
|
if ($propList.count -gt 1) {
|
||||||
|
$range = $FirstDiffCol + ($i + 2 ) + ":" + $lastDiffCol + ($i + 2 )
|
||||||
|
Set-Format -WorkSheet $ws -Range $range -BackgroundColor $AddBackgroundColor
|
||||||
|
}
|
||||||
|
Set-Format -WorkSheet $ws -Range ("A" + ($i + 2 )) -BackgroundColor $AddBackgroundColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Close-ExcelPackage -ExcelPackage $xl -Show:$Show
|
||||||
|
}
|
||||||
|
if ($PassThru) {$expandedDiff}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user