├── src
├── en-US
│ └── images
│ │ └── NewReportScreenshot.png
├── HtmlReport.psm1
├── Public
│ ├── New-Table.ps1
│ ├── New-Chart.ps1
│ └── New-Report.ps1
├── Private
│ └── _classes.ps1
├── HtmlReport.psd1
└── Templates
│ └── template.html
├── .gitignore
├── README.md
├── LICENSE
└── Build.ps1
/src/en-US/images/NewReportScreenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jaykul/HtmlReport/HEAD/src/en-US/images/NewReportScreenshot.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore packages (this is for nuget stuff)
2 | packages/
3 | # ignore output (because we "build" stuff there)
4 | output/
5 | # Ignore version number folders (these are our release directories for testing)
6 | [0-9]*.[0-9]*.*/
--------------------------------------------------------------------------------
/src/HtmlReport.psm1:
--------------------------------------------------------------------------------
1 | $PSModuleRoot = $PSScriptRoot
2 |
3 | . $PSScriptRoot\Private\_classes.ps1
4 | . $PSScriptRoot\Public\New-Chart.ps1
5 | . $PSScriptRoot\Public\New-Table.ps1
6 | . $PSScriptRoot\Public\New-Report.ps1
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HtmlReport
2 | Making HTML reports with charts and tables, from templates, in PowerShell
3 |
4 | Still in progress, but here's an example of a report:
5 |
6 | ```posh
7 | $topVM = ps | Sort PrivateMemorySize -Descending |
8 | Select -First 10 |
9 | ForEach { ,@(($_.ProcessName + " " + $_.Id), $_.PrivateMemorySize) }
10 |
11 | $topCPU = ps | Sort CPU -Descending |
12 | Select -First 10 |
13 | ForEach { ,@(($_.ProcessName + " " + $_.Id), $_.CPU) }
14 |
15 | New-Report -Title "Piggy Processes" -Input {
16 | New-Chart Bar "Top VM Users" -input $topVm
17 | New-Chart Column "Top CPU Overall" -input $topCPU
18 | ps | Select ProcessName, Id, CPU, WorkingSet, *MemorySize | New-Table "All Processes"
19 | } > Report.html
20 | ```
21 |
22 | 
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Joel Bennett
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Public/New-Table.ps1:
--------------------------------------------------------------------------------
1 | function New-Table {
2 | #.Synopsis
3 | # Creates a new TableData object for rendering in New-Report
4 | #.Example
5 | # Get-ChildItem C:\Users -Directory |
6 | # Select LastWriteTime, @{Name="Length"; Expression={
7 | # (Get-ChildItem $_.FullName -Recurse -File -Force | Measure Length -Sum).Sum
8 | # } }, Name |
9 | # New-Table -Title $Pwd -Description "Full file listing from $($Pwd.Name)"
10 | #
11 | # Collect the list of user directories and measure the size of each
12 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
13 | [CmdletBinding()]
14 | param(
15 | # A title that goes on the top of the table
16 | [Parameter(Mandatory)]
17 | [string]$Title,
18 |
19 | # Description to go above the table
20 | [Parameter()]
21 | [string]$Description,
22 |
23 | # Data for the table (can be piped in)
24 | [Parameter(Mandatory,ValueFromPipeline)]
25 | [PSObject]$InputObject,
26 |
27 | # Emphasis value: default (unadorned), primary (highlighted), success (green), info (blue), warning (yellow), danger (red)
28 | [Parameter()]
29 | [Emphasis]$Emphasis = "primary"
30 | )
31 | begin {
32 | $TableData = @()
33 | }
34 | process {
35 | $TableData += $InputObject
36 | }
37 | end {
38 | [Table]::new($Title, [PSObject]$TableData, $Description, $Emphasis)
39 | }
40 | }
--------------------------------------------------------------------------------
/src/Public/New-Chart.ps1:
--------------------------------------------------------------------------------
1 | function New-Chart {
2 | #.Synopsis
3 | # Creates a new ChartData for New-Report
4 | #.Description
5 | # Collects ChartData for New-Report.
6 | # ChartData should be in specific shapes in order to work properly, but it depends somewhat on the chart type you're trying to create (LineChart, PieChart, ColumnChart, BarChart, AreaChart, ScatterChart, GeoChart, Timeline). There should be examples for each in the help below...
7 | #.Notes
8 | # TODO: Write examples...
9 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
10 | [CmdletBinding()]
11 | param(
12 | # Chart Type
13 | [ChartType]$ChartType,
14 |
15 | # A title that goes on the top of the table
16 | [Parameter(Mandatory)]
17 | [string]$Title,
18 |
19 | # Description to go above the table
20 | [Parameter()]
21 | [string]$Description,
22 |
23 | # Data for the table (can be piped in)
24 | [Parameter(Mandatory,ValueFromPipeline)]
25 | [PSObject]$InputObject,
26 |
27 | # Emphasis value: default (unadorned), primary (highlighted), success (green), info (blue), warning (yellow), danger (red)
28 | [Parameter()]
29 | [Emphasis]$Emphasis = "default"
30 | )
31 | begin {
32 | $ChartData = @()
33 | }
34 | process {
35 | $ChartData += $InputObject
36 | }
37 | end {
38 | $Chart = [Chart]::new($Title, [PSObject]$ChartData, $Description, $Emphasis)
39 | $Chart.ChartType = $ChartType
40 | $Chart
41 | }
42 | }
--------------------------------------------------------------------------------
/src/Private/_classes.ps1:
--------------------------------------------------------------------------------
1 | $PSModuleRoot = $PSScriptRoot
2 |
3 | enum Emphasis {
4 | default
5 | primary
6 | success
7 | info
8 | warning
9 | danger
10 | }
11 |
12 | enum ChartType {
13 | LineChart
14 | PieChart
15 | ColumnChart
16 | BarChart
17 | AreaChart
18 | ScatterChart
19 | GeoChart
20 | Timeline
21 | }
22 |
23 | class DataWrapper {
24 | DataWrapper([string]$Title, [PSObject]$Data) {
25 | $this.Title = $Title
26 | $this.Data = $Data
27 | }
28 |
29 | DataWrapper([string]$Title, [PSObject]$Data, [string]$Description) {
30 | $this.Title = $Title
31 | $this.Description = $Description
32 | $this.Data = $Data
33 | }
34 |
35 | DataWrapper([string]$Title, [PSObject]$Data, [string]$Description, [Emphasis]$Emphasis) {
36 | $this.Title = $Title
37 | $this.Description = $Description
38 | $this.Emphasis = $Emphasis
39 | $this.Data = $Data
40 | }
41 |
42 | [string]$Title = ""
43 | [string]$Description = ""
44 | [Emphasis]$Emphasis = "default"
45 | [PSObject]$Data = $null
46 | }
47 |
48 | class Table : DataWrapper {
49 | Table([string]$Title, [PSObject]$Data) : base($Title, $Data) {}
50 | Table([string]$Title, [PSObject]$Data, [string]$Description) : base($Title, $Data, $Description) {}
51 | Table([string]$Title, [PSObject]$Data, [string]$Description, [Emphasis]$Emphasis) : base($Title, $Data, $Description, $Emphasis) {}
52 | }
53 |
54 | class Chart : DataWrapper {
55 | Chart([string]$Title, [PSObject]$Data) : base($Title, $Data) {}
56 | Chart([string]$Title, [PSObject]$Data, [string]$Description) : base($Title, $Data, $Description) {}
57 | Chart([string]$Title, [PSObject]$Data, [string]$Description, [Emphasis]$Emphasis) : base($Title, $Data, $Description, $Emphasis) {}
58 | [ChartType]$ChartType = "Line"
59 | }
--------------------------------------------------------------------------------
/src/HtmlReport.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | # Script module or binary module file associated with this manifest.
3 | RootModule = 'HtmlReport.psm1'
4 |
5 | # Version number of this module.
6 | ModuleVersion = '0.1'
7 |
8 | # ID used to uniquely identify this module
9 | GUID = 'a1e21355-5da0-4cde-b055-cedc5bd85e44'
10 |
11 | # Author of this module
12 | Author = 'Joel "Jaykul" Bennett'
13 |
14 | # Company or vendor of this module
15 | CompanyName = 'HuddledMasses.org'
16 |
17 | # Copyright statement for this module
18 | Copyright = '(c) 2016 Joel "Jaykul" Bennett. All rights reserved.'
19 |
20 | # Description of the functionality provided by this module
21 | Description = 'Generate pretty HTML reports with tables and charts'
22 |
23 | # Minimum version of the Windows PowerShell engine required by this module
24 | PowerShellVersion = '5.0'
25 |
26 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
27 | FunctionsToExport = '*'
28 |
29 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
30 | # AliasesToExport = '*'
31 |
32 | # DSC resources to export from this module
33 | # DscResourcesToExport = @()
34 |
35 | # List of all modules packaged with this module
36 | # ModuleList = @()
37 |
38 | # List of all files packaged with this module
39 | # FileList = @()
40 |
41 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
42 | PrivateData = @{
43 |
44 | PSData = @{
45 |
46 | # Tags applied to this module. These help with module discovery in online galleries.
47 | # Tags = @()
48 |
49 | # A URL to the license for this module.
50 | # LicenseUri = ''
51 |
52 | # A URL to the main website for this project.
53 | # ProjectUri = ''
54 |
55 | # A URL to an icon representing this module.
56 | # IconUri = ''
57 |
58 | # ReleaseNotes of this module
59 | # ReleaseNotes = ''
60 |
61 | } # End of PSData hashtable
62 |
63 | } # End of PrivateData hashtable
64 |
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/src/Templates/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ${Title}
17 |
18 |
21 |
22 |
23 |
24 |
28 |
46 |
47 |
48 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | ${Charts}
77 |
78 |
79 |
80 | ${Tables}
81 |
82 |
83 |
84 |
85 |
87 |
88 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/Public/New-Report.ps1:
--------------------------------------------------------------------------------
1 | $TemplatePath = Join-Path $PSModuleRoot Templates
2 |
3 | $ChartTemplate = @'
4 |
5 |
6 |
7 |
${Description}
8 |
9 |
14 | '@
15 |
16 | $TableTemplate = @'
17 |
18 |
19 |
20 |
${Title}
21 |
${Description}
22 |
25 |
26 |
27 |
28 | '@
29 | function New-Report {
30 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
31 | [CmdletBinding()]
32 | param(
33 | # The template to use for the report (must exist in templates folder)
34 | [Parameter()]
35 | [string]
36 | $Template = "template.html",
37 |
38 | # The title of the report
39 | [Parameter(ValueFromPipelineByPropertyName)]
40 | [string]
41 | $Title,
42 |
43 | # A sentence or two describing the report
44 | [Parameter(ValueFromPipelineByPropertyName)]
45 | [string]
46 | $Description,
47 |
48 | # The author of the report
49 | [Parameter(ValueFromPipelineByPropertyName)]
50 | [string]
51 | $Author=${Env:UserName},
52 |
53 | [Parameter(ValueFromPipeline)]
54 | $InputObject
55 | )
56 |
57 | begin {
58 | Write-Debug "Beginning $($PSBoundParameters | Out-String)"
59 | if($Template -notmatch "\.html$") { $Template += ".html" }
60 | if(!(Test-Path $Template)) {
61 | $Template = Join-Path $TemplatePath $Template
62 | if(!(Test-Path $Template)) {
63 | Write-Error "Template file not found in Templates: $Template"
64 | }
65 | }
66 |
67 | $TemplateContent = Get-Content $Template -Raw
68 | $FinalTable = @()
69 | $FinalChart = @()
70 | $Index = 0
71 | $Finished = $false
72 |
73 | if($InputObject -is [ScriptBlock]) {
74 | $null = $PSBoundParameters.Remove("InputObject")
75 | & $InputObject | New-Report @PSBoundParameters
76 | $Finished = $true
77 | return
78 | }
79 | }
80 |
81 | process {
82 | if($Finished) { return }
83 | Write-Debug "Processing $($_ | Out-String)"
84 | if($Title) {
85 | $FinalTitle = [System.Security.SecurityElement]::Escape($Title)
86 | }
87 | if($Description) {
88 | $FinalDescription = [System.Security.SecurityElement]::Escape($Description)
89 | }
90 | if($Author) {
91 | $FinalAuthor = [System.Security.SecurityElement]::Escape($Author)
92 | }
93 |
94 | if($InputObject -is [ScriptBlock]) {
95 | $Data = & $InputObject
96 | }
97 | elseif($InputObject -is [DataWrapper]) {
98 | if($InputObject.Data -is [ScriptBlock]) {
99 | $Data = & $InputObject.Data
100 | } else {
101 | $Data = $InputObject.Data
102 | }
103 | }
104 | else {
105 | $Data = $InputObject
106 | }
107 |
108 | if($InputObject -is [Table]) {
109 | $Data = $Data | Microsoft.PowerShell.Utility\ConvertTo-Html -As Table -Fragment
110 | # Make sure each row is on a line, and the headers are called out properly
111 | Write-Verbose "Table with $($Data.Count) rows of data."
112 | $Data = "`n{0}`n`n`n{1}`n" -f $Data[2], ($Data[3..($Data.Count - 2)] -join "`n")
113 |
114 | $Table = $TableTemplate -replace '\${Title}', $InputObject.Title `
115 | -replace '\${Description}', $InputObject.Description `
116 | -replace '\${Emphasis}', $("panel-" + $InputObject.Emphasis) `
117 | -replace '\${Data}', $Data
118 |
119 | $FinalTable += $Table
120 | }
121 | if($InputObject -is [Chart]) {
122 | Write-Verbose "$ChartType Chart with $($Data.Count) data.points"
123 | if($Data -isnot [string]) {
124 | # Microsoft's ConvertTo-Json doesn't handle PSObject unwrapping properly
125 | # https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/15123162-convertto-json-doesn-t-serialize-simple-objects-pr
126 | # To bypass this bug, we must round-trip through the CliXml serializer
127 | $TP = [IO.Path]::GetTempFileName()
128 | Export-CliXml -InputObject $Data -LiteralPath $TP
129 | $Data =Import-CliXml -LiteralPath $TP | ConvertTo-json
130 | Remove-Item $TP
131 | # $Data = Microsoft.PowerShell.Utility\ConvertTo-Json -InputObject $Data
132 | }
133 |
134 | $Chart = $ChartTemplate -replace '\${Title}', $InputObject.Title `
135 | -replace '\${Description}', $InputObject.Description `
136 | -replace '\${Emphasis}', $("panel-" + $InputObject.Emphasis) `
137 | -replace '\${ChartType}', $InputObject.ChartType `
138 | -replace '\${Data}', $Data `
139 | -replace '\${id}', ($Index++)
140 |
141 | $FinalChart += $Chart
142 | }
143 | }
144 |
145 | end {
146 | if($Finished) { return }
147 | Write-Debug "Ending $($PSBoundParameters | Out-String)"
148 | $Output = $TemplateContent -replace '\${Title}', $FinalTitle `
149 | -replace '\${Description}', $FinalDescription `
150 | -replace '\${Author}', $FinalAuthor `
151 | -replace '\${Tables}', ($FinalTable -join "`n`n") `
152 | -replace '\${Charts}', ($FinalChart -join "`n")
153 | Write-Output $Output
154 | }
155 | }
--------------------------------------------------------------------------------
/Build.ps1:
--------------------------------------------------------------------------------
1 | #requires -Module Configuration
2 | [CmdletBinding()]
3 | param(
4 | [Alias("PSPath")]
5 | [string]$Path = $PSScriptRoot,
6 | [string]$ModuleName = $(Split-Path $Path -Leaf),
7 | # The target framework for .net (for packages), with fallback versions
8 | # The default supports PS3: "net40","net35","net20","net45"
9 | # To only support PS4, use: "net45","net40","net35","net20"
10 | # To support PS2, you use: "net35","net20"
11 | [string[]]$TargetFramework = @("net40","net35","net20","net45"),
12 | [switch]$Monitor,
13 | [Nullable[int]]$RevisionNumber = ${Env:APPVEYOR_BUILD_NUMBER}
14 | )
15 |
16 | $ErrorActionPreference = "Stop"
17 | Set-StrictMode -Version Latest
18 | Write-Host "BUILDING: $ModuleName from $Path"
19 |
20 | # The output path is just a temporary build location
21 | $OutputPath = Join-Path $Path output
22 | $null = mkdir $OutputPath -Force
23 |
24 | # We expect the source for the module in a subdirectory called one of three things:
25 | $SourcePath = "src", "source", ${ModuleName} | ForEach { Join-Path $Path $_ -Resolve -ErrorAction SilentlyContinue } | Select -First 1
26 | if(!$SourcePath) {
27 | Write-Warning "This Build script expects a 'Source' or '$ModuleName' folder to be alongside it."
28 | throw "Can't find module source folder."
29 | }
30 | $ManifestPath = Join-Path $SourcePath "${ModuleName}.psd1" -Resolve -ErrorAction SilentlyContinue
31 | if(!$ManifestPath) {
32 | Write-Warning "This Build script expects a '${ModuleName}.psd1' in the '$SourcePath' folder."
33 | throw "Can't find module source files"
34 | }
35 |
36 | # Figure out the new build version
37 | [Version]$Version = Get-Metadata $ManifestPath -PropertyName ModuleVersion
38 |
39 | # If the RevisionNumber is specified as ZERO, this is a release build ...
40 | # If the RevisionNumber is not specified, this is a dev box build
41 | # If the RevisionNumber is specified, we assume this is a CI build
42 | if($RevisionNumber -ge 0) {
43 | # For CI builds we don't increment the build number
44 | $Build = if($Version.Build -le 0) { 0 } else { $Version.Build }
45 | } else {
46 | # For dev builds, assume we're working on the NEXT release
47 | $Build = if($Version.Build -le 0) { 1 } else { $Version.Build + 1}
48 | }
49 |
50 | if([string]::IsNullOrEmpty($RevisionNumber)) {
51 | $Version = New-Object Version $Version.Major, $Version.Minor, $Build
52 | } else {
53 | $Version = New-Object Version $Version.Major, $Version.Minor, $Build, $RevisionNumber
54 | }
55 |
56 | # The release path is where the final module goes
57 | $ReleasePath = Join-Path $Path $Version
58 |
59 | Write-Verbose "OUTPUT Release Path: $ReleasePath"
60 | if(Test-Path $ReleasePath) {
61 | Write-Verbose " Clean up old build"
62 | Write-Verbose "DELETE $ReleasePath\"
63 | Remove-Item $ReleasePath -Recurse -Force -ErrorAction SilentlyContinue
64 | Write-Verbose "DELETE $OutputPath\build.log"
65 | Remove-Item $OutputPath\build.log -Recurse -Force -ErrorAction SilentlyContinue
66 | }
67 |
68 | ## Find dependency Package Files
69 | $PackagesConfig = (Join-Path $Path packages.config)
70 | if(Test-Path $PackagesConfig) {
71 | Write-Verbose " Copying Packages"
72 | foreach($Package in ([xml](Get-Content $PackagesConfig)).packages.package) {
73 | $LibPath = "$ReleasePath\lib"
74 | $folder = Join-Path $Path "packages\$($Package.id)*"
75 |
76 | # The git NativeBinaries are special -- we need to copy all the "windows" binaries:
77 | if($Package.id -eq "LibGit2Sharp.NativeBinaries") {
78 | $targets = Join-Path $folder 'libgit2\windows'
79 | $LibPath = Join-Path $LibPath "NativeBinaries"
80 | } else {
81 | # Check for each TargetFramework, in order of preference, fall back to using the lib folder
82 | $targets = ($TargetFramework -replace '^','lib\') + 'lib' | ForEach-Object { Join-Path $folder $_ }
83 | }
84 |
85 | $PackageSource = Get-Item $targets -ErrorAction SilentlyContinue | Select -First 1 -Expand FullName
86 | if(!$PackageSource) {
87 | throw "Could not find a lib folder for $($Package.id) from package. You may need to run Setup.ps1"
88 | }
89 |
90 | Write-Verbose "robocopy $PackageSource $LibPath /E /NP /LOG+:'$OutputPath\build.log' /R:2 /W:15"
91 | $null = robocopy $PackageSource $LibPath /E /NP /LOG+:"$OutputPath\build.log" /R:2 /W:15
92 | if($LASTEXITCODE -ne 0 -and $LASTEXITCODE -ne 1 -and $LASTEXITCODE -ne 3) {
93 | throw "Failed to copy Package $($Package.id) (${LASTEXITCODE}), see build.log for details"
94 | }
95 | }
96 | }
97 |
98 |
99 | ## Copy PowerShell source Files
100 | $ReleaseManifest = Join-Path $ReleasePath "${ModuleName}.psd1"
101 |
102 |
103 | # if the Source folder has "Public" and optionally "Private" in it, then the psm1 must be assembled:
104 | if(Test-Path (Join-Path $SourcePath Public) -Type Container){
105 | Write-Verbose " Collating Module Source"
106 | $RootModule = Get-Metadata -Path $ManifestPath -PropertyName RootModule -ErrorAction SilentlyContinue
107 | if(!$RootModule) {
108 | $RootModule = Get-Metadata -Path $ManifestPath -PropertyName ModuleToProcess -ErrorAction SilentlyContinue
109 | if(!$RootModule) {
110 | $RootModule = "${ModuleName}.psm1"
111 | }
112 | }
113 | $null = mkdir $ReleasePath -Force
114 | $ReleaseModule = Join-Path $ReleasePath ${RootModule}
115 | Write-Verbose " Setting content for $ReleaseModule"
116 |
117 | $FunctionsToExport = Join-Path $SourcePath Public\*.ps1 -Resolve | % { [System.IO.Path]::GetFileNameWithoutExtension($_) }
118 | Set-Content $ReleaseModule ((
119 | (Get-Content (Join-Path $SourcePath Private\*.ps1) -Raw) +
120 | (Get-Content (Join-Path $SourcePath Public\*.ps1) -Raw)) -join "`r`n`r`n`r`n") -Encoding UTF8
121 |
122 | # If there are any folders that aren't Public, Private, Tests, or Specs ...
123 | if($OtherFolders = Get-ChildItem $SourcePath -Directory -Exclude Public, Private, Tests, Specs) {
124 | # Then we need to copy everything in them
125 | Copy-Item $OtherFolders -Recurse -Destination $ReleasePath
126 | }
127 |
128 | # Finally, we need to copy any files in the Source directory
129 | Get-ChildItem $SourcePath -File |
130 | Where Name -ne $RootModule |
131 | Copy-Item -Destination $ReleasePath
132 |
133 | Set-ItemProperty $ReleaseManifest -name IsReadOnly -value $false
134 | Update-Manifest $ReleaseManifest -Property FunctionsToExport -Value $FunctionsToExport
135 | } else {
136 | # Legacy modules just have "stuff" in the source folder and we need to copy all of it
137 | Write-Verbose " Copying Module Source"
138 | Write-Verbose "COPY $SourcePath\"
139 | $null = robocopy $SourcePath\ $ReleasePath /E /NP /LOG+:"$OutputPath\build.log" /R:2 /W:15
140 | if($LASTEXITCODE -ne 3) {
141 | throw "Failed to copy Module (${LASTEXITCODE}), see build.log for details"
142 | }
143 | }
144 |
145 | ## Touch the PSD1 Version:
146 | Write-Verbose " Update Module Version"
147 |
148 | ## Bump the version (note that this doesn't change source code, you're still responsible)
149 | Update-Metadata -Path $ReleaseManifest -PropertyName 'ModuleVersion' -Value $Version
150 |
151 | ## Validate
152 | Write-Host "`nVALIDATE: ScriptAnalyzer on $ReleasePath"
153 | Invoke-ScriptAnalyzer $ReleasePath -Recurse
154 |
155 | Write-Output (Get-Item $ReleasePath)
--------------------------------------------------------------------------------