Private/PowerShell/Read-BrownservePowerShellModule.ps1
function Read-BrownservePowerShellModule { [CmdletBinding()] param ( [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0 )] [string] $ModulePath ) $Return = @{} # Import the module content as an array (so we can read line-by-line) try { $ModuleContent = Get-Content $ModulePath } catch { throw "Failed to import module file content from '$ModulePath'.`n$($_.Exception.Message)" } # The regex for matching the description block $DescriptionOpener = '\.SYNOPSIS' $DescriptionCloser = '#>' # The regex for matching our opening and closing lines $CustomCodeOpener = '\#\#\# Start user defined module steps' $CustomCodeClosing = '\#\#\# End user defined module steps' # Set up our special variables for counting lines $CustomLineCount = 0 $DescLineCount = 0 $CustomCodeStart = $null $CustomCodeEnd = $null $DescriptionStart = $null $DescriptionEnd = $null # First see if we can find the description (it may not be present) $ModuleContent | ForEach-Object { $Line = $_.Trim() # Start by looking for the opening text if (-not $DescriptionStart) { $RegexMatch = [regex]::Match($Line, $DescriptionOpener) if ($RegexMatch.Success) { # Our custom code will start on the next line _after_ this one $DescriptionStart = $DescLineCount + 1 Write-Verbose "Module description starts on line $DescriptionStart" } } if (-not $DescriptionEnd) { $RegexMatch = [regex]::Match($Line, $DescriptionCloser) if ($RegexMatch.Success) { # Our custom code will end on the next line _before_ this one $DescriptionEnd = $DescLineCount - 1 Write-Verbose "User defined module content ends on line $DescriptionEnd" } } # Increment our line counter $DescLineCount ++ } # Start reading through the _init script line by line... $ModuleContent | ForEach-Object { $Line = $_.Trim() # If we haven't already found our custom code opening block then see if this line matches it if (-not $CustomCodeStart) { $RegexMatch = [regex]::Match($Line, $CustomCodeOpener) if ($RegexMatch.Success) { # Our custom code will start on the next line _after_ this one $CustomCodeStart = $CustomLineCount + 1 Write-Verbose "User defined module content starts on line $CustomCodeStart" } } if (-not $CustomCodeEnd) { $RegexMatch = [regex]::Match($Line, $CustomCodeClosing) if ($RegexMatch.Success) { # Our custom code will end on the next line _before_ this one $CustomCodeEnd = $CustomLineCount - 1 Write-Verbose "User defined module content ends on line $CustomCodeEnd" } } # Increment our line counter $CustomLineCount ++ } # Add the returned customisations to the return object if ($CustomCodeStart -and $CustomCodeEnd) { # Extract those lines from the array $CustomCode = $ModuleContent[$CustomCodeStart..$CustomCodeEnd] # Only return something if we have something to return if ($CustomCode) { # This covers cases where people have accidentally deleted the line in the in-between if (-not ($CustomCode -match $CustomCodeOpener)) { $Return.Add('CustomCode', $CustomCode) } } } # Otherwise raise an error else { throw "Unable to find user defined module content block in $ModulePath." } # If we've actually found the description then return it too if ($DescriptionStart -and $DescriptionEnd) { # Extract those lines from the array $Description = $ModuleContent[$DescriptionStart..$DescriptionEnd] # Only return something if we have something to return if ($Description) { $Return.Add('Description', $Description) } } # Don't return an error for descriptions, they are optional if ($Return -ne @{}) { Return [pscustomobject]$Return } } |