PSProject.psm1

function New-PSProject {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$ProjectName,

        [Parameter(Mandatory = $false)]
        [string]$FilePath,

        [Parameter(Mandatory = $false, HelpMessage = "This variable holds the details which gets added to module manifest file")]
        [hashtable]$ModuleDetails,

        [Parameter(Mandatory = $false)]
        [switch]$Advanced
    )
    
    begin {
        #region parameters

        $directories = @("Classes", "Private", "Public", "en-US", "formats", "types", "Tests")
        $functionFileName = "Get-Something.ps1"
        $classFileName = "class.ps1"
        $aboutHelpFile = "about_$ProjectName.help.txt"
        $readMe = "README.md"
        $formats = @{
            "List" = "$ProjectName.ListView.ps1xml"
            "Table" = "$ProjectName.TableView.ps1xml"
        }
        $types = "$ProjectName.types.ps1xml"
        $private = "common.ps1"

        #Model file contents
        $moduleContents = 'Get-ChildItem -Path "$PSScriptRoot\*.ps1" | ForEach-Object { . $_.FullName }'
        $functionContents = _function
        $classContents = _class
        $aboutContents = _about -ModuleName $ProjectName
        $listContents = _list -ModuleName $ProjectName
        $tableContents = _table -ModuleName $ProjectName
        $typeContents = _type -ModuleName $ProjectName
        $readMeContents = _readMe -ModuleName $ProjectName

        if (!($PSBoundParameters.ContainsKey("FilePath"))) {
            $FilePath = $PSScriptRoot
        }
        
        $projectPath = "$FilePath\$ProjectName"

        if (!($PSBoundParameters.ContainsKey("ModuleDetails"))) {
            $ModuleDetails = @{
                Path = "$projectPath\$ProjectName.psd1"
                Guid = New-Guid
                Author = $env:USERNAME
                CompanyName = 'Unknown'
                RootModule = "$ProjectName.psm1"
                TypesToProcess = @(".\$types")
                FormatsToProcess = @(".\$ProjectName.format.ps1xml")
            }
        }

        Write-Verbose "Begin!"

        #endregion parameters
    }
    
    process {
        try {

            Write-Verbose "Creating new project"

            if ($Advanced.IsPresent) {
                
                #region CREATE PROJECT FOLDER STRUCTURE

                # creating project directory
                New-Item $projectPath -ItemType Directory | Out-Null

                # creating sub folder for publishing module
                New-Item "$projectPath\$ProjectName" -ItemType Directory | Out-Null

                # 1) create module manifest
                New-ModuleManifest @ModuleDetails

                # 2) create psm1 file for the module
                New-Item -Path $projectPath -Name "$ProjectName.psm1" -ItemType File | Out-Null
                $moduleContents | Set-Content "$projectPath\$ProjectName.psm1"

                # 3) create read me
                New-Item -Path $projectPath -Name $readMe -ItemType File | Out-Null
                $readMeContents | Set-Content "$projectPath\$readMe"

                # publish to folder
                Copy-Item ("$projectPath\$ProjectName.psm1", "$projectPath\$ProjectName.psd1") -Destination "$projectPath\$ProjectName"

                foreach ($directory in $directories) {
                    New-Item $projectPath -Name $directory -ItemType Directory | Out-Null
                    if ($directory -eq "Classes") {
                        New-Item "$projectPath\$directory" -Name $classFileName -ItemType File | Out-Null
                        $classContents | Set-Content "$projectPath\$directory\$classFileName"
                    }
                    elseif ($directory -eq "Public") {
                        New-Item "$projectPath\$directory" -Name $functionFileName -ItemType File | Out-Null
                        $functionContents | Set-Content "$projectPath\$directory\$functionFileName"
                    }
                    elseif ($directory -eq "Private") {
                        New-Item "$projectPath\$directory" -Name $private -ItemType File | Out-Null
                    }
                    elseif ($directory -eq "formats") {
                        New-Item "$projectPath\$directory" -Name $formats.List -ItemType File | Out-Null
                        $listContents | Set-Content "$projectPath\$directory\$($formats.List)"

                        New-Item "$projectPath\$directory" -Name $formats.Table -ItemType File | Out-Null
                        $tableContents | Set-Content "$projectPath\$directory\$($formats.Table)"
                    }
                    elseif ($directory -eq "types") {
                        New-Item "$projectPath\$directory" -Name $types -ItemType File | Out-Null
                        $typeContents | Set-Content "$projectPath\$directory\$types"
                    }
                    elseif ($directory -eq "en-US") {
                        New-Item "$projectPath\$directory" -Name $aboutHelpFile -ItemType File | Out-Null
                        $aboutContents | Set-Content "$projectPath\$directory\$aboutHelpFile"
                    }
                    elseif ($directory -eq "Tests") {
                        New-Item "$projectPath\$directory" -Name "$($functionFileName.Replace(".ps1", ".Tests.ps1"))" -ItemType File | Out-Null
                    }
                }

                #endregion CREATE PROJECT FOLDER STRUCTURE

            } else {
                # creating project directory
                New-Item $projectPath -ItemType Directory | Out-Null

                # 1) create module manifest
                New-ModuleManifest @ModuleDetails

                # 2) create psm1 file for the module
                New-Item -Path $projectPath -Name "$ProjectName.psm1" -ItemType File | Out-Null
                $moduleContents | Set-Content "$projectPath\$ProjectName.psm1"

                New-Item $projectPath -Name $functionFileName -ItemType File | Out-Null
                $functionContents | Set-Content "$projectPath\$functionFileName"

                # 3) create read me
                New-Item -Path $projectPath -Name $readMe -ItemType File | Out-Null
                $readMeContents | Set-Content "$projectPath\$readMe"

            }
        }
        catch {
            Write-Host $_ -ForegroundColor Red
        }
    }
    
    end {
        Write-Verbose "End!"
    }
}

function _function {
    $contents = '
function Verb-Noun {
    <#
    .SYNOPSIS
        Short description
    .DESCRIPTION
        Long description
    .EXAMPLE
        PS C:\> <example usage>
        Explanation of what the example does
    .INPUTS
        Inputs (if any)
    .OUTPUTS
        Output (if any)
    .NOTES
        General notes
    #>
     
    [CmdletBinding()]
    param (
        [Parameter()]
        [TypeName]
        $ParameterName
    )
 
    begin {
         
    }
 
    process {
         
    }
 
    end {
         
    }
}
    '

    return $contents.Trim()
}

function _class {
    
    return '
class ClassName {
 
}
    '
.Trim()
}

function _about ($ModuleName) {
    $contents = "
TOPIC
    about_$ModuleName
 
SHORT DESCRIPTION
    {{ Provide a short description about your project or module }}
 
LONG DESCRIPTION
    {{ A detailed explanation about your project or module }}
    "

    return $contents.Trim()
}

function _list ($ModuleName) {
    $contents = "
<?xml version='1.0' encoding='utf-8' ?>
<Configuration>
    <ViewDefinitions>
        <View>
            <Name>$ModuleName.ListView</Name>
            <ViewSelectedBy>
                <TypeName>{{ $($ModuleName)Type }}</TypeName>
            </ViewSelectedBy>
            <ListControl>
                <ListEntries>
                    <ListEntry>
                        <ListItems>
                            <ListItem>
                                <PropertyName>{{ PropertyName }}</PropertyName>
                            </ListItem>
                            <ListItem>
                                <PropertyName>{{ PropertyName }}</PropertyName>
                            </ListItem>
                            <ListItem>
                                <PropertyName>{{ PropertyName }}</PropertyName>
                            </ListItem>
                            <ListItem>
                                <PropertyName>{{ PropertyName }}</PropertyName>
                            </ListItem>
                            <ListItem>
                                <PropertyName>{{ PropertyName }}</PropertyName>
                            </ListItem>
                        </ListItems>
                    </ListEntry>
                </ListEntries>
            </ListControl>
        </View>
    </ViewDefinitions>
</Configuration>
    "

    return $contents.Trim()
}

function _table ($ModuleName) {
    $contents = "
<?xml version='1.0' encoding='utf-8' ?>
<Configuration>
    <ViewDefinitions>
        <View>
            <Name>$ModuleName.TableView</Name>
            <ViewSelectedBy>
                <TypeName>{{ $($ModuleName)Type }}</TypeName>
            </ViewSelectedBy>
            <TableControl>
                <TableHeaders>
                <TableColumnHeader>
                    <Label>{{ PropertyName }}</Label>
                </TableColumnHeader>
                <TableColumnHeader>
                    <Label>{{ PropertyName }}</Label>
                </TableColumnHeader>
                <TableColumnHeader>
                    <Label>{{ PropertyName }}</Label>
                </TableColumnHeader>
                </TableHeaders>
                <TableRowEntries>
                <TableRowEntry>
                    <TableColumnItems>
                        <TableColumnItem>
                            <PropertyName>{{ PropertyName }}</PropertyName>
                        </TableColumnItem>
                        <TableColumnItem>
                            <PropertyName>{{ PropertyName }}</PropertyName>
                        </TableColumnItem>
                        <TableColumnItem>
                            <PropertyName>{{ PropertyName }}</PropertyName>
                        </TableColumnItem>
                    </TableColumnItems>
                </TableRowEntry>
                </TableRowEntries>
            </TableControl>
        </View>
    </ViewDefinitions>
</Configuration>
    "

    return $contents.Trim()
}

function _type ($ModuleName) {
    $contents =  "
<?xml version='1.0' encoding='utf-8' ?>
<Types>
    <Type>
        <Name>$($ModuleName)</Name>
        <Members>
            <MemberSet>
                <Name>{{ PSStandardMembers }}</Name>
                <Members>
                <PropertySet>
                    <Name>{{ DefaultDisplayPropertySet }}</Name>
                    <ReferencedProperties>
                        <Name>{{ PROPERTYNAME }}</Name>
                        <Name>{{ PROPERTYNAME }}</Name>
                        <Name>{{ PROPERTYNAME }}</Name>
                        <Name>{{ PROPERTYNAME }}</Name>
                    </ReferencedProperties>
                </PropertySet>
                </Members>
            </MemberSet>
        </Members>
    </Type>
</Types>
    "

    return $contents.Trim()
}

function _readMe ($ModuleName) {
    $contents = "
# $($ModuleName.ToUpper())
 
{{ Description }}
    "

    return $contents.Trim()
}

function Merge-Files {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]]$FilePath,

        [Parameter(Mandatory = $true)]
        [string]$Pattern,

        [Parameter(Mandatory = $true)]
        [string]$OutPath
    )
    
    begin {
        Write-Verbose "Begin!"
    }
    
    process {
        try {
            Write-Verbose "Trying to merge files"

            $allFiles = Get-ChildItem $FilePath -Filter $Pattern | Select-Object Name, FullName

            Get-Content $allFiles.FullName -Raw | Set-Content $OutPath
        }
        catch {
            Write-Host $_ -ForegroundColor Red
        }
    }
    
    end {
        Write-Verbose "End!"
    }
}
Export-ModuleMember -Function *-*