Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Create the base module structure for a new module. This is my slight adaptation to Jeff Hick's [original code](https://gist.github.com/jdhitsolutions/6d26c983a13efae93363e0f9a9e2996b) presented at the Chicago PowerShell Conference 2020.
#requires -version 5.1
#requires -module PowerShellGet
<#
The function assumes you have git installed and use it for source control
This code contains hard-coded references for my environment. This file
is offered as educational and reference material. It will not run for you
without revision.
#>
Function New-ModuleBase {
[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Mandatory, Position = 0)]
[ValidateNotNullorEmpty()]
[string] $ModuleName,
[string] $ModulePath=(Get-Location),
[Parameter(Mandatory)]
[ValidateNotNullorEmpty()]
[string] $Description,
[string] $Author,
[Parameter(HelpMessage = "Enter a list of function names you plan to write")]
[string[]] $Functions,
[ValidateSet("Desktop", "Core")]
[string[]] $Compatible = @("Desktop", "Core"),
[alias("gh")]
[switch] $GitHub,
[string] $GitHubTokenPath
)
if (-Not(git --version)) {
Write-Error "This function requires that you have git installed, as this module creation function is tied into Git as it's source control provider."
}
if ($PSBoundParameters.ContainsKey('GitHub') -and $null -eq $GitHubTokenPath) {
Write-Error "When specifying the -GitHub switch, you must also specify the -GitHubTokanPath."
break
}
Write-Verbose "Provisioning a new module called $ModuleName"
$Base = $ModulePath
$Path = Join-Path -Path $Base -ChildPath $ModuleName
if (Test-Path -Path $path) {
Write-Warning "A module already exists at $Path"
}
else {
New-Item -Path $base -Name $ModuleName -ItemType Directory
$FolderStructure = "Tests",`
"$(Join-Path -Path Functions -ChildPath Public)",`
"$(Join-Path -Path Functions -ChildPath Private)",`
"$(Join-Path -Path Functions -ChildPath ArgCompleter)",`
"Formats"
Write-Verbose "Creating folder structure"
$FolderStructure | ForEach-Object {
New-Item -Path $path -Name $_ -ItemType Directory
}
Write-Verbose "Creating README.md"
$readme = @"
# $ModuleName
$Description
This module is under development.
Last updated $(Get-Date -format u)
"@
Set-Content -Value $readme -Path (Join-Path -Path $path -ChildPath "README.md")
Write-Verbose "Creating license"
#update your licensing info
$lic = @"
MIT License
Copyright (c) $((Get-Date).Year) - Present $Author
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"@
Set-Content -Value $lic -Path (Join-Path -Path $path -ChildPath "LICENSE")
Write-Verbose "Creating module files"
#you can also set defaults using $PSDefaultParameterValues
$psd1 = @{
Path = "$(Join-Path -Path $path -ChildPath $($modulename+".psd1"))"
Author = $Author
CompanyName = ""
CompatiblePSEditions = $Compatible
Copyright = "2020 - Present $Author"
Description = $description
FunctionsToExport = $functions
RootModule = "$modulename.psm1"
ModuleVersion = "0.0.1"
PowerShellVersion = "5.1"
}
New-ModuleManifest @psd1
$psm1 = @"
#enable verbose messaging in the psm1 file
if (`$MyInvocation.line -match "-verbose") {
`$VerbosePreference = "continue"
}
Write-Verbose "Loading public functions"
#dot source public functions
`$FunctionsPublicFilesPath = `$(Join-Path . Functions Public *.ps1)
Get-ChildItem `$FunctionsPublicFilesPath |
ForEach-Object {
Write-Verbose `$_.fullname
. `$_.fullname
}
Write-Verbose "Loading private functions"
#dot source private functions
`$FunctionsPrivateFilesPath = `$(Join-Path . Functions Private *.ps1)
Get-ChildItem `$FunctionsPublicFilesPath |
ForEach-Object {
Write-Verbose `$_.fullname
. `$_.fullname
}
Write-Verbose "Loading public ArgCompleters functions"
#dot source public functions
`$FunctionsArgCompleterFilesPath = `$(Join-Path . Functions ArgCompleter *.ps1)
Get-ChildItem `$FunctionsArgCompleterFilesPath |
ForEach-Object {
Write-Verbose `$_.fullname
. `$_.fullname
}
"@
Set-Content -Value $psm1 -Path (Join-Path -Path $path -ChildPath "$modulename.psm1")
if ($Functions) {
foreach ($f in $Functions) {
Write-Verbose "Creating Function ``$f`` .ps1 file in $(Join-Path $Path Functions Public)"
New-Item -Path "$(Join-Path $path Functions Public)" `
-Name "$f.ps1"
$txt = @"
<#
.SYNOPSIS
.DESCRIPTION
.EXAMPLE
.NOTES
Author: $Author
Handle:
Site:
#>
Function $f`(){
[CmdletBinding()]
Param()
Begin {
Write-Verbose "[BEGIN ] Starting `$(`$MyInvocation.MyCommand)"
}
Process {
Write-Verbose "[PROCESS] Processing"
}
End {
Write-Verbose "[END ] Starting `$(`$MyInvocation.MyCommand)"
}
}
"@
Set-Content -Value $txt -Path "$(Join-Path $path Functions Public $($f+".ps1"))"
}
}
Write-Verbose "Creating changelog.md"
$change = @"
# Changelog for $ModuleName
## v$($psd1.moduleVersion)
+ Initial file commit.
"@
Set-Content -Value $change -Path (Join-Path -Path $path -ChildPath "changelog.md")
Write-Verbose "Inititalizing git"
#my git configuration is already configured with global settings and excludes
if ($pscmdlet.ShouldProcess($path, "Initialize git")) {
git init $Path
Set-Location $Path
git add .
git commit -m "Initial git commit"
}
if ($GitHub) {
Write-Verbose "Creating private GitHub repo"
#my gittoken is stored in a CMS Mesage
$token = Unprotect-CmsMessage -path $GitHubTokenPath
#parameters for my New-GitHubRepository function
$new = @{
Name = $ModuleName
Description = $Description
Private = $True
NoWiki = $True
UserToken = $token
}
$repo = New-GitHubRepository @new
Write-Verbose "Updating the module manifest"
$up = @{
Path = "$(Join-Path $path $("$modulename".psd1))"
ProjectURI = $repo.URL
LicenseURI = "$($repo.URL)/blob/master/license.txt"
}
Update-ModuleManifest @up
git add .
git commit -m "manifest update"
if ($pscmdlet.ShouldProcess($repo.url, "Adding remote repo")) {
git remote add origin $repo.clone
git push -u origin master
}
}
} #else path is ok
}
Function New-GitHubRepository {
<#
.Synopsis
Create a GitHub repository
.Description
This command will create a GitHub repository online. The command assumes you have a Github account.
#>
[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Position = 0, Mandatory, HelpMessage = "Enter the new repository name")]
[ValidateNotNullorEmpty()]
# The name for the new repository.
[string]$Name,
# Add a repository description
[string]$Description,
#Make the repository private
[switch]$Private,
#Turn off the repository Wiki
[switch]$NoWiki,
#Turn off Issues
[switch]$NoIssues,
#Disallow downloads
[switch]$NoDownloads,
#auto setup with a README file
[switch]$AutoInitialize,
#license templates found at https://github.com/github/choosealicense.com/tree/gh-pages/_licenses
[ValidateSet("MIT", "apache-2.0", "gpl-3.0", "ms-pl", "unlicense")]
#specify what type of license to use
[string]$LicenseTemplate,
[Alias("token")]
[ValidateNotNullorEmpty()]
#Specify your user token
[string]$UserToken = $gitToken,
#write full native response to the pipeline
[switch]$Raw
)
Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)"
#display PSBoundparameters formatted nicely for Verbose output
[string]$pb = ($PSBoundParameters | Format-Table -AutoSize | Out-String).TrimEnd()
Write-Verbose "[BEGIN ] PSBoundparameters: `n$($pb.split("`n").Foreach({"$("`t"*2)$_"}) | Out-String) `n"
#create the header
$head = @{
Accept = 'application/vnd.github.v3+json'
Authorization = "token $UserToken"
}
#create a hashtable from properties
$hash = @{
name = $Name
description = $Description
private = $Private -as [boolean]
has_wiki = (-Not $NoWiki)
has_issues = (-Not $NoIssues)
has_downloads = (-Not $NoDownloads)
auto_init = $AutoInitialize -as [boolean]
}
if ($LicenseTemplate) {
$hash.add("license_template", $LicenseTemplate)
}
$body = $hash | ConvertTo-Json
Write-Verbose "[PROCESS] Sending json"
Write-Verbose $body
#define parameter hashtable for Invoke-RestMethod
$paramHash = @{
Uri = "https://api.github.com/user/repos"
Method = "Post"
body = $body
ContentType = "application/json"
Headers = $head
UseBasicParsing = $True
DisableKeepAlive = $True
}
#should process
if ($PSCmdlet.ShouldProcess("$name [$description]")) {
$r = Invoke-RestMethod @paramHash
if ($r.id -AND $Raw) {
Write-Verbose "[PROCESS] Raw result"
$r
}
elseif ($r.id) {
Write-Verbose "[PROCESS] Formatted results"
$r | Select-Object @{Name = "Name"; Expression = { $_.name } },
@{Name = "Description"; Expression = { $_.description } },
@{Name = "Private"; Expression = { $_.private } },
@{Name = "Issues"; Expression = { $_.has_issues } },
@{Name = "Wiki"; Expression = { $_.has_wiki } },
@{Name = "URL"; Expression = { $_.html_url } },
@{Name = "Clone"; Expression = { $_.clone_url } }
}
else {
Write-Warning "Something went wrong with this process"
}
if ($r.clone_url) {
$msg = @"
To push an existing local repository to Github run these commands:
-> git remote add origin $($r.clone_url)"
-> git push -u origin master
"@
Write-Host $msg -ForegroundColor Green
}
}
Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment