Skip to content
This repository was archived by the owner on Feb 24, 2021. It is now read-only.

Commit c29e314

Browse files
authored
Merge pull request #325 from X-Guardian/PowerShellHelp-Update
New-DscResourcePowerShellHelp: Update Function and Add Tests
2 parents 175d755 + 9d5c6b1 commit c29e314

File tree

5 files changed

+1313
-39
lines changed

5 files changed

+1313
-39
lines changed

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
## Unreleased
44

5-
- Added `Publish-WikiContent` helper function to publish auto-generated Wiki files
6-
to the relevant DSC resource GitHub Wiki ([issue #142](https://github.com/PowerShell/DscResource.Tests/issues/142)).
75
- Fixes issue where Reset-DSC causes a Warning to be logged if a DSC
86
configuration is not currently running.
97
- Added issue templates.
@@ -54,8 +52,10 @@
5452
the resource file.
5553
- There should be no additional localized string keys in the resource
5654
file that do not exist in the en-US resource file.
57-
- Added a new function `Publish-WikiContent` to publish the contents of the
58-
DSC Resource Wiki content artifact to the relevant GitHub Wiki.
55+
- Added `Publish-WikiContent` helper function to publish auto-generated Wiki files
56+
to the relevant DSC resource GitHub Wiki ([issue #142](https://github.com/PowerShell/DscResource.Tests/issues/142)).
57+
- Update New-DscResourcePowerShellHelp to output the PowerShell help files to
58+
the resource specific path and fix the example processing.
5959

6060
## 0.3.0.0
6161

Lines changed: 203 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,91 @@
1+
<#
2+
Define enumeration for use by help example generation to determine the type of
3+
block that a text line is within.
4+
#>
5+
if (-not ([System.Management.Automation.PSTypeName]'HelpExampleBlockType').Type)
6+
{
7+
$typeDefinition = @'
8+
public enum HelpExampleBlockType
9+
{
10+
None,
11+
PSScriptInfo,
12+
Configuration,
13+
ExampleCommentHeader
14+
}
15+
'@
16+
Add-Type -TypeDefinition $typeDefinition
17+
}
18+
19+
$projectRootPath = Split-Path -Path $PSScriptRoot -Parent
20+
$testHelperPath = Join-Path -Path $projectRootPath -ChildPath 'TestHelper.psm1'
21+
Import-Module -Name $testHelperPath -Force
22+
23+
$moduleName = $ExecutionContext.SessionState.Module
24+
$script:localizedData = Get-LocalizedData -ModuleName $moduleName -ModuleRoot $PSScriptRoot
25+
126
<#
227
.SYNOPSIS
328
4-
New-DscResourcePowerShellHelp generates PowerShell compatable help files for a DSC
29+
New-DscResourcePowerShellHelp generates PowerShell compatible help files for a DSC
530
resource module
631
732
.DESCRIPTION
833
934
The New-DscResourcePowerShellHelp cmdlet will review all of the MOF based resources
1035
in a specified module directory and will inject PowerShell help files for each resource
11-
in to the specified directory. These help files include details on the property types for
36+
in to the resource's subdirectory. These help files include details on the property types for
1237
each resource, as well as a text description and examples where they exist.
13-
14-
.PARAMETER OutputPath
15-
16-
Where should the files be saved to (ususally the "en-US" folder inside the module for US english)
38+
a README.md with a text description must exist in the resource's subdirectory for the
39+
help file to be generated.
40+
These help files can then be read by passing the name of the resource as a parameter to Get-Help.
1741
1842
.PARAMETER ModulePath
1943
2044
The path to the root of the DSC resource module (where the PSD1 file is found, not the folder for
21-
and individual DSC resource)
45+
each individual DSC resource)
2246
2347
.EXAMPLE
2448
2549
This example shows how to generate help for a specific module
2650
27-
New-DscResourcePowerShellHelp -ModulePath C:\repos\SharePointdsc -OutputPath C:\repos\SharePointDsc\en-US
51+
New-DscResourcePowerShellHelp -ModulePath C:\repos\SharePointdsc
2852
2953
#>
3054
function New-DscResourcePowerShellHelp
3155
{
3256
[CmdletBinding()]
3357
param
3458
(
35-
[parameter(Mandatory = $true)]
36-
[System.String]
37-
$OutputPath,
38-
3959
[parameter(Mandatory = $true)]
4060
[System.String]
4161
$ModulePath
4262
)
4363

44-
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath "MofHelper.psm1")
64+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'MofHelper.psm1') -Verbose:$false
4565

46-
$mofSearchPath = (Join-Path -Path $ModulePath -ChildPath "\**\*.schema.mof")
66+
$mofSearchPath = (Join-Path -Path $ModulePath -ChildPath '\**\*.schema.mof')
4767
$mofSchemas = Get-ChildItem -Path $mofSearchPath -Recurse
68+
Write-Verbose -Message ($script:localizedData.FoundMofFilesMessage -f $mofSchemas.Count, $ModulePath)
4869
$mofSchemas | ForEach-Object {
4970
$mofFileObject = $_
5071

51-
$descriptionPath = Join-Path -Path $_.DirectoryName -ChildPath "readme.md"
72+
$result = (Get-MofSchemaObject -FileName $_.FullName) | Where-Object -FilterScript {
73+
($_.ClassName -eq $mofFileObject.Name.Replace('.schema.mof', '')) `
74+
-and ($null -ne $_.FriendlyName)
75+
}
76+
$descriptionPath = Join-Path -Path $mofFileObject.DirectoryName -ChildPath 'readme.md'
77+
5278
if (Test-Path -Path $descriptionPath)
5379
{
54-
$result = (Get-MofSchemaObject -FileName $_.FullName) | Where-Object {
55-
($_.ClassName -eq $mofFileObject.Name.Replace(".schema.mof", "")) `
56-
-and ($null -ne $_.FriendlyName)
57-
}
58-
Write-Verbose -Message "Generating help document for $($result.FriendlyName)"
80+
Write-Verbose -Message ($script:localizedData.GenerateHelpDocumentMessage -f $result.FriendlyName)
5981

60-
$output = ".NAME" + [Environment]::NewLine
82+
$output = '.NAME' + [Environment]::NewLine
6183
$output += " $($result.FriendlyName)"
6284
$output += [Environment]::NewLine + [Environment]::NewLine
6385

6486
$descriptionContent = Get-Content -Path $descriptionPath -Raw
65-
$descriptionContent = $descriptionContent.Replace("**Description**", ".DESCRIPTION")
6687
$descriptionContent = $descriptionContent -replace "\n", "`n "
88+
$descriptionContent = $descriptionContent -replace "# Description\r\n ", ".DESCRIPTION"
6789

6890
$output += $descriptionContent
6991
$output += [Environment]::NewLine
@@ -94,21 +116,175 @@ function New-DscResourcePowerShellHelp
94116

95117
if ($null -ne $exampleFiles)
96118
{
119+
$exampleCount = 1
120+
121+
Write-Verbose -Message "Found $($exampleFiles.count) Examples for resource $($result.FriendlyName)"
122+
97123
foreach ($exampleFile in $exampleFiles)
98124
{
99-
$exampleContent = Get-Content -Path $exampleFile.FullName -Raw
100-
$exampleContent = $exampleContent -replace "<#"
101-
$exampleContent = $exampleContent -replace "#>"
125+
$exampleContent = Get-DscResourceHelpExampleContent `
126+
-ExamplePath $exampleFile.FullName `
127+
-ExampleNumber ($exampleCount++)
102128

103129
$output += $exampleContent
104130
$output += [Environment]::NewLine
105131
}
106132
}
133+
else
134+
{
135+
Write-Warning -Message ($script:localizedData.NoExampleFileFoundWarning -f $result.FriendlyName)
136+
}
107137

108-
$savePath = Join-Path -Path $OutputPath -ChildPath "about_$($result.FriendlyName).help.txt"
138+
$savePath = Join-Path -Path $mofFileObject.DirectoryName -ChildPath "\en-US\about_$($result.FriendlyName).help.txt"
139+
Write-Verbose -Message ($script:localizedData.OutputHelpDocumentMessage -f $savePath)
109140
$output | Out-File -FilePath $savePath -Encoding utf8 -Force
110141
}
142+
else
143+
{
144+
Write-Warning -Message ($script:localizedData.NoDescriptionFileFoundWarning -f $result.FriendlyName)
145+
}
146+
}
147+
}
148+
149+
<#
150+
.SYNOPSIS
151+
This function reads an example file from a resource and converts
152+
it to help text for inclusion in a PowerShell help file.
153+
154+
.DESCRIPTION
155+
The function will read the example PS1 file and convert the
156+
help header into the description text for the example.
157+
158+
.PARAMETER ExamplePath
159+
The path to the example file.
160+
161+
.PARAMETER ModulePath
162+
The number of the example.
163+
164+
.EXAMPLE
165+
Get-DscResourceHelpExampleContent -ExamplePath 'C:\repos\NetworkingDsc\Examples\Resources\DhcpClient\1-DhcpClient_EnableDHCP.ps1' -ExampleNumber 1
166+
167+
Reads the content of 'C:\repos\NetworkingDsc\Examples\Resources\DhcpClient\1-DhcpClient_EnableDHCP.ps1'
168+
and converts it to help text in preparation for being added to a PowerShell help file.
169+
#>
170+
function Get-DscResourceHelpExampleContent
171+
{
172+
[CmdletBinding()]
173+
[OutputType([System.String])]
174+
param
175+
(
176+
[Parameter(Mandatory = $true)]
177+
[System.String]
178+
$ExamplePath,
179+
180+
[Parameter(Mandatory = $true)]
181+
[System.Int32]
182+
$ExampleNumber
183+
)
184+
185+
$exampleContent = Get-Content -Path $ExamplePath
186+
187+
# Use a string builder to assemble the example description and code
188+
$exampleDescriptionStringBuilder = New-Object -TypeName System.Text.StringBuilder
189+
$exampleCodeStringBuilder = New-Object -TypeName System.Text.StringBuilder
190+
191+
<#
192+
Step through each line in the source example and determine
193+
the content and act accordingly:
194+
\<#PSScriptInfo...#\> - Drop block
195+
\#Requires - Drop Line
196+
\<#...#\> - Drop .EXAMPLE, .SYNOPSIS and .DESCRIPTION but include all other lines
197+
Configuration ... - Include entire block until EOF
198+
#>
199+
$blockType = [HelpExampleBlockType]::None
200+
201+
foreach ($exampleLine in $exampleContent)
202+
{
203+
Write-Debug -Message ('Processing Line: {0}' -f $exampleLine)
204+
205+
# Determine the behavior based on the current block type
206+
switch ($blockType.ToString())
207+
{
208+
'PSScriptInfo'
209+
{
210+
Write-Debug -Message 'PSScriptInfo Block Processing'
211+
212+
# Exclude PSScriptInfo block from any output
213+
if ($exampleLine -eq '#>')
214+
{
215+
Write-Debug -Message 'PSScriptInfo Block Ended'
216+
217+
# End of the PSScriptInfo block
218+
$blockType = [HelpExampleBlockType]::None
219+
}
220+
}
221+
222+
'Configuration'
223+
{
224+
Write-Debug -Message 'Configuration Block Processing'
225+
226+
# Include all lines in the configuration block in the code output
227+
$null = $exampleCodeStringBuilder.AppendLine($exampleLine)
228+
}
229+
230+
'ExampleCommentHeader'
231+
{
232+
Write-Debug -Message 'ExampleCommentHeader Block Processing'
233+
234+
# Include all lines in Example Comment Header block except for headers
235+
$exampleLine = $exampleLine.TrimStart()
236+
237+
if ($exampleLine -notin ('.SYNOPSIS', '.DESCRIPTION', '.EXAMPLE', '#>'))
238+
{
239+
# Not a header so add this to the output
240+
$null = $exampleDescriptionStringBuilder.AppendLine($exampleLine)
241+
}
242+
243+
if ($exampleLine -eq '#>')
244+
{
245+
Write-Debug -Message 'ExampleCommentHeader Block Ended'
246+
247+
# End of the Example Comment Header block
248+
$blockType = [HelpExampleBlockType]::None
249+
}
250+
}
251+
252+
default
253+
{
254+
Write-Debug -Message 'Not Currently Processing Block'
255+
256+
# Check the current line
257+
if ($exampleLine.TrimStart() -eq '<#PSScriptInfo')
258+
{
259+
Write-Debug -Message 'PSScriptInfo Block Started'
260+
261+
$blockType = [HelpExampleBlockType]::PSScriptInfo
262+
}
263+
elseif ($exampleLine -match 'Configuration')
264+
{
265+
Write-Debug -Message 'Configuration Block Started'
266+
267+
$null = $exampleCodeStringBuilder.AppendLine($exampleLine)
268+
$blockType = [HelpExampleBlockType]::Configuration
269+
}
270+
elseif ($exampleLine.TrimStart() -eq '<#')
271+
{
272+
Write-Debug -Message 'ExampleCommentHeader Block Started'
273+
274+
$blockType = [HelpExampleBlockType]::ExampleCommentHeader
275+
}
276+
}
277+
}
111278
}
279+
280+
# Assemble the final output
281+
$null = $exampleStringBuilder = New-Object -TypeName System.Text.StringBuilder
282+
$null = $exampleStringBuilder.AppendLine(".EXAMPLE $ExampleNumber")
283+
$null = $exampleStringBuilder.AppendLine()
284+
$null = $exampleStringBuilder.AppendLine($exampleDescriptionStringBuilder)
285+
$null = $exampleStringBuilder.Append($exampleCodeStringBuilder)
286+
287+
return $exampleStringBuilder.ToString()
112288
}
113289

114-
Export-ModuleMember -Function *
290+
Export-ModuleMember -Function New-DscResourcePowerShellHelp
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# culture="en-US"
2+
ConvertFrom-StringData @'
3+
FoundMofFilesMessage = Found {0} MOF files in path '{1}'.
4+
GenerateHelpDocumentMessage = Generating help document for '{0}'.
5+
OutputHelpDocumentMessage = Outputting help document to '{0}'.
6+
NoDescriptionFileFoundWarning = No README.md description file found for '{0}', skipping.
7+
NoExampleFileFoundWarning = No Example files found for resource '{0}'.
8+
'@

README.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -561,14 +561,32 @@ replacing `<repoName>` with the name of the repository.
561561

562562
## Documentation Helper Module
563563

564-
> DscResource.DocumentationHelper\DscResource.DocumentationHelper.psd1
565-
> DscResource.DocumentationHelper\MofHelper.psm1
566-
> DscResource.DocumentationHelper\PowerShellHelp.psm1
567-
> DscResource.DocumentationHelper\WikiPages.psm1
568-
569-
This module is used by some HQRM DSC Resource modules to produce Wiki Content to
570-
be distributed with the DSC Resource module as well as published in the Wiki
571-
section of the DSC Resource repo on GitHub.
564+
This module consists of the following three nested modules:
565+
566+
### MofHelper
567+
568+
A helper module containing the `Get-MofSchemaObject` function used to return the
569+
contents of the schema.mof files as a PowerShell object to be used in other scripts.
570+
571+
### PowerShellHelp
572+
573+
A module containing the function `New-DscResourcePowerShellHelp` that when run will
574+
process all of the MOF based resources in a specified module directory and create
575+
PowerShell help files for each resource into the resource's en-US subdirectory. These
576+
help files include details on the property types for each resource, as well as a text
577+
description and examples where they exist.
578+
579+
A README.md with a text description must exist in the resource's subdirectory for the
580+
help file to be generated.
581+
582+
When the DSC resource module is imported, these help files can then be read by passing
583+
the name of the resource as a parameter to `Get-Help`.
584+
585+
### WikiPages
586+
587+
A module containing the function `New-DscResourceWikiSite` that is used by some HQRM
588+
DSC Resource modules to produce Wiki Content to be distributed with the DSC Resource
589+
module as well as published in the Wiki section of the DSC Resource repo on GitHub.
572590

573591
It is usually called by the ```Invoke-AppveyorAfterTestTask``` task in AppVeyor.psm1
574592
when the ```-type``` parameter is set to 'Wiki'. For example:

0 commit comments

Comments
 (0)