Skip to content

Commit

Permalink
Write-ModuleStubFile: Add Aliases for Functions (dsccommunity#1225)
Browse files Browse the repository at this point in the history
- Changes to Write-ModuleStubFile.ps1
  - Create aliases for cmdlets in the stubbed module which have aliases (issue dsccommunity#1224).
  - Use a string builder to build the function stubs.
  - Fixed formatting issues for the function to work with modules other than SqlServer.
  • Loading branch information
randomnote1 authored and johlju committed Sep 20, 2018
1 parent 4ead350 commit edb611d
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 38 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
([issue #1182](https://github.com/PowerShell/SqlServerDsc/issues/1182)).
- Changes to SqlServerDatabaseMail
- Minor update to Ensure parameter description in the README.md.
- Changes to Write-ModuleStubFile.ps1
- Create aliases for cmdlets in the stubbed module which have aliases
([issue #1224](https://github.com/PowerShell/SqlServerDsc/issues/1224)).
[Dan Reist (@randomnote1)](https://github.com/randomnote1)
- Use a string builder to build the function stubs.
- Fixed formatting issues for the function to work with modules other than SqlServer.

## 12.0.0.0

Expand Down
194 changes: 156 additions & 38 deletions Tests/Unit/Stubs/Write-ModuleStubFile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,67 +3,185 @@
Generates a file contaning function stubs of all cmdlets from the module given as a parameter.
.PARAMETER ModuleName
The name of the module to load and generate stubs from. This module must exist on the computer where this function is ran.
The name of the module to load and generate stubs from. This module must exist on the computer where this function is run.
.PARAMETER Path
Path to where to write the stubs file. The filename will be generated from the module name.
Path to where to write the stubs file. The filename will be generated from the module name. The default path is the working directory.
.EXAMPLE
Write-ModuleStubFile -ModuleName 'SqlServer' -Path 'C:\Source'
Write-ModuleStubFile -ModuleName OperationsManager
.EXAMPLE
Write-ModuleStubFile -ModuleName SqlServer -Path C:\Source
#>
function Write-ModuleStubFile {
function Write-ModuleStubFile
{
param
(
[Parameter( Mandatory )]
[System.String] $ModuleName,
[Parameter(Mandatory = $true)]
[System.String]
$ModuleName,

[Parameter( Mandatory )]
[System.String] $Path
[Parameter()]
[System.IO.DirectoryInfo]
$Path = ( Get-Location ).Path
)

Import-Module $ModuleName -DisableNameChecking -Force

( ( get-command -Module $ModuleName -CommandType 'Cmdlet' ) | ForEach-Object -Begin {
"# Suppressing this rule because these functions are from an external module"
"# and are only being used as stubs",
"[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUserNameAndPassWordParams', '')]"
"param()"
""
} -Process {
$signature = $null
$command = $_
# Import the supplied module
Import-Module -Name $ModuleName -DisableNameChecking -Force -ErrorAction Stop

# Get the module object
$module = Get-Module -Name $ModuleName

# Define the output file name
$outFile = Join-Path -Path $Path -ChildPath "$($module.Name )_$($module.Version)_Stubs.psm1"

# Verify the output file doesn't already exist
if ( Test-Path -Path $outFile )
{
throw "The file '$outFile' already exists."
}

# Define the length of the indent
$indent = ' ' * 4

# Define the header of the file
$headerStringBuilder = New-Object -TypeName System.Text.StringBuilder
$null = $headerStringBuilder.AppendLine('<#')
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.AppendLine('.SYNOPSIS')
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.AppendLine("Cmdlet stubs for the module $($module.Name).")
$null = $headerStringBuilder.AppendLine()
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.AppendLine('.DESCRIPTION')
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.AppendLine("This module contains the stubs for the cmdlets in the module $($module.Name) version $($module.Version.ToString()).")
$null = $headerStringBuilder.AppendLine()
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.AppendLine('.NOTES')
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.Append($indent)
$null = $headerStringBuilder.AppendLine("The stubs in this module were generated from the $($MyInvocation.MyCommand) function which is distributed as part of the SqlServerDsc module.")
$null = $headerStringBuilder.AppendLine('#>')
$null = $headerStringBuilder.AppendLine()
$null = $headerStringBuilder.AppendLine('# Suppressing this rule because these functions are from an external module and are only being used as stubs')
$null = $headerStringBuilder.AppendLine('[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(''PSAvoidUsingUserNameAndPassWordParams'', '''')]')
$null = $headerStringBuilder.AppendLine('param()')
$headerStringBuilder.ToString() | Out-File -FilePath $outFile -Encoding utf8 -Append


# Get the cmdlets in the module
$cmdlets = Get-Command -Module $ModuleName -CommandType Cmdlet

foreach ( $cmdlet in $cmdlets )
{
# Clear the alias variable to ensure unnecessary aliases are not created
Remove-Variable -Name alias -ErrorAction SilentlyContinue

# Create a string builder object to build the functions
$functionDefinition = New-Object -TypeName System.Text.StringBuilder

# Reset the end of definition variable
$endOfDefinition = $false
$metadata = New-Object -TypeName System.Management.Automation.CommandMetaData -ArgumentList $command

# Get the Cmdlet metadata
$metadata = New-Object -TypeName System.Management.Automation.CommandMetaData -ArgumentList $cmdlet

# Get the definition of the cmdlet
$definition = [System.Management.Automation.ProxyCommand]::Create($metadata)
foreach ($line in $definition -split "`n")

# Define the beginning of the function
$null = $functionDefinition.AppendLine("function $($cmdlet.Name)")
$null = $functionDefinition.AppendLine('{')


# Iterate over each line in the cmdlet
foreach ( $line in $definition.Split([System.Environment]::NewLine) )
{
$line = $line -replace '\[Microsoft.SqlServer.*.\]', '[object]'
# Reset variables which are used to determine what kind of line this is currently on
$endOfParameter = $false
$formatParam = $false

# Make the objects generic to better support mocking
$line = $line -replace '\[Microsoft.[\d\w\.]+\[\]\]', '[System.Object[]]'
$line = $line -replace '\[Microsoft.[\d\w\.]+\]', '[System.Object]'
$line = $line -replace 'SupportsShouldProcess=\$true, ', ''

if( $line.Contains( '})' ) )
# Determine if any line modifications need to be made
switch -Regex ( $line.TrimEnd() )
{
# Last line of param section
'\}\)$'
{
$line = $line -replace '\}\)(\s+)?$','}'
$endOfDefinition = $true
}

# Last line of a parameter definition
',$'
{
$endOfParameter = $true
}

# Format Param line
'param\($'
{
$line = $line -replace 'param\(','param'
$formatParam = $true
}
}

# Write the current line with an indent
if ( -not [System.String]::IsNullOrEmpty($line.Trim()) )
{
$line = $line.Remove( $line.Length - 2 )
$endOfDefinition = $true
$null = $functionDefinition.Append($indent)
$null = $functionDefinition.AppendLine($line.TrimEnd())
}

if( $line.Trim() -ne '' ) {
$signature += " $line"
} else {
$signature += $line
# Add a blank line after the parameter section
if ( $endOfParameter )
{
$null = $functionDefinition.AppendLine()
}

if( $endOfDefinition )
# Move the right paranthesis at the end of the param section to a new line
if ( $endOfDefinition )
{
$signature += "`n )"
$null = $functionDefinition.Append($indent)
$null = $functionDefinition.AppendLine(')')
break
}

# Move the left parenthesis to the next line after the "param" keyword
if ( $formatParam )
{
$null = $functionDefinition.Append($indent)
$null = $functionDefinition.AppendLine('(')
}
}

# Build the body of the function
$null = $functionDefinition.AppendLine()
$null = $functionDefinition.Append($indent)
$null = $functionDefinition.AppendLine('throw ''{0}: StubNotImplemented'' -f $MyInvocation.MyCommand')
$null = $functionDefinition.AppendLine('}')
$null = $functionDefinition.AppendLine()

# Find any aliases which may exist for the cmdlet
$alias = Get-Alias -Definition $cmdlet.Name -ErrorAction SilentlyContinue

# If any aliases exist
if ( $alias )
{
# Create an alias in the stubs
$null = $functionDefinition.Append("New-Alias -Name $($alias.DisplayName) -Value $($alias.Definition)")
$null = $functionDefinition.AppendLine()
}

"function $($command.Name) {"
"$signature"
""
" throw '{0}: StubNotImplemented' -f $`MyInvocation.MyCommand"
"}"
""
} ) | Out-String | Out-File ( Join-Path -Path $Path -ChildPath "$(( get-module $moduleName -ListAvailable).Name )Stub.psm1") -Encoding utf8 -Append
# Export the function text to the file
$functionDefinition.ToString() | Out-File -FilePath $outFile -Encoding utf8 -Append
}
}

0 comments on commit edb611d

Please sign in to comment.