From d8d624ba9c741455847da84ccfbf273f46cc3504 Mon Sep 17 00:00:00 2001 From: DarkLite1 Date: Wed, 26 Jul 2017 13:37:08 +0200 Subject: [PATCH] Added the function 'Update-FirstObjectProperties' Added help text in 'Export-Excel' Added try/catch to 'Install' and 'InstallModule' Improved code readability in 'Install' and 'InstallModule' --- Export-Excel.ps1 | 116 +++++++++++++++++++--------- ImportExcel.psd1 | 2 +- ImportExcel.psm1 | 66 ++++++++-------- Install.ps1 | 128 ++++++++++++++++++++----------- InstallModule.ps1 | 110 +++++++++++++++++--------- Update-FirstObjectProperties.ps1 | 92 ++++++++++++++++++++++ 6 files changed, 365 insertions(+), 149 deletions(-) create mode 100644 Update-FirstObjectProperties.ps1 diff --git a/Export-Excel.ps1 b/Export-Excel.ps1 index c3a775e..cfbcddc 100644 --- a/Export-Excel.ps1 +++ b/Export-Excel.ps1 @@ -147,6 +147,40 @@ Function Export-Excel { Export all services to an Excel sheet where all cells have a 'Conditional formatting rule' in Excel that will show the background fill color in 'LightPink' and the text color in 'DarkRed' when the value contains the word 'Stop'. If the value contains the word 'Running' it will have a background fill color in 'Cyan' and a text color 'Blue'. In case none of these conditions are met the color will be the default, black text on a white background. + .EXAMPLE + $ExcelParams = @{ + Path = $env:TEMP + '\Excel.xlsx' + Show = $true + Verbose = $true + } + Remove-Item -Path $ExcelParams.Path -Force -EA Ignore + + $Array = @() + + $Obj1 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + } + + $Obj2 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + Member3 = 'Third' + } + + $Obj3 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + Member3 = 'Third' + Member4 = 'Fourth' + } + + $Array = $Obj1, $Obj2, $Obj3 + $Array | Out-GridView -Title 'Not showing Member3 and Member4' + $Array | Update-FirstObjectProperties | Export-Excel @ExcelParams -WorkSheetname Numbers + + Updates the first object of the array by adding property 'Member3' and 'Member4'. Afterwards. all objects are exported to an Excel file and all column headers are visible. + .EXAMPLE Get-Process | Export-Excel .\test.xlsx -WorkSheetname Processes -IncludePivotTable -Show -PivotRows Company -PivotData PM @@ -155,6 +189,9 @@ Function Export-Excel { .EXAMPLE Get-Service | Export-Excel 'c:\temp\test.xlsx' -Show -IncludePivotTable -PivotRows status -PivotData @{status='count'} + + .LINK + https://github.com/dfinke/ImportExcel #> [CmdLetBinding()] @@ -390,50 +427,55 @@ Function Export-Excel { } Process { - if ($firstTimeThru) { - $firstTimeThru = $false - $isDataTypeValueType = $TargetData.GetType().name -match $pattern - Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" - } - - if ($isDataTypeValueType) { - $ColumnIndex = $StartColumn - - Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData - - $ColumnIndex += 1 - $Row += 1 - } - else { - #region Add headers - if (-not $script:Header) { - $ColumnIndex = $StartColumn - $script:Header = $TargetData.PSObject.Properties.Name - - if ($NoHeader) { - # Don't push the headers to the spread sheet - $Row -= 1 - } - else { - foreach ($Name in $script:Header) { - $ws.Cells[$Row, $ColumnIndex].Value = $Name - Write-Verbose "Cell '$Row`:$ColumnIndex' add header '$Name'" - $ColumnIndex += 1 - } - } + Try { + if ($firstTimeThru) { + $firstTimeThru = $false + $isDataTypeValueType = $TargetData.GetType().name -match $pattern + Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" } - #endregion - $Row += 1 - $ColumnIndex = $StartColumn + if ($isDataTypeValueType) { + $ColumnIndex = $StartColumn - foreach ($Name in $script:Header) { - #region Add non header values - Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData.$Name + Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData $ColumnIndex += 1 + $Row += 1 + } + else { + #region Add headers + if (-not $script:Header) { + $ColumnIndex = $StartColumn + $script:Header = $TargetData.PSObject.Properties.Name + + if ($NoHeader) { + # Don't push the headers to the spread sheet + $Row -= 1 + } + else { + foreach ($Name in $script:Header) { + $ws.Cells[$Row, $ColumnIndex].Value = $Name + Write-Verbose "Cell '$Row`:$ColumnIndex' add header '$Name'" + $ColumnIndex += 1 + } + } + } #endregion + + $Row += 1 + $ColumnIndex = $StartColumn + + foreach ($Name in $script:Header) { + #region Add non header values + Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData.$Name + + $ColumnIndex += 1 + #endregion + } } + } + Catch { + throw "Failed exporting worksheet '$WorkSheetname' to '$Path': $_" } } diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 166d46b..d39e4bb 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -4,7 +4,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. -ModuleVersion = '3.0.1' +ModuleVersion = '3.0.2' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' diff --git a/ImportExcel.psm1 b/ImportExcel.psm1 index 426fc70..45a8cbc 100644 --- a/ImportExcel.psm1 +++ b/ImportExcel.psm1 @@ -1,46 +1,49 @@ Add-Type -Path "$($PSScriptRoot)\EPPlus.dll" -. $PSScriptRoot\Export-Excel.ps1 -. $PSScriptRoot\New-ConditionalFormattingIconSet.ps1 -. $PSScriptRoot\New-ConditionalText.ps1 -. $PSScriptRoot\Export-ExcelSheet.ps1 -. $PSScriptRoot\New-ExcelChart.ps1 -. $PSScriptRoot\Invoke-Sum.ps1 -. $PSScriptRoot\InferData.ps1 -. $PSScriptRoot\Get-ExcelColumnName.ps1 -. $PSScriptRoot\Get-XYRange.ps1 . $PSScriptRoot\Charting.ps1 -. $PSScriptRoot\New-PSItem.ps1 -. $PSScriptRoot\Pivot.ps1 -. $PSScriptRoot\Get-ExcelSheetInfo.ps1 -. $PSScriptRoot\Get-ExcelWorkbookInfo.ps1 -. $PSScriptRoot\Get-HtmlTable.ps1 -. $PSScriptRoot\Import-Html.ps1 -. $PSScriptRoot\Get-Range.ps1 -. $PSScriptRoot\TrackingUtils.ps1 -. $PSScriptRoot\Copy-ExcelWorkSheet.ps1 -. $PSScriptRoot\Set-CellStyle.ps1 . $PSScriptRoot\ConvertFromExcelData.ps1 . $PSScriptRoot\ConvertFromExcelToSQLInsert.ps1 . $PSScriptRoot\ConvertToExcelXlsx.ps1 +. $PSScriptRoot\Copy-ExcelWorkSheet.ps1 +. $PSScriptRoot\Export-Excel.ps1 +. $PSScriptRoot\Export-ExcelSheet.ps1 +. $PSScriptRoot\Get-ExcelColumnName.ps1 +. $PSScriptRoot\Get-ExcelSheetInfo.ps1 +. $PSScriptRoot\Get-ExcelWorkbookInfo.ps1 +. $PSScriptRoot\Get-HtmlTable.ps1 +. $PSScriptRoot\Get-Range.ps1 +. $PSScriptRoot\Get-XYRange.ps1 +. $PSScriptRoot\Import-Html.ps1 +. $PSScriptRoot\InferData.ps1 +. $PSScriptRoot\Invoke-Sum.ps1 +. $PSScriptRoot\New-ConditionalFormattingIconSet.ps1 +. $PSScriptRoot\New-ConditionalText.ps1 +. $PSScriptRoot\New-ExcelChart.ps1 +. $PSScriptRoot\New-PSItem.ps1 +. $PSScriptRoot\Pivot.ps1 +. $PSScriptRoot\Set-CellStyle.ps1 +. $PSScriptRoot\TrackingUtils.ps1 +. $PSScriptRoot\Update-FirstObjectProperties.ps1 -if($PSVersionTable.PSVersion.Major -ge 5) { - . $PSScriptRoot\plot.ps1 - function New-Plot { +if ($PSVersionTable.PSVersion.Major -ge 5) { + . $PSScriptRoot\Plot.ps1 + + Function New-Plot { [OutputType([PSPlot])] - param() + Param() - [psplot]::new() + [PSPlot]::new() } -} else { - Write-Warning "PowerShell 5 is required for plot.ps1" - Write-Warning "PowerShell Excel is ready, except for that functionality" +} +else { + Write-Warning 'PowerShell 5 is required for plot.ps1' + Write-Warning 'PowerShell Excel is ready, except for that functionality' } -function Import-Excel { +Function Import-Excel { <# .SYNOPSIS Read the content of an Excel sheet. @@ -73,12 +76,13 @@ function Import-Excel { .LINK https://github.com/dfinke/ImportExcel #> - param( - [Alias("FullName")] + + Param( + [Alias('FullName')] [Parameter(ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true, Mandatory=$true)] [ValidateScript({ Test-Path $_ -PathType Leaf })] $Path, - [Alias("Sheet")] + [Alias('Sheet')] $WorkSheetname=1, [int]$HeaderRow=1, [string[]]$Header, diff --git a/Install.ps1 b/Install.ps1 index b43443a..a827fce 100644 --- a/Install.ps1 +++ b/Install.ps1 @@ -1,52 +1,94 @@ -param([string]$InstallDirectory) +<# + .SYNOPSIS + Download the module files from GitHub. -$fileList = echo ` - EPPlus.dll ` - ImportExcel.psd1 ` - ImportExcel.psm1 ` - Export-Excel.ps1 ` - New-ConditionalFormattingIconSet.ps1 ` - Export-ExcelSheet.ps1 ` - New-ExcelChart.ps1 ` - Invoke-Sum.ps1 ` - InferData.ps1 ` - Get-ExcelColumnName.ps1 ` - Get-XYRange.ps1 ` - Charting.ps1 ` - New-PSItem.ps1 ` - Pivot.ps1 ` - New-ConditionalText.ps1 ` - Get-HtmlTable.ps1 ` - Import-Html.ps1 ` - Get-ExcelSheetInfo.ps1 ` - Get-ExcelWorkbookInfo.ps1 ` - Get-Range.ps1 ` - TrackingUtils.ps1 ` - Copy-ExcelWorkSheet.ps1 ` - Set-CellStyle.ps1 ` - plot.ps1 + .DESCRIPTION + Download the module files from GitHub to the local client in the module folder. +#> -if ('' -eq $InstallDirectory) -{ - $personalModules = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath WindowsPowerShell\Modules +[CmdLetBinding()] +Param ( + [ValidateNotNullOrEmpty()] + [String]$ModuleName = 'ImportExcel', + [String]$InstallDirectory, + [ValidateNotNullOrEmpty()] + [String]$GitPath = 'https://raw.github.com/dfinke/ImportExcel/master' +) - if (($env:PSModulePath -split ';') -notcontains $personalModules) { - Write-Warning "$personalModules is not in `$env:PSModulePath" +Begin { + Try { + Write-Verbose "$ModuleName module installation started" + + $Files = @( + 'Charting.ps1', + 'ConvertFromExcelData.ps1', + 'ConvertFromExcelToSQLInsert.ps1', + 'ConvertToExcelXlsx.ps1', + 'Copy-ExcelWorkSheet.ps1', + 'EPPlus.dll', + 'Export-Excel.ps1', + 'Export-ExcelSheet.ps1', + 'Get-ExcelColumnName.ps1', + 'Get-ExcelSheetInfo.ps1', + 'Get-ExcelWorkbookInfo.ps1', + 'Get-HtmlTable.ps1', + 'Get-Range.ps1', + 'Get-XYRange.ps1', + 'Import-Html.ps1', + 'ImportExcel.psd1', + 'ImportExcel.psm1', + 'InferData.ps1', + 'Invoke-Sum.ps1', + 'New-ConditionalFormattingIconSet.ps1', + 'New-ConditionalText.ps1', + 'New-ExcelChart.ps1', + 'New-PSItem.ps1', + 'Pivot.ps1', + 'Plot.ps1', + 'Set-CellStyle.ps1', + 'TrackingUtils.ps1', + 'Update-FirstObjectProperties.ps1' + ) } - - if (!(Test-Path $personalModules)) { - Write-Error "$personalModules does not exist" + Catch { + throw "Failed installing the module in the install directory '$InstallDirectory': $_" } - - $InstallDirectory = Join-Path -Path $personalModules -ChildPath ImportExcel } -if (!(Test-Path $InstallDirectory)) { - $null = mkdir $InstallDirectory -} +Process { + Try { + if (-not $InstallDirectory) { + Write-Verbose "$ModuleName no installation directory provided" -$wc = New-Object System.Net.WebClient -$fileList | - ForEach-Object { - $wc.DownloadFile("https://raw.github.com/dfinke/ImportExcel/master/$_","$installDirectory\$_") + $PersonalModules = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath WindowsPowerShell\Modules + + if (($env:PSModulePath -split ';') -notcontains $PersonalModules) { + Write-Warning "$ModuleName personal module path '$PersonalModules' not found in '`$env:PSModulePath'" + } + + if (-not (Test-Path $PersonalModules)) { + Write-Error "$ModuleName path '$PersonalModules' does not exist" + } + + $InstallDirectory = Join-Path -Path $PersonalModules -ChildPath $ModuleName + Write-Verbose "$ModuleName default installation directory is '$InstallDirectory'" + } + + if (-not (Test-Path $InstallDirectory)) { + New-Item -Path $InstallDirectory -ItemType Directory -EA Stop | Out-Null + Write-Verbose "$ModuleName created module folder '$InstallDirectory'" + } + + $WebClient = New-Object System.Net.WebClient + + $Files | ForEach-Object { + $WebClient.DownloadFile("$GitPath/$_","$installDirectory\$_") + Write-Verbose "$ModuleName installed module file '$_'" + } + + Write-Verbose "$ModuleName module installation successful" } + Catch { + throw "Failed installing the module in the install directory '$InstallDirectory': $_" + } +} \ No newline at end of file diff --git a/InstallModule.ps1 b/InstallModule.ps1 index 045df72..53c4c23 100644 --- a/InstallModule.ps1 +++ b/InstallModule.ps1 @@ -1,40 +1,76 @@ -$ModuleName = "ImportExcel" -$ModulePath = "C:\Program Files\WindowsPowerShell\Modules" -$TargetPath = "$($ModulePath)\$($ModuleName)" +<# + .SYNOPSIS + Install the module in the PowerShell module folder. -if(!(Test-Path $TargetPath)) { md $TargetPath | out-null} + .DESCRIPTION + Install the module in the PowerShell module folder by copying all the files. +#> -$targetFiles = echo ` - *.psm1 ` - *.psd1 ` - *.dll ` - New-ConditionalText.ps1 ` - New-ConditionalFormattingIconSet.ps1 ` - Export-Excel.ps1 ` - Export-ExcelSheet.ps1 ` - New-ExcelChart.ps1 ` - Invoke-Sum.ps1 ` - InferData.ps1 ` - Get-ExcelColumnName.ps1 ` - Get-XYRange.ps1 ` - Charting.ps1 ` - New-PSItem.ps1 ` - Pivot.ps1 ` - Get-ExcelSheetInfo.ps1 ` - Get-ExcelWorkbookInfo.ps1 ` - New-ConditionalText.ps1 ` - Get-HtmlTable.ps1 ` - Import-Html.ps1 ` - Get-Range.ps1 ` - TrackingUtils.ps1 ` - Copy-ExcelWorkSheet.ps1 ` - Set-CellStyle.ps1 ` - ConvertFromExcelToSQLInsert.ps1 ` - ConvertFromExcelData.ps1 ` - ConvertToExcelXlsx.ps1 ` - plot.ps1 +[CmdLetBinding()] +Param ( + [ValidateNotNullOrEmpty()] + [String]$ModuleName = 'ImportExcel', + [ValidateScript({Test-Path -Path $_ -Type Container})] + [String]$ModulePath = 'C:\Program Files\WindowsPowerShell\Modules' +) -Get-ChildItem $targetFiles | - ForEach-Object { - Copy-Item -Verbose -Path $_.FullName -Destination "$($TargetPath)\$($_.name)" - } \ No newline at end of file +Begin { + Try { + Write-Verbose "$ModuleName module installation started" + + $Files = @( + '*.dll', + '*.psd1', + '*.psm1', + 'Charting.ps1', + 'ConvertFromExcelData.ps1', + 'ConvertFromExcelToSQLInsert.ps1', + 'ConvertToExcelXlsx.ps1', + 'Copy-ExcelWorkSheet.ps1', + 'Export-Excel.ps1', + 'Export-ExcelSheet.ps1', + 'Get-ExcelColumnName.ps1', + 'Get-ExcelSheetInfo.ps1', + 'Get-ExcelWorkbookInfo.ps1', + 'Get-HtmlTable.ps1', + 'Get-Range.ps1', + 'Get-XYRange.ps1', + 'Import-Html.ps1', + 'InferData.ps1', + 'Invoke-Sum.ps1', + 'New-ConditionalText.ps1', + 'New-ConditionalFormattingIconSet.ps1', + 'New-ExcelChart.ps1', + 'New-PSItem.ps1', + 'Pivot.ps1', + 'Plot.ps1', + 'Set-CellStyle.ps1', + 'TrackingUtils.ps1', + 'Update-FirstObjectProperties.ps1' + ) + } + Catch { + throw "Failed installing the module '$ModuleName': $_" + } +} + +Process { + Try { + $TargetPath = Join-Path -Path $ModulePath -ChildPath $ModuleName + + if (-not (Test-Path $TargetPath)) { + New-Item -Path $TargetPath -ItemType Directory -EA Stop | Out-Null + Write-Verbose "$ModuleName created module folder '$TargetPath'" + } + + Get-ChildItem $Files | ForEach-Object { + Copy-Item -Path $_.FullName -Destination "$($TargetPath)\$($_.Name)" + Write-Verbose "$ModuleName installed module file '$($_.Name)'" + } + + Write-Verbose "$ModuleName module installation successful" + } + Catch { + throw "Failed installing the module '$ModuleName': $_" + } +} \ No newline at end of file diff --git a/Update-FirstObjectProperties.ps1 b/Update-FirstObjectProperties.ps1 new file mode 100644 index 0000000..6716a59 --- /dev/null +++ b/Update-FirstObjectProperties.ps1 @@ -0,0 +1,92 @@ +Function Update-FirstObjectProperties { + <# + .SYNOPSIS + Updates the first object to contain all the properties of the object with the most properties in the array. + + .DESCRIPTION + Updates the first object to contain all the properties of the object with the most properties in the array. This is usefull when not all objects have the same quantity of properties and CmdLets like Out-GridView or Export-Excel are not able to show all the properties because the first object doesn't have them all. + + .EXAMPLE + $Array = @() + + $Obj1 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + } + + $Obj2 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + Member3 = 'Third' + } + + $Obj3 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + Member3 = 'Third' + Member4 = 'Fourth' + } + + $Array = $Obj1, $Obj2, $Obj3 + $Array | Out-GridView -Title 'Not showing Member3 and Member4' + $Array | Update-FirstObjectProperties | Out-GridView -Title 'All properties are visible' + + Updates the fist object of the array by adding Member3 and Member4. + + .EXAMPLE + $ExcelParams = @{ + Path = $env:TEMP + '\Excel.xlsx' + Show = $true + Verbose = $true + } + Remove-Item -Path $ExcelParams.Path -Force -EA Ignore + + $Array = @() + + $Obj1 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + } + + $Obj2 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + Member3 = 'Third' + } + + $Obj3 = [PSCustomObject]@{ + Member1 = 'First' + Member2 = 'Second' + Member3 = 'Third' + Member4 = 'Fourth' + } + + $Array = $Obj1, $Obj2, $Obj3 + $Array | Out-GridView -Title 'Not showing Member3 and Member4' + $Array | Update-FirstObjectProperties | Export-Excel @ExcelParams -WorkSheetname Numbers + + Updates the first object of the array by adding property 'Member3' and 'Member4'. Afterwards. all objects are exported to an Excel file and all column headers are visible. + + .LINK + https://github.com/dfinke/ImportExcel + + .NOTES + CHANGELOG + 2017/06/08 Function born #> + + Try { + $Union = @() + $Input | ForEach-Object { + If ($Union.Count) { + $_ | Get-Member | Where {-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: $_" + } +} \ No newline at end of file