[cmdletbinding(DefaultParameterSetName='Scope')] Param( [Parameter(Mandatory = $true, ParameterSetName = 'ModulePath')] [ValidateNotNullOrEmpty()] [String]$ModulePath, # Path to install the module to, PSModulePath "CurrentUser" or "AllUsers", if not provided "CurrentUser" used. [Parameter(ParameterSetName = 'Scope')] [ValidateSet('CurrentUser', 'AllUsers')] [string] $Scope = 'CurrentUser', [Parameter(Mandatory=$true, ParameterSetName = 'PreCheckOnly')] [switch]$PreCheckOnly, [Parameter(ParameterSetName = 'ModulePath')] [Parameter(ParameterSetName = 'Scope')] [switch]$SkipPreChecks, [Parameter(ParameterSetName = 'ModulePath')] [Parameter(ParameterSetName = 'Scope')] [switch]$SkipPostChecks, [Parameter(ParameterSetName = 'ModulePath')] [Parameter(ParameterSetName = 'Scope')] [switch]$SkipPesterTests, [Parameter(ParameterSetName = 'ModulePath')] [Parameter(ParameterSetName = 'Scope')] [switch]$SkipHelp, [Parameter(ParameterSetName = 'ModulePath')] [Parameter(ParameterSetName = 'Scope')] [switch]$CleanModuleDir ) Function Show-Warning { param( [Parameter(Position=0,ValueFromPipeline=$true)] $message ) process { write-output "##vso[task.logissue type=warning]File $message" $message >> $script:warningfile } } if ($PSScriptRoot) { $workingdir = Split-Path -Parent $PSScriptRoot Push-Location $workingdir } $psdpath = Get-Item "*.psd1" if (-not $psdpath -or $psdpath.count -gt 1) { if ($PSScriptRoot) { Pop-Location } throw "Did not find a unique PSD file " } else { try {$null = Test-ModuleManifest -Path $psdpath -ErrorAction stop} catch {throw $_ ; return} $ModuleName = $psdpath.Name -replace '\.psd1$' , '' $Settings = $(& ([scriptblock]::Create(($psdpath | Get-Content -Raw)))) $approvedVerbs = Get-Verb | Select-Object -ExpandProperty verb $script:warningfile = Join-Path -Path $pwd -ChildPath "warnings.txt" } #pre-build checks - manifest found, files in it found, public functions and aliases loaded in it. Public functions correct. if (-not $SkipPreChecks) { #Check files in the manifest are present foreach ($file in $Settings.FileList) { if (-not (Test-Path $file)) { Show-Warning "File $file in the manifest file list is not present" } } #Check files in public have Approved_verb-noun names and are 1 function using the file name as its name with # its name and any alias names in the manifest; function should have a param block and help should be in an MD file # We will want a regex which captures from "function verb-noun {" to its closing "}" # need to match each { to a } - $reg is based on https://stackoverflow.com/questions/7898310/using-regex-to-balance-match-parenthesis $reg = [Regex]::new(@" function\s*[-\w]+\s*{ # The function name and opening '{' (?: [^{}]+ # Match all non-braces | (? { ) # Match '{', and capture into 'open' | (?<-open> } ) # Match '}', and delete the 'open' capture )* (?(open)(?!)) # Fails if 'open' stack isn't empty } # Functions closing '}' "@, 57) # 57 = compile,multi-line ignore case and white space. foreach ($file in (Get-Item .\Public\*.ps1)) { $name = $file.name -replace(".ps1","") if ($name -notmatch ("(\w+)-\w+")) {Show-Warning "$name in the public folder is not a verb-noun name"} elseif ($Matches[1] -notin $approvedVerbs) {Show-Warning "$name in the public folder does not start with an approved verb"} if(-not ($Settings.FunctionsToExport -ceq $name)) { Show-Warning ('File {0} in the public folder does not match an exported function in the manifest' -f $file.name) } else { $fileContent = Get-Content $file -Raw $m = $reg.Matches($fileContent) if ($m.Count -eq 0) {Show-Warning ('Could not find {0} function in {1}' -f $name, $file.name); continue} elseif ($m.Count -ge 2) {Show-Warning ('Multiple functions in {0}' -f $item.name) ; Continue} elseif ($m[0] -imatch "^\function\s" -and $m[0] -cnotmatch "^\w+\s+$name") {Show-Warning ('function name does not match file name for {0}' -f $file.name)} #$m[0] runs form the f of function to its final } -find the section up to param, check for aliases & comment-based help $m2 = [regex]::Match($m[0],"^.*?param",17) # 17 = multi-line, ignnore case if (-not $m2.Success) {Show-Warning "function $name has no param() block"} else { if ($m2.value -match "(?