diff --git a/.build/scripts/Build-PSModule.ps1 b/.build/scripts/Build-PSModule.ps1
index b27e72b..bf51c80 100644
--- a/.build/scripts/Build-PSModule.ps1
+++ b/.build/scripts/Build-PSModule.ps1
@@ -148,6 +148,10 @@ function Build-PSModule {
# Compile to nupkg (run in isolated scope to suppress all output)
$savedGlobalVerbose = $global:VerbosePreference
+ # Compress to zip
+ $zipOutputPath = "$outputPath\$moduleName.zip"
+ Compress-Archive -Path $outputModulePath -DestinationPath $zipOutputPath -Verbose:$false
+
$nupkgOutputPath = & {
$VerbosePreference = 'SilentlyContinue'
$global:VerbosePreference = 'SilentlyContinue'
@@ -169,6 +173,13 @@ function Build-PSModule {
$global:VerbosePreference = $savedGlobalVerbose
+ # Hashes
+ $algorithm = 'sha256'
+ $zipOutputPath, $nupkgOutputPath | foreach {
+ $hash = (Get-FileHash -Path $_ -Algorithm $algorithm).Hash
+ Set-Content -Path "$_.$algorithm" -Value $hash -NoNewline -Encoding utf8
+ }
+
Write-Verbose "Module built successfully to: $nupkgOutputPath"
}
diff --git a/.build/scripts/Publish-GitHubModule.ps1 b/.build/scripts/Publish-GitHubModule.ps1
index 571933d..f5d01f9 100644
--- a/.build/scripts/Publish-GitHubModule.ps1
+++ b/.build/scripts/Publish-GitHubModule.ps1
@@ -160,12 +160,20 @@ function Publish-GitHubModule {
Write-Verbose "Package URL: https://github.com/$Owner/$Repository/packages"
# Set environment variables for release
- "module_name=$ModuleName" | Out-File -FilePath $env:GITHUB_ENV -Append
+ "module_name=$moduleName" | Out-File -FilePath $env:GITHUB_ENV -Append
"module_version=$version" | Out-File -FilePath $env:GITHUB_ENV -Append
- $nupkgHash = (Get-FileHash -Path $nupkgFile.FullName -Algorithm SHA256).Hash
- "nupkg_hash=$nupkgHash" | Out-File -FilePath $env:GITHUB_ENV -Append
- "nupkg_name=$($nupkgFile.Name)" | Out-File -FilePath $env:GITHUB_ENV -Append
+ $nupkgRelPath = ".output/$moduleName.$version.nupkg"
+ $zipRelPath = ".output/$moduleName.zip"
+ $algorithm = 'sha256'
+ $nupkgHashPath, $zipHashPath = $nupkgRelPath, $zipRelPath | foreach {
+ "$_.$algorithm"
+ }
+
+ "nupkg_path=$nupkgRelPath" | Out-File -FilePath $env:GITHUB_ENV -Append
+ "zip_path=$zipRelPath" | Out-File -FilePath $env:GITHUB_ENV -Append
+ "nupkg_hash_path=$nupkgHashPath" | Out-File -FilePath $env:GITHUB_ENV -Append
+ "zip_hash_path=$zipHashPath" | Out-File -FilePath $env:GITHUB_ENV -Append
}
finally {
# Clean up - remove the source
diff --git a/.build/scripts/Publish-PSGalleryModule.ps1 b/.build/scripts/Publish-PSGalleryModule.ps1
deleted file mode 100644
index 75695e0..0000000
--- a/.build/scripts/Publish-PSGalleryModule.ps1
+++ /dev/null
@@ -1,228 +0,0 @@
-<#
- .SYNOPSIS
- Publishes a PowerShell module to PowerShell Gallery.
-
- .DESCRIPTION
- Downloads the latest release from GitHub and publishes the module package to PowerShell Gallery.
- Requires a PowerShell Gallery API key to be provided.
-
- .PARAMETER Owner
- GitHub repository owner (user or organisation).
- If not provided, uses GITHUB_OWNER environment variable.
-
- .PARAMETER Repository
- GitHub repository name.
- If not provided, uses GITHUB_REPOSITORY environment variable.
-
- .PARAMETER Token
- GitHub Personal Access Token with repository read permissions.
- If not provided, uses GITHUB_TOKEN environment variable.
-
- .PARAMETER ApiKey
- PowerShell Gallery API key for publishing modules.
- If not provided, uses PSGALLERY_API_KEY environment variable.
-
- .PARAMETER Force
- Suppresses confirmation prompts during module publishing.
-#>
-[CmdletBinding(SupportsShouldProcess)]
-param(
- [ValidateNotNullOrEmpty()]
- [string]
- $Owner = $env:GITHUB_OWNER,
-
- [ValidateNotNullOrEmpty()]
- [string]
- $Repository = $env:GITHUB_REPOSITORY,
-
- [ValidateNotNullOrEmpty()]
- [string]
- $Token = $env:GITHUB_TOKEN,
-
- [ValidateNotNullOrEmpty()]
- [string]
- $ApiKey = $env:PSGALLERY_API_KEY,
-
- [switch]
- $Force
-)
-
-$ErrorActionPreference = 'Stop'
-$ProgressPreference = 'SilentlyContinue'
-
-function Publish-PSGalleryModule {
- [CmdletBinding(SupportsShouldProcess)]
- <#
- .SYNOPSIS
- Publishes a PowerShell module to PowerShell Gallery.
-
- .DESCRIPTION
- Downloads the latest release from GitHub and publishes the module package to PowerShell Gallery.
- Requires a PowerShell Gallery API key to be provided.
-
- .PARAMETER Owner
- GitHub repository owner (user or organisation).
-
- .PARAMETER Repository
- GitHub repository name.
-
- .PARAMETER Token
- GitHub Personal Access Token with repository read permissions.
-
- .PARAMETER ApiKey
- PowerShell Gallery API key for publishing modules.
-
- .PARAMETER Force
- Suppresses confirmation prompts during module publishing.
- #>
- param(
- [ValidateNotNullOrEmpty()]
- [string]
- $Owner = $env:GITHUB_OWNER,
-
- [ValidateNotNullOrEmpty()]
- [string]
- $Repository = $env:GITHUB_REPOSITORY,
-
- [ValidateNotNullOrEmpty()]
- [string]
- $Token = $env:GITHUB_TOKEN,
-
- [ValidateNotNullOrEmpty()]
- [string]
- $ApiKey = $env:PSGALLERY_API_KEY,
-
- [switch]
- $Force
- )
-
- if ($Force) {
- $ConfirmPreference = 'None'
- }
-
- # Validate required parameters
- if (-not $Owner) {
- throw 'GitHub owner is required. Set GITHUB_OWNER environment variable or provide -Owner parameter.'
- }
-
- if (-not $Repository) {
- throw 'GitHub repository is required. Set GITHUB_REPOSITORY environment variable or provide -Repository parameter.'
- }
-
- if (-not $Token) {
- throw 'GitHub token is required. Set GITHUB_TOKEN environment variable or provide -Token parameter.'
- }
-
- if (-not $ApiKey) {
- throw 'PowerShell Gallery API key is required. Set PSGALLERY_API_KEY environment variable or provide -ApiKey parameter.'
- }
-
- $gitRoot = Resolve-Path -Path "$PSScriptRoot\..\.."
- $tempPath = "$gitRoot\.temp"
-
- # Clean up temp directory if it exists
- if (Test-Path -Path $tempPath) {
- Remove-Item -Path $tempPath -Recurse -Force
- }
-
- New-Item -Path $tempPath -ItemType Directory -Force > $null
-
- try {
- # Get latest release from GitHub
- Write-Verbose 'Getting latest release from GitHub...'
- $headers = @{
- 'Authorization' = "Bearer $Token"
- 'Accept' = 'application/vnd.github.v3+json'
- }
-
- $apiUrl = "https://api.github.com/repos/$Owner/$Repository/releases/latest"
-
- try {
- $release = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Get
- }
- catch {
- if ($_.Exception.Response.StatusCode -eq 404) {
- throw "No releases found for repository '$Owner/$Repository'. Create a release first."
- }
- throw "Failed to get latest release: $_"
- }
-
- Write-Verbose "Found release: $($release.tag_name)"
-
- # Find .nupkg asset
- $nupkgAsset = $release.assets | where name -like '*.nupkg' | select -First 1
-
- if (-not $nupkgAsset) {
- throw "No .nupkg file found in release '$($release.tag_name)'. Ensure the release contains a module package."
- }
-
- Write-Verbose "Found package: $($nupkgAsset.name)"
-
- # Download .nupkg file
- $nupkgPath = "$tempPath\$($nupkgAsset.name)"
-
- Write-Verbose "Downloading package from: $($nupkgAsset.browser_download_url)"
-
- try {
- Invoke-WebRequest -Uri $nupkgAsset.browser_download_url -OutFile $nupkgPath -Headers $headers
- }
- catch {
- throw "Failed to download package: $_"
- }
-
- if (-not (Test-Path -Path $nupkgPath)) {
- throw "Package download failed - file not found at: $nupkgPath"
- }
-
- # Extract module name and version from filename
- $packageName = [IO.Path]::GetFileNameWithoutExtension($nupkgAsset.name)
- $parts = $packageName -split '\.'
-
- if ($parts.Count -lt 4) {
- throw "Unable to parse module name and version from package: $($nupkgAsset.name)"
- }
-
- $moduleName = ($parts[0..($parts.Count - 4)] -join '.')
- $version = ($parts[($parts.Count - 3)..($parts.Count - 1)] -join '.')
-
- Write-Verbose "Module: $moduleName"
- Write-Verbose "Version: $version"
-
- # Push to PowerShell Gallery
- if ($PSCmdlet.ShouldProcess($nupkgPath, 'Publish to PowerShell Gallery')) {
- Write-Verbose 'Pushing package to PowerShell Gallery...'
-
- $pushArgs = @(
- 'nuget', 'push', $nupkgPath,
- '--api-key', $ApiKey,
- '--source', 'https://www.powershellgallery.com/api/v2/package'
- )
-
- $pushOutput = & dotnet @pushArgs 2>&1
-
- if ($LASTEXITCODE -ne 0) {
- $outputText = $pushOutput -join "`n"
- if ($outputText -match 'already exists') {
- throw "Module '$moduleName' version '$version' already exists in PowerShell Gallery. Increment the version to publish a new version."
- }
- throw "Failed to publish to PowerShell Gallery: $outputText"
- }
-
- Write-Host "Module '$moduleName' version '$version' published successfully to PowerShell Gallery." -ForegroundColor Green
- }
- }
- finally {
- # Clean up temp directory
- if (Test-Path -Path $tempPath) {
- Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
- }
- }
-}
-
-try {
- Publish-PSGalleryModule @PSBoundParameters
-}
-catch {
- Write-Host $_ -ForegroundColor Red
- exit 1
-}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6e0408c..7d9cc74 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -84,8 +84,11 @@ jobs:
# Install the module
Install-PSResource -Name '${{ env.module_name }}' -Repository GitHub -Version ${{ env.module_version }} -Credential $githubCredential
```
-
- ### Hashes (Sha256)
- * **${{ env.nupkg_name }}** - ${{ env.nupkg_hash }}
---
*This release was automatically generated by GitHub Actions*
+ files:
+ ${{ env.nupkg_path }}
+ ${{ env.nupkg_hash_path }}
+ ${{ env.zip_path }}
+ ${{ env.zip_hash_path }}
+ docs/*.md
diff --git a/PSModuleTemplate/PSModuleTemplate.psd1 b/PSModuleTemplate/PSModuleTemplate.psd1
new file mode 100644
index 0000000..c9f083d
--- /dev/null
+++ b/PSModuleTemplate/PSModuleTemplate.psd1
@@ -0,0 +1,132 @@
+#
+# Module manifest for module 'PSModuleTemplate'
+#
+# Generated by: jdarcyryan
+#
+# Generated on: 22/02/2026
+#
+
+@{
+
+# Script module or binary module file associated with this manifest.
+RootModule = 'PSModuleTemplate.psm1'
+
+# Version number of this module.
+ModuleVersion = '0.1.0'
+
+# Supported PSEditions
+# CompatiblePSEditions = @()
+
+# ID used to uniquely identify this module
+GUID = '3101ef4b-0651-47b8-ac62-adbe531f52fe'
+
+# Author of this module
+Author = 'jdarcyryan'
+
+# Company or vendor of this module
+CompanyName = 'Unknown'
+
+# Copyright statement for this module
+Copyright = '(c) jdarcyryan. All rights reserved.'
+
+# Description of the functionality provided by this module
+Description = 'PSModuleTemplate'
+
+# Minimum version of the PowerShell engine required by this module
+# PowerShellVersion = ''
+
+# Name of the PowerShell host required by this module
+# PowerShellHostName = ''
+
+# Minimum version of the PowerShell host required by this module
+# PowerShellHostVersion = ''
+
+# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
+# DotNetFrameworkVersion = ''
+
+# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
+# ClrVersion = ''
+
+# Processor architecture (None, X86, Amd64) required by this module
+# ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+# RequiredModules = @()
+
+# Assemblies that must be loaded prior to importing this module
+# RequiredAssemblies = @()
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+# ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+# TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+# FormatsToProcess = @()
+
+# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
+# NestedModules = @()
+
+# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
+FunctionsToExport = @('Get-Greeting', 'Set-SimpleMessage', 'Invoke-ClassDemo')
+
+# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
+CmdletsToExport = @()
+
+# Variables to export from this module
+VariablesToExport = @()
+
+# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
+AliasesToExport = @()
+
+# DSC resources to export from this module
+# DscResourcesToExport = @()
+
+# List of all modules packaged with this module
+# ModuleList = @()
+
+# List of all files packaged with this module
+# FileList = @()
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+ PSData = @{
+
+ # Tags applied to this module. These help with module discovery in online galleries.
+ # Tags = @()
+
+ # A URL to the license for this module.
+ # LicenseUri = ''
+
+ # A URL to the main website for this project.
+ # ProjectUri = ''
+
+ # A URL to an icon representing this module.
+ # IconUri = ''
+
+ # ReleaseNotes of this module
+ # ReleaseNotes = ''
+
+ # Prerelease string of this module
+ # Prerelease = ''
+
+ # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+ # RequireLicenseAcceptance = $false
+
+ # External dependent modules of this module
+ # ExternalModuleDependencies = @()
+
+ } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+
diff --git a/PSModuleTemplate/PSModuleTemplate.psm1 b/PSModuleTemplate/PSModuleTemplate.psm1
new file mode 100644
index 0000000..a29ab77
--- /dev/null
+++ b/PSModuleTemplate/PSModuleTemplate.psm1
@@ -0,0 +1,79 @@
+#region Authoring
+
+###########################################################################
+# PSModuleTemplate
+# Author: James D'Arcy Ryan
+# GitHub: https://github.com/jdarcyryan/PSModuleTemplate
+# License: https://github.com/jdarcyryan/PSModuleTemplate/blob/main/LICENSE
+#
+# A standardized template for creating PowerShell modules with support for
+# classes (PowerShell and C#), private functions, and public functions with
+# automatic discovery and export of commands and aliases.
+#
+# LEGAL NOTICE:
+# The license referenced above applies to the PSModuleTemplate repository
+# and template structure only. Any module created using this template is
+# subject to its own license as specified in the module's LICENSE file,
+# which supersedes the template license for that specific module.
+###########################################################################
+
+#region Authoring
+
+#region Classes
+
+$classesPath = "$PSScriptRoot\classes"
+$classesDataFilePath = "$classesPath\classes.psd1"
+
+if (Test-Path -Path $classesDataFilePath) {
+ $classes = (Import-PowerShellDataFile -Path $classesDataFilePath).classes
+
+ $classes | foreach {
+ $currentClassPath = "$classesPath\$_"
+
+ if (!(Test-Path -Path $currentClassPath)) {
+ throw "Class '$_' does not exist."
+ }
+
+ $extension = (Get-Item -Path $currentClassPath).Extension
+
+ switch ($extension) {
+ '.ps1' {
+ # Process standard classes
+ . $currentClassPath
+ }
+ '.cs' {
+ # Process CSharp classes
+ Add-Type -Path $currentClassPath
+ }
+ default {
+ throw "Unable to process class '$_', $extension is an unsupported file type."
+ }
+ }
+ }
+}
+
+#endregion Classes
+
+#region Private
+
+$privatePath = "$PSScriptRoot\private"
+
+if (Test-Path -Path $privatePath) {
+ Get-ChildItem -Path $privatePath -Filter '*.ps1' | where PSIsContainer -eq $false | foreach {
+ . $_.FullName
+ }
+}
+
+#endregion Private
+
+#region Public
+
+$publicPath = "$PSScriptRoot\public"
+
+if (Test-Path -Path $publicPath) {
+ Get-ChildItem -Path $publicPath -Filter '*.ps1' | where PSIsContainer -eq $false | foreach {
+ . $_.FullName
+ }
+}
+
+#endregion Public
diff --git a/PSModuleTemplate/classes/SimpleCalculator.ps1 b/PSModuleTemplate/classes/SimpleCalculator.ps1
new file mode 100644
index 0000000..2b221ec
--- /dev/null
+++ b/PSModuleTemplate/classes/SimpleCalculator.ps1
@@ -0,0 +1,29 @@
+<#
+.SYNOPSIS
+A simple PowerShell class for basic arithmetic operations.
+
+.DESCRIPTION
+This class provides basic arithmetic functionality including addition and subtraction.
+It demonstrates PowerShell class implementation within the module template.
+#>
+class SimpleCalculator {
+ [int] $LastResult
+
+ SimpleCalculator() {
+ $this.LastResult = 0
+ }
+
+ [int] Add([int] $a, [int] $b) {
+ $this.LastResult = $a + $b
+ return $this.LastResult
+ }
+
+ [int] Subtract([int] $a, [int] $b) {
+ $this.LastResult = $a - $b
+ return $this.LastResult
+ }
+
+ [int] GetLastResult() {
+ return $this.LastResult
+ }
+}
diff --git a/PSModuleTemplate/classes/StringHelper.cs b/PSModuleTemplate/classes/StringHelper.cs
new file mode 100644
index 0000000..145b954
--- /dev/null
+++ b/PSModuleTemplate/classes/StringHelper.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace PSModuleTemplate
+{
+ ///
+ /// A simple C# class for string manipulation operations.
+ ///
+ public class StringHelper
+ {
+ ///
+ /// Reverses the characters in a string.
+ ///
+ /// The string to reverse.
+ /// The reversed string.
+ public static string ReverseString(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ return input;
+
+ char[] charArray = input.ToCharArray();
+ Array.Reverse(charArray);
+ return new string(charArray);
+ }
+
+ ///
+ /// Counts the number of words in a string.
+ ///
+ /// The string to count words in.
+ /// The number of words.
+ public static int CountWords(string input)
+ {
+ if (string.IsNullOrWhiteSpace(input))
+ return 0;
+
+ string[] words = input.Split(new char[] { ' ', '\t', '\n', '\r' },
+ StringSplitOptions.RemoveEmptyEntries);
+ return words.Length;
+ }
+ }
+}
diff --git a/PSModuleTemplate/classes/classes.psd1 b/PSModuleTemplate/classes/classes.psd1
new file mode 100644
index 0000000..3fd24df
--- /dev/null
+++ b/PSModuleTemplate/classes/classes.psd1
@@ -0,0 +1,6 @@
+@{
+ classes = @(
+ ,'SimpleCalculator.ps1'
+ ,'StringHelper.cs'
+ )
+}
diff --git a/PSModuleTemplate/private/Get-CurrentUser.ps1 b/PSModuleTemplate/private/Get-CurrentUser.ps1
new file mode 100644
index 0000000..aa39e25
--- /dev/null
+++ b/PSModuleTemplate/private/Get-CurrentUser.ps1
@@ -0,0 +1,22 @@
+<#
+.SYNOPSIS
+Gets the current user's name from the environment.
+
+.DESCRIPTION
+This private function retrieves the current user's name from the Windows environment variables.
+It provides a simple way to get the logged-in user's identity.
+
+.EXAMPLE
+Get-CurrentUser
+
+Returns the current user's name, e.g., "JohnDoe"
+
+.NOTES
+This is a private helper function used internally by the module.
+#>
+function Get-CurrentUser {
+ [CmdletBinding()]
+ param()
+
+ return $env:USERNAME
+}
diff --git a/PSModuleTemplate/private/Test-StringLength.ps1 b/PSModuleTemplate/private/Test-StringLength.ps1
new file mode 100644
index 0000000..077a56b
--- /dev/null
+++ b/PSModuleTemplate/private/Test-StringLength.ps1
@@ -0,0 +1,48 @@
+<#
+.SYNOPSIS
+Tests if a string meets the specified length requirements.
+
+.DESCRIPTION
+This private function validates whether a given string meets minimum and maximum length requirements.
+It returns a boolean value indicating whether the string passes the length validation.
+
+.PARAMETER InputString
+The string to test for length requirements.
+
+.PARAMETER MinLength
+The minimum required length for the string. Default is 1.
+
+.PARAMETER MaxLength
+The maximum allowed length for the string. Default is 100.
+
+.EXAMPLE
+Test-StringLength -InputString "Hello" -MinLength 3 -MaxLength 10
+
+Returns: $true
+
+.EXAMPLE
+Test-StringLength -InputString "Hi" -MinLength 5
+
+Returns: $false
+
+.NOTES
+This is a private helper function for string validation within the module.
+#>
+function Test-StringLength {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [AllowEmptyString()]
+ [string]
+ $InputString,
+
+ [int]
+ $MinLength = 1,
+
+ [int]
+ $MaxLength = 100
+ )
+
+ $length = $InputString.Length
+ return ($length -ge $MinLength -and $length -le $MaxLength)
+}
diff --git a/PSModuleTemplate/public/Get-Greeting.ps1 b/PSModuleTemplate/public/Get-Greeting.ps1
new file mode 100644
index 0000000..fd600b1
--- /dev/null
+++ b/PSModuleTemplate/public/Get-Greeting.ps1
@@ -0,0 +1,48 @@
+<#
+.SYNOPSIS
+Gets a personalised greeting message.
+
+.DESCRIPTION
+This function creates a friendly greeting message for the specified person.
+It can optionally include the current time in the greeting.
+
+.PARAMETER Name
+The name of the person to greet. This parameter is mandatory.
+
+.PARAMETER IncludeTime
+When specified, includes the current time in the greeting message.
+
+.EXAMPLE
+Get-Greeting -Name "Alice"
+
+Returns: "Hello Alice, how are you today?"
+
+.EXAMPLE
+Get-Greeting -Name "Bob" -IncludeTime
+
+Returns: "Hello Bob, how are you today? The time is 14:30:25"
+
+.NOTES
+This is a simple demonstration function for the PSModuleTemplate.
+#>
+function Get-Greeting {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Name,
+
+ [switch]
+ $IncludeTime
+ )
+
+ $greeting = "Hello $Name, how are you today?"
+
+ if ($IncludeTime) {
+ $currentTime = Get-Date -Format "HH:mm:ss"
+ $greeting += " The time is $currentTime"
+ }
+
+ return $greeting
+}
diff --git a/PSModuleTemplate/public/Invoke-ClassDemo.ps1 b/PSModuleTemplate/public/Invoke-ClassDemo.ps1
new file mode 100644
index 0000000..810c6ab
--- /dev/null
+++ b/PSModuleTemplate/public/Invoke-ClassDemo.ps1
@@ -0,0 +1,68 @@
+<#
+.SYNOPSIS
+Demonstrates the use of both PowerShell and C# classes.
+
+.DESCRIPTION
+This function showcases the SimpleCalculator PowerShell class and StringHelper C# class
+by performing basic operations and returning the results in a formatted object.
+
+.PARAMETER FirstNumber
+The first number for the calculation. Default is 10.
+
+.PARAMETER SecondNumber
+The second number for the calculation. Default is 5.
+
+.PARAMETER TestString
+The string to manipulate using the C# StringHelper class. Default is "Hello World".
+
+.EXAMPLE
+Invoke-ClassDemo
+
+Uses default values to demonstrate both classes.
+
+.EXAMPLE
+Invoke-ClassDemo -FirstNumber 20 -SecondNumber 8 -TestString "PowerShell Rocks"
+
+Performs calculations with 20 and 8, and manipulates the string "PowerShell Rocks".
+
+.NOTES
+This function demonstrates integration between PowerShell and C# classes within the module.
+#>
+function Invoke-ClassDemo {
+ [CmdletBinding()]
+ param(
+ [int]
+ $FirstNumber = 10,
+
+ [int]
+ $SecondNumber = 5,
+
+ [string]
+ $TestString = "Hello World"
+ )
+
+ # Create an instance of the PowerShell class
+ $calculator = [SimpleCalculator]::new()
+
+ # Perform calculations
+ $addResult = $calculator.Add($FirstNumber, $SecondNumber)
+ $subtractResult = $calculator.Subtract($FirstNumber, $SecondNumber)
+
+ # Use the C# class static methods
+ $reversedString = [PSModuleTemplate.StringHelper]::ReverseString($TestString)
+ $wordCount = [PSModuleTemplate.StringHelper]::CountWords($TestString)
+
+ # Return results as a custom object
+ return [PSCustomObject]@{
+ CalculatorResults = @{
+ Addition = $addResult
+ Subtraction = $subtractResult
+ LastResult = $calculator.GetLastResult()
+ }
+ StringResults = @{
+ OriginalString = $TestString
+ ReversedString = $reversedString
+ WordCount = $wordCount
+ }
+ }
+}
diff --git a/PSModuleTemplate/public/Set-SimpleMessage.ps1 b/PSModuleTemplate/public/Set-SimpleMessage.ps1
new file mode 100644
index 0000000..4aa5ff1
--- /dev/null
+++ b/PSModuleTemplate/public/Set-SimpleMessage.ps1
@@ -0,0 +1,45 @@
+<#
+.SYNOPSIS
+Sets a simple message to display.
+
+.DESCRIPTION
+This function allows you to set a custom message that can be displayed.
+The message is returned as output and can be stored or displayed as needed.
+
+.PARAMETER Message
+The message text to set. This parameter is mandatory.
+
+.PARAMETER ToUpper
+When specified, converts the message to uppercase before returning it.
+
+.EXAMPLE
+Set-SimpleMessage -Message "Welcome to PowerShell"
+
+Returns: "Welcome to PowerShell"
+
+.EXAMPLE
+Set-SimpleMessage -Message "hello world" -ToUpper
+
+Returns: "HELLO WORLD"
+
+.NOTES
+This function demonstrates basic parameter handling and string manipulation.
+#>
+function Set-SimpleMessage {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Message,
+
+ [switch]
+ $ToUpper
+ )
+
+ if ($ToUpper) {
+ return $Message.ToUpper()
+ }
+
+ return $Message
+}
diff --git a/docs/.gitkeep b/docs/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/Get-Greeting.md b/docs/Get-Greeting.md
new file mode 100644
index 0000000..a1883c0
--- /dev/null
+++ b/docs/Get-Greeting.md
@@ -0,0 +1,56 @@
+# Get-Greeting
+
+## Synopsis
+
+Gets a personalised greeting message.
+
+## Description
+
+This function creates a friendly greeting message for the specified person.
+It can optionally include the current time in the greeting.
+
+## Syntax
+
+```powershell
+Get-Greeting [-Name ] [-IncludeTime] [-Verbose] [-Debug] [-ErrorAction ] [-WarningAction ] [-InformationAction ] [-ProgressAction ] [-ErrorVariable ] [-WarningVariable ] [-InformationVariable ] [-OutVariable ] [-OutBuffer ] [-PipelineVariable ]
+```
+
+## Parameters
+
+### -Name
+
+The name of the person to greet. This parameter is mandatory.
+
+- **Type**: String
+- **Required**: true
+- **Position**: 1
+- **Default value**: None
+- **Accepts pipeline input**: false
+
+### -IncludeTime
+
+When specified, includes the current time in the greeting message.
+
+- **Type**: SwitchParameter
+- **Required**: false
+- **Position**: named
+- **Default value**: False
+- **Accepts pipeline input**: false
+
+## Examples
+
+### Example 1
+
+Returns: "Hello Alice, how are you today?"
+
+```powershell
+Get-Greeting -Name "Alice"
+```
+
+### Example 2
+
+Returns: "Hello Bob, how are you today? The time is 14:30:25"
+
+```powershell
+Get-Greeting -Name "Bob" -IncludeTime
+```
diff --git a/docs/Invoke-ClassDemo.md b/docs/Invoke-ClassDemo.md
new file mode 100644
index 0000000..eb62ad9
--- /dev/null
+++ b/docs/Invoke-ClassDemo.md
@@ -0,0 +1,66 @@
+# Invoke-ClassDemo
+
+## Synopsis
+
+Demonstrates the use of both PowerShell and C# classes.
+
+## Description
+
+This function showcases the SimpleCalculator PowerShell class and StringHelper C# class
+by performing basic operations and returning the results in a formatted object.
+
+## Syntax
+
+```powershell
+Invoke-ClassDemo [[-FirstNumber ]] [[-SecondNumber ]] [[-TestString ]] [-Verbose] [-Debug] [-ErrorAction ] [-WarningAction ] [-InformationAction ] [-ProgressAction ] [-ErrorVariable ] [-WarningVariable ] [-InformationVariable ] [-OutVariable ] [-OutBuffer ] [-PipelineVariable ]
+```
+
+## Parameters
+
+### -FirstNumber
+
+The first number for the calculation. Default is 10.
+
+- **Type**: Int32
+- **Required**: false
+- **Position**: 1
+- **Default value**: 10
+- **Accepts pipeline input**: false
+
+### -SecondNumber
+
+The second number for the calculation. Default is 5.
+
+- **Type**: Int32
+- **Required**: false
+- **Position**: 2
+- **Default value**: 5
+- **Accepts pipeline input**: false
+
+### -TestString
+
+The string to manipulate using the C# StringHelper class. Default is "Hello World".
+
+- **Type**: String
+- **Required**: false
+- **Position**: 3
+- **Default value**: Hello World
+- **Accepts pipeline input**: false
+
+## Examples
+
+### Example 1
+
+Uses default values to demonstrate both classes.
+
+```powershell
+Invoke-ClassDemo
+```
+
+### Example 2
+
+Performs calculations with 20 and 8, and manipulates the string "PowerShell Rocks".
+
+```powershell
+Invoke-ClassDemo -FirstNumber 20 -SecondNumber 8 -TestString "PowerShell Rocks"
+```
diff --git a/docs/Set-SimpleMessage.md b/docs/Set-SimpleMessage.md
new file mode 100644
index 0000000..179611c
--- /dev/null
+++ b/docs/Set-SimpleMessage.md
@@ -0,0 +1,56 @@
+# Set-SimpleMessage
+
+## Synopsis
+
+Sets a simple message to display.
+
+## Description
+
+This function allows you to set a custom message that can be displayed.
+The message is returned as output and can be stored or displayed as needed.
+
+## Syntax
+
+```powershell
+Set-SimpleMessage [-Message ] [-ToUpper] [-Verbose] [-Debug] [-ErrorAction ] [-WarningAction ] [-InformationAction ] [-ProgressAction ] [-ErrorVariable ] [-WarningVariable ] [-InformationVariable ] [-OutVariable ] [-OutBuffer ] [-PipelineVariable ]
+```
+
+## Parameters
+
+### -Message
+
+The message text to set. This parameter is mandatory.
+
+- **Type**: String
+- **Required**: true
+- **Position**: 1
+- **Default value**: None
+- **Accepts pipeline input**: false
+
+### -ToUpper
+
+When specified, converts the message to uppercase before returning it.
+
+- **Type**: SwitchParameter
+- **Required**: false
+- **Position**: named
+- **Default value**: False
+- **Accepts pipeline input**: false
+
+## Examples
+
+### Example 1
+
+Returns: "Welcome to PowerShell"
+
+```powershell
+Set-SimpleMessage -Message "Welcome to PowerShell"
+```
+
+### Example 2
+
+Returns: "HELLO WORLD"
+
+```powershell
+Set-SimpleMessage -Message "hello world" -ToUpper
+```