|
| 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 | + |
1 | 26 | <#
|
2 | 27 | .SYNOPSIS
|
3 | 28 |
|
4 |
| -New-DscResourcePowerShellHelp generates PowerShell compatable help files for a DSC |
| 29 | +New-DscResourcePowerShellHelp generates PowerShell compatible help files for a DSC |
5 | 30 | resource module
|
6 | 31 |
|
7 | 32 | .DESCRIPTION
|
8 | 33 |
|
9 | 34 | The New-DscResourcePowerShellHelp cmdlet will review all of the MOF based resources
|
10 | 35 | 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 |
12 | 37 | 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. |
17 | 41 |
|
18 | 42 | .PARAMETER ModulePath
|
19 | 43 |
|
20 | 44 | 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) |
22 | 46 |
|
23 | 47 | .EXAMPLE
|
24 | 48 |
|
25 | 49 | This example shows how to generate help for a specific module
|
26 | 50 |
|
27 |
| - New-DscResourcePowerShellHelp -ModulePath C:\repos\SharePointdsc -OutputPath C:\repos\SharePointDsc\en-US |
| 51 | + New-DscResourcePowerShellHelp -ModulePath C:\repos\SharePointdsc |
28 | 52 |
|
29 | 53 | #>
|
30 | 54 | function New-DscResourcePowerShellHelp
|
31 | 55 | {
|
32 | 56 | [CmdletBinding()]
|
33 | 57 | param
|
34 | 58 | (
|
35 |
| - [parameter(Mandatory = $true)] |
36 |
| - [System.String] |
37 |
| - $OutputPath, |
38 |
| - |
39 | 59 | [parameter(Mandatory = $true)]
|
40 | 60 | [System.String]
|
41 | 61 | $ModulePath
|
42 | 62 | )
|
43 | 63 |
|
44 |
| - Import-Module (Join-Path -Path $PSScriptRoot -ChildPath "MofHelper.psm1") |
| 64 | + Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'MofHelper.psm1') -Verbose:$false |
45 | 65 |
|
46 |
| - $mofSearchPath = (Join-Path -Path $ModulePath -ChildPath "\**\*.schema.mof") |
| 66 | + $mofSearchPath = (Join-Path -Path $ModulePath -ChildPath '\**\*.schema.mof') |
47 | 67 | $mofSchemas = Get-ChildItem -Path $mofSearchPath -Recurse
|
| 68 | + Write-Verbose -Message ($script:localizedData.FoundMofFilesMessage -f $mofSchemas.Count, $ModulePath) |
48 | 69 | $mofSchemas | ForEach-Object {
|
49 | 70 | $mofFileObject = $_
|
50 | 71 |
|
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 | + |
52 | 78 | if (Test-Path -Path $descriptionPath)
|
53 | 79 | {
|
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) |
59 | 81 |
|
60 |
| - $output = ".NAME" + [Environment]::NewLine |
| 82 | + $output = '.NAME' + [Environment]::NewLine |
61 | 83 | $output += " $($result.FriendlyName)"
|
62 | 84 | $output += [Environment]::NewLine + [Environment]::NewLine
|
63 | 85 |
|
64 | 86 | $descriptionContent = Get-Content -Path $descriptionPath -Raw
|
65 |
| - $descriptionContent = $descriptionContent.Replace("**Description**", ".DESCRIPTION") |
66 | 87 | $descriptionContent = $descriptionContent -replace "\n", "`n "
|
| 88 | + $descriptionContent = $descriptionContent -replace "# Description\r\n ", ".DESCRIPTION" |
67 | 89 |
|
68 | 90 | $output += $descriptionContent
|
69 | 91 | $output += [Environment]::NewLine
|
@@ -94,21 +116,175 @@ function New-DscResourcePowerShellHelp
|
94 | 116 |
|
95 | 117 | if ($null -ne $exampleFiles)
|
96 | 118 | {
|
| 119 | + $exampleCount = 1 |
| 120 | + |
| 121 | + Write-Verbose -Message "Found $($exampleFiles.count) Examples for resource $($result.FriendlyName)" |
| 122 | + |
97 | 123 | foreach ($exampleFile in $exampleFiles)
|
98 | 124 | {
|
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++) |
102 | 128 |
|
103 | 129 | $output += $exampleContent
|
104 | 130 | $output += [Environment]::NewLine
|
105 | 131 | }
|
106 | 132 | }
|
| 133 | + else |
| 134 | + { |
| 135 | + Write-Warning -Message ($script:localizedData.NoExampleFileFoundWarning -f $result.FriendlyName) |
| 136 | + } |
107 | 137 |
|
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) |
109 | 140 | $output | Out-File -FilePath $savePath -Encoding utf8 -Force
|
110 | 141 | }
|
| 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 | + } |
111 | 278 | }
|
| 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() |
112 | 288 | }
|
113 | 289 |
|
114 |
| -Export-ModuleMember -Function * |
| 290 | +Export-ModuleMember -Function New-DscResourcePowerShellHelp |
0 commit comments