Move help from Comment-based to md. Relocate functions (sans help)

This commit is contained in:
jhoneill
2019-11-17 15:30:15 +00:00
parent 07b36e5e56
commit 6d97018de6
133 changed files with 41075 additions and 5241 deletions

View File

@@ -0,0 +1,154 @@
Function Add-ConditionalFormatting {
Param (
[Parameter(Mandatory = $true, Position = 0)]
[Alias("Range")]
$Address ,
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
[Parameter(Mandatory = $true, ParameterSetName = "NamedRule", Position = 1)]
[OfficeOpenXml.ConditionalFormatting.eExcelConditionalFormattingRuleType]$RuleType ,
[Parameter(ParameterSetName = "NamedRule")]
[Alias("ForegroundColour","FontColor")]
$ForegroundColor,
[Parameter(Mandatory = $true, ParameterSetName = "DataBar")]
[Alias("DataBarColour")]
$DataBarColor,
[Parameter(Mandatory = $true, ParameterSetName = "ThreeIconSet")]
[OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting3IconsSetType]$ThreeIconsSet,
[Parameter(Mandatory = $true, ParameterSetName = "FourIconSet")]
[OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting4IconsSetType]$FourIconsSet,
[Parameter(Mandatory = $true, ParameterSetName = "FiveIconSet")]
[OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting5IconsSetType]$FiveIconsSet,
[Parameter(ParameterSetName = "NamedRule")]
[Parameter(ParameterSetName = "ThreeIconSet")]
[Parameter(ParameterSetName = "FourIconSet")]
[Parameter(ParameterSetName = "FiveIconSet")]
[switch]$Reverse,
[Parameter(ParameterSetName = "NamedRule",Position = 2)]
$ConditionValue,
[Parameter(ParameterSetName = "NamedRule",Position = 3)]
$ConditionValue2,
[Parameter(ParameterSetName = "NamedRule")]
$BackgroundColor,
[Parameter(ParameterSetName = "NamedRule")]
[OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::None ,
[Parameter(ParameterSetName = "NamedRule")]
$PatternColor,
[Parameter(ParameterSetName = "NamedRule")]
$NumberFormat,
[Parameter(ParameterSetName = "NamedRule")]
[switch]$Bold,
[Parameter(ParameterSetName = "NamedRule")]
[switch]$Italic,
[Parameter(ParameterSetName = "NamedRule")]
[switch]$Underline,
[Parameter(ParameterSetName = "NamedRule")]
[switch]$StrikeThru,
[Parameter(ParameterSetName = "NamedRule")]
[switch]$StopIfTrue,
[int]$Priority,
[switch]$PassThru
)
#Allow conditional formatting to work like Set-ExcelRange (with single ADDRESS parameter), split it to get worksheet and range of cells.
If ($Address -is [OfficeOpenXml.Table.ExcelTable]) {
$WorkSheet = $Address.Address.Worksheet
$Address = $Address.Address.Address
}
elseif ($Address.Address -and $Address.Worksheet -and -not $WorkSheet) { #Address is a rangebase or similar
$WorkSheet = $Address.Worksheet[0]
$Address = $Address.Address
}
elseif ($Address -is [String] -and $WorkSheet -and $WorkSheet.Names[$Address] ) { #Address is the name of a named range.
$Address = $WorkSheet.Names[$Address].Address
}
if (($Address -is [OfficeOpenXml.ExcelRow] -and -not $WorkSheet) -or
($Address -is [OfficeOpenXml.ExcelColumn] -and -not $WorkSheet) ){ #EPPLUs Can't get the worksheet object from a row or column object, so bail if that was tried
Write-Warning -Message "Add-ConditionalFormatting does not support Row or Column objects as an address; use a worksheet and/or specify 'R:R' or 'C:C' instead. "; return
}
elseif ($Address -is [OfficeOpenXml.ExcelRow]) { #But if we have a column or row object and a worksheet (I don't know *why*) turn them into a string for the range
$Address = "$($Address.Row):$($Address.Row)"
}
elseif ($Address -is [OfficeOpenXml.ExcelColumn]) {
$Address = (New-Object 'OfficeOpenXml.ExcelAddress' @(1, $address.ColumnMin, 1, $address.ColumnMax).Address) -replace '1',''
if ($Address -notmatch ':') {$Address = "$Address`:$Address"}
}
if ( $Address -is [string] -and $Address -match "!") {$Address = $Address -replace '^.*!',''}
#By this point we should have a worksheet object whose ConditionalFormatting collection we will add to. If not, bail.
if (-not $worksheet -or $WorkSheet -isnot [OfficeOpenXml.ExcelWorksheet]) {write-warning "You need to provide a worksheet object." ; return}
#region create a rule of the right type
if ($RuleType -match 'IconSet$') {Write-warning -Message "You cannot configure a Icon-Set rule in this way; please use -$RuleType <SetName>." ; return}
if ($PSBoundParameters.ContainsKey("DataBarColor" ) ) {if ($DataBarColor -is [string]) {$DataBarColor = [System.Drawing.Color]::$DataBarColor }
$rule = $WorkSheet.ConditionalFormatting.AddDatabar( $Address , $DataBarColor )
}
elseif ($PSBoundParameters.ContainsKey("ThreeIconsSet" ) ) {$rule = $WorkSheet.ConditionalFormatting.AddThreeIconSet($Address , $ThreeIconsSet)}
elseif ($PSBoundParameters.ContainsKey("FourIconsSet" ) ) {$rule = $WorkSheet.ConditionalFormatting.AddFourIconSet( $Address , $FourIconsSet )}
elseif ($PSBoundParameters.ContainsKey("FiveIconsSet" ) ) {$rule = $WorkSheet.ConditionalFormatting.AddFiveIconSet( $Address , $FiveIconsSet )}
else {$rule = ($WorkSheet.ConditionalFormatting)."Add$RuleType"($Address ) }
if ($Reverse) {
if ($rule.type -match 'IconSet$' ) {$rule.reverse = $true}
elseif ($rule.type -match 'ColorScale$') {$temp =$rule.LowValue.Color ; $rule.LowValue.Color = $rule.HighValue.Color; $rule.HighValue.Color = $temp}
else {Write-Warning -Message "-Reverse was ignored because $ruletype does not support it."}
}
#endregion
#region set the rule conditions
#for lessThan/GreaterThan/Equal/Between conditions make sure that strings are wrapped in quotes. Formulas should be passed with = which will be stripped.
if ($RuleType -match "Than|Equal|Between" ) {
if ($PSBoundParameters.ContainsKey("ConditionValue" )) {
$number = $Null
#if the condition type is not a value type, but parses as a number, make it the number
if ($ConditionValue -isnot [System.ValueType] -and [Double]::TryParse($ConditionValue, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number) ) {
$ConditionValue = $number
} #else if it is not a value type, or a formula, or wrapped in quotes, wrap it in quotes.
elseif (($ConditionValue -isnot [System.ValueType])-and ($ConditionValue -notmatch '^=') -and ($ConditionValue -notmatch '^".*"$') ) {
$ConditionValue = '"' + $ConditionValue +'"'
}
}
if ($PSBoundParameters.ContainsKey("ConditionValue2")) {
$number = $Null
if ($ConditionValue -isnot [System.ValueType] -and [Double]::TryParse($ConditionValue2, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number) ) {
$ConditionValue2 = $number
}
elseif (($ConditionValue -isnot [System.ValueType]) -and ($ConditionValue2 -notmatch '^=') -and ($ConditionValue2 -notmatch '^".*"$') ) {
$ConditionValue2 = '"' + $ConditionValue2 + '"'
}
}
}
#But we don't usually want quotes round containstext | beginswith type rules. Can't be Certain they need to be removed, so warn the user their condition might be wrong
if ($RuleType -match "Text|With" -and $ConditionValue -match '^".*"$' ) {
Write-Warning -Message "The condition will look for the quotes at the start and end."
}
if ($PSBoundParameters.ContainsKey("ConditionValue" ) -and
$RuleType -match "Top|Botom" ) {$rule.Rank = $ConditionValue }
if ($PSBoundParameters.ContainsKey("ConditionValue" ) -and
$RuleType -match "StdDev" ) {$rule.StdDev = $ConditionValue }
if ($PSBoundParameters.ContainsKey("ConditionValue" ) -and
$RuleType -match "Than|Equal|Expression" ) {$rule.Formula = ($ConditionValue -replace '^=','') }
if ($PSBoundParameters.ContainsKey("ConditionValue" ) -and
$RuleType -match "Text|With" ) {$rule.Text = ($ConditionValue -replace '^=','') }
if ($PSBoundParameters.ContainsKey("ConditionValue" ) -and
$PSBoundParameters.ContainsKey("ConditionValue2") -and
$RuleType -match "Between" ) {
$rule.Formula = ($ConditionValue -replace '^=','');
$rule.Formula2 = ($ConditionValue2 -replace '^=','')
}
if ($PSBoundParameters.ContainsKey("StopIfTrue") ) {$rule.StopIfTrue = $StopIfTrue }
if ($PSBoundParameters.ContainsKey("Priority") ) {$rule.Priority = $Priority }
#endregion
#region set the rule format
if ($PSBoundParameters.ContainsKey("NumberFormat" ) ) {$rule.Style.NumberFormat.Format = (Expand-NumberFormat $NumberFormat) }
if ($Underline ) {$rule.Style.Font.Underline = [OfficeOpenXml.Style.ExcelUnderLineType]::Single }
elseif ($PSBoundParameters.ContainsKey("Underline" ) ) {$rule.Style.Font.Underline = [OfficeOpenXml.Style.ExcelUnderLineType]::None }
if ($PSBoundParameters.ContainsKey("Bold" ) ) {$rule.Style.Font.Bold = [boolean]$Bold }
if ($PSBoundParameters.ContainsKey("Italic" ) ) {$rule.Style.Font.Italic = [boolean]$Italic }
if ($PSBoundParameters.ContainsKey("StrikeThru" ) ) {$rule.Style.Font.Strike = [boolean]$StrikeThru }
if ($PSBoundParameters.ContainsKey("ForeGroundColor" ) ) {if ($ForeGroundColor -is [string]) {$ForeGroundColor = [System.Drawing.Color]::$ForeGroundColor }
$rule.Style.Font.Color.color = $ForeGroundColor }
if ($PSBoundParameters.ContainsKey("BackgroundColor" ) ) {if ($BackgroundColor -is [string]) {$BackgroundColor = [System.Drawing.Color]::$BackgroundColor }
$rule.Style.Fill.BackgroundColor.color = $BackgroundColor }
if ($PSBoundParameters.ContainsKey("BackgroundPattern") ) {$rule.Style.Fill.PatternType = $BackgroundPattern }
if ($PSBoundParameters.ContainsKey("PatternColor" ) ) {if ($PatternColor -is [string]) {$PatternColor = [System.Drawing.Color]::$PatternColor }
$rule.Style.Fill.PatternColor.color = $PatternColor }
#endregion
#Allow further tweaking by returning the rule, if passthru specified
if ($Passthru) {$rule}
}

View File

@@ -0,0 +1,142 @@
function Add-ExcelChart {
[cmdletbinding(DefaultParameterSetName = 'Worksheet')]
[OutputType([OfficeOpenXml.Drawing.Chart.ExcelChart])]
param(
[Parameter(ParameterSetName = 'Worksheet', Mandatory = $true)]
[OfficeOpenXml.ExcelWorksheet]$Worksheet,
[Parameter(ParameterSetName = 'PivotTable', Mandatory = $true)]
[OfficeOpenXml.Table.PivotTable.ExcelPivotTable]$PivotTable ,
[String]$Title,
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = "ColumnStacked",
[OfficeOpenXml.Drawing.Chart.eTrendLine[]]$ChartTrendLine,
$XRange,
$YRange,
[int]$Width = 500,
[int]$Height = 350,
[int]$Row = 0,
[int]$RowOffSetPixels = 10,
[int]$Column = 6,
[int]$ColumnOffSetPixels = 5,
[OfficeOpenXml.Drawing.Chart.eLegendPosition]$LegendPosition,
$LegendSize,
[Switch]$LegendBold,
[Switch]$NoLegend,
[Switch]$ShowCategory,
[Switch]$ShowPercent,
[String[]]$SeriesHeader,
[Switch]$TitleBold,
[Int]$TitleSize ,
[String]$XAxisTitleText,
[Switch]$XAxisTitleBold,
$XAxisTitleSize ,
[string]$XAxisNumberformat,
$XMajorUnit,
$XMinorUnit,
$XMaxValue,
$XMinValue,
[OfficeOpenXml.Drawing.Chart.eAxisPosition]$XAxisPosition ,
[String]$YAxisTitleText,
[Switch]$YAxisTitleBold,
$YAxisTitleSize,
[string]$YAxisNumberformat,
$YMajorUnit,
$YMinorUnit,
$YMaxValue,
$YMinValue,
[OfficeOpenXml.Drawing.Chart.eAxisPosition]$YAxisPosition,
[Switch]$PassThru
)
try {
if ($PivotTable) {
$Worksheet = $PivotTable.WorkSheet
$chart = $Worksheet.Drawings.AddChart(("Chart" + $PivotTable.Name ), $ChartType, $PivotTable)
}
else {
$ChartName = 'Chart' + (Split-Path -Leaf ([System.IO.path]::GetTempFileName())) -replace 'tmp|\.', ''
$chart = $Worksheet.Drawings.AddChart($ChartName, $ChartType)
$chartDefCount = @($YRange).Count
if ($chartDefCount -eq 1) {
$Series = $chart.Series.Add($YRange, $XRange)
if ($ChartTrendLine) {
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 {
for ($idx = 0; $idx -lt $chartDefCount; $idx += 1) {
if ($Yrange.count -eq $xrange.count) {
$Series = $chart.Series.Add($YRange[$idx], $XRange[$idx])
}
else {
$Series = $chart.Series.Add($YRange[$idx], $XRange)
}
if ($SeriesHeader.Count -gt 0) {
if ($SeriesHeader[$idx] -match '^=') { $Series.HeaderAddress = $SeriesHeader[$idx] -replace '^=', '' }
else { $Series.Header = $SeriesHeader[$idx] }
}
else { $Series.Header = "Series $($idx)" }
}
}
}
if ($Title) {
$chart.Title.Text = $Title
if ($TitleBold) { $chart.Title.Font.Bold = $true }
if ($TitleSize) { $chart.Title.Font.Size = $TitleSize }
}
if ($NoLegend) { $chart.Legend.Remove() }
else {
if ($PSBoundParameters.ContainsKey('LegendPosition')) { $chart.Legend.Position = $LegendPosition }
if ($PSBoundParameters.ContainsKey('LegendBold')) { $chart.Legend.Font.Bold = [boolean]$LegendBold }
if ($LegendSize) { $chart.Legend.Font.Size = $LegendSize }
}
if ($XAxisTitleText) {
$chart.XAxis.Title.Text = $XAxisTitleText
if ($PSBoundParameters.ContainsKey('XAxisTitleBold')) {
$chart.XAxis.Title.Font.Bold = [boolean]$XAxisTitleBold
}
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" }
#$chart.ChartXml.chartSpace.chart.plotArea.catAx.axPos.val = $XAxisPosition.ToString().substring(0,1)}
if ($XMajorUnit) { $chart.XAxis.MajorUnit = $XMajorUnit }
if ($XMinorUnit) { $chart.XAxis.MinorUnit = $XMinorUnit }
if ($null -ne $XMinValue) { $chart.XAxis.MinValue = $XMinValue }
if ($null -ne $XMaxValue) { $chart.XAxis.MaxValue = $XMaxValue }
if ($XAxisNumberformat) { $chart.XAxis.Format = (Expand-NumberFormat $XAxisNumberformat) }
if ($YAxisTitleText) {
$chart.YAxis.Title.Text = $YAxisTitleText
if ($PSBoundParameters.ContainsKey('YAxisTitleBold')) {
$chart.YAxis.Title.Font.Bold = [boolean]$YAxisTitleBold
}
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" }
#$chart.ChartXml.chartSpace.chart.plotArea.valAx.axPos.val= $YAxisPosition.ToString().substring(0,1)}
if ($YMajorUnit) { $chart.YAxis.MajorUnit = $YMajorUnit }
if ($YMinorUnit) { $chart.YAxis.MinorUnit = $YMinorUnit }
if ($null -ne $YMinValue) { $chart.YAxis.MinValue = $YMinValue }
if ($null -ne $YMaxValue) { $chart.YAxis.MaxValue = $YMaxValue }
if ($YAxisNumberformat) { $chart.YAxis.Format = (Expand-NumberFormat $YAxisNumberformat) }
if ($null -ne $chart.Datalabel) {
$chart.Datalabel.ShowCategory = [boolean]$ShowCategory
$chart.Datalabel.ShowPercent = [boolean]$ShowPercent
}
$chart.SetPosition($Row, $RowOffsetPixels, $Column, $ColumnOffsetPixels)
$chart.SetSize($Width, $Height)
if ($PassThru) { return $chart }
}
catch { Write-Warning -Message "Failed adding Chart to worksheet '$($WorkSheet).name': $_" }
}

View File

@@ -0,0 +1,58 @@
Function Add-ExcelDataValidationRule {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline = $true,Position=0)]
[Alias("Address")]
$Range ,
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
[ValidateSet('Any','Custom','DateTime','Decimal','Integer','List','TextLength','Time')]
$ValidationType,
[OfficeOpenXml.DataValidation.ExcelDataValidationOperator]$Operator = [OfficeOpenXml.DataValidation.ExcelDataValidationOperator]::equal ,
$Value,
$Value2,
$Formula,
$Formula2,
$ValueSet,
[switch]$ShowErrorMessage,
[OfficeOpenXml.DataValidation.ExcelDataValidationWarningStyle]$ErrorStyle,
[String]$ErrorTitle,
[String]$ErrorBody,
[switch]$ShowPromptMessage,
[String]$PromptBody,
[String]$PromptTitle,
[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

@@ -0,0 +1,30 @@
function Add-ExcelName {
[CmdletBinding()]
param(
#The range of cells to assign as a name.
[Parameter(Mandatory=$true)]
[OfficeOpenXml.ExcelRange]$Range,
#The name to assign to the range. If the name exists it will be updated to the new range. If no name is specified, the first cell in the range will be used as the name.
[String]$RangeName
)
try {
$ws = $Range.Worksheet
if (-not $RangeName) {
$RangeName = $ws.Cells[$Range.Start.Address].Value
$Range = ($Range.Worksheet.cells[($range.start.row +1), $range.start.Column , $range.end.row, $range.end.column])
}
if ($RangeName -match '\W') {
Write-Warning -Message "Range name '$RangeName' contains illegal characters, they will be replaced with '_'."
$RangeName = $RangeName -replace '\W','_'
}
if ($ws.names[$RangeName]) {
Write-verbose -Message "Updating Named range '$RangeName' to $($Range.FullAddressAbsolute)."
$ws.Names[$RangeName].Address = $Range.FullAddressAbsolute
}
else {
Write-verbose -Message "Creating Named range '$RangeName' as $($Range.FullAddressAbsolute)."
$null = $ws.Names.Add($RangeName, $Range)
}
}
catch {Write-Warning -Message "Failed adding named range '$RangeName' to worksheet '$($ws.Name)': $_" }
}

View File

@@ -0,0 +1,75 @@
function Add-ExcelTable {
[CmdletBinding()]
[OutputType([OfficeOpenXml.Table.ExcelTable])]
param (
[Parameter(Mandatory=$true)]
[OfficeOpenXml.ExcelRange]$Range,
[String]$TableName = "",
[OfficeOpenXml.Table.TableStyles]$TableStyle = 'Medium6',
[Switch]$ShowHeader ,
[Switch]$ShowFilter,
[Switch]$ShowTotal,
[hashtable]$TotalSettings,
[Switch]$ShowFirstColumn,
[Switch]$ShowLastColumn,
[Switch]$ShowRowStripes,
[Switch]$ShowColumnStripes,
[Switch]$PassThru
)
try {
if ($TableName -eq "" -or $null -eq $TableName) {
$tbl = $Range.Worksheet.Tables.Add($Range, "")
}
else {
if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress($TableName)) {
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.
if ($PSBoundParameters.ContainsKey('ShowHeader')) {$tbl.ShowHeader = [bool]$ShowHeader}
if ($PSBoundParameters.ContainsKey('TotalSettings')) {
$tbl.ShowTotal = $true
foreach ($k in $TotalSettings.keys) {
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") ) {
Write-Warning -Message "'$($TotalSettings[$k])' is not a valid total function."
}
else {$tbl.Columns[$k].TotalsRowFunction = $TotalSettings[$k]}
}
}
elseif ($PSBoundParameters.ContainsKey('ShowTotal')) {$tbl.ShowTotal = [bool]$ShowTotal}
if ($PSBoundParameters.ContainsKey('ShowFilter')) {$tbl.ShowFilter = [bool]$ShowFilter}
if ($PSBoundParameters.ContainsKey('ShowFirstColumn')) {$tbl.ShowFirstColumn = [bool]$ShowFirstColumn}
if ($PSBoundParameters.ContainsKey('ShowLastColumn')) {$tbl.ShowLastColumn = [bool]$ShowLastColumn}
if ($PSBoundParameters.ContainsKey('ShowRowStripes')) {$tbl.ShowRowStripes = [bool]$ShowRowStripes}
if ($PSBoundParameters.ContainsKey('ShowColumnStripes')) {$tbl.ShowColumnStripes = [bool]$ShowColumnStripes}
$tbl.TableStyle = $TableStyle
if ($PassThru) {return $tbl}
}
catch {Write-Warning -Message "Failed adding table '$TableName' to worksheet '$WorksheetName': $_"}
}

View File

@@ -0,0 +1,176 @@
function Add-PivotTable {
[cmdletbinding(defaultParameterSetName = 'ChartbyParams')]
[OutputType([OfficeOpenXml.Table.PivotTable.ExcelPivotTable])]
param (
[Parameter(Mandatory = $true)]
[string]$PivotTableName,
[OfficeOpenXml.ExcelAddressBase]
$Address,
$ExcelPackage,
$SourceWorkSheet,
$SourceRange,
$PivotRows,
$PivotData,
$PivotColumns,
$PivotFilter,
[Switch]$PivotDataToColumn,
[ValidateSet("Both", "Columns", "Rows", "None")]
[String]$PivotTotals = "Both",
[Switch]$NoTotalsInPivot,
[String]$GroupDateRow,
[OfficeOpenXml.Table.PivotTable.eDateGroupBy[]]$GroupDatePart,
[String]$GroupNumericRow,
[double]$GroupNumericMin = 0 ,
[double]$GroupNumericMax = [Double]::MaxValue ,
[double]$GroupNumericInterval = 100 ,
[string]$PivotNumberFormat,
[OfficeOpenXml.Table.TableStyles]$PivotTableStyle,
[Parameter(ParameterSetName = 'ChartbyDef', Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
$PivotChartDefinition,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$IncludePivotChart,
[Parameter(ParameterSetName = 'ChartbyParams')]
[String]$ChartTitle = "",
[Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartHeight = 400 ,
[Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartWidth = 600,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRow = 0 ,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumn = 4,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRowOffSetPixels = 0 ,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumnOffSetPixels = 0,
[Parameter(ParameterSetName = 'ChartbyParams')]
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie',
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$NoLegend,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowCategory,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowPercent,
[switch]$Activate,
[Switch]$PassThru
)
if ($PivotTableName.length -gt 250) {
Write-warning -Message "PivotTable name will be truncated"
$PivotTableName = $PivotTableName.Substring(0, 250)
}
if ($Address) {
[OfficeOpenXml.ExcelWorksheet]$wsPivot = $address.Worksheet
}
else {
try {
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
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"]}
}
catch {throw "Could not create the sheet for the PivotTable. $_" }
}
#if the pivot doesn't exist, create it.
if (-not $wsPivot) {throw "There was a problem getting the worksheet for the PivotTable"}
if (-not $wsPivot.PivotTables[$pivotTableName] ) {
try {
#Accept a string or a worksheet object as $SourceWorksheet - we don't need a worksheet if we have a Rangebase .
if ( $SourceWorkSheet -is [string]) {
$SourceWorkSheet = $ExcelPackage.Workbook.Worksheets.where( {$_.name -Like $SourceWorkSheet})[0]
}
elseif ( $SourceWorkSheet -is [int] ) {
$SourceWorkSheet = $ExcelPackage.Workbook.Worksheets[$SourceWorkSheet]
}
if ( $SourceRange -is [OfficeOpenXml.Table.ExcelTable]) {$SourceRange = $SourceRange.Address }
if ( $sourceRange -is [OfficeOpenXml.ExcelRange] -or
$SourceRange -is [OfficeOpenXml.ExcelAddress]) {
$pivotTable = $wsPivot.PivotTables.Add($Address, $SourceRange, $pivotTableName)
}
elseif (-not $SourceRange) {
$pivotTable = $wsPivot.PivotTables.Add($Address, $SourceWorkSheet.cells[$SourceWorkSheet.Dimension.Address], $pivotTableName)
}
elseif ($SourceWorkSheet -isnot [OfficeOpenXml.ExcelWorksheet] ) {
Write-Warning -Message "Could not find source Worksheet for pivot-table '$pivotTableName'." ; return
}
elseif ( $SourceRange -is [String] -or $SourceRange -is [OfficeOpenXml.ExcelAddress]) {
$pivotTable = $wsPivot.PivotTables.Add($Address, $SourceWorkSheet.Cells[$SourceRange], $pivotTableName)
}
else {Write-warning "Could not create a PivotTable with the Source Range provided."; return}
foreach ($Row in $PivotRows) {
try {$null = $pivotTable.RowFields.Add($pivotTable.Fields[$Row]) }
catch {Write-Warning -message "Could not add '$row' to Rows in PivotTable $pivotTableName." }
}
foreach ($Column in $PivotColumns) {
try {$null = $pivotTable.ColumnFields.Add($pivotTable.Fields[$Column])}
catch {Write-Warning -message "Could not add '$Column' to Columns in PivotTable $pivotTableName." }
}
if ($PivotData -is [HashTable] -or $PivotData -is [System.Collections.Specialized.OrderedDictionary]) {
$PivotData.Keys | ForEach-Object {
try {
$df = $pivotTable.DataFields.Add($pivotTable.Fields[$_])
$df.Function = $PivotData.$_
if ($PivotNumberFormat) {$df.Format = (Expand-NumberFormat -NumberFormat $PivotNumberFormat)}
}
catch {Write-Warning -message "Problem adding data fields to PivotTable $pivotTableName." }
}
}
else {
foreach ($field in $PivotData) {
try {
$df = $pivotTable.DataFields.Add($pivotTable.Fields[$field])
$df.Function = 'Count'
}
catch {Write-Warning -message "Problem adding data field '$field' to PivotTable $pivotTableName." }
}
}
foreach ( $pFilter in $PivotFilter) {
try { $null = $pivotTable.PageFields.Add($pivotTable.Fields[$pFilter])}
catch {Write-Warning -message "Could not add '$pFilter' to Filter/Page fields in PivotTable $pivotTableName." }
}
if ($NoTotalsInPivot) {$PivotTotals = "None" }
if ($PivotTotals -eq "None" -or $PivotTotals -eq "Columns") { $pivotTable.RowGrandTotals = $false }
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!
elseif ($PivotTotals -eq "Both" -or $PivotTotals -eq "Columns") { $pivotTable.ColumGrandTotals = $true }
if ($PivotDataToColumn ) { $pivotTable.DataOnRows = $false }
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': $_"}
}
else {
Write-Warning -Message "PivotTable defined in $($pivotTableName) already exists, only the data range will be changed."
$pivotTable = $wsPivot.PivotTables[$pivotTableName]
if (-not $SourceRange) { $SourceRange = $SourceWorkSheet.Dimension.Address}
$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.
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 }
catch {Write-Warning -Message "Failed adding chart for pivotable '$pivotTableName': $_"}
}
elseif ($PivotChartDefinition -and -not $wsPivot.Drawings["Chart$pivotTableName"]) {
if ($PivotChartDefinition -is [System.Management.Automation.PSCustomObject]) {
$params = @{PivotTable = $pivotTable }
$PivotChartDefinition.PSObject.Properties | ForEach-Object {if ( $null -ne $_.value) {$params[$_.name] = $_.value}}
Add-ExcelChart @params
}
elseif ($PivotChartDefinition -is [hashtable] -or $PivotChartDefinition -is [System.Collections.Specialized.OrderedDictionary]) {
Add-ExcelChart -PivotTable $pivotTable @PivotChartDefinition
}
}
if ($PassThru) {return $pivotTable}
}

View File

@@ -0,0 +1,80 @@
function Add-Worksheet {
[cmdletBinding()]
[OutputType([OfficeOpenXml.ExcelWorksheet])]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = "Package", Position = 0)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Parameter(Mandatory = $true, ParameterSetName = "WorkBook")]
[OfficeOpenXml.ExcelWorkbook]$ExcelWorkbook,
[string]$WorksheetName ,
[switch]$ClearSheet,
[Switch]$MoveToStart,
[Switch]$MoveToEnd,
$MoveBefore ,
$MoveAfter ,
[switch]$Activate,
[OfficeOpenXml.ExcelWorksheet]$CopySource,
[parameter(DontShow=$true)]
[Switch] $NoClobber
)
#if we were given a workbook use it, if we were given a package, use its workbook
if ($ExcelPackage -and -not $ExcelWorkbook) {$ExcelWorkbook = $ExcelPackage.Workbook}
# If WorksheetName was given, try to use that worksheet. If it wasn't, and we are copying an existing sheet, try to use the sheet name
# If we are not copying a sheet, and have no name, use the name "SheetX" where X is the number of the new sheet
if (-not $WorksheetName -and $CopySource -and -not $ExcelWorkbook[$CopySource.Name]) {$WorksheetName = $CopySource.Name}
elseif (-not $WorksheetName) {$WorksheetName = "Sheet" + (1 + $ExcelWorkbook.Worksheets.Count)}
else {$ws = $ExcelWorkbook.Worksheets[$WorksheetName]}
#If -clearsheet was specified and the named sheet exists, delete it
if ($ws -and $ClearSheet) { $ExcelWorkbook.Worksheets.Delete($WorksheetName) ; $ws = $null }
#Copy or create new sheet as needed
if (-not $ws -and $CopySource) {
Write-Verbose -Message "Copying into worksheet '$WorksheetName'."
$ws = $ExcelWorkbook.Worksheets.Add($WorksheetName, $CopySource)
}
elseif (-not $ws) {
$ws = $ExcelWorkbook.Worksheets.Add($WorksheetName)
Write-Verbose -Message "Adding worksheet '$WorksheetName'."
}
else {Write-Verbose -Message "Worksheet '$WorksheetName' already existed."}
#region Move sheet if needed
if ($MoveToStart) {$ExcelWorkbook.Worksheets.MoveToStart($WorksheetName) }
elseif ($MoveToEnd ) {$ExcelWorkbook.Worksheets.MoveToEnd($WorksheetName) }
elseif ($MoveBefore ) {
if ($ExcelWorkbook.Worksheets[$MoveBefore]) {
if ($MoveBefore -is [int]) {
$ExcelWorkbook.Worksheets.MoveBefore($ws.Index, $MoveBefore)
}
else {$ExcelWorkbook.Worksheets.MoveBefore($WorksheetName, $MoveBefore)}
}
else {Write-Warning "Can't find worksheet '$MoveBefore'; worsheet '$WorksheetName' will not be moved."}
}
elseif ($MoveAfter ) {
if ($MoveAfter -eq "*") {
if ($WorksheetName -lt $ExcelWorkbook.Worksheets[1].Name) {$ExcelWorkbook.Worksheets.MoveToStart($WorksheetName)}
else {
$i = 1
While ($i -lt $ExcelWorkbook.Worksheets.Count -and ($ExcelWorkbook.Worksheets[$i + 1].Name -le $WorksheetName) ) { $i++}
$ExcelWorkbook.Worksheets.MoveAfter($ws.Index, $i)
}
}
elseif ($ExcelWorkbook.Worksheets[$MoveAfter]) {
if ($MoveAfter -is [int]) {
$ExcelWorkbook.Worksheets.MoveAfter($ws.Index, $MoveAfter)
}
else {
$ExcelWorkbook.Worksheets.MoveAfter($WorksheetName, $MoveAfter)
}
}
else {Write-Warning "Can't find worksheet '$MoveAfter'; worsheet '$WorksheetName' will not be moved."}
}
#endregion
if ($Activate) {Select-Worksheet -ExcelWorksheet $ws }
if ($ExcelPackage -and -not (Get-Member -InputObject $ExcelPackage -Name $ws.Name)) {
$sb = [scriptblock]::Create(('$this.workbook.Worksheets["{0}"]' -f $ws.name))
Add-Member -InputObject $ExcelPackage -MemberType ScriptProperty -Name $ws.name -Value $sb
}
return $ws
}

View File

@@ -0,0 +1,34 @@
Function Close-ExcelPackage {
[CmdLetBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")]
Param (
[parameter(Mandatory=$true, ValueFromPipeline=$true)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[switch]$Show,
[Switch]$NoSave,
$SaveAs,
[ValidateNotNullOrEmpty()]
[String]$Password,
[switch]$Calculate
)
if ( $NoSave) {$ExcelPackage.Dispose()}
else {
if ($Calculate) {
try { [OfficeOpenXml.CalculationExtension]::Calculate($ExcelPackage.Workbook) }
Catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook."}
}
if ($SaveAs) {
$SaveAs = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($SaveAs)
if ($Password) {$ExcelPackage.SaveAs( $SaveAs, $Password ) }
else {$ExcelPackage.SaveAs( $SaveAs)}
}
else {
if ($Password) {$ExcelPackage.Save($Password) }
else {$ExcelPackage.Save() }
$SaveAs = $ExcelPackage.File.FullName
}
$ExcelPackage.Dispose()
if ($Show) {Start-Process -FilePath $SaveAs }
}
}

View File

@@ -0,0 +1,199 @@
Function Compare-WorkSheet {
[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(
[parameter(Mandatory=$true,Position=0)]
$Referencefile ,
[parameter(Mandatory=$true,Position=1)]
$Differencefile ,
$WorkSheetName = "Sheet1",
$Property = "*" ,
$ExcludeProperty ,
[Parameter(ParameterSetName='B', Mandatory)]
[String[]]$Headername,
[Parameter(ParameterSetName='C', Mandatory)]
[switch]$NoHeader,
[int]$Startrow = 1,
$AllDataBackgroundColor,
$BackgroundColor,
$TabColor,
$Key = "Name" ,
$FontColor,
[Switch]$Show,
[switch]$GridView,
[Switch]$PassThru,
[Switch]$IncludeEqual,
[Switch]$ExcludeDifferent
)
#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 we can have 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 {
$sheet1 = Import-Excel -Path $Referencefile -WorksheetName $WorkSheet1 @params
$sheet2 = Import-Excel -Path $Differencefile -WorksheetName $WorkSheet2 @Params
}
Catch {Write-Warning -Message "Could not read the worksheet from $Referencefile and/or $Differencefile." ; return }
#Get Column headings and create a hash table of Name to column letter.
$headings = $Sheet1[-1].psobject.Properties.name # This preserves the sequence - using get-member would sort them alphabetically!
$headings | ForEach-Object -Begin {$columns = @{} ; $i= 1 } -Process {$Columns[$_] = [OfficeOpenXml.ExcelAddress]::GetAddress(1,($i ++)) -replace "\d","" }
#Make a list of property headings using the Property (default "*") and ExcludeProperty parameters
if ($Key -eq "Name" -and $NoHeader) {$Key = "p1"}
$propList = @()
foreach ($p in $Property) {$propList += ($headings.where({$_ -like $p}) )}
foreach ($p in $ExcludeProperty) {$propList = $propList.where({$_ -notlike $p}) }
if (($headings -contains $key) -and ($propList -notcontains $Key)) {$propList += $Key}
$propList = $propList | Select-Object -Unique
if ($propList.Count -eq 0) {Write-Warning -Message "No Columns are selected with -Property = '$Property' and -excludeProperty = '$ExcludeProperty'." ; return}
#Add RowNumber, Sheetname and file name to every row
$firstDataRow = $startRow + 1
if ($Headername -or $NoHeader) {$firstDataRow -- }
$i = $firstDataRow ; foreach ($row in $Sheet1) {Add-Member -InputObject $row -MemberType NoteProperty -Name "_Row" -Value ($i ++)
Add-Member -InputObject $row -MemberType NoteProperty -Name "_Sheet" -Value $worksheet1
Add-Member -InputObject $row -MemberType NoteProperty -Name "_File" -Value $Referencefile}
$i = $firstDataRow ; foreach ($row in $Sheet2) {Add-Member -InputObject $row -MemberType NoteProperty -Name "_Row" -Value ($i ++)
Add-Member -InputObject $row -MemberType NoteProperty -Name "_Sheet" -Value $worksheet2
Add-Member -InputObject $row -MemberType NoteProperty -Name "_File" -Value $Differencefile}
if ($ExcludeDifferent -and -not $IncludeEqual) {$IncludeEqual = $true}
#Do the comparison and add file,sheet and row to the result - these are prefixed with "_" to show they are added the addition will fail if the sheet has these properties so split the operations
[PSCustomObject[]]$diff = Compare-Object -ReferenceObject $Sheet1 -DifferenceObject $Sheet2 -Property $propList -PassThru -IncludeEqual:$IncludeEqual -ExcludeDifferent:$ExcludeDifferent |
Sort-Object -Property "_Row","File"
#if BackgroundColor was specified, set it on extra or extra or changed rows
if ($diff -and $BackgroundColor) {
#Differences may only exist in one file. So gather the changes for each file; open the file, update each impacted row in the shee, save the file
$updates = $diff.where({$_.SideIndicator -ne "=="}) | Group-object -Property "_File"
foreach ($file in $updates) {
try {$xl = Open-ExcelPackage -Path $file.name }
catch {Write-warning -Message "Can't open $($file.Name) for writing." ; return}
if ($PSBoundParameters.ContainsKey("AllDataBackgroundColor")) {
$file.Group._sheet | Sort-Object -Unique | ForEach-Object {
$ws = $xl.Workbook.Worksheets[$_]
if ($headerName) {$range = "A" + $startrow + ":" + $ws.dimension.end.address}
else {$range = "A" + ($startrow + 1) + ":" + $ws.dimension.end.address}
Set-Format -WorkSheet $ws -BackgroundColor $AllDataBackgroundColor -Range $Range
}
}
foreach ($row in $file.group) {
$ws = $xl.Workbook.Worksheets[$row._Sheet]
$range = $ws.Dimension -replace "\d+",$row._row
Set-Format -WorkSheet $ws -Range $range -BackgroundColor $BackgroundColor
}
if ($PSBoundParameters.ContainsKey("TabColor")) {
if ($TabColor -is [string]) {$TabColor = [System.Drawing.Color]::$TabColor }
foreach ($tab in ($file.group._sheet | Select-Object -Unique)) {
$xl.Workbook.Worksheets[$tab].TabColor = $TabColor
}
}
$xl.save() ; $xl.Stream.Close() ; $xl.Dispose()
}
}
#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) -or ($key -is [hashtable])) ) {
$updates = $diff.where({$_.SideIndicator -ne "=="}) | Group-object -Property $Key | Where-Object {$_.count -eq 2}
if ($updates) {
$XL1 = Open-ExcelPackage -path $Referencefile
if ($oneFile ) {$xl2 = $xl1}
else {$xl2 = Open-ExcelPackage -path $Differencefile }
foreach ($u in $updates) {
foreach ($p in $propList) {
if ($u.group[0]._file -eq $Referencefile) {
$ws1 = $xl1.Workbook.Worksheets[$u.Group[0]._sheet]
$ws2 = $xl2.Workbook.Worksheets[$u.Group[1]._sheet]
}
else {
$ws1 = $xl2.Workbook.Worksheets[$u.Group[0]._sheet]
$ws2 = $xl1.Workbook.Worksheets[$u.Group[1]._sheet]
}
if($u.Group[0].$p -ne $u.Group[1].$p ) {
Set-Format -WorkSheet $ws1 -Range ($Columns[$p] + $u.Group[0]._Row) -FontColor $FontColor
Set-Format -WorkSheet $ws2 -Range ($Columns[$p] + $u.Group[1]._Row) -FontColor $FontColor
}
}
}
$xl1.Save() ; $xl1.Stream.Close() ; $xl1.Dispose()
if (-not $oneFile) {$xl2.Save() ; $xl2.Stream.Close() ; $xl2.Dispose()}
}
}
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 will not be redirected
if (-not $diff) {Write-Host "Comparison of $Referencefile::$worksheet1 and $Differencefile::$WorkSheet2 returned no results." }
if ($Show) {
Start-Process -FilePath $Referencefile
if (-not $oneFile) { Start-Process -FilePath $Differencefile }
if ($GridView) { Write-Warning -Message "-GridView is ignored when -Show is specified" }
}
elseif ($GridView -and $propList -contains $key) {
if ($IncludeEqual -and -not $ExcludeDifferent) {
$GroupedRows = $diff | Group-Object -Property $key
}
else { #to get the right now numbers on the grid we need to have all the rows.
$GroupedRows = Compare-Object -ReferenceObject $Sheet1 -DifferenceObject $Sheet2 -Property $propList -PassThru -IncludeEqual |
Group-Object -Property $key
}
#Additions, deletions and unchanged rows will give a group of 1; changes will give a group of 2 .
#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
$Sheet2 | ForEach-Object -Begin {$Rowhash = @{} } -Process {$Rowhash[$_.$key] = $_._row }
$ExpandedDiff = ForEach ($g in $GroupedRows) {
#we're going to create a custom object from a hash table. We want the fields to be ordered
$hash = [ordered]@{}
foreach ($result IN $g.Group) {
# if result indicates equal or "in Reference" set the reference side row. If we did that on a previous result keep it. Otherwise set to "blank"
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[$g.Name]
#position the key as the next field (only appears once)
$Hash[$key] = $g.Name
#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 by reference row number, and fill in any blanks in the difference-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" } }
#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 we had to put the equal rows back, take them out; sort, make sure all the columns are present in row 1 so the grid puts them in, and output
if ( $ExcludeDifferent) {$ExpandedDiff = $ExpandedDiff.where({$_.side -eq "=="}) | Sort-Object -Property "<row" ,">row" }
elseif ( $IncludeEqual) {$ExpandedDiff = $ExpandedDiff | Sort-Object -Property "<row" ,">row" }
else {$ExpandedDiff = $ExpandedDiff.where({$_.side -ne "=="}) | Sort-Object -Property "<row" ,">row" }
$ExpandedDiff | Update-FirstObjectProperties | Out-GridView -Title "Comparing $Referencefile::$worksheet1 (<=) with $Differencefile::$WorkSheet2 (=>)"
}
elseif ($GridView ) {Write-Warning -Message "To use -GridView you must specify -Key and it must match one of the included properties." }
elseif (-not $PassThru) {return ($diff | Select-Object -Property (@(@{n="_Side";e={$_.SideIndicator}},"_File" ,"_Sheet","_Row") + $propList))}
if ( $PassThru) {return $diff }
}

View File

@@ -0,0 +1,58 @@
Function Convert-ExcelRangeToImage {
[alias("Convert-XlRangeToImage")]
Param (
[parameter(Mandatory=$true)]
$Path,
$workSheetname = "Sheet1" ,
[parameter(Mandatory=$true)]
$range,
$destination = "$pwd\temp.png",
[switch]$show
)
$extension = $destination -replace '^.*\.(\w+)$' ,'$1'
if ($extension -in @('JPEG','BMP','PNG')) {
$Format = [system.Drawing.Imaging.ImageFormat]$extension
} #if we don't recognise the extension OR if it is JPG with an E, use JPEG format
else { $Format = [system.Drawing.Imaging.ImageFormat]::Jpeg}
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Starting Excel"
$xlApp = New-Object -ComObject "Excel.Application"
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Opening Workbook and copying data"
$xlWbk = $xlApp.Workbooks.Open($Path)
$xlWbk.Worksheets($workSheetname).Select()
$null = $xlWbk.ActiveSheet.Range($range).Select()
$null = $xlApp.Selection.Copy()
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.
$image = Get-Clipboard -Format Image
$image.Save($destination, $Format)
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Closing Excel"
$null = $xlWbk.ActiveSheet.Range("a1").Select()
$null = $xlApp.Selection.Copy()
$xlApp.Quit()
Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Completed
if ($show) {Start-Process -FilePath $destination}
else {Get-Item -Path $destination}
}
<#
del demo*.xlsx
$workSheetname = 'Processes'
$Path = "$pwd\demo.xlsx"
$myData = Get-Process | Select-Object -Property Name,WS,CPU,Description,company,startTime
$excelPackage = $myData | Export-Excel -KillExcel -Path $Path -WorkSheetname $workSheetname -ClearSheet -AutoSize -AutoFilter -BoldTopRow -FreezeTopRow -PassThru
$workSheet = $excelPackage.Workbook.Worksheets[$workSheetname]
$range = $workSheet.Dimension.Address
Set-Format -WorkSheet $workSheet -Range "b:b" -NumberFormat "#,###" -AutoFit
Set-Format -WorkSheet $workSheet -Range "C:C" -NumberFormat "#,##0.00" -AutoFit
Set-Format -WorkSheet $workSheet -Range "F:F" -NumberFormat "dd MMMM HH:mm:ss" -AutoFit
Add-ConditionalFormatting -WorkSheet $workSheet -Range "c2:c1000" -DataBarColor Blue
Add-ConditionalFormatting -WorkSheet $workSheet -Range "b2:B1000" -RuleType GreaterThan -ConditionValue '104857600' -ForeGroundColor "Red" -Bold
Export-Excel -ExcelPackage $excelPackage -WorkSheetname $workSheetname
Convert-ExcelRangeToImage -Path $Path -workSheetname $workSheetname -range $range -destination "$pwd\temp.png" -show
#>
#Convert-ExcelRangeToImage -Path $Path -workSheetname $workSheetname -range $range -destination "$pwd\temp.png" -show

View File

@@ -0,0 +1,161 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# ConvertFrom-ExcelData
## 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.
## SYNTAX
```
ConvertFrom-ExcelData [-Path] <Object> [[-scriptBlock] <ScriptBlock>] [[-WorkSheetname] <Object>]
[[-HeaderRow] <Int32>] [[-Header] <String[]>] [-NoHeader] [-DataOnly] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### EXAMPLE 1
```
ConvertFrom-ExcelData .\testSQLGen.xlsx {
```
param($propertyNames, $record)
$reportRecord = @()
foreach ($pn in $propertyNames) {
$reportRecord += "{0}: {1}" -f $pn, $record.$pn
}
$reportRecord +=""
$reportRecord -join "\`r\`n"
}
First: John
Last: Doe
The Zip: 12345
....
## PARAMETERS
### -Path
{{ Fill Path Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases: FullName
Required: True
Position: 1
Default value: None
Accept pipeline input: True (ByPropertyName, ByValue)
Accept wildcard characters: False
```
### -scriptBlock
{{ Fill scriptBlock Description }}
```yaml
Type: ScriptBlock
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -WorkSheetname
{{ Fill WorkSheetname Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases: Sheet
Required: False
Position: 3
Default value: 1
Accept pipeline input: False
Accept wildcard characters: False
```
### -HeaderRow
{{ Fill HeaderRow Description }}
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: 4
Default value: 1
Accept pipeline input: False
Accept wildcard characters: False
```
### -Header
{{ Fill Header Description }}
```yaml
Type: String[]
Parameter Sets: (All)
Aliases:
Required: False
Position: 5
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -NoHeader
{{ Fill NoHeader Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: False
Accept pipeline input: False
Accept wildcard characters: False
```
### -DataOnly
{{ Fill DataOnly Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: False
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
## OUTPUTS
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,29 @@
function ConvertFrom-ExcelData {
[alias("Use-ExcelData")]
param(
[Alias("FullName")]
[Parameter(ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true)]
[ValidateScript( { Test-Path $_ -PathType Leaf })]
$Path,
[ScriptBlock]$scriptBlock,
[Alias("Sheet")]
$WorkSheetname = 1,
[int]$HeaderRow = 1,
[string[]]$Header,
[switch]$NoHeader,
[switch]$DataOnly
)
$null = $PSBoundParameters.Remove('scriptBlock')
$params = @{} + $PSBoundParameters
$data = Import-Excel @params
$PropertyNames = $data[0].psobject.Properties |
Where-Object {$_.membertype -match 'property'} |
Select-Object -ExpandProperty name
foreach ($record in $data) {
& $scriptBlock $PropertyNames $record
}
}

View File

@@ -0,0 +1,140 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# ConvertFrom-ExcelSheet
## SYNOPSIS
Reads an Excel file an converts the data to a delimited text file.
## SYNTAX
```
ConvertFrom-ExcelSheet [-Path] <String> [[-OutputPath] <String>] [[-SheetName] <String>] [[-Encoding] <String>]
[[-Extension] <String>] [[-Delimiter] <String>] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### EXAMPLE 1
```
ConvertFrom-ExcelSheet .\TestSheets.xlsx .\data
```
Reads each sheet in TestSheets.xlsx and outputs it to the data directory as the sheet name with the extension .txt.
### EXAMPLE 2
```
ConvertFrom-ExcelSheet .\TestSheets.xlsx .\data sheet?0
```
Reads and outputs sheets like Sheet10 and Sheet20 form TestSheets.xlsx and outputs it to the data directory as the sheet name with the extension .txt.
## PARAMETERS
### -Path
{{ Fill Path Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases: FullName
Required: True
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -OutputPath
{{ Fill OutputPath Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: .\
Accept pipeline input: False
Accept wildcard characters: False
```
### -SheetName
{{ Fill SheetName Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 3
Default value: *
Accept pipeline input: False
Accept wildcard characters: False
```
### -Encoding
{{ Fill Encoding Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 4
Default value: UTF8
Accept pipeline input: False
Accept wildcard characters: False
```
### -Extension
{{ Fill Extension Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 5
Default value: .csv
Accept pipeline input: False
Accept wildcard characters: False
```
### -Delimiter
{{ Fill Delimiter Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 6
Default value: ;
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
## OUTPUTS
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,48 @@
function ConvertFrom-ExcelSheet {
[CmdletBinding()]
param
(
[Alias("FullName")]
[Parameter(Mandatory = $true)]
[String]
$Path,
[String]
$OutputPath = '.\',
[String]
$SheetName = "*",
[ValidateSet('ASCII', 'BigEndianUniCode', 'Default', 'OEM', 'UniCode', 'UTF32', 'UTF7', 'UTF8')]
[string]
$Encoding = 'UTF8',
[ValidateSet('.txt', '.log', '.csv')]
[string]
$Extension = '.csv',
[ValidateSet(';', ',')]
[string]
$Delimiter = ';'
)
$Path = (Resolve-Path $Path).Path
$Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, "Open", "Read", "ReadWrite"
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream
$workbook = $xl.Workbook
$targetSheets = $workbook.Worksheets | Where-Object { $_.Name -like $SheetName }
$params = @{ } + $PSBoundParameters
$params.Remove("OutputPath")
$params.Remove("SheetName")
$params.Remove('Extension')
$params.NoTypeInformation = $true
Foreach ($sheet in $targetSheets) {
Write-Verbose "Exporting sheet: $($sheet.Name)"
$params.Path = "$OutputPath\$($Sheet.Name)$Extension"
Import-Excel $Path -Sheet $($sheet.Name) | Export-Csv @params
}
$Stream.Close()
$Stream.Dispose()
$xl.Dispose()
}

View File

@@ -0,0 +1,48 @@
function ConvertFrom-ExcelToSQLInsert {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
$TableName,
[Alias("FullName")]
[Parameter(ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true)]
[ValidateScript( { Test-Path $_ -PathType Leaf })]
$Path,
[Alias("Sheet")]
$WorkSheetname = 1,
[Alias('HeaderRow', 'TopRow')]
[ValidateRange(1, 9999)]
[Int]$StartRow,
[string[]]$Header,
[switch]$NoHeader,
[switch]$DataOnly,
[switch]$ConvertEmptyStringsToNull,
[switch]$UseMSSQLSyntax
)
$null = $PSBoundParameters.Remove('TableName')
$null = $PSBoundParameters.Remove('ConvertEmptyStringsToNull')
$null = $PSBoundParameters.Remove('UseMSSQLSyntax')
$params = @{} + $PSBoundParameters
ConvertFrom-ExcelData @params {
param($propertyNames, $record)
$ColumnNames = "'" + ($PropertyNames -join "', '") + "'"
if($UseMSSQLSyntax) {
$ColumnNames = "[" + ($PropertyNames -join "], [") + "]"
}
$values = foreach ($propertyName in $PropertyNames) {
if ($ConvertEmptyStringsToNull.IsPresent -and [string]::IsNullOrEmpty($record.$propertyName)) {
'NULL'
}
else {
"'" + $record.$propertyName + "'"
}
}
$targetValues = ($values -join ", ")
"INSERT INTO {0} ({1}) Values({2});" -f $TableName, $ColumnNames, $targetValues
}
}

View File

@@ -0,0 +1,72 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# ConvertTo-ExcelXlsx
## SYNOPSIS
Converts an Excel xls to a xlsx using -ComObject
## SYNTAX
```
ConvertTo-ExcelXlsx [-Path] <String> [-Force] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -Path
{{ Fill Path Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: True
Position: 1
Default value: None
Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```
### -Force
{{ Fill Force Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: False
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
## OUTPUTS
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,55 @@
Function ConvertTo-ExcelXlsx {
[CmdletBinding()]
Param
(
[parameter(Mandatory = $true, ValueFromPipeline)]
[string]$Path,
[parameter(Mandatory = $false)]
[switch]$Force
)
Process {
if (-Not ($Path | Test-Path) ) {
throw "File not found"
}
if (-Not ($Path | Test-Path -PathType Leaf) ) {
throw "Folder paths are not allowed"
}
$xlFixedFormat = 51 #Constant for XLSX Workbook
$xlsFile = Get-Item -Path $Path
$xlsxPath = "{0}x" -f $xlsFile.FullName
if ($xlsFile.Extension -ne ".xls") {
throw "Expected .xls extension"
}
if (Test-Path -Path $xlsxPath) {
if ($Force) {
try {
Remove-Item $xlsxPath -Force
}
catch {
throw "{0} already exists and cannot be removed. The file may be locked by another application." -f $xlsxPath
}
Write-Verbose $("Removed {0}" -f $xlsxPath)
}
else {
throw "{0} already exists!" -f $xlsxPath
}
}
try {
$Excel = New-Object -ComObject "Excel.Application"
}
catch {
throw "Could not create Excel.Application ComObject. Please verify that Excel is installed."
}
$Excel.Visible = $false
$null = $Excel.Workbooks.Open($xlsFile.FullName)
$Excel.ActiveWorkbook.SaveAs($xlsxPath, $xlFixedFormat)
$Excel.ActiveWorkbook.Close()
$Excel.Quit()
}
}

View File

@@ -0,0 +1,95 @@
function Copy-ExcelWorkSheet {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,ValueFromPipeline=$true)]
[Alias('SourceWorkbook')]
$SourceObject,
$SourceWorkSheet = 1 ,
[Parameter(Mandatory = $true)]
$DestinationWorkbook,
$DestinationWorksheet,
[Switch]$Show
)
begin {
#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 ($DestinationWorkbook -is [OfficeOpenXml.ExcelPackage] ) {
if ($Show) {$package2 = $DestinationWorkbook}
$DestinationWorkbook = $DestinationWorkbook.Workbook
}
elseif ($DestinationWorkbook -is [string] -and ($DestinationWorkbook -ne $SourceObject)) {
$package2 = Open-ExcelPackage -Create -Path $DestinationWorkbook
$DestinationWorkbook = $package2.Workbook
}
}
process {
#Special case - given the same path for source and destination worksheet
if ($SourceObject -is [System.String] -and $SourceObject -eq $DestinationWorkbook) {
if (-not $DestinationWorksheet) {Write-Warning -Message "You must specify a destination worksheet name if copying within the same workbook."; return}
else {
Write-Verbose -Message "Copying "
$excel = Open-ExcelPackage -Path $SourceObject
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}
}
}
}
end {
#OK Now we can close the destination package
if ($package2) {Close-ExcelPackage -ExcelPackage $package2 -Show:$Show }
if ($Show -and -not $package2) {
Write-Warning -Message "-Show only works if the Destination workbook is given as a file path or an ExcelPackage object."
}
}
}

View File

@@ -0,0 +1,77 @@
function Expand-NumberFormat {
<#
.SYNOPSIS
Converts short names for number formats to the formatting strings used in Excel
.DESCRIPTION
Where you can type a number format you can write, for example, 'Short-Date'
and the module will translate it into the format string used by Excel.
Some formats, like Short-Date change how they are presented when Excel
loads (so date will use the local ordering of year, month and Day). Other
formats change how they appear when loaded with different cultures
(depending on the country "," or "." or " " may be the thousand seperator
although Excel always stores it as ",")
.EXAMPLE
Expand-NumberFormat percentage
Returns "0.00%"
.EXAMPLE
Expand-NumberFormat Currency
Returns the currency format specified in the local regional settings. This
may not be the same as Excel uses. The regional settings set the currency
symbol and then whether it is before or after the number and separated with
a space or not; for negative numbers the number may be wrapped in parentheses
or a - sign might appear before or after the number and symbol.
So this returns $#,##0.00;($#,##0.00) for English US, #,##0.00 €;€#,##0.00-
for French. (Note some Eurozone countries write €1,23 and others 1,23€ )
In French the decimal point will be rendered as a "," and the thousand
separator as a space.
#>
[cmdletbinding()]
[OutputType([String])]
param (
#the format string to Expand
$NumberFormat
)
switch ($NumberFormat) {
"Currency" {
#https://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.currencynegativepattern(v=vs.110).aspx
$sign = [cultureinfo]::CurrentCulture.NumberFormat.CurrencySymbol
switch ([cultureinfo]::CurrentCulture.NumberFormat.CurrencyPositivePattern) {
0 {$pos = "$Sign#,##0.00" ; break }
1 {$pos = "#,##0.00$Sign" ; break }
2 {$pos = "$Sign #,##0.00" ; break }
3 {$pos = "#,##0.00 $Sign" ; break }
}
switch ([cultureinfo]::CurrentCulture.NumberFormat.CurrencyPositivePattern) {
0 {return "$pos;($Sign#,##0.00)" }
1 {return "$pos;-$Sign#,##0.00" }
2 {return "$pos;$Sign-#,##0.00" }
3 {return "$pos;$Sign#,##0.00-" }
4 {return "$pos;(#,##0.00$Sign)" }
5 {return "$pos;-#,##0.00$Sign" }
6 {return "$pos;#,##0.00-$Sign" }
7 {return "$pos;#,##0.00$Sign-" }
8 {return "$pos;-#,##0.00 $Sign" }
9 {return "$pos;-$Sign #,##0.00" }
10 {return "$pos;#,##0.00 $Sign-" }
11 {return "$pos;$Sign #,##0.00-" }
12 {return "$pos;$Sign -#,##0.00" }
13 {return "$pos;#,##0.00- $Sign" }
14 {return "$pos;($Sign #,##0.00)" }
15 {return "$pos;(#,##0.00 $Sign)" }
}
}
"Number" {return "0.00" } # format id 2
"Percentage" {return "0.00%" } # format id 10
"Scientific" {return "0.00E+00" } # format id 11
"Fraction" {return "# ?/?" } # format id 12
"Short Date" {return "mm-dd-yy" } # format id 14 localized on load by Excel.
"Short Time" {return "h:mm" } # format id 20 localized on load by Excel.
"Long Time" {return "h:mm:ss" } # format id 21 localized on load by Excel.
"Date-Time" {return "m/d/yy h:mm"} # format id 22 localized on load by Excel.
"Text" {return "@" } # format ID 49
Default {return $NumberFormat}
}
}

View File

@@ -0,0 +1,670 @@
function Export-Excel {
[CmdletBinding(DefaultParameterSetName = 'Default')]
[OutputType([OfficeOpenXml.ExcelPackage])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
Param(
[Parameter(ParameterSetName = 'Default', Position = 0)]
[String]$Path,
[Parameter(Mandatory = $true, ParameterSetName = "Package")]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Parameter(ValueFromPipeline = $true)]
[Alias('TargetData')]
$InputObject,
[Switch]$Calculate,
[Switch]$Show,
[String]$WorksheetName = 'Sheet1',
[Alias("P")]
[String]$Password,
[switch]$ClearSheet,
[switch]$Append,
[String]$Title,
[OfficeOpenXml.Style.ExcelFillStyle]$TitleFillPattern = 'Solid',
[Switch]$TitleBold,
[Int]$TitleSize = 22,
$TitleBackgroundColor,
[Switch]$IncludePivotTable,
[String]$PivotTableName,
[String[]]$PivotRows,
[String[]]$PivotColumns,
$PivotData,
[String[]]$PivotFilter,
[Switch]$PivotDataToColumn,
[Hashtable]$PivotTableDefinition,
[Switch]$IncludePivotChart,
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie',
[Switch]$NoLegend,
[Switch]$ShowCategory,
[Switch]$ShowPercent,
[Switch]$AutoSize,
$MaxAutoSizeRows = 1000,
[Switch]$NoClobber,
[Switch]$FreezeTopRow,
[Switch]$FreezeFirstColumn,
[Switch]$FreezeTopRowFirstColumn,
[Int[]]$FreezePane,
[Switch]$AutoFilter,
[Switch]$BoldTopRow,
[Switch]$NoHeader,
[ValidateScript( {
if (-not $_) { throw 'RangeName is null or empty.' }
elseif ($_[0] -notmatch '[a-z]') { throw 'RangeName starts with an invalid character.' }
else { $true }
})]
[String]$RangeName,
[Alias('Table')]
$TableName,
[OfficeOpenXml.Table.TableStyles]$TableStyle = [OfficeOpenXml.Table.TableStyles]::Medium6,
[Switch]$Barchart,
[Switch]$PieChart,
[Switch]$LineChart ,
[Switch]$ColumnChart ,
[Object[]]$ExcelChartDefinition,
[String[]]$HideSheet,
[String[]]$UnHideSheet,
[Switch]$MoveToStart,
[Switch]$MoveToEnd,
$MoveBefore ,
$MoveAfter ,
[Switch]$KillExcel,
[Switch]$AutoNameRange,
[Int]$StartRow = 1,
[Int]$StartColumn = 1,
[alias('PT')]
[Switch]$PassThru,
[String]$Numberformat = 'General',
[string[]]$ExcludeProperty,
[Switch]$NoAliasOrScriptPropeties,
[Switch]$DisplayPropertySet,
[String[]]$NoNumberConversion,
[Object[]]$ConditionalFormat,
[Object[]]$ConditionalText,
[Object[]]$Style,
[ScriptBlock]$CellStyleSB,
#If there is already content in the workbook the sheet with the PivotTable will not be active UNLESS Activate is specified
[switch]$Activate,
[Parameter(ParameterSetName = 'Default')]
[Switch]$Now,
[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.
[ValidateSet("Both","Columns","Rows","None")]
[String]$PivotTotals = "Both",
#Included for compatibility - equivalent to -PivotTotals "None"
[Switch]$NoTotalsInPivot,
[Switch]$ReZip
)
begin {
$numberRegex = [Regex]'\d'
$isDataTypeValueType = $false
if ($NoClobber) {Write-Warning -Message "-NoClobber parameter is no longer used" }
#Open the file, get the worksheet, and decide where in the sheet we are writing, and if there is a number format to apply.
try {
$script:Header = $null
if ($Append -and $ClearSheet) {throw "You can't use -Append AND -ClearSheet." ; return}
#To force -Now not to format as a table, allow $false in -TableName to be "No table"
$TableName = if ($null -eq $TableName -or ($TableName -is [bool] -and $false -eq $TableName)) { $null } else {[String]$TableName}
if ($Now -or (-not $Path -and -not $ExcelPackage) ) {
if (-not $PSBoundParameters.ContainsKey("Path")) { $Path = [System.IO.Path]::GetTempFileName() -replace '\.tmp', '.xlsx' }
if (-not $PSBoundParameters.ContainsKey("Show")) { $Show = $true }
if (-not $PSBoundParameters.ContainsKey("AutoSize")) { $AutoSize = $true }
#"Now" option will create a table, unless something passed in TableName/Table Style. False in TableName will block autocreation
if (-not $PSBoundParameters.ContainsKey("TableName") -and
-not $PSBoundParameters.ContainsKey("TableStyle") -and
-not $AutoFilter) {
$TableName = 'Table1'
}
}
if ($ExcelPackage) {
$pkg = $ExcelPackage
$Path = $pkg.File
}
Else { $pkg = Open-ExcelPackage -Path $Path -Create -KillExcel:$KillExcel -Password:$Password}
}
catch {throw "Could not open Excel Package $path"}
try {
$params = @{WorksheetName=$WorksheetName}
foreach ($p in @("ClearSheet", "MoveToStart", "MoveToEnd", "MoveBefore", "MoveAfter", "Activate")) {if ($PSBoundParameters[$p]) {$params[$p] = $PSBoundParameters[$p]}}
$ws = $pkg | Add-WorkSheet @params
if ($ws.Name -ne $WorksheetName) {
Write-Warning -Message "The Worksheet name has been changed from $WorksheetName to $($ws.Name), this may cause errors later."
$WorksheetName = $ws.Name
}
}
catch {throw "Could not get worksheet $worksheetname"}
try {
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
$headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
#using a slightly odd syntax otherwise header ends up as a 2D array
$ws.Cells[$headerRange].Value | ForEach-Object -Begin {$Script:header = @()} -Process {$Script:header += $_ }
#if we did not get AutoNameRange, but headers have ranges of the same name make autoNameRange True, otherwise make it false
if (-not $AutoNameRange) {
$AutoNameRange = $true ; foreach ($h in $header) {if ($ws.names.name -notcontains $h) {$AutoNameRange = $false} }
}
#if we did not get a Rangename but there is a Range which covers the active part of the sheet, set Rangename to that.
if (-not $RangeName -and $ws.names.where({$_.name[0] -match '[a-z]'})) {
$theRange = $ws.names.where({
($_.Name[0] -match '[a-z]' ) -and
($_.Start.Row -eq $StartRow) -and
($_.Start.Column -eq $StartColumn) -and
($_.End.Row -eq $ws.Dimension.End.Row) -and
($_.End.Column -eq $ws.Dimension.End.column) } , 'First', 1)
if ($theRange) {$rangename = $theRange.name}
}
#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 ($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
$AutoFilter = $false
}
#if we did not get $autofilter but a filter range is set and it covers the right area, set autofilter to true
elseif (-not $AutoFilter -and $ws.Names['_xlnm._FilterDatabase']) {
if ( ($ws.Names['_xlnm._FilterDatabase'].Start.Row -eq $StartRow) -and
($ws.Names['_xlnm._FilterDatabase'].Start.Column -eq $StartColumn) -and
($ws.Names['_xlnm._FilterDatabase'].End.Row -eq $ws.Dimension.End.Row) -and
($ws.Names['_xlnm._FilterDatabase'].End.Column -eq $ws.Dimension.End.Column) ) {$AutoFilter = $true}
}
$row = $ws.Dimension.End.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) {
#Can only add a title if not appending!
$Row = $StartRow
$ws.Cells[$Row, $StartColumn].Value = $Title
$ws.Cells[$Row, $StartColumn].Style.Font.Size = $TitleSize
if ($PSBoundParameters.ContainsKey("TitleBold")) {
#Set title to Bold face font if -TitleBold was specified.
#Otherwise the default will be unbolded.
$ws.Cells[$Row, $StartColumn].Style.Font.Bold = [boolean]$TitleBold
}
if ($TitleBackgroundColor ) {
if ($TitleBackgroundColor -is [string]) {$TitleBackgroundColor = [System.Drawing.Color]::$TitleBackgroundColor }
$ws.Cells[$Row, $StartColumn].Style.Fill.PatternType = $TitleFillPattern
$ws.Cells[$Row, $StartColumn].Style.Fill.BackgroundColor.SetColor($TitleBackgroundColor)
}
$Row ++ ; $startRow ++
}
else { $Row = $StartRow }
$ColumnIndex = $StartColumn
$Numberformat = Expand-NumberFormat -NumberFormat $Numberformat
if ((-not $ws.Dimension) -and ($Numberformat -ne $ws.Cells.Style.Numberformat.Format)) {
$ws.Cells.Style.Numberformat.Format = $Numberformat
$setNumformat = $false
}
else { $setNumformat = ($Numberformat -ne $ws.Cells.Style.Numberformat.Format) }
}
catch {throw "Failed preparing to export to worksheet '$WorksheetName' to '$Path': $_"}
#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
if it is a data table don't do foreach on it (slow) - put the whole table in and set dates on date columns,
set things up for the end block, and skip the process block #>
if ($InputObject -is [System.Data.DataTable]) {
#don't leave caller with a renamed table, save the name and set it back later
$orginalTableName = $InputObject.TableName
if ($TableName) {
$InputObject.TableName = $TableName
}
while ($InputObject.TableName -in $pkg.Workbook.Worksheets.Tables.name) {
Write-Warning "Table name $($InputObject.TableName) is not unique, adding '_' to it "
$InputObject.TableName += "_"
}
if ($TableName -or $PSBoundParameters.ContainsKey("TableStyle")) {
$TableName = $null
$null = $ws.Cells[$row,$StartColumn].LoadFromDataTable($InputObject, (-not $noHeader),$TableStyle )
}
else {
$null = $ws.Cells[$row,$StartColumn].LoadFromDataTable($InputObject, (-not $noHeader) )
}
$InputObject.TableName = $orginalTableName
foreach ($c in $InputObject.Columns.where({$_.datatype -eq [datetime]})) {
Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat 'Date-Time'
}
foreach ($c in $InputObject.Columns.where({$_.datatype -eq [timespan]})) {
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 { if ($PSBoundParameters.ContainsKey("InputObject")) {
try {
if ($null -eq $InputObject) {$row += 1}
foreach ($TargetData in $InputObject) {
if ($firstTimeThru) {
$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')
if ($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'" }
}
#region Add headers - if we are appending, or we have been through here once already we will have the headers
if (-not $script:Header) {
if ($DisplayPropertySet -and $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
$script:Header = $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( {$_ -notin $ExcludeProperty})
}
else {
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 {
$ColumnIndex = $StartColumn
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
<#
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 {
if ($firstTimeThru -and $ws.Dimension) {
$LastRow = $ws.Dimension.End.Row
$LastCol = $ws.Dimension.End.Column
$endAddress = $ws.Dimension.End.Address
}
else {
$LastRow = $Row
$LastCol = $ColumnIndex
$endAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($LastRow , $LastCol)
}
$startAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($StartRow, $StartColumn)
$dataRange = "{0}:{1}" -f $startAddress, $endAddress
Write-Debug "Data Range '$dataRange'"
if ($AutoNameRange) {
try {
if (-not $script:header) {
# if there aren't any headers, use the the first row of data to name the ranges: this is the last point that headers will be used.
$headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow
#using a slightly odd syntax otherwise header ends up as a 2D array
$ws.Cells[$headerRange].Value | ForEach-Object -Begin {$Script:header = @()} -Process {$Script:header += $_ }
if ($PSBoundParameters.ContainsKey($TargetData)) { #if Export was called with data that writes no header start the range at $startRow ($startRow is data)
$targetRow = $StartRow
}
else { $targetRow = $StartRow + 1 } #if Export was called without data to add names (assume $startRow is a header) or...
} # ... called with data that writes a header, then start the range at $startRow + 1
else { $targetRow = $StartRow + 1 }
#Dimension.start.row always seems to be one so we work out the target row
#, but start.column is the first populated one and .Columns is the count of populated ones.
# 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
foreach ($c in 0..($LastCol - $StartColumn)) {
$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 )]
try {#this test can throw with some names, surpress any error
if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress(($targetRangeName -replace '\W' , '_' ))) {
Write-Warning -Message "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property."
}
}
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': $_" }
}
#Empty string is not allowed as a name for ranges or tables.
if ($RangeName) { Add-ExcelName -Range $ws.Cells[$dataRange] -RangeName $RangeName}
#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) {
Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $PSBoundParameters['TableName'] -TableStyle $TableStyle
}
elseif ($PSBoundParameters.ContainsKey('TableStyle')) {
Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName "" -TableStyle $TableStyle
}
elseif ($AutoFilter) {
try {
$ws.Cells[$dataRange].AutoFilter = $true
Write-Verbose -Message "Enabled autofilter. "
}
catch {Write-Warning -Message "Failed adding autofilter to worksheet '$WorksheetName': $_"}
}
if ($PivotTableDefinition) {
foreach ($item in $PivotTableDefinition.GetEnumerator()) {
$params = $item.value
if ($Activate) {$params.Activate = $true }
if ($params.keys -notcontains 'SourceRange' -and
($params.Keys -notcontains 'SourceWorkSheet' -or $params.SourceWorkSheet -eq $WorksheetName)) {$params.SourceRange = $dataRange}
if ($params.Keys -notcontains 'SourceWorkSheet') {$params.SourceWorkSheet = $ws }
if ($params.Keys -notcontains 'NoTotalsInPivot' -and $NoTotalsInPivot ) {$params.PivotTotals = 'None'}
if ($params.Keys -notcontains 'PivotTotals' -and $PivotTotals ) {$params.PivotTotals = $PivotTotals}
if ($params.Keys -notcontains 'PivotDataToColumn' -and $PivotDataToColumn) {$params.PivotDataToColumn = $true}
Add-PivotTable -ExcelPackage $pkg -PivotTableName $item.key @Params
}
}
if ($IncludePivotTable -or $IncludePivotChart) {
$params = @{
'SourceRange' = $dataRange
}
if ($PivotTableName -and ($pkg.workbook.worksheets.tables.name -contains $PivotTableName)) {
Write-Warning -Message "The selected PivotTable name '$PivotTableName' is already used as a table name. Adding a suffix of 'Pivot'."
$PivotTableName += 'Pivot'
}
if ($PivotTableName) {$params.PivotTableName = $PivotTableName}
else {$params.PivotTableName = $WorksheetName + 'PivotTable'}
if ($Activate) {$params.Activate = $true }
if ($PivotFilter) {$params.PivotFilter = $PivotFilter}
if ($PivotRows) {$params.PivotRows = $PivotRows}
if ($PivotColumns) {$Params.PivotColumns = $PivotColumns}
if ($PivotData) {$Params.PivotData = $PivotData}
if ($NoTotalsInPivot) {$params.PivotTotals = "None" }
Elseif ($PivotTotals) {$params.PivotTotals = $PivotTotals}
if ($PivotDataToColumn) {$params.PivotDataToColumn = $true}
if ($IncludePivotChart) {
$params.IncludePivotChart = $true
$Params.ChartType = $ChartType
if ($ShowCategory) {$params.ShowCategory = $true}
if ($ShowPercent) {$params.ShowPercent = $true}
if ($NoLegend) {$params.NoLegend = $true}
}
Add-PivotTable -ExcelPackage $pkg -SourceWorkSheet $ws @params
}
try {
#Allow single switch or two seperate ones.
if ($FreezeTopRowFirstColumn -or ($FreezeTopRow -and $FreezeFirstColumn)) {
$ws.View.FreezePanes(2, 2)
Write-Verbose -Message "Froze top row and first column"
}
elseif ($FreezeTopRow) {
$ws.View.FreezePanes(2, 1)
Write-Verbose -Message "Froze top row"
}
elseif ($FreezeFirstColumn) {
$ws.View.FreezePanes(1, 2)
Write-Verbose -Message "Froze first column"
}
#Must be 1..maxrows or and array of 1..maxRows,1..MaxCols
if ($FreezePane) {
$freezeRow, $freezeColumn = $FreezePane
if (-not $freezeColumn -or $freezeColumn -eq 0) {
$freezeColumn = 1
}
if ($freezeRow -ge 1) {
$ws.View.FreezePanes($freezeRow, $freezeColumn)
Write-Verbose -Message "Froze panes at row $freezeRow and column $FreezeColumn"
}
}
}
catch {Write-Warning -Message "Failed adding Freezing the panes in worksheet '$WorksheetName': $_"}
if ($PSBoundParameters.ContainsKey("BoldTopRow")) { #it sets bold as far as there are populated cells: for whole row could do $ws.row($x).style.font.bold = $true
try {
if ($Title) {
$range = $ws.Dimension.Address -replace '\d+', ($StartRow + 1)
}
else {
$range = $ws.Dimension.Address -replace '\d+', $StartRow
}
$ws.Cells[$range].Style.Font.Bold = [boolean]$BoldTopRow
Write-Verbose -Message "Set $range font style to bold."
}
catch {Write-Warning -Message "Failed setting the top row to bold in worksheet '$WorksheetName': $_"}
}
if ($AutoSize -and -not $env:NoAutoSize) {
try {
#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"
}
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) {
try {
$pkg.Workbook.WorkSheets.Where({$_.Name -like $sheet}) | ForEach-Object {
$_.Hidden = 'Hidden'
Write-verbose -Message "Sheet '$($_.Name)' Hidden."
}
}
catch {Write-Warning -Message "Failed hiding worksheet '$sheet': $_"}
}
foreach ($Sheet in $UnHideSheet) {
try {
$pkg.Workbook.WorkSheets.Where({$_.Name -like $sheet}) | ForEach-Object {
$_.Hidden = 'Visible'
Write-verbose -Message "Sheet '$($_.Name)' shown"
}
}
catch {Write-Warning -Message "Failed showing worksheet '$sheet': $_"}
}
if (-not $pkg.Workbook.Worksheets.Where({$_.Hidden -eq 'visible'})) {
Write-Verbose -Message "No Sheets were left visible, making $WorksheetName visible"
$ws.Hidden = 'Visible'
}
foreach ($chartDef in $ExcelChartDefinition) {
if ($chartDef -is [System.Management.Automation.PSCustomObject]) {
$params = @{}
$chartDef.PSObject.Properties | ForEach-Object {if ( $null -ne $_.value) {$params[$_.name] = $_.value}}
Add-ExcelChart -Worksheet $ws @params
}
elseif ($chartDef -is [hashtable] -or $chartDef -is[System.Collections.Specialized.OrderedDictionary]) {
Add-ExcelChart -Worksheet $ws @chartDef
}
}
if ($Calculate) {
try { [OfficeOpenXml.CalculationExtension]::Calculate($ws) }
catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook. $_"}
}
if ($Barchart -or $PieChart -or $LineChart -or $ColumnChart) {
if ($NoHeader) {$FirstDataRow = $startRow}
else {$FirstDataRow = $startRow + 1 }
$range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $startColumn, $FirstDataRow, $lastCol )
$xCol = $ws.cells[$range] | Where-Object {$_.value -is [string] } | ForEach-Object {$_.start.column} | Sort-Object | Select-Object -first 1
if (-not $xcol) {
$xcol = $StartColumn
$range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, ($startColumn +1), $FirstDataRow, $lastCol )
}
$yCol = $ws.cells[$range] | Where-Object {$_.value -is [valueType] -or $_.Formula } | ForEach-Object {$_.start.column} | Sort-Object | Select-Object -first 1
if (-not ($xCol -and $ycol)) { Write-Warning -Message "Can't identify a string column and a number column to use as chart labels and data. "}
else {
$params = @{
XRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $xcol , $lastrow, $xcol)
YRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $ycol , $lastrow, $ycol)
Title = ''
Column = ($lastCol +1)
Width = 800
}
if ($ShowPercent) {$params["ShowPercent"] = $true}
if ($ShowCategory) {$params["ShowCategory"] = $true}
if ($NoLegend) {$params["NoLegend"] = $true}
if (-not $NoHeader) {$params["SeriesHeader"] = $ws.Cells[$startRow, $YCol].Value}
if ($ColumnChart) {$Params["chartType"] = "ColumnStacked" }
elseif ($Barchart) {$Params["chartType"] = "BarStacked" }
elseif ($PieChart) {$Params["chartType"] = "PieExploded3D" }
elseif ($LineChart) {$Params["chartType"] = "Line" }
Add-ExcelChart -Worksheet $ws @params
}
}
# It now doesn't matter if the conditional formating rules are passed in $conditionalText or $conditional format.
# Just one with an alias for compatiblity it will break things for people who are using both at once
foreach ($c in (@() + $ConditionalText + $ConditionalFormat) ) {
try {
#we can take an object with a .ConditionalType property made by New-ConditionalText or with a .Formatter Property made by New-ConditionalFormattingIconSet or a hash table
if ($c.ConditionalType) {
$cfParams = @{RuleType = $c.ConditionalType; ConditionValue = $c.Text ;
BackgroundColor = $c.BackgroundColor; BackgroundPattern = $c.PatternType ;
ForeGroundColor = $c.ConditionalTextColor}
if ($c.Range) {$cfParams.Range = $c.Range}
else {$cfParams.Range = $ws.Dimension.Address }
Add-ConditionalFormatting -WorkSheet $ws @cfParams
Write-Verbose -Message "Added conditional formatting to range $($c.range)"
}
elseif ($c.formatter) {
switch ($c.formatter) {
"ThreeIconSet" {Add-ConditionalFormatting -WorkSheet $ws -ThreeIconsSet $c.IconType -range $c.range -reverse:$c.reverse }
"FourIconSet" {Add-ConditionalFormatting -WorkSheet $ws -FourIconsSet $c.IconType -range $c.range -reverse:$c.reverse }
"FiveIconSet" {Add-ConditionalFormatting -WorkSheet $ws -FiveIconsSet $c.IconType -range $c.range -reverse:$c.reverse }
}
Write-Verbose -Message "Added conditional formatting to range $($c.range)"
}
elseif ($c -is [hashtable] -or $c -is[System.Collections.Specialized.OrderedDictionary]) {
if (-not $c.Range -or $c.Address) {$c.Address = $ws.Dimension.Address }
Add-ConditionalFormatting -WorkSheet $ws @c
}
}
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) {
try {
$TotalRows = $ws.Dimension.Rows
$LastColumn = $ws.Dimension.Address -replace "^.*:(\w*)\d+$" , '$1'
& $CellStyleSB $ws $TotalRows $LastColumn
}
catch {Write-Warning -Message "Failed processing CellStyleSB in worksheet '$WorksheetName': $_"}
}
#Can only add password, may want to support -password $Null removing password.
if ($Password) {
try {
$ws.Protection.SetPassword($Password)
Write-Verbose -Message 'Set password on workbook'
}
catch {throw "Failed setting password for worksheet '$WorksheetName': $_"}
}
if ($PassThru) { $pkg }
else {
if ($ReturnRange) {$dataRange }
if ($Password) { $pkg.Save($Password) }
else { $pkg.Save() }
Write-Verbose -Message "Saved workbook $($pkg.File)"
if ($ReZip) {
Write-Verbose -Message "Re-Zipping $($pkg.file) using .NET ZIP library"
try {
Add-Type -AssemblyName 'System.IO.Compression.Filesystem' -ErrorAction stop
}
catch {
Write-Error "The -ReZip parameter requires .NET Framework 4.5 or later to be installed. Recommend to install Powershell v4+"
continue
}
try {
$TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
$null = [io.compression.zipfile]::ExtractToDirectory($pkg.File, $TempZipPath)
Remove-Item $pkg.File -Force
$null = [io.compression.zipfile]::CreateFromDirectory($TempZipPath, $pkg.File)
}
catch {throw "Error resizipping $path : $_"}
}
$pkg.Dispose()
if ($Show) { Invoke-Item $Path }
}
}
}

View File

@@ -0,0 +1,138 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Export-ExcelSheet
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Export-ExcelSheet [-Path] <String> [[-OutputPath] <String>] [[-SheetName] <String>] [[-Encoding] <String>] [[-Extension] <String>] [[-Delimiter] <String>] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -Delimiter
{{ Fill Delimiter Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Accepted values: ;, ,
Required: False
Position: 5
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Encoding
{{ Fill Encoding Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Accepted values: ASCII, BigEndianUniCode, Default, OEM, UniCode, UTF32, UTF7, UTF8
Required: False
Position: 3
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Extension
{{ Fill Extension Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Accepted values: .txt, .log, .csv
Required: False
Position: 4
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -OutputPath
{{ Fill OutputPath Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Path
{{ Fill Path Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -SheetName
{{ Fill SheetName Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,40 @@
function Export-ExcelSheet {
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[String]$Path,
[String]$OutputPath = '.\',
[String]$SheetName,
[ValidateSet('ASCII', 'BigEndianUniCode','Default','OEM','UniCode','UTF32','UTF7','UTF8')]
[string]$Encoding = 'UTF8',
[ValidateSet('.txt', '.log','.csv')]
[string]$Extension = '.csv',
[ValidateSet(';', ',')]
[string]$Delimiter = ';'
)
$Path = (Resolve-Path $Path).Path
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path
$workbook = $xl.Workbook
$targetSheets = $workbook.Worksheets | Where-Object {$_.Name -Match $SheetName}
$params = @{} + $PSBoundParameters
$params.Remove("OutputPath")
$params.Remove("SheetName")
$params.Remove('Extension')
$params.NoTypeInformation = $true
Foreach ($sheet in $targetSheets)
{
Write-Verbose "Exporting sheet: $($sheet.Name)"
$params.Path = "$OutputPath\$($Sheet.Name)$Extension"
Import-Excel $Path -Sheet $($sheet.Name) | Export-Csv @params
}
$xl.Dispose()
}

View File

@@ -0,0 +1,120 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Export-MultipleExcelSheets
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Export-MultipleExcelSheets [-Path] <Object> [-InfoMap] <Hashtable> [[-Password] <String>] [-Show] [-AutoSize] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -AutoSize
{{ Fill AutoSize Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -InfoMap
{{ Fill InfoMap Description }}
```yaml
Type: Hashtable
Parameter Sets: (All)
Aliases:
Required: True
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Password
{{ Fill Password Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Path
{{ Fill Path Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Show
{{ Fill Show Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,27 @@
function Export-MultipleExcelSheets {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
param(
[Parameter(Mandatory = $true)]
$Path,
[Parameter(Mandatory = $true)]
[hashtable]$InfoMap,
[string]$Password,
[Switch]$Show,
[Switch]$AutoSize
)
$parameters = @{ } + $PSBoundParameters
$parameters.Remove("InfoMap")
$parameters.Remove("Show")
$parameters.Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
foreach ($entry in $InfoMap.GetEnumerator()) {
Write-Progress -Activity "Exporting" -Status "$($entry.Key)"
$parameters.WorkSheetname = $entry.Key
& $entry.Value | Export-Excel @parameters
}
if ($Show) { Invoke-Item $Path }
}

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

@@ -0,0 +1,60 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Get-ExcelColumnName
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Get-ExcelColumnName [[-columnNumber] <Object>] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -columnNumber
{{ Fill columnNumber Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### System.Object
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,27 @@
function Get-ExcelColumnName {
param(
[Parameter(ValueFromPipeline=$true)]
$columnNumber=1
)
Process {
$dividend = $columnNumber
$columnName = New-Object System.Collections.ArrayList($null)
while($dividend -gt 0) {
$modulo = ($dividend - 1) % 26
if ($columnName.length -eq 0) {
[char](65 + $modulo)
} else {
$columnName.insert(0,[char](65 + $modulo))
}
$dividend = [int](($dividend -$modulo)/26)
}
[PSCustomObject] @{
ColumnNumber = $columnNumber
ColumnName = $columnName -join ''
}
}
}

View File

@@ -0,0 +1,28 @@
Function Get-ExcelSheetInfo {
[CmdletBinding()]
param(
[Alias('FullName')]
[Parameter(ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true, Mandatory=$true)]
$Path
)
process {
$Path = (Resolve-Path $Path).ProviderPath
$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path,'Open','Read','ReadWrite'
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream
$workbook = $xl.Workbook
if ($workbook -and $workbook.Worksheets) {
$workbook.Worksheets |
Select-Object -Property name,index,hidden,@{
Label = 'Path'
Expression = {$Path}
}
}
$stream.Close()
$stream.Dispose()
$xl.Dispose()
$xl = $null
}
}

View File

@@ -0,0 +1,27 @@
Function Get-ExcelWorkbookInfo {
[CmdletBinding()]
Param (
[Alias('FullName')]
[Parameter(ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true, Mandatory=$true)]
[String]$Path
)
Process {
Try {
$Path = (Resolve-Path $Path).ProviderPath
$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path,'Open','Read','ReadWrite'
$xl = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $stream
$workbook = $xl.Workbook
$workbook.Properties
$stream.Close()
$stream.Dispose()
$xl.Dispose()
$xl = $null
}
Catch {
throw "Failed retrieving Excel workbook information for '$Path': $_"
}
}
}

View File

@@ -0,0 +1,121 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Get-HtmlTable
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Get-HtmlTable [-url] <Object> [[-tableIndex] <Object>] [[-Header] <Object>] [[-FirstDataRow] <Int32>]
[-UseDefaultCredentials] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -FirstDataRow
{{ Fill FirstDataRow Description }}
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: 3
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Header
{{ Fill Header Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -UseDefaultCredentials
{{ Fill UseDefaultCredentials Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -tableIndex
{{ Fill tableIndex Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -url
{{ Fill url Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,44 @@
# https://www.leeholmes.com/blog/2015/01/05/extracting-tables-from-powershells-invoke-webrequest/
# tweaked from the above code
function Get-HtmlTable {
param(
[Parameter(Mandatory=$true)]
$url,
$tableIndex=0,
$Header,
[int]$FirstDataRow=0,
[Switch]$UseDefaultCredentials
)
$r = Invoke-WebRequest $url -UseDefaultCredentials: $UseDefaultCredentials
$table = $r.ParsedHtml.getElementsByTagName("table")[$tableIndex]
$propertyNames=$Header
$totalRows=@($table.rows).count
for ($idx = $FirstDataRow; $idx -lt $totalRows; $idx++) {
$row = $table.rows[$idx]
$cells = @($row.cells)
if(!$propertyNames) {
if($cells[0].tagName -eq 'th') {
$propertyNames = @($cells | ForEach-Object {$_.innertext -replace ' ',''})
} else {
$propertyNames = @(1..($cells.Count + 2) | Foreach-Object { "P$_" })
}
continue
}
$result = [ordered]@{}
for($counter = 0; $counter -lt $cells.Count; $counter++) {
$propertyName = $propertyNames[$counter]
if(!$propertyName) { $propertyName= '[missing]'}
$result.$propertyName= $cells[$counter].InnerText
}
[PSCustomObject]$result
}
}

View File

@@ -0,0 +1,87 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Get-Range
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Get-Range [[-start] <Object>] [[-stop] <Object>] [[-step] <Object>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -start
{{ Fill start Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -step
{{ Fill step Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -stop
{{ Fill stop Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,3 @@
function Get-Range ($start=0,$stop,$step=1) {
for ($idx = $start; $idx -lt $stop; $idx+=$step) {$idx}
}

View File

@@ -0,0 +1,57 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Get-XYRange
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Get-XYRange [[-targetData] <Object>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -targetData
{{ Fill targetData Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,26 @@
function Get-XYRange {
param($targetData)
$record = $targetData | Select-Object -First 1
$p=$record.psobject.Properties.name
$infer = for ($idx = 0; $idx -lt $p.Count; $idx++) {
$name = $p[$idx]
$value = $record.$name
$result=Invoke-AllTests $value -OnlyPassing -FirstOne
[PSCustomObject]@{
Name = $name
Value = $value
DataType = $result.DataType
ExcelColumn = (Get-ExcelColumnName ($idx+1)).ColumnName
}
}
[PSCustomObject]@{
XRange = $infer | Where-Object -FilterScript {$_.datatype -match 'string'} | Select-Object -First 1 -Property excelcolumn, name
YRange = $infer | Where-Object -FilterScript {$_.datatype -match 'int|double'} | Select-Object -First 1 -Property excelcolumn, name
}
}

View File

@@ -0,0 +1,399 @@
function Import-Excel {
<#
.SYNOPSIS
Create custom objects from the rows in an Excel worksheet.
.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.
By default, the property names of the objects are retrieved from the column headers. Because an object cannot have a blank 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.
.PARAMETER Path
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
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
Import only rows and columns that contain data, empty rows and empty columns are not imported.
.PARAMETER HeaderName
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.
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.
.PARAMETER NoHeader
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.
.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.
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
By default all rows up to the last cell in the sheet will be imported. If specified, import stops at this row.
.PARAMETER StartColumn
The number of the first column to read data from (1 by default).
.PARAMETER EndColumn
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
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 doesnt 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
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: 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 -HeaderName 'Movie name', 'Year', 'Rating', 'Genre'
Movie name: The Bodyguard
Year : 1992
Rating : 9
Genre :
Movie name: The Matrix
Year : 1999
Rating : 8
Genre :
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
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.
.EXAMPLE
>
PS> ,(Import-Excel -Path .\SysTables_AdventureWorks2014.xlsx) |
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.
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.
NOTE: You need to install the SqlServer module from the PowerShell Gallery in oder to get the Write-SqlTableData cmdlet.
.LINK
https://github.com/dfinke/ImportExcel
.NOTES
#>
[CmdLetBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
Param (
[Alias('FullName')]
[Parameter(ParameterSetName = "PathA", Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0 )]
[Parameter(ParameterSetName = "PathB", Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0 )]
[Parameter(ParameterSetName = "PathC", Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, Position = 0 )]
[String]$Path,
[Parameter(ParameterSetName = "PackageA", Mandatory)]
[Parameter(ParameterSetName = "PackageB", Mandatory)]
[Parameter(ParameterSetName = "PackageC", Mandatory)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Alias('Sheet')]
[Parameter(Position = 1)]
[ValidateNotNullOrEmpty()]
[String]$WorksheetName,
[Parameter(ParameterSetName = 'PathB' , Mandatory)]
[Parameter(ParameterSetName = 'PackageB', Mandatory)]
[String[]]$HeaderName ,
[Parameter(ParameterSetName = 'PathC' , Mandatory)]
[Parameter(ParameterSetName = 'PackageC', Mandatory)]
[Switch]$NoHeader ,
[Alias('HeaderRow', 'TopRow')]
[ValidateRange(1, 9999)]
[Int]$StartRow = 1,
[Alias('StopRow', 'BottomRow')]
[Int]$EndRow ,
[Alias('LeftColumn')]
[Int]$StartColumn = 1,
[Alias('RightColumn')]
[Int]$EndColumn ,
[Switch]$DataOnly,
[string[]]$AsText,
[ValidateNotNullOrEmpty()]
[String]$Password
)
begin {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
Function Get-PropertyNames {
<#
.SYNOPSIS
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 (
[Parameter(Mandatory)]
[Int[]]$Columns,
[Parameter(Mandatory)]
[Int]$StartRow
)
Try {
if ($HeaderName) {
$i = 0
foreach ($H in $HeaderName) {
$H | Select-Object @{N = 'Column'; E = { $Columns[$i] } }, @{N = 'Value'; E = { $H } }
$i++
}
}
elseif ($NoHeader) {
$i = 0
foreach ($C in $Columns) {
$i++
$C | Select-Object @{N = 'Column'; E = { $_ } }, @{N = 'Value'; E = { 'P' + $i } }
}
}
else {
if ($StartRow -lt 1) {
throw 'The top row can never be less than 1 when we need to retrieve headers from the worksheet.' ; return
}
foreach ($C in $Columns) {
$Worksheet.Cells[$StartRow, $C] | Where-Object { $_.Value } | Select-Object @{N = 'Column'; E = { $C } }, Value
}
}
}
Catch {
throw "Failed creating property names: $_" ; return
}
}
}
process {
if ($path) {
$extension = [System.IO.Path]::GetExtension($Path)
if ($extension -notmatch '.xlsx$|.xlsm$') {
throw "Import-Excel does not support reading this extension type $($extension)"
}
$resolvedPath = (Resolve-Path $Path -ErrorAction SilentlyContinue)
if ($resolvedPath) {
$Path = $resolvedPath.ProviderPath
}
else {
throw "'$($Path)' file not found"
}
$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
#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 (-not $EndRow ) { $EndRow = $Worksheet.Dimension.End.Row }
if (-not $EndColumn) { $EndColumn = $Worksheet.Dimension.End.Column }
$endAddress = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[$EndRow]C[$EndColumn]", 0, 0)
if ($DataOnly) {
#If we are using headers startrow will be the header-row so examine data from startRow + 1,
if ($NoHeader) { $range = "A" + ($StartRow ) + ":" + $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.
#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 ($null -ne $cell.Value ) { $colHash[$cell.Start.Column] = 1; $rowHash[$cell.Start.row] = 1 }
}
$rows = ( $StartRow..$EndRow ).Where( { $rowHash[$_] })
$columns = ($StartColumn..$EndColumn).Where( { $colHash[$_] })
}
else {
$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." } }
elseif ($HeaderName) { $Rows = $StartRow..$EndRow }
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
#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."; return
}
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."; return
}
#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
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) {
#Disabled write-verbose for speed
# Write-Verbose "Import row '$R'"
$NewRow = [Ordered]@{ }
if ($TextColRegEx) {
foreach ($P in $PropertyNames) {
if ($TextColRegEx.IsMatch($P.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
}
#endregion
}
Write-Debug $sw.Elapsed.TotalMilliseconds
}
catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$Worksheetname': $_"; return }
finally {
if ($Path) { $stream.close(); $ExcelPackage.Dispose() }
}
}
}

View File

@@ -0,0 +1,121 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Import-Html
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Import-Html [[-url] <Object>] [[-index] <Object>] [[-Header] <Object>] [[-FirstDataRow] <Int32>]
[-UseDefaultCredentials] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -FirstDataRow
{{ Fill FirstDataRow Description }}
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: 3
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Header
{{ Fill Header Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -UseDefaultCredentials
{{ Fill UseDefaultCredentials Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -index
{{ Fill index Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -url
{{ Fill url Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

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

View File

@@ -0,0 +1,72 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Import-UPS
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Import-UPS [[-TrackingNumber] <Object>] [-UseDefaultCredentials]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -TrackingNumber
{{ Fill TrackingNumber Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -UseDefaultCredentials
{{ Fill UseDefaultCredentials Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,18 @@
function Import-USPS {
param(
$TrackingNumber,
[Switch]$UseDefaultCredentials
)
Import-Html "https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=$($TrackingNumber)" 0 -UseDefaultCredentials: $UseDefaultCredentials
}
function Import-UPS {
param(
$TrackingNumber,
[Switch]$UseDefaultCredentials
)
Import-Html "https://wwwapps.ups.com/WebTracking/track?track=yes&trackNums=$($TrackingNumber)" 0 -UseDefaultCredentials: $UseDefaultCredentials
}

View File

@@ -0,0 +1,72 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Import-USPS
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Import-USPS [[-TrackingNumber] <Object>] [-UseDefaultCredentials]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -TrackingNumber
{{ Fill TrackingNumber Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -UseDefaultCredentials
{{ Fill UseDefaultCredentials Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,9 @@
function Import-USPS {
param(
$TrackingNumber,
[Switch]$UseDefaultCredentials
)
Import-Html "https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=$($TrackingNumber)" 0 -UseDefaultCredentials: $UseDefaultCredentials
}

View File

@@ -0,0 +1,87 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version: https://github.com/dfinke/ImportExcel
schema: 2.0.0
---
# Invoke-Sum
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Invoke-Sum [[-data] <Object>] [[-dimension] <Object>] [[-measure] <Object>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -data
{{ Fill data Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -dimension
{{ Fill dimension Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -measure
{{ Fill measure Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,41 @@
function Invoke-Sum {
param(
$data,
$dimension,
$measure
)
if(!$measure) {$measure = $dimension}
$h=@{}
foreach ($item in $data){
$key=$item.$dimension
if(!$key) {$key="[missing]"}
if(!$h.ContainsKey($key)) {
$h.$key=[ordered]@{}
}
foreach($m in $measure) {
$value = $item.$m
if($value -is [string] -or $value -is [System.Enum]) {
$value = 1
}
$h.$key.$m+=$value
}
}
foreach ($entry in $h.GetEnumerator()){
$nh=[ordered]@{Name=$entry.key}
foreach ($item in $entry.value.getenumerator()) {
$nh.($item.key)=$item.value
}
[pscustomobject]$nh
}
}

View File

@@ -0,0 +1,135 @@
function Join-Worksheet {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = "Default", Position = 0)]
[Parameter(ParameterSetName = "Table" , Position = 0)]
[String]$Path ,
[Parameter(Mandatory = $true, ParameterSetName = "PackageDefault")]
[Parameter(Mandatory = $true, ParameterSetName = "PackageTable")]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
$WorkSheetName = 'Combined',
[switch]$Clearsheet,
[switch]$NoHeader,
[string]$FromLabel = "From" ,
[switch]$LabelBlocks,
[Switch]$AutoSize,
[Switch]$FreezeTopRow,
[Switch]$FreezeFirstColumn,
[Switch]$FreezeTopRowFirstColumn,
[Int[]]$FreezePane,
[Parameter(ParameterSetName = 'Default')]
[Parameter(ParameterSetName = 'PackageDefault')]
[Switch]$AutoFilter,
[Switch]$BoldTopRow,
[switch]$HideSource,
[String]$Title,
[OfficeOpenXml.Style.ExcelFillStyle]$TitleFillPattern = 'Solid',
$TitleBackgroundColor,
[Switch]$TitleBold,
[Int]$TitleSize = 22,
[Hashtable]$PivotTableDefinition,
[Object[]]$ExcelChartDefinition,
[Object[]]$ConditionalFormat,
[Object[]]$ConditionalText,
[switch]$AutoNameRange,
[ValidateScript( {
if (-not $_) { throw 'RangeName is null or empty.' }
elseif ($_[0] -notmatch '[a-z]') { throw 'RangeName starts with an invalid character.' }
else { $true }
})]
[String]$RangeName,
[ValidateScript( {
if (-not $_) { throw 'Tablename is null or empty.' }
elseif ($_[0] -notmatch '[a-z]') { throw 'Tablename starts with an invalid character.' }
else { $true }
})]
[Parameter(ParameterSetName = 'Table' , Mandatory = $true)]
[Parameter(ParameterSetName = 'PackageTable' , Mandatory = $true)]
[String]$TableName,
[Parameter(ParameterSetName = 'Table')]
[Parameter(ParameterSetName = 'PackageTable')]
[OfficeOpenXml.Table.TableStyles]$TableStyle = 'Medium6',
[switch]$ReturnRange,
[switch]$Show,
[switch]$PassThru
)
#region get target worksheet, select it and move it to the end.
if ($Path -and -not $ExcelPackage) {$ExcelPackage = Open-ExcelPackage -path $Path }
$destinationSheet = Add-WorkSheet -ExcelPackage $ExcelPackage -WorkSheetname $WorkSheetName -ClearSheet:$Clearsheet
foreach ($w in $ExcelPackage.Workbook.Worksheets) {$w.view.TabSelected = $false}
$destinationSheet.View.TabSelected = $true
$ExcelPackage.Workbook.Worksheets.MoveToEnd($WorkSheetName)
#row to insert at will be 1 on a blank sheet and lastrow + 1 on populated one
$row = (1 + $destinationSheet.Dimension.End.Row )
#endregion
#region Setup title and header rows
#Title parameters work as they do in Export-Excel .
if ($row -eq 1 -and $Title) {
$destinationSheet.Cells[1, 1].Value = $Title
$destinationSheet.Cells[1, 1].Style.Font.Size = $TitleSize
if ($TitleBold) {$destinationSheet.Cells[1, 1].Style.Font.Bold = $True }
#Can only set TitleBackgroundColor if TitleFillPattern is something other than None.
if ($TitleBackgroundColor -AND ($TitleFillPattern -ne 'None')) {
if ($TitleBackgroundColor -is [string]) {$TitleBackgroundColor = [System.Drawing.Color]::$TitleBackgroundColor }
$destinationSheet.Cells[1, 1].Style.Fill.PatternType = $TitleFillPattern
$destinationSheet.Cells[1, 1].Style.Fill.BackgroundColor.SetColor($TitleBackgroundColor)
}
elseif ($TitleBackgroundColor) { Write-Warning "Title Background Color ignored. You must set the TitleFillPattern parameter to a value other than 'None'. Try 'Solid'." }
$row = 2
}
if (-not $noHeader) {
#Assume every row has titles in row 1, copy row 1 from first sheet to new sheet.
$destinationSheet.Select("A$row")
$ExcelPackage.Workbook.Worksheets[1].cells["1:1"].Copy($destinationSheet.SelectedRange)
#fromlabel can't be an empty string
if ($FromLabel ) {
#Add a column which says where the data comes from.
$fromColumn = ($destinationSheet.Dimension.Columns + 1)
$destinationSheet.Cells[$row, $fromColumn].Value = $FromLabel
}
$row += 1
}
#endregion
foreach ($i in 1..($ExcelPackage.Workbook.Worksheets.Count - 1) ) {
$sourceWorksheet = $ExcelPackage.Workbook.Worksheets[$i]
#Assume row one is titles, so data itself starts at A2.
if ($NoHeader) {$sourceRange = $sourceWorksheet.Dimension.Address}
else {$sourceRange = $sourceWorksheet.Dimension.Address -replace "A1:", "A2:"}
#Position insertion point/
$destinationSheet.Select("A$row")
if ($LabelBlocks) {
$destinationSheet.Cells[$row, 1].value = $sourceWorksheet.Name
$destinationSheet.Cells[$row, 1].Style.Font.Bold = $true
$destinationSheet.Cells[$row, 1].Style.Font.Size += 2
$row += 1
}
$destinationSheet.Select("A$row")
#And finally we're ready to copy the data.
$sourceWorksheet.Cells[$sourceRange].Copy($destinationSheet.SelectedRange)
#Fill in column saying where data came from.
if ($fromColumn) { $row..$destinationSheet.Dimension.Rows | ForEach-Object {$destinationSheet.Cells[$_, $fromColumn].Value = $sourceWorksheet.Name} }
#Update where next insertion will go.
$row = $destinationSheet.Dimension.Rows + 1
if ($HideSource) {$sourceWorksheet.Hidden = [OfficeOpenXml.eWorkSheetHidden]::Hidden}
}
#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
'Path', 'Clearsheet', 'NoHeader', 'FromLabel', 'LabelBlocks', 'HideSource',
'Title', 'TitleFillPattern', 'TitleBackgroundColor', 'TitleBold', 'TitleSize' | ForEach-Object {$null = $params.Remove($_)}
if ($params.Keys.Count) {
if ($Title) { $params.StartRow = 2}
$params.WorkSheetName = $WorkSheetName
$params.ExcelPackage = $ExcelPackage
Export-Excel @Params
}
else {
Close-ExcelPackage -ExcelPackage $ExcelPackage
$ExcelPackage.Dispose()
$ExcelPackage = $null
}
}

View File

@@ -0,0 +1,147 @@
function Merge-MultipleSheets {
[cmdletbinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification="False positives when initializing variable in begin block")]
[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 (
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
$Path ,
[int]$Startrow = 1,
[String[]]$Headername,
[switch]$NoHeader,
$WorksheetName = "Sheet1",
[Alias('OutFile')]
$OutputFile = ".\temp.xlsx",
[Alias('OutSheet')]
$OutputSheetName = "Sheet1",
$Property = "*" ,
$ExcludeProperty ,
$Key = "Name" ,
$KeyFontColor = [System.Drawing.Color]::Red,
$ChangeBackgroundColor = [System.Drawing.Color]::Orange,
$DeleteBackgroundColor = [System.Drawing.Color]::LightPink,
$AddBackgroundColor = [System.Drawing.Color]::Orange,
[switch]$HideRowNumbers ,
[switch]$Passthru ,
[Switch]$Show
)
begin { $filestoProcess = @() }
process { $filestoProcess += $Path}
end {
if ($filestoProcess.Count -eq 1 -and $WorksheetName -match '\*') {
Write-Progress -Activity "Merging sheets" -CurrentOperation "Expanding * to names of sheets in $($filestoProcess[0]). "
$excel = Open-ExcelPackage -Path $filestoProcess
$WorksheetName = $excel.Workbook.Worksheets.Name.where({$_ -like $WorksheetName})
Close-ExcelPackage -NoSave -ExcelPackage $excel
}
#Merge identically named sheets in different work books;
if ($filestoProcess.Count -ge 2 -and $WorksheetName -is "string" ) {
Get-Variable -Name 'HeaderName','NoHeader','StartRow','Key','Property','ExcludeProperty','WorksheetName' -ErrorAction SilentlyContinue |
Where-Object {$_.Value} | ForEach-Object -Begin {$params= @{} } -Process {$params[$_.Name] = $_.Value}
Write-Progress -Activity "Merging sheets" -CurrentOperation "comparing '$WorksheetName' in $($filestoProcess[-1]) against $($filestoProcess[0]). "
$merged = Merge-Worksheet @params -Referencefile $filestoProcess[0] -Differencefile $filestoProcess[-1]
$nextFileNo = 2
while ($nextFileNo -lt $filestoProcess.count -and $merged) {
Write-Progress -Activity "Merging sheets" -CurrentOperation "comparing '$WorksheetName' in $($filestoProcess[-$nextFileNo]) against $($filestoProcess[0]). "
$merged = Merge-Worksheet @params -ReferenceObject $merged -Differencefile $filestoProcess[-$nextFileNo]
$nextFileNo ++
}
}
#Merge different sheets from one workbook
elseif ($filestoProcess.Count -eq 1 -and $WorksheetName.Count -ge 2 ) {
Get-Variable -Name 'HeaderName','NoHeader','StartRow','Key','Property','ExcludeProperty' -ErrorAction SilentlyContinue |
Where-Object {$_.Value} | ForEach-Object -Begin {$params= @{} } -Process {$params[$_.Name] = $_.Value}
Write-Progress -Activity "Merging sheets" -CurrentOperation "Comparing $($WorksheetName[-1]) against $($WorksheetName[0]). "
$merged = Merge-Worksheet @params -Referencefile $filestoProcess[0] -Differencefile $filestoProcess[0] -WorksheetName $WorksheetName[0,-1]
$nextSheetNo = 2
while ($nextSheetNo -lt $WorksheetName.count -and $merged) {
Write-Progress -Activity "Merging sheets" -CurrentOperation "Comparing $($WorksheetName[-$nextSheetNo]) against $($WorksheetName[0]). "
$merged = Merge-Worksheet @params -ReferenceObject $merged -Differencefile $filestoProcess[0] -WorksheetName $WorksheetName[-$nextSheetNo] -DiffPrefix $WorksheetName[-$nextSheetNo]
$nextSheetNo ++
}
}
#We either need one Worksheet name and many files or one file and many sheets.
else { Write-Warning -Message "Need at least two files to process" ; return }
#if the process didn't return data then abandon now.
if (-not $merged) {Write-Warning -Message "The merge operation did not return any data."; return }
$orderByProperties = $merged[0].psobject.properties.where({$_.name -match "row$"}).name
Write-Progress -Activity "Merging sheets" -CurrentOperation "creating output sheet '$OutputSheetName' in $OutputFile"
$excel = $merged | Sort-Object -Property $orderByProperties |
Export-Excel -Path $OutputFile -Worksheetname $OutputSheetName -ClearSheet -BoldTopRow -AutoFilter -PassThru
$sheet = $excel.Workbook.Worksheets[$OutputSheetName]
#We will put in a conditional format for "if all the others are not flagged as 'same'" to mark rows where something is added, removed or changed
$sameChecks = @()
#All the 'difference' columns in the sheet are labeled with the file they came from, 'reference' columns need their
#headers prefixed with the ref file name, $colnames is the basis of a regular expression to identify what should have $refPrefix appended
$colNames = @("^_Row$")
if ($key -ne "*")
{$colnames += "^$Key$"}
if ($filesToProcess.Count -ge 2) {
$refPrefix = (Split-Path -Path $filestoProcess[0] -Leaf) -replace "\.xlsx$"," "
}
else {$refPrefix = $WorksheetName[0] }
Write-Progress -Activity "Merging sheets" -CurrentOperation "applying formatting to sheet '$OutputSheetName' in $OutputFile"
#Find the column headings which are in the form "diffFile is"; which will hold 'Same', 'Added' or 'Changed'
foreach ($cell in $sheet.Cells[($sheet.Dimension.Address -replace "\d+$","1")].Where({$_.value -match "\sIS$"}) ) {
#Work leftwards across the headings applying conditional formatting which says
# 'Format this cell if the "IS" column has a value of ...' until you find a heading which doesn't have the prefix.
$prefix = $cell.value -replace "\sIS$",""
$columnNo = $cell.start.Column -1
$cellAddr = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R1C$columnNo",1,$columnNo)
while ($sheet.cells[$cellAddr].value -match $prefix) {
$condFormattingParams = @{RuleType='Expression'; BackgroundPattern='Solid'; Worksheet=$sheet; StopIfTrue=$true; Range=$([OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[1]C[$columnNo]:R[1048576]C[$columnNo]",0,0)) }
Add-ConditionalFormatting @condFormattingParams -ConditionValue ($cell.Address + '="Added"' ) -BackgroundColor $AddBackgroundColor
Add-ConditionalFormatting @condFormattingParams -ConditionValue ($cell.Address + '="Changed"') -BackgroundColor $ChangeBackgroundColor
Add-ConditionalFormatting @condFormattingParams -ConditionValue ($cell.Address + '="Removed"') -BackgroundColor $DeleteBackgroundColor
$columnNo --
$cellAddr = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R1C$columnNo",1,$columnNo)
}
#build up a list of prefixes in $colnames - we'll use that to set headers on rows from the reference file; and build up the "if the 'is' cell isn't same" list
$colNames += $prefix
$sameChecks += (($cell.Address -replace "1","2") +'<>"Same"')
}
#For all the columns which don't match one of the Diff-file prefixes or "_Row" or the 'Key' columnn name; add the reference file prefix to their header.
$nameRegex = $colNames -Join '|'
foreach ($cell in $sheet.Cells[($sheet.Dimension.Address -replace "\d+$","1")].Where({$_.value -Notmatch $nameRegex}) ) {
$cell.Value = $refPrefix + $cell.Value
$condFormattingParams = @{RuleType='Expression'; BackgroundPattern='Solid'; Worksheet=$sheet; StopIfTrue=$true; Range=[OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[2]C[$($cell.start.column)]:R[1048576]C[$($cell.start.column)]",0,0)}
Add-ConditionalFormatting @condFormattingParams -ConditionValue ("OR(" +(($sameChecks -join ",") -replace '<>"Same"','="Added"' ) +")" ) -BackgroundColor $DeleteBackgroundColor
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
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 ($Key -ne '*') {
Add-ConditionalFormatting -Worksheet $sheet -Range "B2:B1048576" -ForeGroundColor $KeyFontColor -BackgroundPattern 'None' -RuleType Expression -ConditionValue ("OR(" +($sameChecks -join ",") +")" )
$sheet.view.FreezePanes(2, 3)
}
else {$sheet.view.FreezePanes(2, 2) }
#Go back over the headings to find and hide the "is" columns;
foreach ($cell in $sheet.Cells[($sheet.Dimension.Address -replace "\d+$","1")].Where({$_.value -match "\sIS$"}) ) {
$sheet.Column($cell.start.Column).HIDDEN = $true
}
#If specified, look over the headings for "row" and hide the columns which say "this was in row such-and-such"
if ($HideRowNumbers) {
foreach ($cell in $sheet.Cells[($sheet.Dimension.Address -replace "\d+$","1")].Where({$_.value -match "Row$"}) ) {
$sheet.Column($cell.start.Column).HIDDEN = $true
}
}
if ($Passthru) {$excel}
else {Close-ExcelPackage -ExcelPackage $excel -Show:$Show}
Write-Progress -Activity "Merging sheets" -Completed
}
}

View File

@@ -0,0 +1,263 @@
function Merge-Worksheet {
[cmdletbinding(SupportsShouldProcess=$true)]
Param(
[parameter(ParameterSetName='A',Mandatory=$true,Position=0)] #A = Compare two files default headers
[parameter(ParameterSetName='B',Mandatory=$true,Position=0)] #B = Compare two files user supplied headers
[parameter(ParameterSetName='C',Mandatory=$true,Position=0)] #C = Compare two files headers P1, P2, P3 etc
$Referencefile ,
[parameter(ParameterSetName='A',Mandatory=$true,Position=1)]
[parameter(ParameterSetName='B',Mandatory=$true,Position=1)]
[parameter(ParameterSetName='C',Mandatory=$true,Position=1)]
[parameter(ParameterSetName='E',Mandatory=$true,Position=1)] #D Compare two objects; E = Compare one object one file that uses default headers
[parameter(ParameterSetName='F',Mandatory=$true,Position=1)] #F = Compare one object one file that uses user supplied headers
[parameter(ParameterSetName='G',Mandatory=$true,Position=1)] #G Compare one object one file that uses headers P1, P2, P3 etc
$Differencefile ,
[parameter(ParameterSetName='A',Position=2)] #Applies to all sets EXCEPT D which is two objects (no sheets)
[parameter(ParameterSetName='B',Position=2)]
[parameter(ParameterSetName='C',Position=2)]
[parameter(ParameterSetName='E',Position=2)]
[parameter(ParameterSetName='F',Position=2)]
[parameter(ParameterSetName='G',Position=2)]
$WorksheetName = "Sheet1",
[parameter(ParameterSetName='A')] #Applies to all sets EXCEPT D which is two objects (no sheets, so no start row )
[parameter(ParameterSetName='B')]
[parameter(ParameterSetName='C')]
[parameter(ParameterSetName='E')]
[parameter(ParameterSetName='F')]
[parameter(ParameterSetName='G')]
[int]$Startrow = 1,
[Parameter(ParameterSetName='B',Mandatory=$true)] #Compare object + sheet or 2 sheets with user supplied headers
[Parameter(ParameterSetName='F',Mandatory=$true)]
[String[]]$Headername,
[Parameter(ParameterSetName='C',Mandatory=$true)] #Compare object + sheet or 2 sheets with headers of P1, P2, P3 ...
[Parameter(ParameterSetName='G',Mandatory=$true)]
[switch]$NoHeader,
[parameter(ParameterSetName='D',Mandatory=$true)]
[parameter(ParameterSetName='E',Mandatory=$true)]
[parameter(ParameterSetName='F',Mandatory=$true)]
[parameter(ParameterSetName='G',Mandatory=$true)]
[Alias('RefObject')]
$ReferenceObject ,
[parameter(ParameterSetName='D',Mandatory=$true,Position=1)]
[Alias('DiffObject')]
$DifferenceObject ,
[parameter(ParameterSetName='D',Position=2)]
[parameter(ParameterSetName='E',Position=2)]
[parameter(ParameterSetName='F',Position=2)]
[parameter(ParameterSetName='G',Position=2)]
$DiffPrefix = "=>" ,
[parameter(Position=3)]
[Alias('OutFile')]
$OutputFile ,
[parameter(Position=4)]
[Alias('OutSheet')]
$OutputSheetName = "Sheet1",
$Property = "*" ,
$ExcludeProperty ,
$Key = "Name" ,
$KeyFontColor = [System.Drawing.Color]::DarkRed ,
$ChangeBackgroundColor = [System.Drawing.Color]::Orange,
$DeleteBackgroundColor = [System.Drawing.Color]::LightPink,
$AddBackgroundColor = [System.Drawing.Color]::PaleGreen,
[switch]$HideEqual ,
[switch]$Passthru ,
[Switch]$Show
)
#region Read Excel data
if ($Differencefile -is [System.IO.FileInfo]) {$Differencefile = $Differencefile.FullName}
if ($Referencefile -is [System.IO.FileInfo]) {$Referencefile = $Referencefile.FullName}
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 $WorksheetName 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) {$Worksheet2 = $DiffPrefix = $WorksheetName[1] ; $Worksheet1 = $WorksheetName[0] ; }
elseif ($WorksheetName -is [string]) {$Worksheet2 = $Worksheet1 = $WorksheetName ;
$DiffPrefix = (Split-Path -Path $Differencefile -Leaf) -replace "\.xlsx$","" }
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::$Worksheet1 and/or $Differencefile::$Worksheet2." ; return }
if ($NoHeader) {$firstDataRow = $Startrow } else {$firstDataRow = $Startrow + 1}
}
elseif ( $Differencefile) {
if ($WorksheetName -isnot [string]) {Write-Warning -Message "You must provide a single Worksheet name." ; return }
$params = @{WorksheetName=$WorksheetName; Path=$Differencefile; ErrorAction=[System.Management.Automation.ActionPreference]::Stop }
foreach ($p in @("HeaderName","NoHeader","StartRow")) {if ($PSBoundParameters[$p]) {$params[$p] = $PSBoundParameters[$p]}}
try {$DifferenceObject = Import-Excel @Params }
Catch {Write-Warning -Message "Could not read the Worksheet '$WorksheetName' from $Differencefile::$WorksheetName." ; return }
if ($DiffPrefix -eq "=>" ) {
$DiffPrefix = (Split-Path -Path $Differencefile -Leaf) -replace "\.xlsx$",""
}
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 = @()
$DifferenceObject = $DifferenceObject | Update-FirstObjectProperties
$headings = $DifferenceObject[0].psobject.Properties.Name # This preserves the sequence - using get-member would sort them alphabetically! There may be extra properties in
if ($NoHeader -and "Name" -eq $Key) {$Key = "p1"}
if ($headings -notcontains $Key -and
('*' -ne $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) -and
('*' -ne $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
#If key is "*" we treat it differently , and we will create a script property which concatenates all the Properties in $Proplist
$ConCatblock = [scriptblock]::Create( ($proplist | ForEach-Object {'$this."' + $_ + '"'}) -join " + ")
#Build the list of the properties to output, in order.
$diffpart = @()
$refpart = @()
foreach ($p in $proplist.Where({$key -ne $_}) ) {$refPart += $p ; $diffPart += "$DiffPrefix $p" }
$lastRefColNo = $proplist.count
$FirstDiffColNo = $lastRefColNo + 1
if ($key -ne '*') {
$outputProps = @($key) + $refpart + $diffpart
#If we are using a single column as the key, don't duplicate it, so the last difference column will be A if there is one property, C if there are two, E if there are 3
$lastDiffColNo = (2 * $proplist.count) - 1
}
else {
$outputProps = @( ) + $refpart + $diffpart
#If we not using a single column as a key all columns are duplicated so, the Last difference column will be B if there is one property, D if there are two, F if there are 3
$lastDiffColNo = (2 * $proplist.count )
}
#Add RowNumber to every row
#If one sheet has extra rows we can get a single "==" result from compare, with the row from the reference sheet, but
#the row in the other sheet might be different so we will look up the row number from the key field - build a hash table for that here
#If we have "*" as the key ad the script property to concatenate the [selected] properties.
$Rowhash = @{}
$rowNo = $firstDataRow
foreach ($row in $ReferenceObject) {
if ($null -eq $row._row) {Add-Member -InputObject $row -MemberType NoteProperty -Value ($rowNo ++) -Name "_Row" }
else {$rowNo++ }
if ($Key -eq '*' ) {Add-Member -InputObject $row -MemberType ScriptProperty -Value $ConCatblock -Name "_All" }
}
$rowNo = $firstDataRow
foreach ($row in $DifferenceObject) {
Add-Member -InputObject $row -MemberType NoteProperty -Value $rowNo -Name "$DiffPrefix Row" -Force
if ($Key -eq '*' ) {
Add-Member -InputObject $row -MemberType ScriptProperty -Value $ConCatblock -Name "_All"
$Rowhash[$row._All] = $rowNo
}
else {$Rowhash[$row.$key] = $rowNo }
$rowNo ++
}
if ($DifferenceObject.count -gt $Rowhash.Keys.Count) {
Write-Warning -Message "Difference object has $($DifferenceObject.Count) rows; but only $($Rowhash.keys.count) unique keys"
}
if ($Key -eq '*') {$key = "_ALL"}
#endregion
#We need to know all the properties we've met on the objects we've diffed
$eDiffProps = [ordered]@{}
#When we do a compare object changes will result in two rows so we group them and join them together.
$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.
$hash = [ordered]@{}
foreach ($result in $_.Group) {
if ($result.SideIndicator -ne "=>") {$hash["_Row"] = $result._Row }
elseif (-not $hash["$DiffPrefix Row"]) {$hash["_Row"] = "" }
#if we have already set the side, this must be the second record, so set side to indicate "changed"; if we got two "Same" indicators we may have a classh of keys
if ($hash.Side) {
if ($hash.Side -eq $result.SideIndicator) {Write-Warning -Message "'$keyval' may be a duplicate."}
$hash.Side = "<>"
}
else {$hash["Side"] = $result.SideIndicator}
switch ($hash.side) {
'==' { $hash["$DiffPrefix is"] = 'Same' }
'=>' { $hash["$DiffPrefix is"] = 'Added' }
'<>' { if (-not $hash["_Row"]) {
$hash["$DiffPrefix is"] = 'Added'
}
else {
$hash["$DiffPrefix is"] = 'Changed'
}
}
'<=' { $hash["$DiffPrefix is"] = 'Removed'}
}
#find the number of the row in the the "difference" object which has this key. If it is the object is only in the reference this will be blank.
$hash["$DiffPrefix Row"] = $Rowhash[$keyval]
$hash[$key] = $keyval
#Create FieldName and/or =>FieldName columns
foreach ($p in $result.psobject.Properties.name.where({$_ -ne $key -and $_ -ne "SideIndicator" -and $_ -ne "$DiffPrefix Row" })) {
if ($result.SideIndicator -eq "==" -and $p -in $propList)
{$hash[("$p")] = $hash[("$DiffPrefix $p")] = $result.$P}
elseif ($result.SideIndicator -eq "==" -or $result.SideIndicator -eq "<=")
{$hash[("$p")] = $result.$P}
elseif ($result.SideIndicator -eq "=>") { $hash[("$DiffPrefix $p")] = $result.$P}
}
}
foreach ($k in $hash.keys) {$eDiffProps[$k] = $true}
[Pscustomobject]$hash
} | Sort-Object -Property "_row"
#Already sorted by reference row number, fill in any blanks in the difference-row column.
for ($i = 1; $i -lt $expandedDiff.Count; $i++) {if (-not $expandedDiff[$i]."$DiffPrefix Row") {$expandedDiff[$i]."$DiffPrefix Row" = $expandedDiff[$i-1]."$DiffPrefix Row" } }
#Now re-Sort by difference row number, and fill in any blanks in the reference-row column.
$expandedDiff = $expandedDiff | Sort-Object -Property "$DiffPrefix Row"
for ($i = 1; $i -lt $expandedDiff.Count; $i++) {if (-not $expandedDiff[$i]."_Row") {$expandedDiff[$i]."_Row" = $expandedDiff[$i-1]."_Row" } }
$AllProps = @("_Row") + $OutputProps + $eDiffProps.keys.where({$_ -notin ($outputProps + @("_row","side","SideIndicator","_ALL" ))})
if ($PassThru -or -not $OutputFile) {return ($expandedDiff | Select-Object -Property $allprops | Sort-Object -Property "_row", "$DiffPrefix Row" ) }
elseif ($PSCmdlet.ShouldProcess($OutputFile,"Write Output to Excel file")) {
$expandedDiff = $expandedDiff | Sort-Object -Property "_row", "$DiffPrefix Row"
$xl = $expandedDiff | Select-Object -Property $OutputProps | Update-FirstObjectProperties |
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-ExcelRange -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-ExcelRange -Worksheet $ws -Range $range -BackgroundColor $ChangeBackgroundColor
}
elseif ( $expandedDiff[$i].side -eq "<=" ) {
$rangeR1C1 = "R[{0}]C[1]:R[{0}]C[{1}]" -f ($i + 2 ) , $lastRefColNo
$range = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1($rangeR1C1,0,0)
Set-ExcelRange -Worksheet $ws -Range $range -BackgroundColor $DeleteBackgroundColor
}
elseif ( $expandedDiff[$i].side -eq "=>" ) {
if ($propList.count -gt 1) {
$rangeR1C1 = "R[{0}]C[{1}]:R[{0}]C[{2}]" -f ($i + 2 ) , $FirstDiffColNo , $lastDiffColNo
$range = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1($rangeR1C1,0,0)
Set-ExcelRange -Worksheet $ws -Range $range -BackgroundColor $AddBackgroundColor
}
Set-ExcelRange -Worksheet $ws -Range ("A" + ($i + 2 )) -BackgroundColor $AddBackgroundColor
}
}
Close-ExcelPackage -ExcelPackage $xl -Show:$Show
}
}

View File

@@ -0,0 +1,57 @@
function New-ConditionalFormattingIconSet {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system State')]
param(
[Parameter(Mandatory=$true)]
$Range,
[ValidateSet("ThreeIconSet","FourIconSet","FiveIconSet")]
$ConditionalFormat,
[Switch]$Reverse
)
DynamicParam {
$IconType = New-Object System.Management.Automation.ParameterAttribute
$IconType.Position = 2
$IconType.Mandatory = $true
$attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($IconType)
switch ($ConditionalFormat) {
"ThreeIconSet" {
$IconTypeParam = New-Object System.Management.Automation.RuntimeDefinedParameter('IconType', [OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting3IconsSetType], $attributeCollection)
}
"FourIconSet" {
$IconTypeParam = New-Object System.Management.Automation.RuntimeDefinedParameter('IconType', [OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting4IconsSetType], $attributeCollection)
}
"FiveIconSet" {
$IconTypeParam = New-Object System.Management.Automation.RuntimeDefinedParameter('IconType', [OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting5IconsSetType], $attributeCollection)
}
}
$paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add('IconType', $IconTypeParam)
return $paramDictionary
}
End {
$bp = @{}+$PSBoundParameters
$obj = [PSCustomObject]@{
Range = $Range
Formatter = $ConditionalFormat
IconType = $bp.IconType
Reverse = $Reverse
}
$obj.pstypenames.Clear()
$obj.pstypenames.Add("ConditionalFormatIconSet")
$obj
}
}

View File

@@ -0,0 +1,41 @@
function New-ConditionalText {
[cmdletbinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system State')]
param(
#[Parameter(Mandatory=$true)]
[Alias("ConditionValue")]
$Text,
[Alias("ForeGroundColor")]
$ConditionalTextColor=[System.Drawing.Color]::DarkRed,
$BackgroundColor=[System.Drawing.Color]::LightPink,
[String]$Range,
[OfficeOpenXml.Style.ExcelFillStyle]$PatternType=[OfficeOpenXml.Style.ExcelFillStyle]::Solid,
[ValidateSet(
"LessThan", "LessThanOrEqual", "GreaterThan", "GreaterThanOrEqual",
"Equal", "NotEqual",
"Top", "TopPercent", "Bottom", "BottomPercent",
"ContainsText", "NotContainsText", "BeginsWith", "EndsWith",
"ContainsBlanks", "NotContainsBlanks", "ContainsErrors", "NotContainsErrors",
"DuplicateValues", "UniqueValues",
"Tomorrow", "Today", "Yesterday", "Last7Days",
"NextWeek", "ThisWeek", "LastWeek",
"NextMonth", "ThisMonth", "LastMonth",
"AboveAverage", "AboveOrEqualAverage", "BelowAverage", "BelowOrEqualAverage"
)]
[Alias("RuleType")]
$ConditionalType="ContainsText"
)
$obj = [PSCustomObject]@{
Text = $Text
ConditionalTextColor = $ConditionalTextColor
ConditionalType = $ConditionalType
PatternType = $PatternType
Range = $Range
BackgroundColor = $BackgroundColor
}
$obj.pstypenames.Clear()
$obj.pstypenames.Add("ConditionalText")
$obj
}

View File

@@ -0,0 +1,88 @@
function New-ExcelChartDefinition {
[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()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Does not change system State')]
param(
$Title = "Chart Title",
$Header,
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = "ColumnStacked",
[OfficeOpenXml.Drawing.Chart.eTrendLine[]]$ChartTrendLine,
$XRange,
$YRange,
$Width = 500,
$Height = 350,
$Row = 0,
$RowOffSetPixels = 10,
$Column = 6,
$ColumnOffSetPixels = 5,
[OfficeOpenXml.Drawing.Chart.eLegendPosition]$LegendPosition,
$LegendSize,
[Switch]$LegendBold,
[Switch]$NoLegend,
[Switch]$ShowCategory,
[Switch]$ShowPercent,
$SeriesHeader,
[Switch]$TitleBold,
[Int]$TitleSize ,
[String]$XAxisTitleText,
[Switch]$XAxisTitleBold,
$XAxisTitleSize ,
[string]$XAxisNumberformat,
$XMajorUnit,
$XMinorUnit,
$XMaxValue,
$XMinValue,
[OfficeOpenXml.Drawing.Chart.eAxisPosition]$XAxisPosition ,
[String]$YAxisTitleText,
[Switch]$YAxisTitleBold,
$YAxisTitleSize,
[string]$YAxisNumberformat,
$YMajorUnit,
$YMinorUnit,
$YMaxValue,
$YMinValue,
[OfficeOpenXml.Drawing.Chart.eAxisPosition]$YAxisPosition
)
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
[PSCustomObject]@{
Title = $Title
ChartType = $ChartType
ChartTrendLine = $ChartTrendLine
XRange = $XRange
YRange = $YRange
Width = $Width
Height = $Height
Row = $Row
RowOffSetPixels = $RowOffSetPixels
Column = $Column
ColumnOffSetPixels = $ColumnOffSetPixels
LegendPosition = $LegendPosition
LegendSize = $LegendSize
Legendbold = $LegendBold
NoLegend = $NoLegend -as [Boolean]
ShowCategory = $ShowCategory -as [Boolean]
ShowPercent = $ShowPercent -as [Boolean]
SeriesHeader = $SeriesHeader
TitleBold = $TitleBold -as [Boolean]
TitleSize = $TitleSize
XAxisTitleText = $XAxisTitleText
XAxisTitleBold = $XAxisTitleBold -as [Boolean]
XAxisTitleSize = $XAxisTitleSize
XAxisNumberformat = $XAxisNumberformat
XMajorUnit = $XMajorUnit
XMinorUnit = $XMinorUnit
XMaxValue = $XMaxValue
XMinValue = $XMinValue
XAxisPosition = $XAxisPosition
YAxisTitleText = $YAxisTitleText
YAxisTitleBold = $YAxisTitleBold -as [Boolean]
YAxisTitleSize = $YAxisTitleSize
YAxisNumberformat = $YAxisNumberformat
YMajorUnit = $YMajorUnit
YMinorUnit = $YMinorUnit
YMaxValue = $YMaxValue
YMinValue = $YMinValue
YAxisPosition = $YAxisPosition
}
}

View File

@@ -0,0 +1,570 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# New-ExcelStyle
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
New-ExcelStyle [[-Range] <Object>] [[-NumberFormat] <Object>] [[-BorderAround] <ExcelBorderStyle>]
[[-BorderColor] <Object>] [[-BorderBottom] <ExcelBorderStyle>] [[-BorderTop] <ExcelBorderStyle>]
[[-BorderLeft] <ExcelBorderStyle>] [[-BorderRight] <ExcelBorderStyle>] [[-FontColor] <Object>]
[[-Value] <Object>] [[-Formula] <Object>] [-ArrayFormula] [-ResetFont] [-Bold] [-Italic] [-Underline]
[[-UnderLineType] <ExcelUnderLineType>] [-StrikeThru] [[-FontShift] <ExcelVerticalAlignmentFont>]
[[-FontName] <String>] [[-FontSize] <Single>] [[-BackgroundColor] <Object>]
[[-BackgroundPattern] <ExcelFillStyle>] [[-PatternColor] <Object>] [-WrapText]
[[-HorizontalAlignment] <ExcelHorizontalAlignment>] [[-VerticalAlignment] <ExcelVerticalAlignment>]
[[-TextRotation] <Int32>] [-AutoSize] [[-Width] <Single>] [[-Height] <Single>] [-Hidden] [-Locked] [-Merge]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -ArrayFormula
{{ Fill ArrayFormula Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AutoSize
{{ Fill AutoSize Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases: AutoFit
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BackgroundColor
{{ Fill BackgroundColor Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 15
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BackgroundPattern
{{ Fill BackgroundPattern Description }}
```yaml
Type: ExcelFillStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Solid, DarkGray, MediumGray, LightGray, Gray125, Gray0625, DarkVertical, DarkHorizontal, DarkDown, DarkUp, DarkGrid, DarkTrellis, LightVertical, LightHorizontal, LightDown, LightUp, LightGrid, LightTrellis
Required: False
Position: 16
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Bold
{{ Fill Bold Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BorderAround
{{ Fill BorderAround Description }}
```yaml
Type: ExcelBorderStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BorderBottom
{{ Fill BorderBottom Description }}
```yaml
Type: ExcelBorderStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double
Required: False
Position: 4
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BorderColor
{{ Fill BorderColor Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 3
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BorderLeft
{{ Fill BorderLeft Description }}
```yaml
Type: ExcelBorderStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double
Required: False
Position: 6
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BorderRight
{{ Fill BorderRight Description }}
```yaml
Type: ExcelBorderStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double
Required: False
Position: 7
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BorderTop
{{ Fill BorderTop Description }}
```yaml
Type: ExcelBorderStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double
Required: False
Position: 5
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -FontColor
{{ Fill FontColor Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases: ForegroundColor
Required: False
Position: 8
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -FontName
{{ Fill FontName Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 13
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -FontShift
{{ Fill FontShift Description }}
```yaml
Type: ExcelVerticalAlignmentFont
Parameter Sets: (All)
Aliases:
Accepted values: None, Baseline, Subscript, Superscript
Required: False
Position: 12
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -FontSize
{{ Fill FontSize Description }}
```yaml
Type: Single
Parameter Sets: (All)
Aliases:
Required: False
Position: 14
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Formula
{{ Fill Formula Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 10
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Height
{{ Fill Height Description }}
```yaml
Type: Single
Parameter Sets: (All)
Aliases:
Required: False
Position: 22
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Hidden
{{ Fill Hidden Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -HorizontalAlignment
{{ Fill HorizontalAlignment Description }}
```yaml
Type: ExcelHorizontalAlignment
Parameter Sets: (All)
Aliases:
Accepted values: General, Left, Center, CenterContinuous, Right, Fill, Distributed, Justify
Required: False
Position: 18
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Italic
{{ Fill Italic Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Locked
{{ Fill Locked Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Merge
{{ Fill Merge Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -NumberFormat
{{ Fill NumberFormat Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases: NFormat
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -PatternColor
{{ Fill PatternColor Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases: PatternColour
Required: False
Position: 17
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Range
{{ Fill Range Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases: Address
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -ResetFont
{{ Fill ResetFont Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -StrikeThru
{{ Fill StrikeThru Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -TextRotation
{{ Fill TextRotation Description }}
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: 20
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -UnderLineType
{{ Fill UnderLineType Description }}
```yaml
Type: ExcelUnderLineType
Parameter Sets: (All)
Aliases:
Accepted values: None, Single, Double, SingleAccounting, DoubleAccounting
Required: False
Position: 11
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Underline
{{ Fill Underline Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Value
{{ Fill Value Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 9
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -VerticalAlignment
{{ Fill VerticalAlignment Description }}
```yaml
Type: ExcelVerticalAlignment
Parameter Sets: (All)
Aliases:
Accepted values: Top, Center, Bottom, Distributed, Justify
Required: False
Position: 19
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Width
{{ Fill Width Description }}
```yaml
Type: Single
Parameter Sets: (All)
Aliases:
Required: False
Position: 21
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -WrapText
{{ Fill WrapText Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,45 @@
function New-ExcelStyle {
param (
[Alias("Address")]
$Range ,
[Alias("NFormat")]
$NumberFormat,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround,
$BorderColor=[System.Drawing.Color]::Black,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderBottom,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderTop,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderLeft,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight,
[Alias('ForegroundColor')]
$FontColor,
$Value,
$Formula,
[Switch]$ArrayFormula,
[Switch]$ResetFont,
[Switch]$Bold,
[Switch]$Italic,
[Switch]$Underline,
[OfficeOpenXml.Style.ExcelUnderLineType]$UnderLineType = [OfficeOpenXml.Style.ExcelUnderLineType]::Single,
[Switch]$StrikeThru,
[OfficeOpenXml.Style.ExcelVerticalAlignmentFont]$FontShift,
[String]$FontName,
[float]$FontSize,
$BackgroundColor,
[OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid ,
[Alias("PatternColour")]
$PatternColor,
[Switch]$WrapText,
[OfficeOpenXml.Style.ExcelHorizontalAlignment]$HorizontalAlignment,
[OfficeOpenXml.Style.ExcelVerticalAlignment]$VerticalAlignment,
[ValidateRange(-90, 90)]
[int]$TextRotation ,
[Alias("AutoFit")]
[Switch]$AutoSize,
[float]$Width,
[float]$Height,
[Switch]$Hidden,
[Switch]$Locked,
[Switch]$Merge
)
$PSBoundParameters
}

View File

@@ -0,0 +1,42 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# New-PSItem
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
New-PSItem
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,25 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function', Target='New*', Justification='Does not change system State')]
param()
function New-PSItem {
$totalArgs = $args.Count
if($args[-1] -is [array]) {
$script:PSItemHeader=$args[-1]
$totalArgs-=1
}
$h=[ordered]@{}
for ($idx = 0; $idx -lt $totalArgs; $idx+=1) {
if($PSItemHeader) {
$key = $PSItemHeader[$idx]
} else {
$key = "P$($idx+1)"
}
$h.$key=$args[$idx]
}
[PSCustomObject]$h
}

View File

@@ -0,0 +1,72 @@
function New-PivotTableDefinition {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system State')]
param(
[Parameter(Mandatory)]
[Alias("PivtoTableName")]#Previous typo - use alias to avoid breaking scripts
$PivotTableName,
$SourceWorkSheet,
$SourceRange,
$PivotRows,
[hashtable]$PivotData,
$PivotColumns,
$PivotFilter,
[Switch]$PivotDataToColumn,
[ValidateSet("Both", "Columns", "Rows", "None")]
[String]$PivotTotals = "Both",
[Switch]$NoTotalsInPivot,
[String]$GroupDateRow,
[OfficeOpenXml.Table.PivotTable.eDateGroupBy[]]$GroupDatePart,
[String]$GroupNumericRow,
[double]$GroupNumericMin = 0 ,
[double]$GroupNumericMax = [Double]::MaxValue ,
[double]$GroupNumericInterval = 100 ,
[string]$PivotNumberFormat,
[OfficeOpenXml.Table.TableStyles]$PivotTableStyle,
[Parameter(ParameterSetName = 'ChartbyDef', Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
$PivotChartDefinition,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$IncludePivotChart,
[Parameter(ParameterSetName = 'ChartbyParams')]
[String]$ChartTitle,
[Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartHeight = 400 ,
[Parameter(ParameterSetName = 'ChartbyParams')]
[int]$ChartWidth = 600,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRow = 0 ,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumn = 4,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartRowOffSetPixels = 0 ,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Int]$ChartColumnOffSetPixels = 0,
[Parameter(ParameterSetName = 'ChartbyParams')]
[OfficeOpenXml.Drawing.Chart.eChartType]$ChartType = 'Pie',
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$NoLegend,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowCategory,
[Parameter(ParameterSetName = 'ChartbyParams')]
[Switch]$ShowPercent,
[switch]$Activate
)
$validDataFuntions = [system.enum]::GetNames([OfficeOpenXml.Table.PivotTable.DataFieldFunctions])
if ($PivotData.values.Where( {$_ -notin $validDataFuntions}) ) {
Write-Warning -Message ("Pivot data functions might not be valid, they should be one of " + ($validDataFuntions -join ", ") + ".")
}
$parameters = @{} + $PSBoundParameters
if ($NoTotalsInPivot) {
$parameters.Remove('NoTotalsInPivot')
$parameters["PivotTotals"] = "None"
}
$parameters.Remove('PivotTableName')
if ($PivotChartDefinition) {
$parameters.PivotChartDefinition.XRange = $null
$parameters.PivotChartDefinition.YRange = $null
$parameters.PivotChartDefinition.SeriesHeader = $null
}
@{$PivotTableName = $parameters}
}

View File

@@ -0,0 +1,44 @@
Function Open-ExcelPackage {
[CmdLetBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")]
[OutputType([OfficeOpenXml.ExcelPackage])]
Param (
#The path to the file to open.
[Parameter(Mandatory=$true)]$Path,
#If specified, any running instances of Excel will be terminated before opening the file.
[switch]$KillExcel,
#The password for a protected worksheet, as a [normal] string (not a secure string).
[String]$Password,
#By default Open-ExcelPackage will only opens an existing file; -Create instructs it to create a new file if required.
[switch]$Create
)
if($KillExcel) {
Get-Process -Name "excel" -ErrorAction Ignore | Stop-Process
while (Get-Process -Name "excel" -ErrorAction Ignore) {}
}
$Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
#If -Create was not specified only open the file if it exists already (send a warning if it doesn't exist).
if ($Create -and -not (Test-Path -Path $path)) {
#Create the directory if required.
$targetPath = Split-Path -Parent -Path $Path
if (!(Test-Path -Path $targetPath)) {
Write-Debug "Base path $($targetPath) does not exist, creating"
$null = New-item -ItemType Directory -Path $targetPath -ErrorAction Ignore
}
New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path
}
elseif (Test-Path -Path $path) {
if ($Password) {$pkgobj = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path , $Password }
else {$pkgobj = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path }
if ($pkgobj) {
foreach ($w in $pkgobj.Workbook.Worksheets) {
$sb = [scriptblock]::Create(('$this.workbook.Worksheets["{0}"]' -f $w.name))
Add-Member -InputObject $pkgobj -MemberType ScriptProperty -Name $w.name -Value $sb
}
return $pkgobj
}
}
else {Write-Warning "Could not find $path" }
}

View File

@@ -0,0 +1,28 @@
Function Remove-WorkSheet {
[cmdletbinding(SupportsShouldProcess=$true)]
param(
# [Parameter(ValueFromPipelineByPropertyName)]
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('Path')]
$FullName,
[String[]]$WorksheetName = "Sheet1",
[Switch]$Show
)
Process {
if (!$FullName) {
throw "Remove-WorkSheet requires the and Excel file"
}
$pkg = Open-ExcelPackage -Path $FullName
if ($pkg) {
foreach ($wsn in $WorksheetName) {
if ($PSCmdlet.ShouldProcess($FullName,"Remove Sheet $wsn")) {
$pkg.Workbook.Worksheets.Delete($wsn)
}
}
Close-ExcelPackage -ExcelPackage $pkg -Show:$Show
}
}
}

View File

@@ -0,0 +1,24 @@
function Select-Worksheet {
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Package', Position = 0)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Parameter(Mandatory = $true, ParameterSetName = 'Workbook')]
[OfficeOpenXml.ExcelWorkbook]$ExcelWorkbook,
[Parameter(ParameterSetName='Package')]
[Parameter(ParameterSetName='Workbook')]
[string]$WorksheetName,
[Parameter(ParameterSetName='Sheet',Mandatory=$true)]
[OfficeOpenXml.ExcelWorksheet]$ExcelWorksheet
)
#if we were given a package, use its workbook
if ($ExcelPackage -and -not $ExcelWorkbook) {$ExcelWorkbook = $ExcelPackage.Workbook}
#if we now have workbook, get the worksheet; if we were given a sheet get the workbook
if ($ExcelWorkbook -and $WorksheetName) {$ExcelWorksheet = $ExcelWorkbook.Worksheets[$WorksheetName]}
elseif ($ExcelWorksheet -and -not $ExcelWorkbook) {$ExcelWorkbook = $ExcelWorksheet.Workbook ; }
#if we didn't get to a worksheet give up. If we did set all works sheets to not selected and then the one we want to selected.
if (-not $ExcelWorksheet) {Write-Warning -Message "The worksheet $WorksheetName was not found." ; return }
else {
foreach ($w in $ExcelWorkbook.Worksheets) {$w.View.TabSelected = $false}
$ExcelWorksheet.View.TabSelected = $true
}
}

View File

@@ -0,0 +1,112 @@
Function Send-SQLDataToExcel {
[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

@@ -0,0 +1,119 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# Set-CellStyle
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Set-CellStyle [[-WorkSheet] <Object>] [[-Row] <Object>] [[-LastColumn] <Object>] [[-Pattern] <ExcelFillStyle>]
[[-Color] <Object>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -Color
{{ Fill Color Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 4
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -LastColumn
{{ Fill LastColumn Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Pattern
{{ Fill Pattern Description }}
```yaml
Type: ExcelFillStyle
Parameter Sets: (All)
Aliases:
Accepted values: None, Solid, DarkGray, MediumGray, LightGray, Gray125, Gray0625, DarkVertical, DarkHorizontal, DarkDown, DarkUp, DarkGrid, DarkTrellis, LightVertical, LightHorizontal, LightDown, LightUp, LightGrid, LightTrellis
Required: False
Position: 3
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -Row
{{ Fill Row Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -WorkSheet
{{ Fill WorkSheet Description }}
```yaml
Type: Object
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,16 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function', Target='Set*', Justification='Does not change system state')]
param()
function Set-CellStyle {
param(
$WorkSheet,
$Row,
$LastColumn,
[OfficeOpenXml.Style.ExcelFillStyle]$Pattern,
$Color
)
if ($Color -is [string]) {$Color = [System.Drawing.Color]::$Color }
$t=$WorkSheet.Cells["A$($Row):$($LastColumn)$($Row)"]
$t.Style.Fill.PatternType=$Pattern
$t.Style.Fill.BackgroundColor.SetColor($Color)
}

View File

@@ -0,0 +1,127 @@
Function Set-ExcelColumn {
[cmdletbinding()]
[Alias("Set-Column")]
[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 (
[Parameter(ParameterSetName="Package",Mandatory=$true)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Parameter(ParameterSetName="Package")]
[String]$Worksheetname = "Sheet1",
[Parameter(ParameterSetName="sheet",Mandatory=$true)]
[OfficeOpenXml.ExcelWorksheet]$Worksheet,
[Parameter(ValueFromPipeline=$true)]
[ValidateRange(0,16384)]
$Column = 0 ,
[ValidateRange(1,1048576)]
[Int]$StartRow ,
$Value ,
$Heading ,
[Alias("NFormat")]
$NumberFormat,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround,
$FontColor,
[Switch]$Bold,
[Switch]$Italic,
[Switch]$Underline,
[OfficeOpenXml.Style.ExcelUnderLineType]$UnderLineType = [OfficeOpenXml.Style.ExcelUnderLineType]::Single,
[Switch]$StrikeThru,
[OfficeOpenXml.Style.ExcelVerticalAlignmentFont]$FontShift,
[String]$FontName,
[float]$FontSize,
$BackgroundColor,
[OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid ,
[Alias("PatternColour")]
$PatternColor,
[Switch]$WrapText,
[OfficeOpenXml.Style.ExcelHorizontalAlignment]$HorizontalAlignment,
[OfficeOpenXml.Style.ExcelVerticalAlignment]$VerticalAlignment,
[ValidateRange(-90, 90)]
[int]$TextRotation ,
[Alias("AutoFit")]
[Switch]$AutoSize,
[float]$Width,
[Switch]$AutoNameRange,
[Switch]$Hide,
[Switch]$Specified,
[Switch]$PassThru
)
begin {
#if we were passed a package object and a worksheet name , get the worksheet.
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,
#if Column and Startrow aren't specified, assume first unused column, and first row
if (-not $StartRow) {$startRow = $Worksheet.Dimension.Start.Row }
$startColumn = $Worksheet.Dimension.Start.Column
$endColumn = $Worksheet.Dimension.End.Column
$endRow = $Worksheet.Dimension.End.Row
}
process {
if ($null -eq $workSheet.Dimension) {Write-Warning "Can't format an empty worksheet."; return}
if ($Column -eq 0 ) {$Column = $endColumn + 1 }
$columnName = (New-Object 'OfficeOpenXml.ExcelCellAddress' @(1, $column)).Address -replace "1",""
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 ($PSBoundParameters.ContainsKey('Heading')) {
$Worksheet.Cells[$StartRow, $Column].Value = $Heading
$StartRow ++
if ($AutoNameRange) {
Add-ExcelName -Range $Worksheet.Cells[$StartRow, $Column, $endRow, $Column] -RangeName $Heading
}
}
elseif ($AutoNameRange) {
Add-ExcelName -Range $Worksheet.Cells[($StartRow+1), $Column, $endRow, $Column] -RangeName $Worksheet.Cells[$StartRow, $Column].Value
}
#Fill in the data -it can be zero null or and empty string.
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.
$cellData = & ([scriptblock]::create( $Value ))
if ($null -eq $cellData) {Write-Verbose -Message "Script block evaluates to null."}
else {Write-Verbose -Message "Script block evaluates to '$cellData'"}
}
else { $cellData = $Value}
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)) {
# 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/") {
$referenceAddress = $cellData -replace "^xl://internal/" , ""
$display = $referenceAddress -replace "!A1$" , ""
$h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
$Worksheet.Cells[$Row, $Column].HyperLink = $h
}
else {$Worksheet.Cells[$Row, $Column].HyperLink = $cellData }
$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 }
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' }
}}
#region Apply formatting
$params = @{}
foreach ($p in @('Underline','Bold','Italic','StrikeThru', 'FontName', 'FontSize','FontShift','NumberFormat','TextRotation',
'WrapText', 'HorizontalAlignment','VerticalAlignment', 'Autosize', 'Width', 'FontColor'
'BorderAround', 'BackgroundColor', 'BackgroundPattern', 'PatternColor')) {
if ($PSBoundParameters.ContainsKey($p)) {$params[$p] = $PSBoundParameters[$p]}
}
if ($params.Count) {
$theRange = "$columnName$StartRow`:$columnName$endRow"
Set-ExcelRange -WorkSheet $Worksheet -Range $theRange @params
}
#endregion
if ($PSBoundParameters.ContainsKey('Hide')) {$workSheet.Column($Column).Hidden = [bool]$Hide}
#return the new data if -passthru was specified.
if ($PassThru) { $Worksheet.Column($Column)}
elseif ($ReturnRange) { $theRange}
}
}

View File

@@ -0,0 +1,199 @@
function Set-ExcelRange {
[cmdletbinding()]
[Alias("Set-Format")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system state')]
Param (
[Parameter(ValueFromPipeline = $true,Position=0)]
[Alias("Address")]
$Range ,
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
[Alias("NFormat")]
$NumberFormat,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround,
$BorderColor=[System.Drawing.Color]::Black,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderBottom,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderTop,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderLeft,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight,
[Alias('ForegroundColor')]
$FontColor,
$Value,
$Formula,
[Switch]$ArrayFormula,
[Switch]$ResetFont,
[Switch]$Bold,
[Switch]$Italic,
[Switch]$Underline,
[OfficeOpenXml.Style.ExcelUnderLineType]$UnderLineType = [OfficeOpenXml.Style.ExcelUnderLineType]::Single,
[Switch]$StrikeThru,
[OfficeOpenXml.Style.ExcelVerticalAlignmentFont]$FontShift,
[String]$FontName,
[float]$FontSize,
$BackgroundColor,
[OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid ,
[Alias("PatternColour")]
$PatternColor,
[Switch]$WrapText,
[OfficeOpenXml.Style.ExcelHorizontalAlignment]$HorizontalAlignment,
[OfficeOpenXml.Style.ExcelVerticalAlignment]$VerticalAlignment,
[ValidateRange(-90, 90)]
[int]$TextRotation ,
[Alias("AutoFit")]
[Switch]$AutoSize,
[float]$Width,
[float]$Height,
[Switch]$Hidden,
[Switch]$Locked,
[Switch]$Merge
)
process {
if ($Range -is [Array]) {
$null = $PSBoundParameters.Remove("Range")
$Range | Set-ExcelRange @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 ($Range -is [OfficeOpenXml.Table.ExcelTable]) {$Range = $Range.Address}
elseif ($WorkSheet -and ($Range -is [string] -or $Range -is [OfficeOpenXml.ExcelAddress])) {
$Range = $WorkSheet.Cells[$Range]
}
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) {
$Range.Style.Font.Color.SetColor( ([System.Drawing.Color]::Black))
$Range.Style.Font.Bold = $false
$Range.Style.Font.Italic = $false
$Range.Style.Font.UnderLine = $false
$Range.Style.Font.Strike = $false
$Range.Style.Font.VerticalAlign = [OfficeOpenXml.Style.ExcelVerticalAlignmentFont]::None
}
if ($PSBoundParameters.ContainsKey('Underline')) {
$Range.Style.Font.UnderLine = [boolean]$Underline
$Range.Style.Font.UnderLineType = $UnderLineType
}
if ($PSBoundParameters.ContainsKey('Bold')) {
$Range.Style.Font.Bold = [boolean]$bold
}
if ($PSBoundParameters.ContainsKey('Italic')) {
$Range.Style.Font.Italic = [boolean]$italic
}
if ($PSBoundParameters.ContainsKey('StrikeThru')) {
$Range.Style.Font.Strike = [boolean]$StrikeThru
}
if ($PSBoundParameters.ContainsKey('FontSize')){
$Range.Style.Font.Size = $FontSize
}
if ($PSBoundParameters.ContainsKey('FontName')){
$Range.Style.Font.Name = $FontName
}
if ($PSBoundParameters.ContainsKey('FontShift')){
$Range.Style.Font.VerticalAlign = $FontShift
}
if ($PSBoundParameters.ContainsKey('FontColor')){
if ($FontColor -is [string]) {$FontColor = [System.Drawing.Color]::$FontColor }
$Range.Style.Font.Color.SetColor( $FontColor)
}
if ($PSBoundParameters.ContainsKey('TextRotation')) {
$Range.Style.TextRotation = $TextRotation
}
if ($PSBoundParameters.ContainsKey('WrapText')) {
$Range.Style.WrapText = [boolean]$WrapText
}
if ($PSBoundParameters.ContainsKey('HorizontalAlignment')) {
$Range.Style.HorizontalAlignment = $HorizontalAlignment
}
if ($PSBoundParameters.ContainsKey('VerticalAlignment')) {
$Range.Style.VerticalAlignment = $VerticalAlignment
}
if ($PSBoundParameters.ContainsKey('Merge')) {
$Range.Merge = [boolean]$Merge
}
if ($PSBoundParameters.ContainsKey('Value')) {
if ($Value -match '^=') {$PSBoundParameters["Formula"] = $Value -replace '^=','' }
else {
$Range.Value = $Value
if ($Value -is [datetime]) { $Range.Style.Numberformat.Format = 'm/d/yy h:mm' }# This is not a custom format, but a preset recognized as date and localized. It might be overwritten in a moment
if ($Value -is [timespan]) { $Range.Style.Numberformat.Format = '[h]:mm:ss' }
}
}
if ($PSBoundParameters.ContainsKey('Formula')) {
if ($ArrayFormula) {$Range.CreateArrayFormula(($Formula -replace '^=','')) }
else {$Range.Formula = ($Formula -replace '^=','') }
}
if ($PSBoundParameters.ContainsKey('NumberFormat')) {
$Range.Style.Numberformat.Format = (Expand-NumberFormat $NumberFormat)
}
if ($BorderColor -is [string]) {$BorderColor = [System.Drawing.Color]::$BorderColor }
if ($PSBoundParameters.ContainsKey('BorderAround')) {
$Range.Style.Border.BorderAround($BorderAround, $BorderColor)
}
if ($PSBoundParameters.ContainsKey('BorderBottom')) {
$Range.Style.Border.Bottom.Style=$BorderBottom
$Range.Style.Border.Bottom.Color.SetColor($BorderColor)
}
if ($PSBoundParameters.ContainsKey('BorderTop')) {
$Range.Style.Border.Top.Style=$BorderTop
$Range.Style.Border.Top.Color.SetColor($BorderColor)
}
if ($PSBoundParameters.ContainsKey('BorderLeft')) {
$Range.Style.Border.Left.Style=$BorderLeft
$Range.Style.Border.Left.Color.SetColor($BorderColor)
}
if ($PSBoundParameters.ContainsKey('BorderRight')) {
$Range.Style.Border.Right.Style=$BorderRight
$Range.Style.Border.Right.Color.SetColor($BorderColor)
}
if ($PSBoundParameters.ContainsKey('BackgroundColor')) {
$Range.Style.Fill.PatternType = $BackgroundPattern
if ($BackgroundColor -is [string]) {$BackgroundColor = [System.Drawing.Color]::$BackgroundColor }
$Range.Style.Fill.BackgroundColor.SetColor($BackgroundColor)
if ($PatternColor) {
if ($PatternColor -is [string]) {$PatternColor = [System.Drawing.Color]::$PatternColor }
$Range.Style.Fill.PatternColor.SetColor( $PatternColor)
}
}
if ($PSBoundParameters.ContainsKey('Height')) {
if ($Range -is [OfficeOpenXml.ExcelRow] ) {$Range.Height = $Height }
elseif ($Range -is [OfficeOpenXml.ExcelRange] ) {
($Range.Start.Row)..($Range.Start.Row + $Range.Rows) |
ForEach-Object {$Range.WorkSheet.Row($_).Height = $Height }
}
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 -and -not $env:NoAutoSize) {
try {
if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.AutoFit() }
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)) }
}
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')) {
if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.Width = $Width}
elseif ($Range -is [OfficeOpenXml.ExcelRange] ) {
($Range.Start.Column)..($Range.Start.Column + $Range.Columns - 1) |
ForEach-Object {
#$ws.Column($_).Width = $Width
$Range.Worksheet.Column($_).Width = $Width
}
}
else {Write-Warning -Message ("Can set the width of a column or a range but not a {0} object" -f ($Range.GetType().name)) }
}
if ($PSBoundParameters.ContainsKey('Hidden')) {
if ($Range -is [OfficeOpenXml.ExcelRow] -or
$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)) }
}
if ($PSBoundParameters.ContainsKey('Locked')) {
$Range.Style.Locked=$Locked
}
}
}
}

View File

@@ -0,0 +1,124 @@
Function Set-ExcelRow {
[cmdletbinding()]
[Alias("Set-Row")]
[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 (
[Parameter(ParameterSetName="Package",Mandatory=$true)]
[OfficeOpenXml.ExcelPackage]$ExcelPackage,
[Parameter(ParameterSetName="Package")]
$Worksheetname = "Sheet1",
[Parameter(ParameterSetName="Sheet",Mandatory=$true)]
[OfficeOpenXml.Excelworksheet] $Worksheet,
[Parameter(ValueFromPipeline = $true)]
$Row = 0 ,
[int]$StartColumn,
$Value,
$Heading ,
[Switch]$HeadingBold,
[Int]$HeadingSize ,
[Alias("NFormat")]
$NumberFormat,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround,
$BorderColor=[System.Drawing.Color]::Black,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderBottom,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderTop,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderLeft,
[OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight,
$FontColor,
[Switch]$Bold,
[Switch]$Italic,
[Switch]$Underline,
[OfficeOpenXml.Style.ExcelUnderLineType]$UnderLineType = [OfficeOpenXml.Style.ExcelUnderLineType]::Single,
[Switch]$StrikeThru,
[OfficeOpenXml.Style.ExcelVerticalAlignmentFont]$FontShift,
[String]$FontName,
[float]$FontSize,
$BackgroundColor,
[OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid ,
[Alias("PatternColour")]
$PatternColor,
[Switch]$WrapText,
[OfficeOpenXml.Style.ExcelHorizontalAlignment]$HorizontalAlignment,
[OfficeOpenXml.Style.ExcelVerticalAlignment]$VerticalAlignment,
[ValidateRange(-90, 90)]
[int]$TextRotation ,
[float]$Height,
[Switch]$Hide,
[Switch]$ReturnRange,
[Switch]$PassThru
)
begin {
#if we were passed a package object and a worksheet name , get the worksheet.
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,
#if row and start column aren't specified assume first unused row, and first column
if (-not $StartColumn) {$StartColumn = $Worksheet.Dimension.Start.Column }
$startRow = $Worksheet.Dimension.Start.Row + 1
$endColumn = $Worksheet.Dimension.End.Column
$endRow = $Worksheet.Dimension.End.Row
}
process {
if ($null -eq $workSheet.Dimension) {Write-Warning "Can't format an empty worksheet."; return}
if ($Row -eq 0 ) {$Row = $endRow + 1 }
Write-Verbose -Message "Updating Row $Row"
#Add a row label
if ($Heading) {
$Worksheet.Cells[$Row, $StartColumn].Value = $Heading
if ($HeadingBold) {$Worksheet.Cells[$Row, $StartColumn].Style.Font.Bold = $true}
if ($HeadingSize) {$Worksheet.Cells[$Row, $StartColumn].Style.Font.Size = $HeadingSize}
$StartColumn ++
}
#Fill in the data
if ($PSBoundParameters.ContainsKey('Value')) {foreach ($column in ($StartColumn..$endColumn)) {
#We might want the column name in a script block
$columnName = (New-Object -TypeName OfficeOpenXml.ExcelCellAddress @(1,$column)).Address -replace "1",""
if ($Value -is [scriptblock] ) {
#re-create the script block otherwise variables from this function are out of scope.
$cellData = & ([scriptblock]::create( $Value ))
if ($null -eq $cellData) {Write-Verbose -Message "Script block evaluates to null."}
else {Write-Verbose -Message "Script block evaluates to '$cellData'"}
}
else{$cellData = $Value}
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)) {
# 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/") {
$referenceAddress = $cellData -replace "^xl://internal/" , ""
$display = $referenceAddress -replace "!A1$" , ""
$h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
$Worksheet.Cells[$Row, $Column].HyperLink = $h
}
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
}
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 [timespan]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = '[h]:mm:ss' }
}}
#region Apply formatting
$params = @{}
foreach ($p in @('Underline','Bold','Italic','StrikeThru', 'FontName', 'FontSize', 'FontShift','NumberFormat','TextRotation',
'WrapText', 'HorizontalAlignment','VerticalAlignment', 'Height', 'FontColor'
'BorderAround', 'BorderBottom', 'BorderTop', 'BorderLeft', 'BorderRight', 'BorderColor',
'BackgroundColor', 'BackgroundPattern', 'PatternColor')) {
if ($PSBoundParameters.ContainsKey($p)) {$params[$p] = $PSBoundParameters[$p]}
}
if ($params.Count) {
$theRange = New-Object -TypeName OfficeOpenXml.ExcelAddress @($Row, $StartColumn, $Row, $endColumn)
Set-ExcelRange -WorkSheet $Worksheet -Range $theRange @params
}
#endregion
if ($PSBoundParameters.ContainsKey('Hide')) {$workSheet.Row($Row).Hidden = [bool]$Hide}
#return the new data if -passthru was specified.
if ($passThru) {$Worksheet.Row($Row)}
elseif ($ReturnRange) {$theRange}
}
}

View File

@@ -0,0 +1,349 @@
---
external help file: ImportExcel-help.xml
Module Name: ImportExcel
online version:
schema: 2.0.0
---
# Set-WorkSheetProtection
## SYNOPSIS
{{ Fill in the Synopsis }}
## SYNTAX
```
Set-WorkSheetProtection [-WorkSheet] <ExcelWorksheet> [-IsProtected] [-AllowAll] [-BlockSelectLockedCells]
[-BlockSelectUnlockedCells] [-AllowFormatCells] [-AllowFormatColumns] [-AllowFormatRows] [-AllowInsertColumns]
[-AllowInsertRows] [-AllowInsertHyperlinks] [-AllowDeleteColumns] [-AllowDeleteRows] [-AllowSort]
[-AllowAutoFilter] [-AllowPivotTables] [-BlockEditObject] [-BlockEditScenarios] [[-LockAddress] <String>]
[[-UnLockAddress] <String>] [<CommonParameters>]
```
## DESCRIPTION
{{ Fill in the Description }}
## EXAMPLES
### Example 1
```powershell
PS C:\> {{ Add example code here }}
```
{{ Add example description here }}
## PARAMETERS
### -AllowAll
{{ Fill AllowAll Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowAutoFilter
{{ Fill AllowAutoFilter Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowDeleteColumns
{{ Fill AllowDeleteColumns Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowDeleteRows
{{ Fill AllowDeleteRows Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowFormatCells
{{ Fill AllowFormatCells Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowFormatColumns
{{ Fill AllowFormatColumns Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowFormatRows
{{ Fill AllowFormatRows Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowInsertColumns
{{ Fill AllowInsertColumns Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowInsertHyperlinks
{{ Fill AllowInsertHyperlinks Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowInsertRows
{{ Fill AllowInsertRows Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowPivotTables
{{ Fill AllowPivotTables Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -AllowSort
{{ Fill AllowSort Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BlockEditObject
{{ Fill BlockEditObject Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BlockEditScenarios
{{ Fill BlockEditScenarios Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BlockSelectLockedCells
{{ Fill BlockSelectLockedCells Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -BlockSelectUnlockedCells
{{ Fill BlockSelectUnlockedCells Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -IsProtected
{{ Fill IsProtected Description }}
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -LockAddress
{{ Fill LockAddress Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -UnLockAddress
{{ Fill UnLockAddress Description }}
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -WorkSheet
{{ Fill WorkSheet Description }}
```yaml
Type: ExcelWorksheet
Parameter Sets: (All)
Aliases:
Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### None
## OUTPUTS
### System.Object
## NOTES
## RELATED LINKS

View File

@@ -0,0 +1,55 @@
Function Set-WorkSheetProtection {
[Cmdletbinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',Justification='Does not change system state')]
param (
[Parameter(Mandatory=$true)]
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
[switch]$IsProtected,
[switch]$AllowAll,
[switch]$BlockSelectLockedCells,
[switch]$BlockSelectUnlockedCells,
[switch]$AllowFormatCells,
[switch]$AllowFormatColumns,
[switch]$AllowFormatRows,
[switch]$AllowInsertColumns,
[switch]$AllowInsertRows,
[switch]$AllowInsertHyperlinks,
[switch]$AllowDeleteColumns,
[switch]$AllowDeleteRows,
[switch]$AllowSort,
[switch]$AllowAutoFilter,
[switch]$AllowPivotTables,
[switch]$BlockEditObject,
[switch]$BlockEditScenarios,
[string]$LockAddress,
[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

@@ -0,0 +1,23 @@
[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 {
Try {
$Union = @()
$Input | ForEach-Object {
If ($Union.Count) {
$_ | Get-Member | Where-Object {-not ($Union[0] | Get-Member $_.Name)} | ForEach-Object {
$Union[0] | Add-Member -MemberType NoteProperty -Name $_.Name -Value $Null
}
}
$Union += $_
}
$Union
}
Catch {
throw "Failed updating the properties of the first object: $_"
}
}